commit 09778e09 switched from using ioctl(SIOCBRDELBR) for bridge device deletion to using a netlink RTM_DELLINK message, which is the more modern way to delete a bridge (and also doesn't require the bridge to be ~IFF_UP to succeed). However, although older kernels (e.g. 2.6.32, in RHEL6/CentOS6) support deleting *some* link types with RTM_NEWLINK, they don't support deleting bridges, and there is no compile-time way to figure this out. This patch moves the body of the SIOCBRDELBR version of virNetDevBridgeDelete() into a static function, calls the new function from the original, and also calls the new function from the RTM_DELLINK version if the RTM_DELLINK message generates an EOPNOTSUPP error (this version of the function had to be copied essentially verbatim from virNetlinkDelLink() rather than just calling virNetlinkDelLink() in order to avoid logging the "Operation Not Supported" error prior to retrying with SIOCBRDELBR) This resolves a similar issue to that reported in: https://bugzilla.redhat.com/show_bug.cgi?id=1252780 --- Note: this is the version that is simpler, but duplicates an entire function src/util/virnetdevbridge.c | 114 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index ae38901..779b068 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -558,16 +558,9 @@ int virNetDevBridgeCreate(const char *brname) * * Returns 0 in case of success or an errno code in case of failure. */ -#if defined(__linux__) && defined(HAVE_LIBNL) -int virNetDevBridgeDelete(const char *brname) -{ - /* If netlink is available, use it, as it is successful at - * deleting a bridge even if it is currently IFF_UP. - */ - return virNetlinkDelLink(brname); -} -#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRDELBR) -int virNetDevBridgeDelete(const char *brname) +#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRDELBR) +static int +virNetDevBridgeDeleteWithIoctl(const char *brname) { int fd = -1; int ret = -1; @@ -587,8 +580,107 @@ int virNetDevBridgeDelete(const char *brname) VIR_FORCE_CLOSE(fd); return ret; } +#endif + + +#if defined(__linux__) && defined(HAVE_LIBNL) +int +virNetDevBridgeDelete(const char *brname) +{ + /* If netlink is available, use it, as it is successful at + * deleting a bridge even if it is currently IFF_UP. + */ + int rc = -1; + struct nlmsghdr *resp = NULL; + struct nlmsgerr *err; + struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; + unsigned int recvbuflen; + struct nl_msg *nl_msg; + + nl_msg = nlmsg_alloc_simple(RTM_DELLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + + if (nla_put(nl_msg, IFLA_IFNAME, strlen(brname)+1, brname) < 0) + goto buffer_too_small; + + if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { + goto cleanup; + } + + if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL) + goto malformed_resp; + + switch (resp->nlmsg_type) { + case NLMSG_ERROR: + err = (struct nlmsgerr *)NLMSG_DATA(resp); + if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) + goto malformed_resp; + + switch (err->error) { + case 0: + break; + case -EOPNOTSUPP: +# if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRDELBR) + /* fallback to ioctl if netlink doesn't support deleting + * bridges + */ + ignore_value(virNetDevSetOnline(brname, false)); + rc = virNetDevBridgeDeleteWithIoctl(brname); + goto cleanup; +# endif + /* intentionally fall through if virNetDevBridgeDeleteWithIoctl() + * isn't available. + */ + default: + virReportSystemError(-err->error, + _("error destroying bridge interface %s"), + brname); + goto cleanup; + } + break; + + case NLMSG_DONE: + break; + default: + goto malformed_resp; + } + + rc = 0; + cleanup: + nlmsg_free(nl_msg); + VIR_FREE(resp); + return rc; + + malformed_resp: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + goto cleanup; + buffer_too_small: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + goto cleanup; +} + + +#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRDELBR) +int +virNetDevBridgeDelete(const char *brname) +{ + return virNetDevBridgeDeleteWithIoctl(brname); +} + + #elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCIFDESTROY) -int virNetDevBridgeDelete(const char *brname) +int +virNetDevBridgeDelete(const char *brname) { int s; struct ifreq ifr; -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list