[PATCH 0/2] virnetdevbridge: support VLAN configuration on FreeBSD
This series implements VLAN networking on FreeBSD. Specifically, it implements controlling bridge's VLAN filtering via the `macTableManager='libvirt'` in the network XML. And various configurations specified by domain's <vlan> element. I have documented my testing of these configurations here: https://gist.github.com/novel/e26e90f031f965920587bf126899356e I'd definitely appreciate a second pair of eyes on this to make sure the documented behavior matches the XML intent. Roman Bogorodskiy (2): virnetdevbridge: support VLAN filtering setting on FreeBSD virnetdevbridge: support VLAN configuration on FreeBSD src/util/virnetdevbridge.c | 110 +++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-) -- 2.55.0
FreeBSD 15.0+ and newer support VLAN filtering for bridges. It is controlled by the IFBRF_VLANFILTER flag. Implement virNetDevBridgeGetVlanFiltering() and virNetDevBridgeSetVlanFiltering() for systems that have this flag defined. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/util/virnetdevbridge.c | 56 ++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 20c7a25585..c8da3f11ee 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -53,7 +53,8 @@ VIR_LOG_INIT("util.netdevbridge"); static int virNetDevBridgeCmd(const char *brname, u_long op, void *arg, - size_t argsize) + size_t argsize, + bool set) { struct ifdrv ifd = { 0 }; VIR_AUTOCLOSE s = -1; @@ -75,7 +76,7 @@ static int virNetDevBridgeCmd(const char *brname, ifd.ifd_len = argsize; ifd.ifd_data = arg; - return ioctl(s, SIOCSDRVSPEC, &ifd); + return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd); } #endif @@ -693,7 +694,7 @@ int virNetDevBridgeAddPort(const char *brname, return -1; } - if (virNetDevBridgeCmd(brname, BRDGADD, &req, sizeof(req)) < 0) { + if (virNetDevBridgeCmd(brname, BRDGADD, &req, sizeof(req), true) < 0) { virReportSystemError(errno, _("Unable to add bridge %1$s port %2$s"), brname, ifname); return -1; @@ -759,7 +760,7 @@ int virNetDevBridgeRemovePort(const char *brname, return -1; } - if (virNetDevBridgeCmd(brname, BRDGDEL, &req, sizeof(req)) < 0) { + if (virNetDevBridgeCmd(brname, BRDGDEL, &req, sizeof(req), true) < 0) { virReportSystemError(errno, _("Unable to remove bridge %1$s port %2$s"), brname, ifname); return -1; @@ -883,7 +884,7 @@ int virNetDevBridgeSetSTPDelay(const char *brname, delay_seconds = delay_seconds < 4 ? 4 : delay_seconds; param.ifbrp_fwddelay = delay_seconds & 0xff; - if (virNetDevBridgeCmd(brname, BRDGSFD, ¶m, sizeof(param)) < 0) { + if (virNetDevBridgeCmd(brname, BRDGSFD, ¶m, sizeof(param), true) < 0) { virReportSystemError(errno, _("Unable to set STP delay on %1$s"), brname); return -1; @@ -996,6 +997,51 @@ virNetDevBridgeSetVlanFiltering(const char *brname, } +#elif defined(WITH_BSD_BRIDGE_MGMT) && defined(IFBRF_VLANFILTER) +int +virNetDevBridgeGetVlanFiltering(const char *brname, + bool *enable) +{ + struct ifbrparam req; + + if (virNetDevBridgeCmd(brname, BRDGGFLAGS, &req, sizeof(req), false) < 0) { + virReportSystemError(errno, + _("Unable to get bridge %1$s flags"), brname); + return -1; + } + + *enable = !!(req.ifbrp_flags & IFBRF_VLANFILTER); + return 0; +} + + +int +virNetDevBridgeSetVlanFiltering(const char *brname, + bool enable) +{ + struct ifbrparam req; + + if (virNetDevBridgeCmd(brname, BRDGGFLAGS, &req, sizeof(req), false) < 0) { + virReportSystemError(errno, + _("Unable to get bridge %1$s flag"), brname); + return -1; + } + + if (enable) + req.ifbrp_flags |= IFBRF_VLANFILTER; + else + req.ifbrp_flags &= ~IFBRF_VLANFILTER; + + if (virNetDevBridgeCmd(brname, BRDGSFLAGS, &req, sizeof(req), true) < 0) { + virReportSystemError(errno, + _("Unable to set bridge %1$s flag"), brname); + return -1; + } + + return 0; +} + + #else int virNetDevBridgeGetVlanFiltering(const char *brname G_GNUC_UNUSED, -- 2.55.0
Implement VLAN configuration for FreeBSD bridges. The following configurations are supported: <vlan> <tag id='42'/> </vlan> In this mode untagged traffic from the guest will be tagged with VLAN 42, and VLAN 42 traffic will reach the guest untagged. Trunk configuration: <vlan trunk='yes'> <tag id='42'/> <tag id='43'/> </vlan> In this mode bridge passes the VLAN 42 and 43 tagged traffic from and to the guest. Trunk configuration with nativeMode='untagged'. <vlan trunk='yes'> <tag id='42' nativeMode='untagged'/> <tag id='43'/> </vlan> In this mode the untagged traffic from the guest will be tagged with VLAN 42. And the bridge will allow traffic tagged with VLAN 43. This implementation does not allow nativeMode='tagged' as it is not supported by the FreeBSD bridges. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/util/virnetdevbridge.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index c8da3f11ee..4b804e4faa 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -681,10 +681,48 @@ int virNetDevBridgeAddPort(const char *brname, const virNetDevVlan *virtVlan) { struct ifbreq req = { 0 }; +# if defined(BRDG_VLAN_OP_SET) + struct ifbif_vlan_req vlreq = { 0 }; +# endif + + if (virtVlan && + virtVlan->nativeMode == VIR_NATIVE_VLAN_MODE_TAGGED) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("native tagged VLAN mode is not supported on this platform")); + return -1; + } if (virtVlan) { +# if defined(BRDG_VLAN_OP_SET) + size_t i; + + for (i = 0; i < virtVlan->nTags; i++) { + if (virtVlan->tag[i] < DOT1Q_VID_MIN || + virtVlan->tag[i] > DOT1Q_VID_MAX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("VLAN tag %1$u is not supported on this platform"), + virtVlan->tag[i]); + return -1; + } + } + + if (virtVlan->trunk) { + for (i = 0; i < virtVlan->nTags; i++) { + vlreq.bv_op = BRDG_VLAN_OP_SET; + strlcpy(vlreq.bv_ifname, ifname, sizeof(vlreq.bv_ifname)); + + if (virtVlan->tag[i] != virtVlan->nativeTag) + BRVLAN_SET(&vlreq.bv_set, virtVlan->tag[i]); + else + req.ifbr_pvid = virtVlan->tag[i]; + } + } else { + req.ifbr_pvid = virtVlan->tag[0]; + } +# else virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return -1; +# endif /* defined(BRDG_VLAN_OP_SET) */ } if (virStrcpyStatic(req.ifbr_ifsname, ifname) < 0) { @@ -700,6 +738,22 @@ int virNetDevBridgeAddPort(const char *brname, return -1; } +# if defined(BRDG_VLAN_OP_SET) + if (req.ifbr_pvid != 0 && + virNetDevBridgeCmd(brname, BRDGSIFPVID, &req, sizeof(req), true) < 0) { + virReportSystemError(errno, + _("Unable to set VLAN for bridge %1$s port %2$s"), brname, ifname); + return -1; + } + + if (vlreq.bv_op != 0 && + virNetDevBridgeCmd(brname, BRDGSIFVLANSET, &vlreq, sizeof(vlreq), true) < 0) { + virReportSystemError(errno, + _("Unable to set VLAN for bridge %1$s port %2$s"), brname, ifname); + return -1; + } +# endif /* defined(BRDG_VLAN_OP_SET) */ + return 0; } #else -- 2.55.0
On 9/7/26 20:15, Roman Bogorodskiy wrote:
This series implements VLAN networking on FreeBSD.
Specifically, it implements controlling bridge's VLAN filtering via the `macTableManager='libvirt'` in the network XML. And various configurations specified by domain's <vlan> element.
I have documented my testing of these configurations here:
https://gist.github.com/novel/e26e90f031f965920587bf126899356e
I'd definitely appreciate a second pair of eyes on this to make sure the documented behavior matches the XML intent.
Roman Bogorodskiy (2): virnetdevbridge: support VLAN filtering setting on FreeBSD virnetdevbridge: support VLAN configuration on FreeBSD
src/util/virnetdevbridge.c | 110 +++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (2)
-
Michal Prívozník -
Roman Bogorodskiy