---
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, ¶m, 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