--- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list