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