[lxc-devel] [lxd/master] Network: Adds support for using uplink bridge using bridge.driver=openvswitch for OVN networks

tomponline on Github lxc-bot at linuxcontainers.org
Mon Nov 2 12:12:07 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 539 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201102/b0db7241/attachment.bin>
-------------- next part --------------
From 9ec01f2daad31649135557aa9dd443c25a0609b6 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 2 Nov 2020 12:09:44 +0000
Subject: [PATCH] lxd/network/driver/ovn: Adds support for using uplink bridge
 using bridge.driver=openvswitch

In this scenario the intermediate OVS bridge and connecting veth pair is not needed and we configure OVN to connect its patch port directly to the existing uplink OVS bridge.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/network/driver_ovn.go | 195 ++++++++++++++++++++++----------------
 1 file changed, 111 insertions(+), 84 deletions(-)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 825b9e4d09..950ac04be9 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -860,76 +860,86 @@ func (n *ovn) uplinkPortBridgeVars(uplinkNet Network) *ovnUplinkPortBridgeVars {
 // startUplinkPortBridge creates veth pair (if doesn't exist), creates OVS bridge (if doesn't exist) and
 // connects veth pair to uplink bridge and OVS bridge.
 func (n *ovn) startUplinkPortBridge(uplinkNet Network) error {
-	vars := n.uplinkPortBridgeVars(uplinkNet)
-
 	// Do this after gaining lock so that on failure we revert before release locking.
 	revert := revert.New()
 	defer revert.Fail()
 
-	// Create veth pair if needed.
-	if !InterfaceExists(vars.uplinkEnd) && !InterfaceExists(vars.ovsEnd) {
-		_, err := shared.RunCommand("ip", "link", "add", "dev", vars.uplinkEnd, "type", "veth", "peer", "name", vars.ovsEnd)
-		if err != nil {
-			return errors.Wrapf(err, "Failed to create the uplink veth interfaces %q and %q", vars.uplinkEnd, vars.ovsEnd)
+	ovs := openvswitch.NewOVS()
+
+	// If uplink is a native bridge, then use a separate OVS bridge with veth pair connection to native bridge.
+	if uplinkNet.Config()["bridge.driver"] != "openvswitch" {
+		vars := n.uplinkPortBridgeVars(uplinkNet)
+
+		// Create veth pair if needed.
+		if !InterfaceExists(vars.uplinkEnd) && !InterfaceExists(vars.ovsEnd) {
+			_, err := shared.RunCommand("ip", "link", "add", "dev", vars.uplinkEnd, "type", "veth", "peer", "name", vars.ovsEnd)
+			if err != nil {
+				return errors.Wrapf(err, "Failed to create the uplink veth interfaces %q and %q", vars.uplinkEnd, vars.ovsEnd)
+			}
+
+			revert.Add(func() { shared.RunCommand("ip", "link", "delete", vars.uplinkEnd) })
 		}
 
-		revert.Add(func() { shared.RunCommand("ip", "link", "delete", vars.uplinkEnd) })
-	}
+		// Ensure that the veth interfaces inherit the uplink bridge's MTU (which the OVS bridge also inherits).
+		uplinkNetConfig := uplinkNet.Config()
+		if uplinkNetConfig["bridge.mtu"] != "" {
+			err := InterfaceSetMTU(vars.uplinkEnd, uplinkNetConfig["bridge.mtu"])
+			if err != nil {
+				return err
+			}
 
-	// Ensure that the veth interfaces inherit the uplink bridge's MTU (which the OVS bridge also inherits).
-	uplinkNetConfig := uplinkNet.Config()
-	if uplinkNetConfig["bridge.mtu"] != "" {
-		err := InterfaceSetMTU(vars.uplinkEnd, uplinkNetConfig["bridge.mtu"])
-		if err != nil {
-			return err
+			err = InterfaceSetMTU(vars.ovsEnd, uplinkNetConfig["bridge.mtu"])
+			if err != nil {
+				return err
+			}
 		}
 
-		err = InterfaceSetMTU(vars.ovsEnd, uplinkNetConfig["bridge.mtu"])
+		// Ensure correct sysctls are set on uplink veth interfaces to avoid getting IPv6 link-local addresses.
+		err := util.SysctlSet(
+			fmt.Sprintf("net/ipv6/conf/%s/disable_ipv6", vars.uplinkEnd), "1",
+			fmt.Sprintf("net/ipv6/conf/%s/disable_ipv6", vars.ovsEnd), "1",
+			fmt.Sprintf("net/ipv6/conf/%s/forwarding", vars.uplinkEnd), "0",
+			fmt.Sprintf("net/ipv6/conf/%s/forwarding", vars.ovsEnd), "0",
+		)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to configure uplink veth interfaces %q and %q", vars.uplinkEnd, vars.ovsEnd)
 		}
-	}
 
-	// Ensure correct sysctls are set on uplink veth interfaces to avoid getting IPv6 link-local addresses.
-	err := util.SysctlSet(
-		fmt.Sprintf("net/ipv6/conf/%s/disable_ipv6", vars.uplinkEnd), "1",
-		fmt.Sprintf("net/ipv6/conf/%s/disable_ipv6", vars.ovsEnd), "1",
-		fmt.Sprintf("net/ipv6/conf/%s/forwarding", vars.uplinkEnd), "0",
-		fmt.Sprintf("net/ipv6/conf/%s/forwarding", vars.ovsEnd), "0",
-	)
-	if err != nil {
-		return errors.Wrapf(err, "Failed to configure uplink veth interfaces %q and %q", vars.uplinkEnd, vars.ovsEnd)
-	}
-
-	// Connect uplink end of veth pair to uplink bridge and bring up.
-	_, err = shared.RunCommand("ip", "link", "set", "master", uplinkNet.Name(), "dev", vars.uplinkEnd, "up")
-	if err != nil {
-		return errors.Wrapf(err, "Failed to connect uplink veth interface %q to uplink bridge %q", vars.uplinkEnd, uplinkNet.Name())
-	}
+		// Connect uplink end of veth pair to uplink bridge and bring up.
+		_, err = shared.RunCommand("ip", "link", "set", "master", uplinkNet.Name(), "dev", vars.uplinkEnd, "up")
+		if err != nil {
+			return errors.Wrapf(err, "Failed to connect uplink veth interface %q to uplink bridge %q", vars.uplinkEnd, uplinkNet.Name())
+		}
 
-	// Ensure uplink OVS end veth interface is up.
-	_, err = shared.RunCommand("ip", "link", "set", "dev", vars.ovsEnd, "up")
-	if err != nil {
-		return errors.Wrapf(err, "Failed to bring up uplink veth interface %q", vars.ovsEnd)
-	}
+		// Ensure uplink OVS end veth interface is up.
+		_, err = shared.RunCommand("ip", "link", "set", "dev", vars.ovsEnd, "up")
+		if err != nil {
+			return errors.Wrapf(err, "Failed to bring up uplink veth interface %q", vars.ovsEnd)
+		}
 
-	// Create uplink OVS bridge if needed.
-	ovs := openvswitch.NewOVS()
-	err = ovs.BridgeAdd(vars.ovsBridge, true)
-	if err != nil {
-		return errors.Wrapf(err, "Failed to create uplink OVS bridge %q", vars.ovsBridge)
-	}
+		// Create uplink OVS bridge if needed.
+		err = ovs.BridgeAdd(vars.ovsBridge, true)
+		if err != nil {
+			return errors.Wrapf(err, "Failed to create uplink OVS bridge %q", vars.ovsBridge)
+		}
 
-	// Connect OVS end veth interface to OVS bridge.
-	err = ovs.BridgePortAdd(vars.ovsBridge, vars.ovsEnd, true)
-	if err != nil {
-		return errors.Wrapf(err, "Failed to connect uplink veth interface %q to uplink OVS bridge %q", vars.ovsEnd, vars.ovsBridge)
-	}
+		// Connect OVS end veth interface to OVS bridge.
+		err = ovs.BridgePortAdd(vars.ovsBridge, vars.ovsEnd, true)
+		if err != nil {
+			return errors.Wrapf(err, "Failed to connect uplink veth interface %q to uplink OVS bridge %q", vars.ovsEnd, vars.ovsBridge)
+		}
 
-	// Associate OVS bridge to logical OVN provider.
-	err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name())
-	if err != nil {
-		return errors.Wrapf(err, "Failed to associate uplink OVS bridge %q to OVN provider %q", vars.ovsBridge, uplinkNet.Name())
+		// Associate OVS bridge to logical OVN provider.
+		err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name())
+		if err != nil {
+			return errors.Wrapf(err, "Failed to associate uplink OVS bridge %q to OVN provider %q", vars.ovsBridge, uplinkNet.Name())
+		}
+	} else {
+		// If uplink is an openvswitch bridge, have OVN logical provider connect directly to it.
+		err := ovs.OVNBridgeMappingAdd(uplinkNet.Name(), uplinkNet.Name())
+		if err != nil {
+			return errors.Wrapf(err, "Failed to associate uplink OVS bridge %q to OVN provider %q", uplinkNet.Name(), uplinkNet.Name())
+		}
 	}
 
 	routerExtPortIPv6 := net.ParseIP(n.config[ovnVolatileUplinkIPv6])
@@ -1074,47 +1084,64 @@ func (n *ovn) deleteUplinkPort() error {
 
 // deleteUplinkPortBridge deletes uplink OVS bridge, OVN bridge mappings and veth interfaces if not in use.
 func (n *ovn) deleteUplinkPortBridge(uplinkNet Network) error {
-	// Check OVS uplink bridge exists, if it does, check whether the uplink network is in use.
-	removeVeths := false
-	vars := n.uplinkPortBridgeVars(uplinkNet)
-	if InterfaceExists(vars.ovsBridge) {
-		uplinkUsed, err := n.checkUplinkUse()
-		if err != nil {
-			return err
-		}
-
-		// Remove OVS bridge if the uplink network isn't used by any other OVN networks.
-		if !uplinkUsed {
-			removeVeths = true
-
-			ovs := openvswitch.NewOVS()
-			err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name())
+	// If uplink is a native bridge, then clean up separate OVS bridge and veth pair connection if not in use.
+	if uplinkNet.Config()["bridge.driver"] != "openvswitch" {
+		// Check OVS uplink bridge exists, if it does, check whether the uplink network is in use.
+		removeVeths := false
+		vars := n.uplinkPortBridgeVars(uplinkNet)
+		if InterfaceExists(vars.ovsBridge) {
+			uplinkUsed, err := n.checkUplinkUse()
 			if err != nil {
 				return err
 			}
 
-			err = ovs.BridgeDelete(vars.ovsBridge)
-			if err != nil {
-				return err
+			// Remove OVS bridge if the uplink network isn't used by any other OVN networks.
+			if !uplinkUsed {
+				removeVeths = true
+
+				ovs := openvswitch.NewOVS()
+				err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name())
+				if err != nil {
+					return err
+				}
+
+				err = ovs.BridgeDelete(vars.ovsBridge)
+				if err != nil {
+					return err
+				}
 			}
+		} else {
+			removeVeths = true // Remove the veths if OVS bridge already gone.
 		}
-	} else {
-		removeVeths = true // Remove the veths if OVS bridge already gone.
-	}
 
-	// Remove the veth interfaces if they exist.
-	if removeVeths {
-		if InterfaceExists(vars.uplinkEnd) {
-			_, err := shared.RunCommand("ip", "link", "delete", "dev", vars.uplinkEnd)
-			if err != nil {
-				return errors.Wrapf(err, "Failed to delete the uplink veth interface %q", vars.uplinkEnd)
+		// Remove the veth interfaces if they exist.
+		if removeVeths {
+			if InterfaceExists(vars.uplinkEnd) {
+				_, err := shared.RunCommand("ip", "link", "delete", "dev", vars.uplinkEnd)
+				if err != nil {
+					return errors.Wrapf(err, "Failed to delete the uplink veth interface %q", vars.uplinkEnd)
+				}
+			}
+
+			if InterfaceExists(vars.ovsEnd) {
+				_, err := shared.RunCommand("ip", "link", "delete", "dev", vars.ovsEnd)
+				if err != nil {
+					return errors.Wrapf(err, "Failed to delete the uplink veth interface %q", vars.ovsEnd)
+				}
 			}
 		}
+	} else {
+		uplinkUsed, err := n.checkUplinkUse()
+		if err != nil {
+			return err
+		}
 
-		if InterfaceExists(vars.ovsEnd) {
-			_, err := shared.RunCommand("ip", "link", "delete", "dev", vars.ovsEnd)
+		// Remove uplink OVS bridge mapping if not in use by other OVN networks.
+		if !uplinkUsed {
+			ovs := openvswitch.NewOVS()
+			err = ovs.OVNBridgeMappingDelete(uplinkNet.Name(), uplinkNet.Name())
 			if err != nil {
-				return errors.Wrapf(err, "Failed to delete the uplink veth interface %q", vars.ovsEnd)
+				return err
 			}
 		}
 	}


More information about the lxc-devel mailing list