[libvirt] [PATCH 2/2] BSD: implement bridge add/remove port and set STP

Roman Bogorodskiy bogorodskiy at gmail.com
Wed Jun 19 16:47:31 UTC 2013


---
 configure.ac               |  11 ++++
 src/util/virnetdevbridge.c | 134 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 59a3d6d..ef246a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2399,6 +2399,17 @@ AC_CHECK_DECLS([link_addr],
                 #include <net/if_dl.h>
                ])
 
+# Check for BSD approach for bridge management
+AC_CHECK_DECLS([BRDGSFD, BRDGADD, BRDGDEL],
+               [AC_DEFINE([HAVE_BSD_BRIDGE_MGMT],
+                          [1],
+                          [whether BSD style bridge management is available])],
+               [],
+               [#include <net/if.h>
+                #include <net/ethernet.h>
+                #include <net/if_bridgevar.h>
+               ])
+
 # Detect when running under the clang static analyzer's scan-build driver
 # or Coverity-prevent's cov-build.  Define STATIC_ANALYSIS accordingly.
 AC_CACHE_CHECK([whether this build is done by a static analysis tool],
diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
index df606d2..ffcb4a4 100644
--- a/src/util/virnetdevbridge.c
+++ b/src/util/virnetdevbridge.c
@@ -45,9 +45,52 @@
 # define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
 #endif
 
+#if defined(HAVE_BSD_BRIDGE_MGMT)
+# include <net/ethernet.h>
+# include <net/if_bridgevar.h>
+#endif
+
 #define VIR_FROM_THIS VIR_FROM_NONE
 
 
+#if defined(HAVE_BSD_BRIDGE_MGMT)
+static int virNetDevBridgeCmd(const char *brname,
+                              u_long op,
+                              void *arg,
+                              size_t argsize)
+{
+    int s;
+    int ret = -1;
+    struct ifdrv ifd;
+
+    memset(&ifd, 0, sizeof(ifd));
+
+    if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Cannot open network interface control socket"));
+        return -1;
+    }
+
+    if (virStrcpyStatic(ifd.ifd_name, brname) == NULL) {
+       virReportSystemError(ERANGE,
+                            _("Network interface name '%s' is too long"),
+                            brname);
+       goto cleanup;
+    }
+
+    ifd.ifd_cmd = op;
+    ifd.ifd_len = argsize;
+    ifd.ifd_data = arg;
+
+    ret = ioctl(s, SIOCSDRVSPEC, &ifd);
+
+cleanup:
+    VIR_FORCE_CLOSE(s);
+
+    return ret;
+}
+#endif
+
 #if defined(HAVE_STRUCT_IFREQ) && defined(__linux__)
 # define SYSFS_NET_DIR "/sys/class/net"
 /*
@@ -322,6 +365,28 @@ cleanup:
     VIR_FORCE_CLOSE(fd);
     return ret;
 }
+#elif defined(HAVE_BSD_BRIDGE_MGMT)
+int virNetDevBridgeAddPort(const char *brname,
+                           const char *ifname)
+{
+    struct ifbreq req;
+
+    memset(&req, 0, sizeof(req));
+    if (virStrcpyStatic(req.ifbr_ifsname, ifname) == NULL) {
+        virReportSystemError(ERANGE,
+                             _("Network interface name '%s' is too long"),
+                             ifname);
+        return -1;
+    }
+
+    if (virNetDevBridgeCmd(brname, BRDGADD, &req, sizeof(req)) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to add bridge %s port %s"), brname, ifname);
+        return -1;
+    }
+
+    return 0;
+}
 #else
 int virNetDevBridgeAddPort(const char *brname,
                            const char *ifname)
@@ -370,6 +435,28 @@ cleanup:
     VIR_FORCE_CLOSE(fd);
     return ret;
 }
+#elif defined(HAVE_BSD_BRIDGE_MGMT)
+int virNetDevBridgeRemovePort(const char *brname,
+                           const char *ifname)
+{
+    struct ifbreq req;
+
+    memset(&req, 0, sizeof(req));
+    if (virStrcpyStatic(req.ifbr_ifsname, ifname) == NULL) {
+        virReportSystemError(ERANGE,
+                             _("Network interface name '%s' is too long"),
+                             ifname);
+        return -1;
+    }
+
+    if (virNetDevBridgeCmd(brname, BRDGDEL, &req, sizeof(req)) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to remove bridge %s port %s"), brname, ifname);
+       return -1;
+    }
+
+    return 0;
+}
 #else
 int virNetDevBridgeRemovePort(const char *brname,
                               const char *ifname)
@@ -501,7 +588,50 @@ cleanup:
     VIR_FORCE_CLOSE(fd);
     return ret;
 }
-#else /* !__linux__ */
+#elif defined(HAVE_BSD_BRIDGE_MGMT)
+int virNetDevBridgeSetSTPDelay(const char *brname,
+                               int delay)
+{
+    struct ifbrparam param;
+
+    /* FreeBSD doesn't allow setting STP delay < 4 */
+    delay = delay < 4 ? 4 : delay;
+    param.ifbrp_fwddelay = ((u_long)delay) & 0xff;
+
+    if (virNetDevBridgeCmd(brname, BRDGSFD, &param, sizeof(param)) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to set STP delay on %s"), brname);
+        return -1;
+    }
+
+    return 0;
+}
+int virNetDevBridgeGetSTPDelay(const char *brname,
+                               int *delay ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS,
+                         _("Unable to get STP delay on %s on this platform"),
+                         brname);
+    return -1;
+}
+
+int virNetDevBridgeSetSTP(const char *brname ATTRIBUTE_UNUSED,
+                          bool enable ATTRIBUTE_UNUSED)
+
+{
+    /* FreeBSD doesn't allow to set STP per bridge,
+     * only per-device in bridge */
+    return 0;
+}
+int virNetDevBridgeGetSTP(const char *brname,
+                          bool *enable ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS,
+                         _("Unable to get STP on %s on this platform"),
+                         brname);
+    return -1;
+}
+#else
 int virNetDevBridgeSetSTPDelay(const char *brname,
                                int delay ATTRIBUTE_UNUSED)
 {
@@ -536,4 +666,4 @@ int virNetDevBridgeGetSTP(const char *brname,
                          brname);
     return -1;
 }
-#endif /* __linux__ */
+#endif
-- 
1.8.2.3




More information about the libvir-list mailing list