]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
util: fallback to ioctl(SIOCBRADDBR) if netlink RTM_NEWLINK fails
authorLaine Stump <laine@laine.org>
Wed, 26 Aug 2015 00:48:19 +0000 (20:48 -0400)
committerLaine Stump <laine@laine.org>
Fri, 28 Aug 2015 20:19:05 +0000 (16:19 -0400)
commit fc7b23db switched from using ioctl(SIOCBRADDBR) for bridge
creation to using a netlink RTM_NEWLINK message with IFLA_INFO_KIND =
"bridge", which is the more modern way to create a bridge. However,
although older kernels (e.g. 2.6.32, in RHEL6/CentOS6) support
creating *some* link types with RTM_NEWLINK, they don't support
creating bridges, and there is no compile-time way to figure this out
(since the "type" isn't an enum, but rather a character string).

This patch moves the body of the SIOCBRADDBR version of
virNetDevBridgeCreate() into a static function, calls the new function
from the original, and also calls the new function from the
RTM_NEWLINK version if the RTM_NEWLINK message generates an EOPNOTSUPP
error.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1252780

src/util/virnetdevbridge.c

index aa255d63f1ff48f1b5139fc23093ac2a34e26b19..ae389016ba4c1360070d596640d7158c054dbc5f 100644 (file)
@@ -394,8 +394,33 @@ virNetDevBridgePortSetUnicastFlood(const char *brname ATTRIBUTE_UNUSED,
  *
  * Returns 0 in case of success or -1 on failure
  */
+#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+static int
+virNetDevBridgeCreateWithIoctl(const char *brname)
+{
+    int fd = -1;
+    int ret = -1;
+
+    if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
+        return -1;
+
+    if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to create bridge %s"), brname);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    return ret;
+}
+#endif
+
 #if defined(__linux__) && defined(HAVE_LIBNL)
-int virNetDevBridgeCreate(const char *brname)
+int
+virNetDevBridgeCreate(const char *brname)
 {
     /* use a netlink RTM_NEWLINK message to create the bridge */
     const char *type = "bridge";
@@ -441,6 +466,17 @@ int virNetDevBridgeCreate(const char *brname)
         switch (err->error) {
         case 0:
             break;
+        case -EOPNOTSUPP:
+# if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+            /* fallback to ioctl if netlink doesn't support creating
+             * bridges
+             */
+            rc = virNetDevBridgeCreateWithIoctl(brname);
+            goto cleanup;
+# endif
+            /* intentionally fall through if virNetDevBridgeCreateWithIoctl()
+             * isn't available.
+             */
         default:
             virReportSystemError(-err->error,
                                  _("error creating bridge interface %s"),
@@ -470,29 +506,19 @@ int virNetDevBridgeCreate(const char *brname)
                    _("allocated netlink buffer is too small"));
     goto cleanup;
 }
-#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
-int virNetDevBridgeCreate(const char *brname)
-{
-    int fd = -1;
-    int ret = -1;
 
-    if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
-        return -1;
 
-    if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
-        virReportSystemError(errno,
-                             _("Unable to create bridge %s"), brname);
-        goto cleanup;
-    }
+#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+int
+virNetDevBridgeCreate(const char *brname)
+{
+    return virNetDevBridgeCreateWithIoctl(brname);
+}
 
-    ret = 0;
 
- cleanup:
-    VIR_FORCE_CLOSE(fd);
-    return ret;
-}
 #elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCIFCREATE2)
-int virNetDevBridgeCreate(const char *brname)
+int
+virNetDevBridgeCreate(const char *brname)
 {
     int s;
     struct ifreq ifr;