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