The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/7480

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Adds VLAN support for openvswitch bridges.
From 59ccc7ca5463727c6b5684855c4a3d73a2f22bac Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 2 Jun 2020 10:50:08 +0100
Subject: [PATCH 1/4] lxd/network/utils: Adds IsNativeBridge function

To isolate the logic used for detecting a native linux bridge in a single 
function for re-use.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/network_utils.go | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lxd/network/network_utils.go b/lxd/network/network_utils.go
index bb56b2b187..14fe9230df 100644
--- a/lxd/network/network_utils.go
+++ b/lxd/network/network_utils.go
@@ -92,9 +92,14 @@ func GetIP(subnet *net.IPNet, host int64) net.IP {
        return newIP
 }
 
+// IsNativeBridge returns whether the bridge name specified is a Linux native 
bridge.
+func IsNativeBridge(bridgeName string) bool {
+       return shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bridge", 
bridgeName))
+}
+
 // AttachInterface attaches an interface to a bridge.
 func AttachInterface(bridgeName string, devName string) error {
-       if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bridge", 
bridgeName)) {
+       if IsNativeBridge(bridgeName) {
                _, err := shared.RunCommand("ip", "link", "set", "dev", 
devName, "master", bridgeName)
                if err != nil {
                        return err
@@ -115,7 +120,7 @@ func AttachInterface(bridgeName string, devName string) 
error {
 
 // DetachInterface detaches an interface from a bridge.
 func DetachInterface(bridgeName string, devName string) error {
-       if shared.PathExists(fmt.Sprintf("/sys/class/net/%s/bridge", 
bridgeName)) {
+       if IsNativeBridge(bridgeName) {
                _, err := shared.RunCommand("ip", "link", "set", "dev", 
devName, "nomaster")
                if err != nil {
                        return err

From a6d92324db52ddf9541c06a29b7db4a418cae8cf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 2 Jun 2020 14:39:30 +0100
Subject: [PATCH 2/4] lxd/device/device/utils/network: Allow VLAN ID 0 in
 networkValidVLAN

Openvswitch allows VLAN 0 for untagged frames.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/device_utils_network.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/device/device_utils_network.go 
b/lxd/device/device_utils_network.go
index 0558635f9c..6a15a345d8 100644
--- a/lxd/device/device_utils_network.go
+++ b/lxd/device/device_utils_network.go
@@ -699,8 +699,8 @@ func networkValidVLAN(value string) error {
                return fmt.Errorf("Invalid VLAN ID: %s", value)
        }
 
-       if vlanID < 1 || vlanID > 4094 {
-               return fmt.Errorf("Out of range (1-4094) VLAN ID: %s", value)
+       if vlanID < 0 || vlanID > 4094 {
+               return fmt.Errorf("Out of range (0-4094) VLAN ID: %s", value)
        }
 
        return nil

From 607888d4a827eaa2c9cffd74bcd51140396e8e94 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 2 Jun 2020 14:40:10 +0100
Subject: [PATCH 3/4] test: Updates bridged vlan ID range tests

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 test/suites/container_devices_nic_bridged_vlan.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/suites/container_devices_nic_bridged_vlan.sh 
b/test/suites/container_devices_nic_bridged_vlan.sh
index 1713e2c10f..9f717098b5 100644
--- a/test/suites/container_devices_nic_bridged_vlan.sh
+++ b/test/suites/container_devices_nic_bridged_vlan.sh
@@ -71,7 +71,7 @@ test_container_devices_nic_bridged_vlan() {
   ! lxc config device set "${prefix}-ctA" eth0 vlan = 4096 # Check out of 
range VLAN ID.
   ! lxc config device set "${prefix}-ctA" eth0 vlan = 0 # Check out of range 
VLAN ID.
   ! lxc config device set "${prefix}-ctA" eth0 vlan.tagged = 5,invalid, 6 # 
Check invalid VLAN ID list.
-  ! lxc config device set "${prefix}-ctA" eth0 vlan.tagged=0 # Check out of 
range VLAN ID list.
+  ! lxc config device set "${prefix}-ctA" eth0 vlan.tagged=-1 # Check out of 
range VLAN ID list.
   ! lxc config device set "${prefix}-ctA" eth0 vlan.tagged=4096 # Check out of 
range VLAN ID list.
   lxc config device remove "${prefix}-ctA" eth0
 

From ccf2c7e221dd8c91ab2b788f321741e1d8fd16f3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 2 Jun 2020 14:41:32 +0100
Subject: [PATCH 4/4] lxd/device/nic/bridged: Adds openvswitch vlan support

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/nic_bridged.go | 72 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 68 insertions(+), 4 deletions(-)

diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 132c8944e9..a1c48f1e00 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -286,8 +286,13 @@ func (d *nicBridged) Start() (*deviceConfig.RunConfig, 
error) {
                return nil, err
        }
 
-       // Setup VLAN settings on bridge port.
-       err = d.setupBridgePortVLANs(saveData["host_name"])
+       // Detech bridge type and setup VLAN settings on bridge port.
+       if network.IsNativeBridge(d.config["parent"]) {
+               err = d.setupNativeBridgePortVLANs(saveData["host_name"])
+       } else {
+               err = d.setupOVSBridgePortVLANs(saveData["host_name"])
+       }
+
        if err != nil {
                return nil, err
        }
@@ -1202,8 +1207,8 @@ func (d *nicBridged) networkDHCPv6CreateIAAddress(IP 
net.IP) []byte {
        return data
 }
 
-// setupBridgePortVLANs configures the bridge port with the specified VLAN 
settings in device config.
-func (d *nicBridged) setupBridgePortVLANs(hostName string) error {
+// setupNativeBridgePortVLANs configures the bridge port with the specified 
VLAN settings on the native bridge.
+func (d *nicBridged) setupNativeBridgePortVLANs(hostName string) error {
        // Check vlan_filtering is enabled on bridge if needed.
        if d.config["vlan"] != "" || d.config["vlan.tagged"] != "" {
                vlanFilteringStatus, err := 
network.BridgeVLANFilteringStatus(d.config["parent"])
@@ -1218,6 +1223,11 @@ func (d *nicBridged) setupBridgePortVLANs(hostName 
string) error {
 
        // Set port on bridge to specified untagged PVID.
        if d.config["vlan"] != "" {
+               // Reject VLAN ID 0 if specified (as main validation allows 
VLAN ID 0 to accomodate ovs).
+               if d.config["vlan"] == "0" {
+                       return fmt.Errorf("VLAN ID 0 is not allowed for native 
Linux bridges")
+               }
+
                // Get default PVID membership on port.
                defaultPVID, err := 
network.BridgeVLANDefaultPVID(d.config["parent"])
                if err != nil {
@@ -1246,6 +1256,12 @@ func (d *nicBridged) setupBridgePortVLANs(hostName 
string) error {
        if d.config["vlan.tagged"] != "" {
                for _, vlanID := range strings.Split(d.config["vlan.tagged"], 
",") {
                        vlanID = strings.TrimSpace(vlanID)
+
+                       // Reject VLAN ID 0 if specified (as main validation 
allows VLAN ID 0 to accomodate ovs).
+                       if vlanID == "0" {
+                               return fmt.Errorf("VLAN ID 0 is not allowed for 
native Linux bridges")
+                       }
+
                        _, err := shared.RunCommand("bridge", "vlan", "add", 
"dev", hostName, "vid", vlanID)
                        if err != nil {
                                return err
@@ -1255,3 +1271,51 @@ func (d *nicBridged) setupBridgePortVLANs(hostName 
string) error {
 
        return nil
 }
+
+// setupOVSBridgePortVLANs configures the bridge port with the specified VLAN 
settings on the openvswitch bridge.
+func (d *nicBridged) setupOVSBridgePortVLANs(hostName string) error {
+       // Set port on bridge to specified untagged PVID.
+       if d.config["vlan"] != "" {
+               if d.config["vlan"] == "none" && d.config["vlan.tagged"] == "" {
+                       return fmt.Errorf("vlan=none is not supported with 
openvswitch bridges when not using vlan.tagged")
+               }
+
+               // Configure the untagged 'native' membership settings of the 
port if VLAN ID specified.
+               // Also set the vlan_mode=access, which will drop any tagged 
frames.
+               // Order is important here, as vlan_mode is set to "access", 
assuming that vlan.tagged is not used.
+               // If vlan.tagged is specified, then we expect it to also 
change the vlan_mode as needed.
+               if d.config["vlan"] != "none" {
+                       _, err := shared.RunCommand("ovs-vsctl", "set", "port", 
hostName, "vlan_mode=access", fmt.Sprintf("tag=%s", d.config["vlan"]))
+                       if err != nil {
+                               return err
+                       }
+               }
+       }
+
+       // Add any tagged VLAN memberships.
+       if d.config["vlan.tagged"] != "" {
+               vlanIDs := strings.Split(d.config["vlan.tagged"], ",")
+
+               // Remove any spaces from raw config string.
+               for i, vlanID := range vlanIDs {
+                       vlanIDs[i] = strings.TrimSpace(vlanID)
+               }
+
+               vlanMode := "trunk" // Default to only allowing tagged frames 
(drop untagged frames).
+               if d.config["vlan"] != "none" {
+                       // If untagged vlan mode isn't "none" then allow 
untagged frames for port's 'native' VLAN.
+                       vlanMode = "native-untagged"
+               }
+
+               // Configure the tagged membership settings of the port if VLAN 
ID specified.
+               // Also set the vlan_mode as needed from above.
+               // Must come after the ovs-vsctl command used for setting 
"vlan" mode above so that the correct
+               // vlan_mode is retained.
+               _, err := shared.RunCommand("ovs-vsctl", "set", "port", 
hostName, fmt.Sprintf("vlan_mode=%s", vlanMode), fmt.Sprintf("trunks=%s", 
strings.Join(vlanIDs, ",")))
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to