The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8028
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) === - Ensures consistent use of uplink terminology rather than parent in docs and code. - Adds new validators for forthcoming restricted subnets feature - Bans colon char from network name.
From 5d8ced58e9b060ef3638237f3b6ffeb150c65c23 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 09:38:36 +0100 Subject: [PATCH 1/8] shared/validate/validate: Removes inaccurate comments about optional values Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- shared/validate/validate.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/validate/validate.go b/shared/validate/validate.go index 10067d8c26..92939c4e39 100644 --- a/shared/validate/validate.go +++ b/shared/validate/validate.go @@ -161,7 +161,7 @@ func IsNetworkMAC(value string) error { return nil } -// IsNetworkAddress validates an IP (v4 or v6) address string. If string is empty, returns valid. +// IsNetworkAddress validates an IP (v4 or v6) address string. func IsNetworkAddress(value string) error { ip := net.ParseIP(value) if ip == nil { @@ -184,7 +184,7 @@ func IsNetworkAddressList(value string) error { return nil } -// IsNetworkV4 validates an IPv4 CIDR string. If string is empty, returns valid. +// IsNetworkV4 validates an IPv4 CIDR string. func IsNetworkV4(value string) error { ip, subnet, err := net.ParseCIDR(value) if err != nil { @@ -202,7 +202,7 @@ func IsNetworkV4(value string) error { return nil } -// IsNetworkAddressV4 validates an IPv4 addresss string. If string is empty, returns valid. +// IsNetworkAddressV4 validates an IPv4 addresss string. func IsNetworkAddressV4(value string) error { ip := net.ParseIP(value) if ip == nil || ip.To4() == nil { @@ -212,7 +212,7 @@ func IsNetworkAddressV4(value string) error { return nil } -// IsNetworkAddressCIDRV4 validates an IPv4 addresss string in CIDR format. If string is empty, returns valid. +// IsNetworkAddressCIDRV4 validates an IPv4 addresss string in CIDR format. func IsNetworkAddressCIDRV4(value string) error { ip, subnet, err := net.ParseCIDR(value) if err != nil { @@ -256,7 +256,7 @@ func IsNetworkV4List(value string) error { return nil } -// IsNetworkV6 validates an IPv6 CIDR string. If string is empty, returns valid. +// IsNetworkV6 validates an IPv6 CIDR string. func IsNetworkV6(value string) error { ip, subnet, err := net.ParseCIDR(value) if err != nil { @@ -274,7 +274,7 @@ func IsNetworkV6(value string) error { return nil } -// IsNetworkAddressV6 validates an IPv6 addresss string. If string is empty, returns valid. +// IsNetworkAddressV6 validates an IPv6 addresss string. func IsNetworkAddressV6(value string) error { ip := net.ParseIP(value) if ip == nil || ip.To4() != nil { @@ -284,7 +284,7 @@ func IsNetworkAddressV6(value string) error { return nil } -// IsNetworkAddressCIDRV6 validates an IPv6 addresss string in CIDR format. If string is empty, returns valid. +// IsNetworkAddressCIDRV6 validates an IPv6 addresss string in CIDR format. func IsNetworkAddressCIDRV6(value string) error { ip, subnet, err := net.ParseCIDR(value) if err != nil { From 6bc696e845f1e50f717363cb9b9191320452952a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 09:39:08 +0100 Subject: [PATCH 2/8] shared/validate/validate: Adds IsNetwork and IsNetworkList functions Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- shared/validate/validate.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/shared/validate/validate.go b/shared/validate/validate.go index 92939c4e39..3978ad5a80 100644 --- a/shared/validate/validate.go +++ b/shared/validate/validate.go @@ -184,6 +184,32 @@ func IsNetworkAddressList(value string) error { return nil } +// IsNetwork validates an IP network CIDR string. +func IsNetwork(value string) error { + ip, subnet, err := net.ParseCIDR(value) + if err != nil { + return err + } + + if ip.String() != subnet.IP.String() { + return fmt.Errorf("Not an IP network address %q", value) + } + + return nil +} + +// IsNetworkList validates a comma delimited list of IP network CIDR strings. +func IsNetworkList(value string) error { + for _, network := range strings.Split(value, ",") { + err := IsNetwork(strings.TrimSpace(network)) + if err != nil { + return err + } + } + + return nil +} + // IsNetworkV4 validates an IPv4 CIDR string. func IsNetworkV4(value string) error { ip, subnet, err := net.ParseCIDR(value) From 654413bedc13dd4f2d48d886fe5855f9ca395aaf Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 09:41:09 +0100 Subject: [PATCH 3/8] shared/validate/validate: Re-orders IP validation functions So that IP family functions are together and in logical order (single item validator before list validators). Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- shared/validate/validate.go | 120 ++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/shared/validate/validate.go b/shared/validate/validate.go index 3978ad5a80..2a84a2bf3e 100644 --- a/shared/validate/validate.go +++ b/shared/validate/validate.go @@ -228,6 +228,19 @@ func IsNetworkV4(value string) error { return nil } +// IsNetworkV4List validates a comma delimited list of IPv4 CIDR strings. +func IsNetworkV4List(value string) error { + for _, network := range strings.Split(value, ",") { + network = strings.TrimSpace(network) + err := IsNetworkV4(network) + if err != nil { + return err + } + } + + return nil +} + // IsNetworkAddressV4 validates an IPv4 addresss string. func IsNetworkAddressV4(value string) error { ip := net.ParseIP(value) @@ -238,6 +251,19 @@ func IsNetworkAddressV4(value string) error { return nil } +// IsNetworkAddressV4List validates a comma delimited list of IPv4 addresses. +func IsNetworkAddressV4List(value string) error { + for _, v := range strings.Split(value, ",") { + v = strings.TrimSpace(v) + err := IsNetworkAddressV4(v) + if err != nil { + return err + } + } + + return nil +} + // IsNetworkAddressCIDRV4 validates an IPv4 addresss string in CIDR format. func IsNetworkAddressCIDRV4(value string) error { ip, subnet, err := net.ParseCIDR(value) @@ -256,11 +282,15 @@ func IsNetworkAddressCIDRV4(value string) error { return nil } -// IsNetworkAddressV4List validates a comma delimited list of IPv4 addresses. -func IsNetworkAddressV4List(value string) error { - for _, v := range strings.Split(value, ",") { - v = strings.TrimSpace(v) - err := IsNetworkAddressV4(v) +// IsNetworkRangeV4 validates an IPv4 range in the format "start-end". +func IsNetworkRangeV4(value string) error { + ips := strings.SplitN(value, "-", 2) + if len(ips) != 2 { + return fmt.Errorf("IP range must contain start and end IP addresses") + } + + for _, ip := range ips { + err := IsNetworkAddressV4(ip) if err != nil { return err } @@ -269,11 +299,10 @@ func IsNetworkAddressV4List(value string) error { return nil } -// IsNetworkV4List validates a comma delimited list of IPv4 CIDR strings. -func IsNetworkV4List(value string) error { - for _, network := range strings.Split(value, ",") { - network = strings.TrimSpace(network) - err := IsNetworkV4(network) +// IsNetworkRangeV4List validates a comma delimited list of IPv4 ranges. +func IsNetworkRangeV4List(value string) error { + for _, ipRange := range strings.Split(value, ",") { + err := IsNetworkRangeV4(strings.TrimSpace(ipRange)) if err != nil { return err } @@ -300,31 +329,26 @@ func IsNetworkV6(value string) error { return nil } -// IsNetworkAddressV6 validates an IPv6 addresss string. -func IsNetworkAddressV6(value string) error { - ip := net.ParseIP(value) - if ip == nil || ip.To4() != nil { - return fmt.Errorf("Not an IPv6 address %q", value) +// IsNetworkV6List validates a comma delimited list of IPv6 CIDR strings. +func IsNetworkV6List(value string) error { + for _, network := range strings.Split(value, ",") { + network = strings.TrimSpace(network) + err := IsNetworkV6(network) + if err != nil { + return err + } } return nil } -// IsNetworkAddressCIDRV6 validates an IPv6 addresss string in CIDR format. -func IsNetworkAddressCIDRV6(value string) error { - ip, subnet, err := net.ParseCIDR(value) - if err != nil { - return err - } - - if ip.To4() != nil { +// IsNetworkAddressV6 validates an IPv6 addresss string. +func IsNetworkAddressV6(value string) error { + ip := net.ParseIP(value) + if ip == nil || ip.To4() != nil { return fmt.Errorf("Not an IPv6 address %q", value) } - if ip.String() == subnet.IP.String() { - return fmt.Errorf("Not a usable IPv6 address %q", value) - } - return nil } @@ -340,43 +364,19 @@ func IsNetworkAddressV6List(value string) error { return nil } -// IsNetworkV6List validates a comma delimited list of IPv6 CIDR strings. -func IsNetworkV6List(value string) error { - for _, network := range strings.Split(value, ",") { - network = strings.TrimSpace(network) - err := IsNetworkV6(network) - if err != nil { - return err - } - } - - return nil -} - -// IsNetworkRangeV4 validates an IPv4 range in the format "start-end". -func IsNetworkRangeV4(value string) error { - ips := strings.SplitN(value, "-", 2) - if len(ips) != 2 { - return fmt.Errorf("IP range must contain start and end IP addresses") +// IsNetworkAddressCIDRV6 validates an IPv6 addresss string in CIDR format. +func IsNetworkAddressCIDRV6(value string) error { + ip, subnet, err := net.ParseCIDR(value) + if err != nil { + return err } - for _, ip := range ips { - err := IsNetworkAddressV4(ip) - if err != nil { - return err - } + if ip.To4() != nil { + return fmt.Errorf("Not an IPv6 address %q", value) } - return nil -} - -// IsNetworkRangeV4List validates a comma delimited list of IPv4 ranges. -func IsNetworkRangeV4List(value string) error { - for _, ipRange := range strings.Split(value, ",") { - err := IsNetworkRangeV4(strings.TrimSpace(ipRange)) - if err != nil { - return err - } + if ip.String() == subnet.IP.String() { + return fmt.Errorf("Not a usable IPv6 address %q", value) } return nil From 7a900762a1978b06297a1870514337de45f77cef Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 10:14:08 +0100 Subject: [PATCH 4/8] lxd/device/nic/ovn: Comment Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/nic_ovn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lxd/device/nic_ovn.go b/lxd/device/nic_ovn.go index 71c77419d8..e499c7cf90 100644 --- a/lxd/device/nic_ovn.go +++ b/lxd/device/nic_ovn.go @@ -26,7 +26,7 @@ import ( type nicOVN struct { deviceCommon - network network.Network + network network.Network // Populated in validateConfig(). } // getIntegrationBridgeName returns the OVS integration bridge to use. From c34ee20298981bedd5d392dad010907e5001a218 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 10:29:29 +0100 Subject: [PATCH 5/8] doc/api-extensions: Removes mention of "parent" from projects_networks_restricted_uplinks feature Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- doc/api-extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index bc3ee9e2d2..a2688afac2 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -1157,7 +1157,7 @@ Adds the `features.networks` config key to projects and the ability for a projec ## projects\_networks\_restricted\_uplinks Adds the `restricted.networks.uplinks` project config key to indicate (as a comma delimited list) which networks -the networks created inside the project can use as their uplink parent network. +the networks created inside the project can use as their uplink network. ## custom\_volume\_backup Add custom volume backup support. From 1b2dc8eba3c670b5794af94fad0226668bc95cf3 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 10:29:55 +0100 Subject: [PATCH 6/8] doc/networks: Switch to "uplink" terminology for external OVN network access Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- doc/networks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/networks.md b/doc/networks.md index 6df04b13c4..cc63de9c11 100644 --- a/doc/networks.md +++ b/doc/networks.md @@ -299,7 +299,7 @@ dns.search | string | - | - ipv4.address | string | standard mode | random unused subnet | IPv4 address for the bridge (CIDR notation). Use "none" to turn off IPv4 or "auto" to generate a new one ipv6.address | string | standard mode | random unused subnet | IPv6 address for the bridge (CIDR notation). Use "none" to turn off IPv6 or "auto" to generate a new one ipv6.dhcp.stateful | boolean | ipv6 dhcp | false | Whether to allocate addresses using DHCP -network | string | - | - | Parent network to use for outbound external network access +network | string | - | - | Uplink network to use for external network access ## network: physical From 6085a3da6a9ee8fb27b4e56fdd788165954b5b57 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 9 Oct 2020 10:30:21 +0100 Subject: [PATCH 7/8] lxd/network/driver/ovn: Replace parent terminology with uplink Now that "uplink" concept is formalised in `restricted.networks.uplinks` we should use consistent terminilogy in code. Also "parent" concept is different and used for other meanings, so re-using when talking about uplink is confusing. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 400 +++++++++++++++++++------------------- 1 file changed, 200 insertions(+), 200 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 7387f10270..ca3373c9f4 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -29,11 +29,11 @@ import ( ) const ovnChassisPriorityMax = 32767 -const ovnVolatileParentIPv4 = "volatile.network.ipv4.address" -const ovnVolatileParentIPv6 = "volatile.network.ipv6.address" +const ovnVolatileUplinkIPv4 = "volatile.network.ipv4.address" +const ovnVolatileUplinkIPv6 = "volatile.network.ipv6.address" -// ovnParentVars OVN object variables derived from parent network. -type ovnParentVars struct { +// ovnUplinkVars OVN object variables derived from uplink network. +type ovnUplinkVars struct { // Router. routerExtPortIPv4Net string routerExtPortIPv6Net string @@ -48,10 +48,10 @@ type ovnParentVars struct { dnsIPv4 []net.IP } -// ovnParentPortBridgeVars parent bridge port variables used for start/stop. -type ovnParentPortBridgeVars struct { +// ovnUplinkPortBridgeVars uplink bridge port variables used for start/stop. +type ovnUplinkPortBridgeVars struct { ovsBridge string - parentEnd string + uplinkEnd string ovsEnd string } @@ -103,8 +103,8 @@ func (n *ovn) Validate(config map[string]string) error { "dns.search": validate.IsAny, // Volatile keys populated automatically as needed. - ovnVolatileParentIPv4: validate.Optional(validate.IsNetworkAddressV4), - ovnVolatileParentIPv6: validate.Optional(validate.IsNetworkAddressV6), + ovnVolatileUplinkIPv4: validate.Optional(validate.IsNetworkAddressV4), + ovnVolatileUplinkIPv6: validate.Optional(validate.IsNetworkAddressV6), } err := n.validate(config, rules) @@ -351,102 +351,102 @@ func (n *ovn) getIntSwitchInstancePortPrefix() string { return fmt.Sprintf("%s-instance", n.getNetworkPrefix()) } -// setupParentPort initialises the parent uplink connection. Returns the derived ovnParentVars settings used +// setupUplinkPort initialises the uplink connection. Returns the derived ovnUplinkVars settings used // during the initial creation of the logical network. -func (n *ovn) setupParentPort(routerMAC net.HardwareAddr) (*ovnParentVars, error) { - // Parent network must be in default project. - parentNet, err := LoadByName(n.state, project.Default, n.config["network"]) +func (n *ovn) setupUplinkPort(routerMAC net.HardwareAddr) (*ovnUplinkVars, error) { + // Uplink network must be in default project. + uplinkNet, err := LoadByName(n.state, project.Default, n.config["network"]) if err != nil { - return nil, errors.Wrapf(err, "Failed loading parent network %q", n.config["network"]) + return nil, errors.Wrapf(err, "Failed loading uplink network %q", n.config["network"]) } - switch parentNet.Type() { + switch uplinkNet.Type() { case "bridge": - return n.setupParentPortBridge(parentNet, routerMAC) + return n.setupUplinkPortBridge(uplinkNet, routerMAC) case "physical": - return n.setupParentPortPhysical(parentNet, routerMAC) + return n.setupUplinkPortPhysical(uplinkNet, routerMAC) } - return nil, fmt.Errorf("Failed setting up parent port, network type %q unsupported as OVN parent", parentNet.Type()) + return nil, fmt.Errorf("Failed setting up uplink port, network type %q unsupported as OVN uplink", uplinkNet.Type()) } -// setupParentPortBridge allocates external IPs on the parent bridge. -// Returns the derived ovnParentVars settings. -func (n *ovn) setupParentPortBridge(parentNet Network, routerMAC net.HardwareAddr) (*ovnParentVars, error) { - bridgeNet, ok := parentNet.(*bridge) +// setupUplinkPortBridge allocates external IPs on the uplink bridge. +// Returns the derived ovnUplinkVars settings. +func (n *ovn) setupUplinkPortBridge(uplinkNet Network, routerMAC net.HardwareAddr) (*ovnUplinkVars, error) { + bridgeNet, ok := uplinkNet.(*bridge) if !ok { return nil, fmt.Errorf("Network is not bridge type") } err := bridgeNet.checkClusterWideMACSafe(bridgeNet.config) if err != nil { - return nil, errors.Wrapf(err, "Network %q is not suitable for use as OVN parent", bridgeNet.name) + return nil, errors.Wrapf(err, "Network %q is not suitable for use as OVN uplink", bridgeNet.name) } - v, err := n.allocateParentPortIPs(parentNet, routerMAC) + v, err := n.allocateUplinkPortIPs(uplinkNet, routerMAC) if err != nil { - return nil, errors.Wrapf(err, "Failed allocating parent port IPs on network %q", parentNet.Name()) + return nil, errors.Wrapf(err, "Failed allocating uplink port IPs on network %q", uplinkNet.Name()) } return v, nil } -// setupParentPortPhysical allocates external IPs on the parent network. -// Returns the derived ovnParentVars settings. -func (n *ovn) setupParentPortPhysical(parentNet Network, routerMAC net.HardwareAddr) (*ovnParentVars, error) { - v, err := n.allocateParentPortIPs(parentNet, routerMAC) +// setupUplinkPortPhysical allocates external IPs on the uplink network. +// Returns the derived ovnUplinkVars settings. +func (n *ovn) setupUplinkPortPhysical(uplinkNet Network, routerMAC net.HardwareAddr) (*ovnUplinkVars, error) { + v, err := n.allocateUplinkPortIPs(uplinkNet, routerMAC) if err != nil { - return nil, errors.Wrapf(err, "Failed allocating parent port IPs on network %q", parentNet.Name()) + return nil, errors.Wrapf(err, "Failed allocating uplink port IPs on network %q", uplinkNet.Name()) } return v, nil } -// allocateParentPortIPs attempts to find a free IP in the parent network's OVN ranges and then stores it in -// ovnVolatileParentIPv4 and ovnVolatileParentIPv6 config keys on this network. Returns ovnParentVars settings. -func (n *ovn) allocateParentPortIPs(parentNet Network, routerMAC net.HardwareAddr) (*ovnParentVars, error) { - v := &ovnParentVars{} +// allocateUplinkPortIPs attempts to find a free IP in the uplink network's OVN ranges and then stores it in +// ovnVolatileUplinkIPv4 and ovnVolatileUplinkIPv6 config keys on this network. Returns ovnUplinkVars settings. +func (n *ovn) allocateUplinkPortIPs(uplinkNet Network, routerMAC net.HardwareAddr) (*ovnUplinkVars, error) { + v := &ovnUplinkVars{} - parentNetConf := parentNet.Config() + uplinkNetConf := uplinkNet.Config() - // Parent derived settings. - v.extSwitchProviderName = parentNet.Name() + // Uplink derived settings. + v.extSwitchProviderName = uplinkNet.Name() - // Detect parent gateway setting. - parentIPv4CIDR := parentNetConf["ipv4.address"] - if parentIPv4CIDR == "" { - parentIPv4CIDR = parentNetConf["ipv4.gateway"] + // Detect uplink gateway setting. + uplinkIPv4CIDR := uplinkNetConf["ipv4.address"] + if uplinkIPv4CIDR == "" { + uplinkIPv4CIDR = uplinkNetConf["ipv4.gateway"] } - parentIPv6CIDR := parentNetConf["ipv6.address"] - if parentIPv6CIDR == "" { - parentIPv6CIDR = parentNetConf["ipv6.gateway"] + uplinkIPv6CIDR := uplinkNetConf["ipv6.address"] + if uplinkIPv6CIDR == "" { + uplinkIPv6CIDR = uplinkNetConf["ipv6.gateway"] } - // Optional parent values. - parentIPv4, parentIPv4Net, err := net.ParseCIDR(parentIPv4CIDR) + // Optional uplink values. + uplinkIPv4, uplinkIPv4Net, err := net.ParseCIDR(uplinkIPv4CIDR) if err == nil { - v.dnsIPv4 = []net.IP{parentIPv4} - v.routerExtGwIPv4 = parentIPv4 + v.dnsIPv4 = []net.IP{uplinkIPv4} + v.routerExtGwIPv4 = uplinkIPv4 } - parentIPv6, parentIPv6Net, err := net.ParseCIDR(parentIPv6CIDR) + uplinkIPv6, uplinkIPv6Net, err := net.ParseCIDR(uplinkIPv6CIDR) if err == nil { - v.dnsIPv6 = []net.IP{parentIPv6} - v.routerExtGwIPv6 = parentIPv6 + v.dnsIPv6 = []net.IP{uplinkIPv6} + v.routerExtGwIPv6 = uplinkIPv6 } // Detect optional DNS server list. - if parentNetConf["dns.nameservers"] != "" { + if uplinkNetConf["dns.nameservers"] != "" { // Reset nameservers. v.dnsIPv4 = nil v.dnsIPv6 = nil - nsList := strings.Split(parentNetConf["dns.nameservers"], ",") + nsList := strings.Split(uplinkNetConf["dns.nameservers"], ",") for _, ns := range nsList { nsIP := net.ParseIP(strings.TrimSpace(ns)) if nsIP == nil { - return nil, fmt.Errorf("Invalid parent nameserver") + return nil, fmt.Errorf("Invalid uplink nameserver") } if nsIP.To4() == nil { @@ -457,63 +457,63 @@ func (n *ovn) allocateParentPortIPs(parentNet Network, routerMAC net.HardwareAdd } } - // Parse existing allocated IPs for this network on the parent network (if not set yet, will be nil). - routerExtPortIPv4 := net.ParseIP(n.config[ovnVolatileParentIPv4]) - routerExtPortIPv6 := net.ParseIP(n.config[ovnVolatileParentIPv6]) + // Parse existing allocated IPs for this network on the uplink network (if not set yet, will be nil). + routerExtPortIPv4 := net.ParseIP(n.config[ovnVolatileUplinkIPv4]) + routerExtPortIPv6 := net.ParseIP(n.config[ovnVolatileUplinkIPv6]) // Decide whether we need to allocate new IP(s) and go to the expense of retrieving all allocated IPs. - if (parentIPv4Net != nil && routerExtPortIPv4 == nil) || (parentIPv6Net != nil && routerExtPortIPv6 == nil) { + if (uplinkIPv4Net != nil && routerExtPortIPv4 == nil) || (uplinkIPv6Net != nil && routerExtPortIPv6 == nil) { err := n.state.Cluster.Transaction(func(tx *db.ClusterTx) error { - allAllocatedIPv4, allAllocatedIPv6, err := n.parentAllAllocatedIPs(tx, parentNet.Name()) + allAllocatedIPv4, allAllocatedIPv6, err := n.uplinkAllAllocatedIPs(tx, uplinkNet.Name()) if err != nil { - return errors.Wrapf(err, "Failed to get all allocated IPs for parent") + return errors.Wrapf(err, "Failed to get all allocated IPs for uplink") } - if parentIPv4Net != nil && routerExtPortIPv4 == nil { - if parentNetConf["ipv4.ovn.ranges"] == "" { - return fmt.Errorf(`Missing required "ipv4.ovn.ranges" config key on parent network`) + if uplinkIPv4Net != nil && routerExtPortIPv4 == nil { + if uplinkNetConf["ipv4.ovn.ranges"] == "" { + return fmt.Errorf(`Missing required "ipv4.ovn.ranges" config key on uplink network`) } - ipRanges, err := parseIPRanges(parentNetConf["ipv4.ovn.ranges"], parentNet.DHCPv4Subnet()) + ipRanges, err := parseIPRanges(uplinkNetConf["ipv4.ovn.ranges"], uplinkNet.DHCPv4Subnet()) if err != nil { - return errors.Wrapf(err, "Failed to parse parent IPv4 OVN ranges") + return errors.Wrapf(err, "Failed to parse uplink IPv4 OVN ranges") } - routerExtPortIPv4, err = n.parentAllocateIP(ipRanges, allAllocatedIPv4) + routerExtPortIPv4, err = n.uplinkAllocateIP(ipRanges, allAllocatedIPv4) if err != nil { - return errors.Wrapf(err, "Failed to allocate parent IPv4 address") + return errors.Wrapf(err, "Failed to allocate uplink IPv4 address") } - n.config[ovnVolatileParentIPv4] = routerExtPortIPv4.String() + n.config[ovnVolatileUplinkIPv4] = routerExtPortIPv4.String() } - if parentIPv6Net != nil && routerExtPortIPv6 == nil { - // If IPv6 OVN ranges are specified by the parent, allocate from them. - if parentNetConf["ipv6.ovn.ranges"] != "" { - ipRanges, err := parseIPRanges(parentNetConf["ipv6.ovn.ranges"], parentNet.DHCPv6Subnet()) + if uplinkIPv6Net != nil && routerExtPortIPv6 == nil { + // If IPv6 OVN ranges are specified by the uplink, allocate from them. + if uplinkNetConf["ipv6.ovn.ranges"] != "" { + ipRanges, err := parseIPRanges(uplinkNetConf["ipv6.ovn.ranges"], uplinkNet.DHCPv6Subnet()) if err != nil { - return errors.Wrapf(err, "Failed to parse parent IPv6 OVN ranges") + return errors.Wrapf(err, "Failed to parse uplink IPv6 OVN ranges") } - routerExtPortIPv6, err = n.parentAllocateIP(ipRanges, allAllocatedIPv6) + routerExtPortIPv6, err = n.uplinkAllocateIP(ipRanges, allAllocatedIPv6) if err != nil { - return errors.Wrapf(err, "Failed to allocate parent IPv6 address") + return errors.Wrapf(err, "Failed to allocate uplink IPv6 address") } } else { // Otherwise use EUI64 derived from MAC address. - routerExtPortIPv6, err = eui64.ParseMAC(parentIPv6Net.IP, routerMAC) + routerExtPortIPv6, err = eui64.ParseMAC(uplinkIPv6Net.IP, routerMAC) if err != nil { return err } } - n.config[ovnVolatileParentIPv6] = routerExtPortIPv6.String() + n.config[ovnVolatileUplinkIPv6] = routerExtPortIPv6.String() } err = tx.UpdateNetwork(n.id, n.description, n.config) if err != nil { - return errors.Wrapf(err, "Failed saving allocated parent network IPs") + return errors.Wrapf(err, "Failed saving allocated uplink network IPs") } return nil @@ -524,17 +524,17 @@ func (n *ovn) allocateParentPortIPs(parentNet Network, routerMAC net.HardwareAdd } // Configure variables needed to configure OVN router. - if parentIPv4Net != nil && routerExtPortIPv4 != nil { + if uplinkIPv4Net != nil && routerExtPortIPv4 != nil { routerExtPortIPv4Net := &net.IPNet{ - Mask: parentIPv4Net.Mask, + Mask: uplinkIPv4Net.Mask, IP: routerExtPortIPv4, } v.routerExtPortIPv4Net = routerExtPortIPv4Net.String() } - if parentIPv6Net != nil { + if uplinkIPv6Net != nil { routerExtPortIPv6Net := &net.IPNet{ - Mask: parentIPv6Net.Mask, + Mask: uplinkIPv6Net.Mask, IP: routerExtPortIPv6, } v.routerExtPortIPv6Net = routerExtPortIPv6Net.String() @@ -543,8 +543,8 @@ func (n *ovn) allocateParentPortIPs(parentNet Network, routerMAC net.HardwareAdd return v, nil } -// parentAllAllocatedIPs gets a list of all IPv4 and IPv6 addresses allocated to OVN networks connected to parent. -func (n *ovn) parentAllAllocatedIPs(tx *db.ClusterTx, parentNetName string) ([]net.IP, []net.IP, error) { +// uplinkAllAllocatedIPs gets a list of all IPv4 and IPv6 addresses allocated to OVN networks connected to uplink. +func (n *ovn) uplinkAllAllocatedIPs(tx *db.ClusterTx, uplinkNetName string) ([]net.IP, []net.IP, error) { // Get all managed networks across all projects. projectNetworks, err := tx.GetNonPendingNetworks() if err != nil { @@ -556,11 +556,11 @@ func (n *ovn) parentAllAllocatedIPs(tx *db.ClusterTx, parentNetName string) ([]n for _, networks := range projectNetworks { for _, netInfo := range networks { - if netInfo.Type != "ovn" || netInfo.Config["network"] != parentNetName { + if netInfo.Type != "ovn" || netInfo.Config["network"] != uplinkNetName { continue } - for _, k := range []string{ovnVolatileParentIPv4, ovnVolatileParentIPv6} { + for _, k := range []string{ovnVolatileUplinkIPv4, ovnVolatileUplinkIPv6} { if netInfo.Config[k] != "" { ip := net.ParseIP(netInfo.Config[k]) if ip != nil { @@ -578,8 +578,8 @@ func (n *ovn) parentAllAllocatedIPs(tx *db.ClusterTx, parentNetName string) ([]n return v4IPs, v6IPs, nil } -// parentAllocateIP allocates a free IP from one of the IP ranges. -func (n *ovn) parentAllocateIP(ipRanges []*shared.IPRange, allAllocated []net.IP) (net.IP, error) { +// uplinkAllocateIP allocates a free IP from one of the IP ranges. +func (n *ovn) uplinkAllocateIP(ipRanges []*shared.IPRange, allAllocated []net.IP) (net.IP, error) { for _, ipRange := range ipRanges { inc := big.NewInt(1) @@ -629,73 +629,73 @@ func (n *ovn) parentAllocateIP(ipRanges []*shared.IPRange, allAllocated []net.IP return nil, fmt.Errorf("No free IPs available") } -// startParentPort performs any network start up logic needed to connect the parent uplink connection to OVN. -func (n *ovn) startParentPort() error { - // Parent network must be in default project. - parentNet, err := LoadByName(n.state, project.Default, n.config["network"]) +// startUplinkPort performs any network start up logic needed to connect the uplink connection to OVN. +func (n *ovn) startUplinkPort() error { + // Uplink network must be in default project. + uplinkNet, err := LoadByName(n.state, project.Default, n.config["network"]) if err != nil { - return errors.Wrapf(err, "Failed loading parent network") + return errors.Wrapf(err, "Failed loading uplink network") } - // Lock parent network so that if multiple OVN networks are trying to connect to the same parent we don't + // Lock uplink network so that if multiple OVN networks are trying to connect to the same uplink we don't // race each other setting up the connection. - unlock := locking.Lock(n.parentOperationLockName(parentNet)) + unlock := locking.Lock(n.uplinkOperationLockName(uplinkNet)) defer unlock() - switch parentNet.Type() { + switch uplinkNet.Type() { case "bridge": - return n.startParentPortBridge(parentNet) + return n.startUplinkPortBridge(uplinkNet) case "physical": - return n.startParentPortPhysical(parentNet) + return n.startUplinkPortPhysical(uplinkNet) } - return fmt.Errorf("Failed starting parent port, network type %q unsupported as OVN parent", parentNet.Type()) + return fmt.Errorf("Failed starting uplink port, network type %q unsupported as OVN uplink", uplinkNet.Type()) } -// parentOperationLockName returns the lock name to use for operations on the parent network. -func (n *ovn) parentOperationLockName(parentNet Network) string { - return fmt.Sprintf("network.ovn.%s", parentNet.Name()) +// uplinkOperationLockName returns the lock name to use for operations on the uplink network. +func (n *ovn) uplinkOperationLockName(uplinkNet Network) string { + return fmt.Sprintf("network.ovn.%s", uplinkNet.Name()) } -// parentPortBridgeVars returns the parent port bridge variables needed for port start/stop. -func (n *ovn) parentPortBridgeVars(parentNet Network) *ovnParentPortBridgeVars { - ovsBridge := fmt.Sprintf("lxdovn%d", parentNet.ID()) +// uplinkPortBridgeVars returns the uplink port bridge variables needed for port start/stop. +func (n *ovn) uplinkPortBridgeVars(uplinkNet Network) *ovnUplinkPortBridgeVars { + ovsBridge := fmt.Sprintf("lxdovn%d", uplinkNet.ID()) - return &ovnParentPortBridgeVars{ + return &ovnUplinkPortBridgeVars{ ovsBridge: ovsBridge, - parentEnd: fmt.Sprintf("%sa", ovsBridge), + uplinkEnd: fmt.Sprintf("%sa", ovsBridge), ovsEnd: fmt.Sprintf("%sb", ovsBridge), } } -// startParentPortBridge creates veth pair (if doesn't exist), creates OVS bridge (if doesn't exist) and -// connects veth pair to parent bridge and OVS bridge. -func (n *ovn) startParentPortBridge(parentNet Network) error { - vars := n.parentPortBridgeVars(parentNet) +// 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.parentEnd) && !InterfaceExists(vars.ovsEnd) { - _, err := shared.RunCommand("ip", "link", "add", "dev", vars.parentEnd, "type", "veth", "peer", "name", vars.ovsEnd) + 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.parentEnd, vars.ovsEnd) + 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.parentEnd) }) + 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). - parentNetConfig := parentNet.Config() - if parentNetConfig["bridge.mtu"] != "" { - err := InterfaceSetMTU(vars.parentEnd, parentNetConfig["bridge.mtu"]) + uplinkNetConfig := uplinkNet.Config() + if uplinkNetConfig["bridge.mtu"] != "" { + err := InterfaceSetMTU(vars.uplinkEnd, uplinkNetConfig["bridge.mtu"]) if err != nil { return err } - err = InterfaceSetMTU(vars.ovsEnd, parentNetConfig["bridge.mtu"]) + err = InterfaceSetMTU(vars.ovsEnd, uplinkNetConfig["bridge.mtu"]) if err != nil { return err } @@ -703,55 +703,55 @@ func (n *ovn) startParentPortBridge(parentNet Network) error { // 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.parentEnd), "1", + 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.parentEnd), "0", + 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.parentEnd, vars.ovsEnd) + return errors.Wrapf(err, "Failed to configure uplink veth interfaces %q and %q", vars.uplinkEnd, vars.ovsEnd) } - // Connect parent end of veth pair to parent bridge and bring up. - _, err = shared.RunCommand("ip", "link", "set", "master", parentNet.Name(), "dev", vars.parentEnd, "up") + // 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 parent bridge %q", vars.parentEnd, parentNet.Name()) + 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 parent veth interface %q", vars.ovsEnd) + return errors.Wrapf(err, "Failed to bring up uplink veth interface %q", vars.ovsEnd) } - // Create parent OVS bridge if needed. + // 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 parent uplink OVS bridge %q", vars.ovsBridge) + 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 parent OVS bridge %q", vars.ovsEnd, vars.ovsBridge) + 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, parentNet.Name()) + err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) if err != nil { - return errors.Wrapf(err, "Failed to associate parent OVS bridge %q to OVN provider %q", vars.ovsBridge, parentNet.Name()) + return errors.Wrapf(err, "Failed to associate uplink OVS bridge %q to OVN provider %q", vars.ovsBridge, uplinkNet.Name()) } - routerExtPortIPv6 := net.ParseIP(n.config[ovnVolatileParentIPv6]) + routerExtPortIPv6 := net.ParseIP(n.config[ovnVolatileUplinkIPv6]) if routerExtPortIPv6 != nil { - // Now that the OVN router is connected to the uplink parent bridge, attempt to ping the OVN - // router's external IPv6 from the LXD host running the parent bridge in an attempt to trigger the - // OVN router to learn the parent uplink gateway's MAC address. This is to work around a bug in + // Now that the OVN router is connected to the uplink bridge, attempt to ping the OVN + // router's external IPv6 from the LXD host running the uplink bridge in an attempt to trigger the + // OVN router to learn the uplink gateway's MAC address. This is to work around a bug in // older versions of OVN that meant that the OVN router would not attempt to learn the external // uplink IPv6 gateway MAC address when using SNAT, meaning that external IPv6 connectivity // wouldn't work until the next router advertisement was sent (which could be several minutes). - // By pinging the OVN router's external IP this will trigger an NDP request from the parent bridge + // By pinging the OVN router's external IP this will trigger an NDP request from the uplink bridge // which will cause the OVN router to learn its MAC address. go func() { // Try several attempts as it can take a few seconds for the network to come up. @@ -774,19 +774,19 @@ func (n *ovn) startParentPortBridge(parentNet Network) error { return nil } -// startParentPortPhysical creates OVS bridge (if doesn't exist) and connects parent interface to the OVS bridge. -func (n *ovn) startParentPortPhysical(parentNet Network) error { - vars := n.parentPortBridgeVars(parentNet) +// startUplinkPortPhysical creates OVS bridge (if doesn't exist) and connects uplink interface to the OVS bridge. +func (n *ovn) startUplinkPortPhysical(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() - parentConfig := parentNet.Config() - uplinkHostName := GetHostDevice(parentConfig["parent"], parentConfig["vlan"]) + uplinkConfig := uplinkNet.Config() + uplinkHostName := GetHostDevice(uplinkConfig["parent"], uplinkConfig["vlan"]) if !InterfaceExists(uplinkHostName) { - return fmt.Errorf("Uplink network %q is not started", parentNet.Name()) + return fmt.Errorf("Uplink network %q is not started", uplinkNet.Name()) } // Ensure correct sysctls are set on uplink interface to avoid getting IPv6 link-local addresses. @@ -798,29 +798,29 @@ func (n *ovn) startParentPortPhysical(parentNet Network) error { return errors.Wrapf(err, "Failed to configure uplink interface %q", uplinkHostName) } - // Create parent OVS bridge if needed. + // 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 parent uplink OVS bridge %q", vars.ovsBridge) + 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, uplinkHostName, true) if err != nil { - return errors.Wrapf(err, "Failed to connect uplink interface %q to parent OVS bridge %q", uplinkHostName, vars.ovsBridge) + return errors.Wrapf(err, "Failed to connect uplink interface %q to uplink OVS bridge %q", uplinkHostName, vars.ovsBridge) } // Associate OVS bridge to logical OVN provider. - err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, parentNet.Name()) + err = ovs.OVNBridgeMappingAdd(vars.ovsBridge, uplinkNet.Name()) if err != nil { - return errors.Wrapf(err, "Failed to associate parent OVS bridge %q to OVN provider %q", vars.ovsBridge, parentNet.Name()) + return errors.Wrapf(err, "Failed to associate uplink OVS bridge %q to OVN provider %q", vars.ovsBridge, uplinkNet.Name()) } // Bring uplink interface up. _, err = shared.RunCommand("ip", "link", "set", uplinkHostName, "up") if err != nil { - return errors.Wrapf(err, "Failed to bring up parent interface %q", uplinkHostName) + return errors.Wrapf(err, "Failed to bring up uplink interface %q", uplinkHostName) } revert.Success() @@ -847,7 +847,7 @@ func (n *ovn) checkUplinkUse() (bool, error) { continue // Ignore our own DB record or non OVN networks. } - // Check if another network is using our parent. + // Check if another network is using our uplink. if network.Config["network"] == n.config["network"] { return true, nil } @@ -857,37 +857,37 @@ func (n *ovn) checkUplinkUse() (bool, error) { return false, nil } -// deleteParentPort deletes the parent uplink connection. -func (n *ovn) deleteParentPort() error { - // Parent network must be in default project. +// deleteUplinkPort deletes the uplink connection. +func (n *ovn) deleteUplinkPort() error { + // Uplink network must be in default project. if n.config["network"] != "" { - parentNet, err := LoadByName(n.state, project.Default, n.config["network"]) + uplinkNet, err := LoadByName(n.state, project.Default, n.config["network"]) if err != nil { - return errors.Wrapf(err, "Failed loading parent network") + return errors.Wrapf(err, "Failed loading uplink network") } - // Lock parent network so we don't race each other networks using the OVS uplink bridge. - unlock := locking.Lock(n.parentOperationLockName(parentNet)) + // Lock uplink network so we don't race each other networks using the OVS uplink bridge. + unlock := locking.Lock(n.uplinkOperationLockName(uplinkNet)) defer unlock() - switch parentNet.Type() { + switch uplinkNet.Type() { case "bridge": - return n.deleteParentPortBridge(parentNet) + return n.deleteUplinkPortBridge(uplinkNet) case "physical": - return n.deleteParentPortPhysical(parentNet) + return n.deleteUplinkPortPhysical(uplinkNet) } - return fmt.Errorf("Failed deleting parent port, network type %q unsupported as OVN parent", parentNet.Type()) + return fmt.Errorf("Failed deleting uplink port, network type %q unsupported as OVN uplink", uplinkNet.Type()) } return nil } -// deleteParentPortBridge deletes parent uplink OVS bridge, OVN bridge mappings and veth interfaces if not in use. -func (n *ovn) deleteParentPortBridge(parentNet Network) 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.parentPortBridgeVars(parentNet) + vars := n.uplinkPortBridgeVars(uplinkNet) if InterfaceExists(vars.ovsBridge) { uplinkUsed, err := n.checkUplinkUse() if err != nil { @@ -899,7 +899,7 @@ func (n *ovn) deleteParentPortBridge(parentNet Network) error { removeVeths = true ovs := openvswitch.NewOVS() - err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, parentNet.Name()) + err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err } @@ -915,10 +915,10 @@ func (n *ovn) deleteParentPortBridge(parentNet Network) error { // Remove the veth interfaces if they exist. if removeVeths { - if InterfaceExists(vars.parentEnd) { - _, err := shared.RunCommand("ip", "link", "delete", "dev", vars.parentEnd) + 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.parentEnd) + return errors.Wrapf(err, "Failed to delete the uplink veth interface %q", vars.uplinkEnd) } } @@ -933,11 +933,11 @@ func (n *ovn) deleteParentPortBridge(parentNet Network) error { return nil } -// deleteParentPortPhysical deletes parent uplink OVS bridge and OVN bridge mappings if not in use. -func (n *ovn) deleteParentPortPhysical(parentNet Network) error { +// deleteUplinkPortPhysical deletes uplink OVS bridge and OVN bridge mappings if not in use. +func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { // Check OVS uplink bridge exists, if it does, check whether the uplink network is in use. releaseIF := false - vars := n.parentPortBridgeVars(parentNet) + vars := n.uplinkPortBridgeVars(uplinkNet) if InterfaceExists(vars.ovsBridge) { uplinkUsed, err := n.checkUplinkUse() if err != nil { @@ -949,7 +949,7 @@ func (n *ovn) deleteParentPortPhysical(parentNet Network) error { releaseIF = true ovs := openvswitch.NewOVS() - err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, parentNet.Name()) + err = ovs.OVNBridgeMappingDelete(vars.ovsBridge, uplinkNet.Name()) if err != nil { return err } @@ -965,12 +965,12 @@ func (n *ovn) deleteParentPortPhysical(parentNet Network) error { // Bring down uplink interface if exists. if releaseIF { - parentConfig := parentNet.Config() - parentDev := GetHostDevice(parentConfig["parent"], parentConfig["vlan"]) - if InterfaceExists(parentDev) { - _, err := shared.RunCommand("ip", "link", "set", parentDev, "down") + uplinkConfig := uplinkNet.Config() + uplinkDev := GetHostDevice(uplinkConfig["parent"], uplinkConfig["vlan"]) + if InterfaceExists(uplinkDev) { + _, err := shared.RunCommand("ip", "link", "set", uplinkDev, "down") if err != nil { - return errors.Wrapf(err, "Failed to bring down uplink interface %q", parentDev) + return errors.Wrapf(err, "Failed to bring down uplink interface %q", uplinkDev) } } } @@ -1171,24 +1171,24 @@ func (n *ovn) setup(update bool) error { return err } - // Setup parent port (do this first to check parent is suitable). - parent, err := n.setupParentPort(routerMAC) + // Setup uplink port (do this first to check uplink is suitable). + uplinkNet, err := n.setupUplinkPort(routerMAC) if err != nil { return err } // Parse router IP config. - if parent.routerExtPortIPv4Net != "" { - routerExtPortIPv4, routerExtPortIPv4Net, err = net.ParseCIDR(parent.routerExtPortIPv4Net) + if uplinkNet.routerExtPortIPv4Net != "" { + routerExtPortIPv4, routerExtPortIPv4Net, err = net.ParseCIDR(uplinkNet.routerExtPortIPv4Net) if err != nil { - return errors.Wrapf(err, "Failed parsing router's external parent port IPv4 Net") + return errors.Wrapf(err, "Failed parsing router's external uplink port IPv4 Net") } } - if parent.routerExtPortIPv6Net != "" { - routerExtPortIPv6, routerExtPortIPv6Net, err = net.ParseCIDR(parent.routerExtPortIPv6Net) + if uplinkNet.routerExtPortIPv6Net != "" { + routerExtPortIPv6, routerExtPortIPv6Net, err = net.ParseCIDR(uplinkNet.routerExtPortIPv6Net) if err != nil { - return errors.Wrapf(err, "Failed parsing router's external parent port IPv6 Net") + return errors.Wrapf(err, "Failed parsing router's external uplink port IPv6 Net") } } @@ -1228,15 +1228,15 @@ func (n *ovn) setup(update bool) error { // Configure logical router. // Add default routes. - if parent.routerExtGwIPv4 != nil { - err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, parent.routerExtGwIPv4) + if uplinkNet.routerExtGwIPv4 != nil { + err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, uplinkNet.routerExtGwIPv4) if err != nil { return errors.Wrapf(err, "Failed adding IPv4 default route") } } - if parent.routerExtGwIPv6 != nil { - err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}, parent.routerExtGwIPv6) + if uplinkNet.routerExtGwIPv6 != nil { + err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}, uplinkNet.routerExtGwIPv6) if err != nil { return errors.Wrapf(err, "Failed adding IPv6 default route") } @@ -1317,7 +1317,7 @@ func (n *ovn) setup(update bool) error { } revert.Add(func() { client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) }) - err = client.LogicalSwitchPortLinkProviderNetwork(n.getExtSwitchProviderPortName(), parent.extSwitchProviderName) + err = client.LogicalSwitchPortLinkProviderNetwork(n.getExtSwitchProviderPortName(), uplinkNet.extSwitchProviderName) if err != nil { return errors.Wrapf(err, "Failed linking external switch provider port to external provider network") } @@ -1367,7 +1367,7 @@ func (n *ovn) setup(update bool) error { ServerID: routerIntPortIPv4, ServerMAC: routerMAC, Router: routerIntPortIPv4, - RecursiveDNSServer: parent.dnsIPv4, + RecursiveDNSServer: uplinkNet.dnsIPv4, DomainName: n.getDomainName(), LeaseTime: time.Duration(time.Hour * 1), MTU: bridgeMTU, @@ -1379,7 +1379,7 @@ func (n *ovn) setup(update bool) error { // Create DHCPv6 options for internal switch. err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, routerIntPortIPv6Net, &openvswitch.OVNDHCPv6Opts{ ServerID: routerMAC, - RecursiveDNSServer: parent.dnsIPv6, + RecursiveDNSServer: uplinkNet.dnsIPv6, DNSSearchList: n.getDNSSearchList(), }) if err != nil { @@ -1417,8 +1417,8 @@ func (n *ovn) setup(update bool) error { } var recursiveDNSServer net.IP - if len(parent.dnsIPv6) > 0 { - recursiveDNSServer = parent.dnsIPv6[0] // OVN only supports 1 RA DNS server. + if len(uplinkNet.dnsIPv6) > 0 { + recursiveDNSServer = uplinkNet.dnsIPv6[0] // OVN only supports 1 RA DNS server. } err = client.LogicalRouterPortSetIPv6Advertisements(n.getRouterIntPortName(), &openvswitch.OVNIPv6RAOpts{ @@ -1577,7 +1577,7 @@ func (n *ovn) Rename(newName string) error { return nil } -// Start starts adds the local OVS chassis ID to the OVN chass group and starts the local OVS parent uplink port. +// Start starts adds the local OVS chassis ID to the OVN chass group and starts the local OVS uplink port. func (n *ovn) Start() error { n.logger.Debug("Start") @@ -1591,7 +1591,7 @@ func (n *ovn) Start() error { return err } - err = n.startParentPort() + err = n.startUplinkPort() if err != nil { return err } @@ -1599,7 +1599,7 @@ func (n *ovn) Start() error { return nil } -// Stop deletes the local OVS parent uplink port (if unused) and deletes the local OVS chassis ID from the +// Stop deletes the local OVS uplink port (if unused) and deletes the local OVS chassis ID from the // OVN chass group func (n *ovn) Stop() error { n.logger.Debug("Stop") @@ -1610,8 +1610,8 @@ func (n *ovn) Stop() error { return err } - // Delete local parent uplink port if not used by other OVN networks. - err = n.deleteParentPort() + // Delete local uplink port if not used by other OVN networks. + err = n.deleteUplinkPort() if err != nil { return err } @@ -1663,8 +1663,8 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType cl } // Remove volatile keys associated with old network in new config. - delete(newNetwork.Config, ovnVolatileParentIPv4) - delete(newNetwork.Config, ovnVolatileParentIPv6) + delete(newNetwork.Config, ovnVolatileUplinkIPv4) + delete(newNetwork.Config, ovnVolatileUplinkIPv6) } // Apply changes to all nodes and databse. From 406d4fc37c9b00a0065e237fc74e0122acea92a6 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Tue, 13 Oct 2020 09:36:01 +0100 Subject: [PATCH 8/8] lxd/network/driver/common: Ban : char from network names in ValidateName() This prevents network names from conflicting with vlan alias interface names and when used as a prefix for `restricted.networks.subnets` in projects. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_common.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lxd/network/driver_common.go b/lxd/network/driver_common.go index 3c422c5a1a..23cff9a58c 100644 --- a/lxd/network/driver_common.go +++ b/lxd/network/driver_common.go @@ -101,7 +101,16 @@ func (n *common) validate(config map[string]string, driverRules map[string]func( // ValidateName validates network name. func (n *common) ValidateName(name string) error { - return validate.IsURLSegmentSafe(name) + err := validate.IsURLSegmentSafe(name) + if err != nil { + return err + } + + if strings.Contains(name, ":") { + return fmt.Errorf("Cannot contain %q", ":") + } + + return nil } // ID returns the network ID.
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel