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

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) ===

From f899806b77a562de10764e8f52afb0ac1d6d52fd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 29 Oct 2020 11:03:01 +0000
Subject: [PATCH 1/5] lxd/network/driver/ovn: Adds ovnProjectNetworksWithUplink
 function

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

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 9ce25782e7..0f141d73e2 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -2353,3 +2353,27 @@ func (n *ovn) ovnNICExternalRoutes(ourDeviceInstance 
instance.Instance, ourDevic
 
        return externalRoutes, nil
 }
+
+// ovnProjectNetworksWithUplink accepts a map of all networks in all projects 
and returns a filtered map of OVN
+// networks that use the uplink specified.
+func (n *ovn) ovnProjectNetworksWithUplink(uplink string, projectNetworks 
map[string]map[int64]api.Network) map[string][]*api.Network {
+       ovnProjectNetworksWithOurUplink := make(map[string][]*api.Network)
+       for netProject, networks := range projectNetworks {
+               for _, ni := range networks {
+                       network := ni // Local var creating pointer to rather 
than iterator.
+
+                       // Skip non-OVN networks or those networks that don't 
use the uplink specified.
+                       if network.Type != "ovn" || network.Config["network"] 
!= uplink {
+                               continue
+                       }
+
+                       if ovnProjectNetworksWithOurUplink[netProject] == nil {
+                               ovnProjectNetworksWithOurUplink[netProject] = 
[]*api.Network{&network}
+                       } else {
+                               ovnProjectNetworksWithOurUplink[netProject] = 
append(ovnProjectNetworksWithOurUplink[netProject], &network)
+                       }
+               }
+       }
+
+       return ovnProjectNetworksWithOurUplink
+}

From c6d6045b8f43cf749666eefe99e6c4fa0d36d2e9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 29 Oct 2020 11:04:42 +0000
Subject: [PATCH 2/5] lxd/network/driver/ovn: Updates ovnNetworkExternalSubnets
 to allow optional filtering of our own network's subnets

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/network/driver_ovn.go | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 0f141d73e2..cbfaa1f080 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -2260,13 +2260,18 @@ func (n *ovn) DHCPv6Subnet() *net.IPNet {
        return subnet
 }
 
