diff --git a/00d28a78b-check-accept_ra-before-enabling-ipv6-forward.patch b/00d28a78b-check-accept_ra-before-enabling-ipv6-forward.patch new file mode 100644 index 0000000..cf408e4 --- /dev/null +++ b/00d28a78b-check-accept_ra-before-enabling-ipv6-forward.patch @@ -0,0 +1,260 @@ +From 00d28a78b5d1f6eaf79f06ac59e31c568af9da37 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Fri, 3 Mar 2017 14:14:51 +0100 +Subject: [PATCH 5/5] network: check accept_ra before enabling ipv6 forwarding + +When enabling IPv6 on all interfaces, we may get the host Router +Advertisement routes discarded. To avoid this, the user needs to set +accept_ra to 2 for the interfaces with such routes. + +See https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt +on this topic. + +To avoid user mistakenly losing routes on their hosts, check +accept_ra values before enabling IPv6 forwarding. If a RA route is +detected, but neither the corresponding device nor global accept_ra +is set to 2, the network will fail to start. +--- + src/libvirt_private.syms | 1 + + src/network/bridge_driver.c | 16 +++-- + src/util/virnetdevip.c | 158 ++++++++++++++++++++++++++++++++++++++++++++ + src/util/virnetdevip.h | 1 + + 4 files changed, 171 insertions(+), 5 deletions(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 3b2cb83c4..57acfdbb1 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2067,6 +2067,7 @@ virNetDevBridgeSetVlanFiltering; + virNetDevIPAddrAdd; + virNetDevIPAddrDel; + virNetDevIPAddrGet; ++virNetDevIPCheckIPv6Forwarding; + virNetDevIPInfoAddToDev; + virNetDevIPInfoClear; + virNetDevIPRouteAdd; +diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c +index 4d1a44516..a753cd78b 100644 +--- a/src/network/bridge_driver.c ++++ b/src/network/bridge_driver.c +@@ -61,6 +61,7 @@ + #include "virlog.h" + #include "virdnsmasq.h" + #include "configmake.h" ++#include "virnetlink.h" + #include "virnetdev.h" + #include "virnetdevip.h" + #include "virnetdevbridge.h" +@@ -2389,11 +2390,16 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver, + } + + /* If forward.type != NONE, turn on global IP forwarding */ +- if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE && +- networkEnableIPForwarding(v4present, v6present) < 0) { +- virReportSystemError(errno, "%s", +- _("failed to enable IP forwarding")); +- goto err3; ++ if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE) { ++ if (!virNetDevIPCheckIPv6Forwarding()) ++ goto err3; /* Precise error message already provided */ ++ ++ ++ if (networkEnableIPForwarding(v4present, v6present) < 0) { ++ virReportSystemError(errno, "%s", ++ _("failed to enable IP forwarding")); ++ goto err3; ++ } + } + + +diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c +index 42fbba1eb..a4d382427 100644 +--- a/src/util/virnetdevip.c ++++ b/src/util/virnetdevip.c +@@ -508,6 +508,158 @@ virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs, size_t count) + return ret; + } + ++static int ++virNetDevIPGetAcceptRA(const char *ifname) ++{ ++ char *path = NULL; ++ char *buf = NULL; ++ char *suffix; ++ int accept_ra = -1; ++ ++ if (virAsprintf(&path, "/proc/sys/net/ipv6/conf/%s/accept_ra", ++ ifname ? ifname : "all") < 0) ++ goto cleanup; ++ ++ if ((virFileReadAll(path, 512, &buf) < 0) || ++ (virStrToLong_i(buf, &suffix, 10, &accept_ra) < 0)) ++ goto cleanup; ++ ++ cleanup: ++ VIR_FREE(path); ++ VIR_FREE(buf); ++ ++ return accept_ra; ++} ++ ++struct virNetDevIPCheckIPv6ForwardingData { ++ bool hasRARoutes; ++ ++ /* Devices with conflicting accept_ra */ ++ char **devices; ++ size_t ndevices; ++}; ++ ++static int ++virNetDevIPCheckIPv6ForwardingCallback(const struct nlmsghdr *resp, ++ void *opaque) ++{ ++ struct rtmsg *rtmsg = NLMSG_DATA(resp); ++ int accept_ra = -1; ++ struct rtattr *rta; ++ char *ifname = NULL; ++ struct virNetDevIPCheckIPv6ForwardingData *data = opaque; ++ int ret = 0; ++ int len = RTM_PAYLOAD(resp); ++ int oif = -1; ++ ++ /* Ignore messages other than route ones */ ++ if (resp->nlmsg_type != RTM_NEWROUTE) ++ return ret; ++ ++ /* Extract a few attributes */ ++ for (rta = RTM_RTA(rtmsg); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { ++ switch (rta->rta_type) { ++ case RTA_OIF: ++ oif = *(int *)RTA_DATA(rta); ++ ++ if (!(ifname = virNetDevGetName(oif))) ++ goto error; ++ break; ++ } ++ } ++ ++ /* No need to do anything else for non RA routes */ ++ if (rtmsg->rtm_protocol != RTPROT_RA) ++ goto cleanup; ++ ++ data->hasRARoutes = true; ++ ++ /* Check the accept_ra value for the interface */ ++ accept_ra = virNetDevIPGetAcceptRA(ifname); ++ VIR_DEBUG("Checking route for device %s, accept_ra: %d", ifname, accept_ra); ++ ++ if (accept_ra != 2 && VIR_APPEND_ELEMENT(data->devices, data->ndevices, ifname) < 0) ++ goto error; ++ ++ cleanup: ++ VIR_FREE(ifname); ++ return ret; ++ ++ error: ++ ret = -1; ++ goto cleanup; ++} ++ ++bool ++virNetDevIPCheckIPv6Forwarding(void) ++{ ++ struct nl_msg *nlmsg = NULL; ++ bool valid = false; ++ struct rtgenmsg genmsg; ++ size_t i; ++ struct virNetDevIPCheckIPv6ForwardingData data = { ++ .hasRARoutes = false, ++ .devices = NULL, ++ .ndevices = 0 ++ }; ++ ++ ++ /* Prepare the request message */ ++ if (!(nlmsg = nlmsg_alloc_simple(RTM_GETROUTE, ++ NLM_F_REQUEST | NLM_F_DUMP))) { ++ virReportOOMError(); ++ goto cleanup; ++ } ++ ++ memset(&genmsg, 0, sizeof(genmsg)); ++ genmsg.rtgen_family = AF_INET6; ++ ++ if (nlmsg_append(nlmsg, &genmsg, sizeof(genmsg), NLMSG_ALIGNTO) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("allocated netlink buffer is too small")); ++ goto cleanup; ++ } ++ ++ /* Send the request and loop over the responses */ ++ if (virNetlinkDumpCommand(nlmsg, virNetDevIPCheckIPv6ForwardingCallback, ++ 0, 0, NETLINK_ROUTE, 0, &data) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Failed to loop over IPv6 routes")); ++ goto cleanup; ++ } ++ ++ valid = !data.hasRARoutes || data.ndevices == 0; ++ ++ /* Check the global accept_ra if at least one isn't set on a ++ per-device basis */ ++ if (!valid && data.hasRARoutes) { ++ int accept_ra = virNetDevIPGetAcceptRA(NULL); ++ valid = accept_ra == 2; ++ VIR_DEBUG("Checked global accept_ra: %d", accept_ra); ++ } ++ ++ if (!valid) { ++ virBuffer buf = VIR_BUFFER_INITIALIZER; ++ for (i = 0; i < data.ndevices; i++) { ++ virBufferAdd(&buf, data.devices[i], -1); ++ if (i < data.ndevices - 1) ++ virBufferAddLit(&buf, ", "); ++ } ++ ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Check the host setup: enabling IPv6 forwarding with " ++ "RA routes without accept_ra set to 2 is likely to cause " ++ "routes loss. Interfaces to look at: %s"), ++ virBufferCurrentContent(&buf)); ++ virBufferFreeAndReset(&buf); ++ } ++ ++ cleanup: ++ nlmsg_free(nlmsg); ++ for (i = 0; i < data.ndevices; i++) ++ VIR_FREE(data.devices[i]); ++ return valid; ++} + + #else /* defined(__linux__) && defined(HAVE_LIBNL) */ + +@@ -655,6 +807,12 @@ virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs ATTRIBUTE_UNUSED, + return -1; + } + ++bool ++virNetDevIPCheckIPv6Forwarding(void) ++{ ++ VIR_WARN("built without libnl: unable to check if IPv6 forwarding can be safely enabled"); ++ return true; ++} + + #endif /* defined(__linux__) && defined(HAVE_LIBNL) */ + +diff --git a/src/util/virnetdevip.h b/src/util/virnetdevip.h +index b7abdf94d..cc466ca25 100644 +--- a/src/util/virnetdevip.h ++++ b/src/util/virnetdevip.h +@@ -83,6 +83,7 @@ int virNetDevIPAddrGet(const char *ifname, virSocketAddrPtr addr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + int virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs, size_t count) + ATTRIBUTE_NONNULL(1); ++bool virNetDevIPCheckIPv6Forwarding(void); + + /* virNetDevIPRoute object */ + void virNetDevIPRouteFree(virNetDevIPRoutePtr def); +-- +2.12.0 + diff --git a/3ee35d7d6-more-uses-of-SYSCTL_PATH.patch b/3ee35d7d6-more-uses-of-SYSCTL_PATH.patch new file mode 100644 index 0000000..3e6e739 --- /dev/null +++ b/3ee35d7d6-more-uses-of-SYSCTL_PATH.patch @@ -0,0 +1,46 @@ +From 3ee35d7d6caf0ffa722d60251eabec43c094fb12 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Fri, 3 Mar 2017 14:13:49 +0100 +Subject: [PATCH 3/5] bridge_driver.c: more uses of SYSCTL_PATH + +Replace a few occurences of /proc/sys by the corresponding macro +defined a few lines after: SYSCTL_PATH +--- + src/network/bridge_driver.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c +index 32c5ab7a7..4d1a44516 100644 +--- a/src/network/bridge_driver.c ++++ b/src/network/bridge_driver.c +@@ -85,6 +85,8 @@ + */ + #define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024) + ++#define SYSCTL_PATH "/proc/sys" ++ + VIR_LOG_INIT("network.bridge_driver"); + + static virNetworkDriverStatePtr network_driver; +@@ -2092,15 +2094,14 @@ networkEnableIPForwarding(bool enableIPv4, bool enableIPv6) + &enabled, sizeof(enabled)); + #else + if (enableIPv4) +- ret = virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0); ++ ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0); + if (enableIPv6 && ret == 0) +- ret = virFileWriteStr("/proc/sys/net/ipv6/conf/all/forwarding", "1\n", 0); ++ ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0); ++ + #endif + return ret; + } + +-#define SYSCTL_PATH "/proc/sys" +- + static int + networkSetIPv6Sysctls(virNetworkObjPtr network) + { +-- +2.12.0 + diff --git a/5dd607059-add-virNetDevGetName.patch b/5dd607059-add-virNetDevGetName.patch new file mode 100644 index 0000000..5a59dca --- /dev/null +++ b/5dd607059-add-virNetDevGetName.patch @@ -0,0 +1,70 @@ +From 5dd607059d8a98e04024305ae4afbd038aadbdcd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Wed, 15 Mar 2017 14:46:56 +0100 +Subject: [PATCH 4/5] util: add virNetDevGetName() function + +Add a function getting the name of a network interface out of its index. +--- + src/libvirt_private.syms | 1 + + src/util/virnetdev.c | 19 +++++++++++++++++++ + src/util/virnetdev.h | 2 ++ + 3 files changed, 22 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index f03925bc1..3b2cb83c4 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -1995,6 +1995,7 @@ virNetDevGetIndex; + virNetDevGetLinkInfo; + virNetDevGetMAC; + virNetDevGetMTU; ++virNetDevGetName; + virNetDevGetOnline; + virNetDevGetPhysicalFunction; + virNetDevGetPromiscuous; +diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c +index d12324878..91a5274aa 100644 +--- a/src/util/virnetdev.c ++++ b/src/util/virnetdev.c +@@ -899,6 +899,25 @@ virNetDevGetRcvAllMulti(const char *ifname, + return virNetDevGetIFFlag(ifname, VIR_IFF_ALLMULTI, receive); + } + ++char *virNetDevGetName(int ifindex) ++{ ++ char name[IFNAMSIZ]; ++ char *ifname = NULL; ++ ++ memset(&name, 0, sizeof(name)); ++ ++ if (!if_indextoname(ifindex, name)) { ++ virReportSystemError(errno, ++ _("Failed to convert interface index %d to a name"), ++ ifindex); ++ goto cleanup; ++ } ++ ++ ignore_value(VIR_STRDUP(ifname, name)); ++ ++ cleanup: ++ return ifname; ++} + + /** + * virNetDevGetIndex: +diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h +index 236cf83ef..01e9c5b95 100644 +--- a/src/util/virnetdev.h ++++ b/src/util/virnetdev.h +@@ -157,6 +157,8 @@ int virNetDevSetNamespace(const char *ifname, pid_t pidInNs) + int virNetDevSetName(const char *ifname, const char *newifname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + ++char *virNetDevGetName(int ifindex) ++ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + int virNetDevGetIndex(const char *ifname, int *ifindex) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +-- +2.12.0 + diff --git a/754515b7d-add-virNetlinkDumpCommand.patch b/754515b7d-add-virNetlinkDumpCommand.patch new file mode 100644 index 0000000..4b9002d --- /dev/null +++ b/754515b7d-add-virNetlinkDumpCommand.patch @@ -0,0 +1,125 @@ +From 754515b7db6258ab592265b743128353be0cb32b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Fri, 3 Mar 2017 12:22:50 +0100 +Subject: [PATCH 2/5] util: add virNetlinkDumpCommand() + +virNetlinkCommand() processes only one response message, while some +netlink commands, like route dumping, need to process several. +Add virNetlinkDumpCommand() as a virNetlinkCommand() sister. +--- + src/libvirt_private.syms | 1 + + src/util/virnetlink.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/virnetlink.h | 9 ++++++++ + 3 files changed, 68 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index b46e85f63..f03925bc1 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2138,6 +2138,7 @@ virNetDevVPortProfileOpTypeToString; + # util/virnetlink.h + virNetlinkCommand; + virNetlinkDelLink; ++virNetlinkDumpCommand; + virNetlinkDumpLink; + virNetlinkEventAddClient; + virNetlinkEventRemoveClient; +diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c +index be00351db..9bc1f0f2b 100644 +--- a/src/util/virnetlink.c ++++ b/src/util/virnetlink.c +@@ -335,6 +335,52 @@ int virNetlinkCommand(struct nl_msg *nl_msg, + return ret; + } + ++int ++virNetlinkDumpCommand(struct nl_msg *nl_msg, ++ virNetlinkDumpCallback callback, ++ uint32_t src_pid, uint32_t dst_pid, ++ unsigned int protocol, unsigned int groups, ++ void *opaque) ++{ ++ int ret = -1; ++ bool end = false; ++ int len = 0; ++ struct nlmsghdr *resp = NULL; ++ struct nlmsghdr *msg = NULL; ++ ++ struct sockaddr_nl nladdr = { ++ .nl_family = AF_NETLINK, ++ .nl_pid = dst_pid, ++ .nl_groups = 0, ++ }; ++ virNetlinkHandle *nlhandle = NULL; ++ ++ if (!(nlhandle = virNetlinkSendRequest(nl_msg, src_pid, nladdr, ++ protocol, groups))) ++ goto cleanup; ++ ++ while (!end) { ++ len = nl_recv(nlhandle, &nladdr, (unsigned char **)&resp, NULL); ++ ++ for (msg = resp; NLMSG_OK(msg, len); msg = NLMSG_NEXT(msg, len)) { ++ if (msg->nlmsg_type == NLMSG_DONE) ++ end = true; ++ ++ if (virNetlinkGetErrorCode(msg, len) < 0) ++ goto cleanup; ++ ++ if (callback(msg, opaque) < 0) ++ goto cleanup; ++ } ++ } ++ ++ ret = 0; ++ ++ cleanup: ++ virNetlinkFree(nlhandle); ++ return ret; ++} ++ + /** + * virNetlinkDumpLink: + * +@@ -1061,6 +1107,18 @@ int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, + return -1; + } + ++int ++virNetlinkDumpCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, ++ virNetlinkDumpCallback callback ATTRIBUTE_UNUSED, ++ uint32_t src_pid ATTRIBUTE_UNUSED, ++ uint32_t dst_pid ATTRIBUTE_UNUSED, ++ unsigned int protocol ATTRIBUTE_UNUSED, ++ unsigned int groups ATTRIBUTE_UNUSED, ++ void *opaque ATTRIBUTE_UNUSED) ++{ ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); ++ return -1; ++} + + int + virNetlinkDumpLink(const char *ifname ATTRIBUTE_UNUSED, +diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h +index 11e817c82..088b01343 100644 +--- a/src/util/virnetlink.h ++++ b/src/util/virnetlink.h +@@ -52,6 +52,15 @@ int virNetlinkCommand(struct nl_msg *nl_msg, + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups); + ++typedef int (*virNetlinkDumpCallback)(const struct nlmsghdr *resp, ++ void *data); ++ ++int virNetlinkDumpCommand(struct nl_msg *nl_msg, ++ virNetlinkDumpCallback callback, ++ uint32_t src_pid, uint32_t dst_pid, ++ unsigned int protocol, unsigned int groups, ++ void *opaque); ++ + typedef int (*virNetlinkDelLinkFallback)(const char *ifname); + + int virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback); +-- +2.12.0 + diff --git a/d68cb4f55-extract-the-request-sending-code-from-virNetlin.patch b/d68cb4f55-extract-the-request-sending-code-from-virNetlin.patch new file mode 100644 index 0000000..1a744cf --- /dev/null +++ b/d68cb4f55-extract-the-request-sending-code-from-virNetlin.patch @@ -0,0 +1,165 @@ +From d68cb4f554d16c2af79f64749e18d7d6cd9dd5b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= +Date: Fri, 3 Mar 2017 12:16:32 +0100 +Subject: [PATCH 1/5] util: extract the request sending code from + virNetlinkCommand() + +Allow to reuse as much as possible from virNetlinkCommand(). This +comment prepares for the introduction of virNetlinkDumpCommand() +only differing by how it handles the responses. +--- + src/util/virnetlink.c | 89 +++++++++++++++++++++++++++++++-------------------- + 1 file changed, 54 insertions(+), 35 deletions(-) + +diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c +index a5d10fa8e..be00351db 100644 +--- a/src/util/virnetlink.c ++++ b/src/util/virnetlink.c +@@ -209,61 +209,38 @@ virNetlinkCreateSocket(int protocol) + goto cleanup; + } + +- +-/** +- * virNetlinkCommand: +- * @nlmsg: pointer to netlink message +- * @respbuf: pointer to pointer where response buffer will be allocated +- * @respbuflen: pointer to integer holding the size of the response buffer +- * on return of the function. +- * @src_pid: the pid of the process to send a message +- * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel +- * @protocol: netlink protocol +- * @groups: the group identifier +- * +- * Send the given message to the netlink layer and receive response. +- * Returns 0 on success, -1 on error. In case of error, no response +- * buffer will be returned. +- */ +-int virNetlinkCommand(struct nl_msg *nl_msg, +- struct nlmsghdr **resp, unsigned int *respbuflen, +- uint32_t src_pid, uint32_t dst_pid, ++static virNetlinkHandle * ++virNetlinkSendRequest(struct nl_msg *nl_msg, uint32_t src_pid, ++ struct sockaddr_nl nladdr, + unsigned int protocol, unsigned int groups) + { +- int ret = -1; +- struct sockaddr_nl nladdr = { +- .nl_family = AF_NETLINK, +- .nl_pid = dst_pid, +- .nl_groups = 0, +- }; + ssize_t nbytes; +- struct pollfd fds[1]; + int fd; + int n; +- struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); + virNetlinkHandle *nlhandle = NULL; +- int len = 0; ++ struct pollfd fds[1]; ++ struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); + + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); +- goto cleanup; ++ goto error; + } + + if (!(nlhandle = virNetlinkCreateSocket(protocol))) +- goto cleanup; ++ goto error; + + fd = nl_socket_get_fd(nlhandle); + if (fd < 0) { + virReportSystemError(errno, + "%s", _("cannot get netlink socket fd")); +- goto cleanup; ++ goto error; + } + + if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); +- goto cleanup; ++ goto error; + } + + nlmsg_set_dst(nl_msg, &nladdr); +@@ -274,10 +251,11 @@ int virNetlinkCommand(struct nl_msg *nl_msg, + if (nbytes < 0) { + virReportSystemError(errno, + "%s", _("cannot send to netlink socket")); +- goto cleanup; ++ goto error; + } + + memset(fds, 0, sizeof(fds)); ++ + fds[0].fd = fd; + fds[0].events = POLLIN; + +@@ -289,9 +267,51 @@ int virNetlinkCommand(struct nl_msg *nl_msg, + if (n == 0) + virReportSystemError(ETIMEDOUT, "%s", + _("no valid netlink response was received")); +- goto cleanup; + } + ++ return nlhandle; ++ ++ error: ++ virNetlinkFree(nlhandle); ++ return NULL; ++} ++ ++/** ++ * virNetlinkCommand: ++ * @nlmsg: pointer to netlink message ++ * @respbuf: pointer to pointer where response buffer will be allocated ++ * @respbuflen: pointer to integer holding the size of the response buffer ++ * on return of the function. ++ * @src_pid: the pid of the process to send a message ++ * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel ++ * @protocol: netlink protocol ++ * @groups: the group identifier ++ * ++ * Send the given message to the netlink layer and receive response. ++ * Returns 0 on success, -1 on error. In case of error, no response ++ * buffer will be returned. ++ */ ++int virNetlinkCommand(struct nl_msg *nl_msg, ++ struct nlmsghdr **resp, unsigned int *respbuflen, ++ uint32_t src_pid, uint32_t dst_pid, ++ unsigned int protocol, unsigned int groups) ++{ ++ int ret = -1; ++ struct sockaddr_nl nladdr = { ++ .nl_family = AF_NETLINK, ++ .nl_pid = dst_pid, ++ .nl_groups = 0, ++ }; ++ struct pollfd fds[1]; ++ virNetlinkHandle *nlhandle = NULL; ++ int len = 0; ++ ++ memset(fds, 0, sizeof(fds)); ++ ++ if (!(nlhandle = virNetlinkSendRequest(nl_msg, src_pid, nladdr, ++ protocol, groups))) ++ goto cleanup; ++ + len = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL); + if (len == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +@@ -315,7 +335,6 @@ int virNetlinkCommand(struct nl_msg *nl_msg, + return ret; + } + +- + /** + * virNetlinkDumpLink: + * +-- +2.12.0 + diff --git a/libvirt.changes b/libvirt.changes index c2a7f74..22e9543 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,16 @@ +------------------------------------------------------------------- +Wed Mar 22 08:30:55 UTC 2017 - cbosdonnat@suse.com + +- Fail to start network instead of losing routes if IPv6 forwarding + is required. bsc#1025252 + Added patches: + 00d28a78b-check-accept_ra-before-enabling-ipv6-forward.patch + 3ee35d7d6-more-uses-of-SYSCTL_PATH.patch + 5dd607059-add-virNetDevGetName.patch + 754515b7d-add-virNetlinkDumpCommand.patch + d68cb4f55-extract-the-request-sending-code-from-virNetlin.patch + + ------------------------------------------------------------------- Thu Mar 16 14:23:16 UTC 2017 - jfehlig@suse.com diff --git a/libvirt.spec b/libvirt.spec index 553152e..b7b90ca 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -1,7 +1,7 @@ # # spec file for package libvirt # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -319,6 +319,11 @@ Source100: %{name}-rpmlintrc # Upstream patches Patch0: 67dcb797-virTimeBackOffWait-sleepcap.patch Patch1: 85af0b80-qemu-adaptive-montimeout.patch +Patch2: d68cb4f55-extract-the-request-sending-code-from-virNetlin.patch +Patch3: 754515b7d-add-virNetlinkDumpCommand.patch +Patch4: 3ee35d7d6-more-uses-of-SYSCTL_PATH.patch +Patch5: 5dd607059-add-virNetDevGetName.patch +Patch6: 00d28a78b-check-accept_ra-before-enabling-ipv6-forward.patch # Patches pending upstream review Patch100: libxl-dom-reset.patch Patch101: network-don-t-use-dhcp-authoritative-on-static-netwo.patch @@ -818,9 +823,9 @@ capabilities of recent versions of Linux (and other OSes). %package libs Summary: Client side libraries for libvirt +Group: Development/Libraries/C and C++ # So remote clients can access libvirt over SSH tunnel # (client invokes 'nc' against the UNIX socket on the server) -Group: Development/Libraries/C and C++ Requires: netcat-openbsd # Not technically required, but makes 'out-of-box' config # work correctly & doesn't have onerous dependencies @@ -888,6 +893,11 @@ libvirt plugin for NSS for translating domain names into IP addresses. %setup -q %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 %patch100 -p1 %patch101 -p1 %patch150 -p1