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 <[email protected]>
---
 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

Reply via email to