-// ovnNetworkExternalSubnets returns a list of external subnets used by OVN 
networks (including our own) using the
-// same uplink as this OVN network. OVN networks are considered to be using 
external subnets if their ipv4.address
-// and/or ipv6.address are in the uplink's external routes and the associated 
NAT is disabled for the IP family.
-func (n *ovn) ovnNetworkExternalSubnets(ovnProjectNetworksWithOurUplink 
map[string][]*api.Network, uplinkRoutes []*net.IPNet) ([]*net.IPNet, error) {
+// ovnNetworkExternalSubnets returns a list of external subnets used by OVN 
networks (optionally exluding our own
+// if both ourProject and ourNetwork are non-empty) using the same uplink as 
this OVN network. OVN networks are
+// considered to be using external subnets if their ipv4.address and/or 
ipv6.address are in the uplink's external
+// routes and the associated NAT is disabled for the IP family.
+func (n *ovn) ovnNetworkExternalSubnets(ourProject string, ourNetwork string, 
ovnProjectNetworksWithOurUplink map[string][]*api.Network, uplinkRoutes 
[]*net.IPNet) ([]*net.IPNet, error) {
        externalSubnets := make([]*net.IPNet, 0)
-       for _, networks := range ovnProjectNetworksWithOurUplink {
+       for netProject, networks := range ovnProjectNetworksWithOurUplink {
                for _, netInfo := range networks {
+                       if netProject == ourProject && netInfo.Name == 
ourNetwork {
+                               continue
+                       }
+
                        for _, keyPrefix := range []string{"ipv4", "ipv6"} {
                                if 
!shared.IsTrue(netInfo.Config[fmt.Sprintf("%s.nat", keyPrefix)]) {
                                        _, ipNet, _ := 
net.ParseCIDR(netInfo.Config[fmt.Sprintf("%s.address", keyPrefix)])

From 7872cdf100bfb56814b20357c8d869da194d6db3 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 29 Oct 2020 11:05:15 +0000
Subject: [PATCH 3/5] lxd/network/driver/ovn: Updates ovnNICExternalRoutes to
 optionally filter our own NIC's external routes

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

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index cbfaa1f080..c44d32547a 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -2295,8 +2295,9 @@ func (n *ovn) ovnNetworkExternalSubnets(ourProject 
string, ourNetwork string, ov
        return externalSubnets, nil
 }
 
-// ovnNICExternalRoutes returns a list of external routes currently used by 
OVN NICs (excluding our own) that are
-// connected to OVN networks that share the same uplink as this network uses.
+// ovnNICExternalRoutes returns a list of external routes currently used by 
OVN NICs (optionally excluding our
+// own if both ourDeviceInstance and ourDeviceName are non-empty) that are 
connected to OVN networks that share
+// the same uplink as this network uses.
 func (n *ovn) ovnNICExternalRoutes(ourDeviceInstance instance.Instance, 
ourDeviceName string, ovnProjectNetworksWithOurUplink 
map[string][]*api.Network) ([]*net.IPNet, error) {
        externalRoutes := make([]*net.IPNet, 0)
 
@@ -2327,8 +2328,8 @@ func (n *ovn) ovnNICExternalRoutes(ourDeviceInstance 
instance.Instance, ourDevic
                                continue
                        }
 
-                       // Skip our own device.
-                       if inst.Name == ourDeviceInstance.Name() && 
inst.Project == ourDeviceInstance.Project() && ourDeviceName == devName {
+                       // Skip our own device (if instance and device name 
were supplied).
+                       if ourDeviceInstance != nil && ourDeviceName != "" && 
inst.Name == ourDeviceInstance.Name() && inst.Project == 
ourDeviceInstance.Project() && ourDeviceName == devName {
                                continue
                        }
 

From f1f9e0a46909c4c88c278d0e76fee077d3eb4df2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 29 Oct 2020 11:05:57 +0000
Subject: [PATCH 4/5] lxd/network/driver/ovn: Updates
 InstanceDevicePortValidateExternalRoutes to use new functions and signatures

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

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index c44d32547a..59a885595e 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -1901,26 +1901,11 @@ func (n *ovn) 
InstanceDevicePortValidateExternalRoutes(deviceInstance instance.I
                return err
        }
 
-       // Work out which OVN networks (in all projects and including our own) 
use the same uplink as us.
-       ovnProjectNetworksWithOurUplink := make(map[string][]*api.Network)
-       for netProject, networks := range projectNetworks {
-               for _, network := range networks {
-                       netInfo := network // Local var for adding pointer to 
ovnProjectNetworksWithOurUplink.
-                       // Skip non-OVN networks or those networks that don't 
use the same uplink as us.
-                       if netInfo.Type != "ovn" || netInfo.Config["network"] 
!= n.config["network"] {
-                               continue
-                       }
-
-                       if ovnProjectNetworksWithOurUplink[netProject] == nil {
-                               ovnProjectNetworksWithOurUplink[netProject] = 
[]*api.Network{&netInfo}
-                       } else {
-                               ovnProjectNetworksWithOurUplink[netProject] = 
append(ovnProjectNetworksWithOurUplink[netProject], &netInfo)
-                       }
-               }
-       }
+       // Get OVN networks that use the same uplink as us.
+       ovnProjectNetworksWithOurUplink := 
n.ovnProjectNetworksWithUplink(n.config["network"], projectNetworks)
 
        // Get external subnets used by other OVN networks using our uplink.
-       ovnNetworkExternalSubnets, err := 
n.ovnNetworkExternalSubnets(ovnProjectNetworksWithOurUplink, uplinkRoutes)
+       ovnNetworkExternalSubnets, err := n.ovnNetworkExternalSubnets("", "", 
ovnProjectNetworksWithOurUplink, uplinkRoutes)
        if err != nil {
                return err
        }
@@ -1931,14 +1916,10 @@ func (n *ovn) 
InstanceDevicePortValidateExternalRoutes(deviceInstance instance.I
                return err
        }
 
-       // If validating with an instance, get external routes configured on 
OVN NICs (excluding ours) using
-       // networks that use our uplink.
-       var ovnNICExternalRoutes []*net.IPNet
-       if deviceInstance != nil {
-               ovnNICExternalRoutes, err = 
n.ovnNICExternalRoutes(deviceInstance, deviceName, 
ovnProjectNetworksWithOurUplink)
-               if err != nil {
-                       return err
-               }
+       // Get external routes configured on OVN NICs (excluding ours) using 
networks that use our uplink.
+       ovnNICExternalRoutes, err := n.ovnNICExternalRoutes(deviceInstance, 
deviceName, ovnProjectNetworksWithOurUplink)
+       if err != nil {
+               return err
        }
 
        for _, portExternalRoute := range portExternalRoutes {

From 5a53d16c5db5ef98c3fe13682ca50ee0c9caf810 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 29 Oct 2020 11:03:34 +0000
Subject: [PATCH 5/5] lxd/network/driver/ovn: Updates Validate to check
 external subnets dont overlap with other OVN networks or NICs sharing our
 uplink

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

diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go
index 59a885595e..de2f32024f 100644
--- a/lxd/network/driver_ovn.go
+++ b/lxd/network/driver_ovn.go
@@ -230,7 +230,8 @@ func (n *ovn) Validate(config map[string]string) error {
                return err
        }
 
-       // If NAT disabled, check subnets are within the uplink network's 
routes and project's subnet restrictions.
+       // If NAT disabled, parse the external subnets that are being requested.
+       var externalSubnets []*net.IPNet
        for _, keyPrefix := range []string{"ipv4", "ipv6"} {
                if !shared.IsTrue(config[fmt.Sprintf("%s.nat", keyPrefix)]) && 
validate.IsOneOf(config[fmt.Sprintf("%s.address", keyPrefix)], []string{"", 
"none", "auto"}) != nil {
                        _, ipNet, err := 
net.ParseCIDR(config[fmt.Sprintf("%s.address", keyPrefix)])
@@ -238,10 +239,63 @@ func (n *ovn) Validate(config map[string]string) error {
                                return err
                        }
 
-                       err = n.validateExternalSubnet(uplinkRoutes, 
projectRestrictedSubnets, ipNet)
+                       externalSubnets = append(externalSubnets, ipNet)
+               }
+       }
+
+       if len(externalSubnets) > 0 {
+               var projectNetworks map[string]map[int64]api.Network
+               err = n.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
+                       // Get all managed networks across all projects.
+                       projectNetworks, err = tx.GetNonPendingNetworks()
+                       if err != nil {
+                               return errors.Wrapf(err, "Failed to load all 
networks")
+                       }
+
+                       return nil
+               })
+               if err != nil {
+                       return err
+               }
+
+               // Get OVN networks that use the same uplink as us.
+               ovnProjectNetworksWithOurUplink := 
n.ovnProjectNetworksWithUplink(config["network"], projectNetworks)
+
+               // Get external subnets used by other OVN networks using our 
uplink.
+               ovnNetworkExternalSubnets, err := 
n.ovnNetworkExternalSubnets(n.project, n.name, ovnProjectNetworksWithOurUplink, 
uplinkRoutes)
+               if err != nil {
+                       return err
+               }
+
+               // Get external routes configured on OVN NICs using networks 
that use our uplink.
+               ovnNICExternalRoutes, err := n.ovnNICExternalRoutes(nil, "", 
ovnProjectNetworksWithOurUplink)
+               if err != nil {
+                       return err
+               }
+
+               // Check external subnets are within the uplink network's 
routes and project's subnet restrictions.
+               for _, externalSubnet := range externalSubnets {
+                       err = n.validateExternalSubnet(uplinkRoutes, 
projectRestrictedSubnets, externalSubnet)
                        if err != nil {
                                return err
                        }
+
+                       // Check the external port route doesn't fall within 
any existing OVN network external subnets.
+                       for _, ovnNetworkExternalSubnet := range 
ovnNetworkExternalSubnets {
+                               if SubnetContains(ovnNetworkExternalSubnet, 
externalSubnet) || SubnetContains(externalSubnet, ovnNetworkExternalSubnet) {
+                                       // This error is purposefully vague so 
that it doesn't reveal any names of
+                                       // resources potentially outside of the 
network's project.
+                                       return fmt.Errorf("External subnet %q 
overlaps with another OVN network's external subnet", externalSubnet.String())
+                               }
+                       }
+
+                       for _, ovnNICExternalRoute := range 
ovnNICExternalRoutes {
+                               if SubnetContains(ovnNICExternalRoute, 
externalSubnet) || SubnetContains(externalSubnet, ovnNICExternalRoute) {
+                                       // This error is purposefully vague so 
that it doesn't reveal any names of
+                                       // resources potentially outside of the 
networks's project.
+                                       return fmt.Errorf("External subnet %q 
overlaps with another OVN NIC's external route", externalSubnet.String())
+                               }
+                       }
                }
        }
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to