The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8276
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) === Don't tear down all OVN config and rebuild, instead try and apply only changes, so as to reduce impact on instance port config.
From cba9502715754f6ae05cfa8bb4a4dae4e62c8465 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 11:45:16 +0000 Subject: [PATCH 01/16] lxd/network/openvswitch/ovn: Adds mayExist argument to LogicalRouterAdd Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index d7ad3079ee..86625846c2 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -125,8 +125,14 @@ func (o *OVN) nbctl(args ...string) (string, error) { } // LogicalRouterAdd adds a named logical router. -func (o *OVN) LogicalRouterAdd(routerName OVNRouter) error { - _, err := o.nbctl("lr-add", string(routerName)) +func (o *OVN) LogicalRouterAdd(routerName OVNRouter, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + _, err := o.nbctl(append(args, "lr-add", string(routerName))...) if err != nil { return err } From a67d1ed533580a1e7829ca9afd7a99363eba4ce4 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 11:46:13 +0000 Subject: [PATCH 02/16] lxd/network/openvswitch/ovn: Adds mayExist argument to LogicalRouterSNATAdd Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index 86625846c2..f529d39394 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -151,8 +151,14 @@ func (o OVN) LogicalRouterDelete(routerName OVNRouter) error { } // LogicalRouterSNATAdd adds an SNAT rule to a logical router to translate packets from intNet to extIP. -func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP) error { - _, err := o.nbctl("lr-nat-add", string(routerName), "snat", extIP.String(), intNet.String()) +func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extIP net.IP, mayExist bool) error { + args := []string{} + + if mayExist { + args = append(args, "--may-exist") + } + + _, err := o.nbctl(append(args, "lr-nat-add", string(routerName), "snat", extIP.String(), intNet.String())...) if err != nil { return err } From 94fdc43a5e424d0a9ec4d35e70f12af2a1a5dd65 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 11:46:41 +0000 Subject: [PATCH 03/16] lxd/network/openvswitch/ovn: Simplifies LogicalRouterRouteAdd Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index f529d39394..fa6a409b6c 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -204,8 +204,7 @@ func (o *OVN) LogicalRouterRouteAdd(routerName OVNRouter, destination *net.IPNet args = append(args, "--may-exist") } - args = append(args, "lr-route-add", string(routerName), destination.String(), nextHop.String()) - _, err := o.nbctl(args...) + _, err := o.nbctl(append(args, "lr-route-add", string(routerName), destination.String(), nextHop.String())...) if err != nil { return err } From e47204f3c35bc466639591ff1b13d6302e4d6a21 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 11:46:57 +0000 Subject: [PATCH 04/16] lxd/network/openvswitch/ovn: Adds mayExist argument to LogicalRouterPortAdd Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index fa6a409b6c..f4bd7f186f 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -230,7 +230,29 @@ func (o *OVN) LogicalRouterRouteDelete(routerName OVNRouter, destination *net.IP } // LogicalRouterPortAdd adds a named logical router port to a logical router. -func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, ipAddr ...*net.IPNet) error { +func (o *OVN) LogicalRouterPortAdd(routerName OVNRouter, portName OVNRouterPort, mac net.HardwareAddr, ipAddr []*net.IPNet, mayExist bool) error { + if mayExist { + // Check if it exists and update addresses. + _, err := o.nbctl("list", "Logical_Router_Port", string(portName)) + if err == nil { + // Router port exists. + ips := make([]string, 0, len(ipAddr)) + for _, ip := range ipAddr { + ips = append(ips, ip.String()) + } + + _, err := o.nbctl("set", "Logical_Router_Port", string(portName), + fmt.Sprintf(`networks="%s"`, strings.Join(ips, `","`)), + fmt.Sprintf(`mac="%s"`, fmt.Sprintf(mac.String())), + ) + if err != nil { + return err + } + + return nil + } + } + args := []string{"lrp-add", string(routerName), string(portName), mac.String()} for _, ipNet := range ipAddr { args = append(args, ipNet.String()) From 053db5f5a862163d88b494f58a70e61ac3a26cd2 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 11:47:14 +0000 Subject: [PATCH 05/16] lxd/network/openvswitch/ovn: Adds LogicalRouterSNATDeleteAll function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index f4bd7f186f..47b2bdcceb 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -166,6 +166,16 @@ func (o *OVN) LogicalRouterSNATAdd(routerName OVNRouter, intNet *net.IPNet, extI return nil } +// LogicalRouterSNATDeleteAll deletes all SNAT rules from a logical router. +func (o *OVN) LogicalRouterSNATDeleteAll(routerName OVNRouter) error { + _, err := o.nbctl("--if-exists", "lr-nat-del", string(routerName), "snat") + if err != nil { + return err + } + + return nil +} + // LogicalRouterDNATSNATAdd adds a DNAT and SNAT rule to a logical router to translate packets from extIP to intIP. func (o *OVN) LogicalRouterDNATSNATAdd(routerName OVNRouter, extIP net.IP, intIP net.IP, stateless bool, mayExist bool) error { args := []string{} From b43527e9d9de2b0ff81d5bfda2fb759be59914e2 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 16:30:02 +0000 Subject: [PATCH 06/16] lxd/network/openvswitch/ovn: Clear unused keys in LogicalSwitchSetIPAllocation Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index 47b2bdcceb..01ba706dc4 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -383,14 +383,19 @@ func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { // LogicalSwitchSetIPAllocation sets the IP allocation config on the logical switch. func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllocationOpts) error { + var removeOtherConfigKeys []string args := []string{"set", "logical_switch", string(switchName)} if opts.PrefixIPv4 != nil { args = append(args, fmt.Sprintf("other_config:subnet=%s", opts.PrefixIPv4.String())) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "subnet") } if opts.PrefixIPv6 != nil { args = append(args, fmt.Sprintf("other_config:ipv6_prefix=%s", opts.PrefixIPv6.String())) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "ipv6_prefix") } if len(opts.ExcludeIPv4) > 0 { @@ -406,6 +411,17 @@ func (o *OVN) LogicalSwitchSetIPAllocation(switchName OVNSwitch, opts *OVNIPAllo } args = append(args, fmt.Sprintf("other_config:exclude_ips=%s", strings.Join(excludeIPs, " "))) + } else { + removeOtherConfigKeys = append(removeOtherConfigKeys, "exclude_ips") + } + + // Clear any unused keys first. + if len(removeOtherConfigKeys) > 0 { + removeArgs := append([]string{"remove", "logical_switch", string(switchName), "other_config"}, removeOtherConfigKeys...) + _, err := o.nbctl(removeArgs...) + if err != nil { + return err + } } // Only run command if at least one setting is specified. From 799ce55e8f6a28d9d3ed09aaaeb93c11003a63f5 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:47:47 +0000 Subject: [PATCH 07/16] lxd/network/openvswitch/ovn: Adds support for clearing unused settings in LogicalRouterPortSetIPv6Advertisements Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index 01ba706dc4..cbdb7e018e 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -290,27 +290,53 @@ func (o *OVN) LogicalRouterPortDelete(portName OVNRouterPort) error { func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opts *OVNIPv6RAOpts) error { args := []string{"set", "logical_router_port", string(portName), fmt.Sprintf("ipv6_ra_configs:send_periodic=%t", opts.SendPeriodic), - fmt.Sprintf("ipv6_ra_configs:address_mode=%s", string(opts.AddressMode)), + } + + var removeRAConfigKeys []string + + if opts.AddressMode != "" { + args = append(args, fmt.Sprintf("ipv6_ra_configs:address_mode=%s", string(opts.AddressMode))) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "address_mode") } if opts.MaxInterval > 0 { args = append(args, fmt.Sprintf("ipv6_ra_configs:max_interval=%d", opts.MaxInterval/time.Second)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "max_interval") } if opts.MinInterval > 0 { args = append(args, fmt.Sprintf("ipv6_ra_configs:min_interval=%d", opts.MinInterval/time.Second)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "min_interval") } if opts.MTU > 0 { args = append(args, fmt.Sprintf("ipv6_ra_configs:mtu=%d", opts.MTU)) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "mtu") } if len(opts.DNSSearchList) > 0 { args = append(args, fmt.Sprintf("ipv6_ra_configs:dnssl=%s", strings.Join(opts.DNSSearchList, ","))) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "dnssl") } if opts.RecursiveDNSServer != nil { args = append(args, fmt.Sprintf("ipv6_ra_configs:rdnss=%s", opts.RecursiveDNSServer.String())) + } else { + removeRAConfigKeys = append(removeRAConfigKeys, "rdnss") + } + + // Clear any unused keys first. + if len(removeRAConfigKeys) > 0 { + removeArgs := append([]string{"remove", "logical_router_port", string(portName), "ipv6_ra_configs"}, removeRAConfigKeys...) + _, err := o.nbctl(removeArgs...) + if err != nil { + return err + } } // Configure IPv6 Router Advertisements. From 0334dfe8dc8dbde5ff9ae9d78c879e9f064209ce Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:48:18 +0000 Subject: [PATCH 08/16] lxd/network/openvswitch/ovn: Adds LogicalRouterPortDeleteIPv6Advertisements function Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index cbdb7e018e..a263bb5ca4 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -348,6 +348,17 @@ func (o *OVN) LogicalRouterPortSetIPv6Advertisements(portName OVNRouterPort, opt return nil } +// LogicalRouterPortDeleteIPv6Advertisements removes the IPv6 RA announcement settings from a router port. +func (o *OVN) LogicalRouterPortDeleteIPv6Advertisements(portName OVNRouterPort) error { + // Delete IPv6 Router Advertisements. + _, err := o.nbctl("clear", "logical_router_port", string(portName), "ipv6_ra_configs") + if err != nil { + return err + } + + return nil +} + // LogicalRouterPortLinkChassisGroup links a logical router port to a HA chassis group. func (o *OVN) LogicalRouterPortLinkChassisGroup(portName OVNRouterPort, haChassisGroupName OVNChassisGroup) error { chassisGroupID, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "ha_chassis_group", fmt.Sprintf("name=%s", haChassisGroupName)) From 271257c7c3dc04495a1abfc1ed080ae08840342c Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:52:22 +0000 Subject: [PATCH 09/16] lxd/network/driver/ovn: Enforce that ipv6.address if specified is at least a /64 subnet OVN requires at least a /64 for DHCP and SLAAC. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index db9b7366d2..f9df44f31a 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -205,6 +205,16 @@ func (n *ovn) Validate(config map[string]string) error { return err } + // Check that if IPv6 enabled then the network size must be at least a /64 as both RA and DHCPv6 + // in OVN (as it generates addresses using EUI64) require at least a /64 subnet to operate. + _, ipv6Net, _ := net.ParseCIDR(config["ipv6.address"]) + if ipv6Net != nil { + ones, _ := ipv6Net.Mask.Size() + if ones > 64 { + return fmt.Errorf("IPv6 subnet must be at least a /64") + } + } + // Load the project to get uplink network restrictions. p, err := n.state.Cluster.GetProject(n.project) if err != nil { From 87218ebf8aef6308a4cfaf11da4a5fd80e725e63 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:55:01 +0000 Subject: [PATCH 10/16] lxd/network/driver/ovn: Pass update flag to mayExist where possible And don't delete on failure when updating. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 62 ++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index f9df44f31a..f9b5d47573 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1557,18 +1557,19 @@ func (n *ovn) setup(update bool) error { return err } - revert.Add(func() { client.ChassisGroupDelete(n.getChassisGroupName()) }) - - // Create logical router. - if update { - client.LogicalRouterDelete(n.getRouterName()) + if !update { + revert.Add(func() { client.ChassisGroupDelete(n.getChassisGroupName()) }) } - err = client.LogicalRouterAdd(n.getRouterName()) + // Create logical router. + err = client.LogicalRouterAdd(n.getRouterName(), update) if err != nil { return errors.Wrapf(err, "Failed adding router") } - revert.Add(func() { client.LogicalRouterDelete(n.getRouterName()) }) + + if !update { + revert.Add(func() { client.LogicalRouterDelete(n.getRouterName()) }) + } // Configure logical router. @@ -1589,23 +1590,24 @@ func (n *ovn) setup(update bool) error { } if len(extRouterIPs) > 0 { - // Create external logical switch. - if update { - client.LogicalSwitchDelete(n.getExtSwitchName()) - } - - err = client.LogicalSwitchAdd(n.getExtSwitchName(), false) + err = client.LogicalSwitchAdd(n.getExtSwitchName(), update) if err != nil { return errors.Wrapf(err, "Failed adding external switch") } - revert.Add(func() { client.LogicalSwitchDelete(n.getExtSwitchName()) }) + + if !update { + revert.Add(func() { client.LogicalSwitchDelete(n.getExtSwitchName()) }) + } // Create external router port. - err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterExtPortName(), routerMAC, extRouterIPs...) + err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterExtPortName(), routerMAC, extRouterIPs, update) if err != nil { return errors.Wrapf(err, "Failed adding external router port") } - revert.Add(func() { client.LogicalRouterPortDelete(n.getRouterExtPortName()) }) + + if !update { + revert.Add(func() { client.LogicalRouterPortDelete(n.getRouterExtPortName()) }) + } // Associate external router port to chassis group. err = client.LogicalRouterPortLinkChassisGroup(n.getRouterExtPortName(), n.getChassisGroupName()) @@ -1614,11 +1616,14 @@ func (n *ovn) setup(update bool) error { } // Create external switch port and link to router port. - err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchRouterPortName(), false) + err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchRouterPortName(), update) if err != nil { return errors.Wrapf(err, "Failed adding external switch router port") } - revert.Add(func() { client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) }) + + if !update { + revert.Add(func() { client.LogicalSwitchPortDelete(n.getExtSwitchRouterPortName()) }) + } err = client.LogicalSwitchPortLinkRouter(n.getExtSwitchRouterPortName(), n.getRouterExtPortName()) if err != nil { @@ -1626,11 +1631,14 @@ func (n *ovn) setup(update bool) error { } // Create external switch port and link to external provider network. - err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchProviderPortName(), false) + err = client.LogicalSwitchPortAdd(n.getExtSwitchName(), n.getExtSwitchProviderPortName(), update) if err != nil { return errors.Wrapf(err, "Failed adding external switch provider port") } - revert.Add(func() { client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) }) + + if !update { + revert.Add(func() { client.LogicalSwitchPortDelete(n.getExtSwitchProviderPortName()) }) + } err = client.LogicalSwitchPortLinkProviderNetwork(n.getExtSwitchProviderPortName(), uplinkNet.extSwitchProviderName) if err != nil { @@ -1639,14 +1647,14 @@ func (n *ovn) setup(update bool) error { // Add SNAT rules. if shared.IsTrue(n.config["ipv4.nat"]) && routerIntPortIPv4Net != nil && routerExtPortIPv4 != nil { - err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, routerExtPortIPv4) + err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, routerExtPortIPv4, update) if err != nil { return err } } if shared.IsTrue(n.config["ipv6.nat"]) && routerIntPortIPv6Net != nil && routerExtPortIPv6 != nil { - err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv6Net, routerExtPortIPv6) + err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv6Net, routerExtPortIPv6, update) if err != nil { return err } @@ -1673,7 +1681,10 @@ func (n *ovn) setup(update bool) error { if err != nil { return errors.Wrapf(err, "Failed adding internal switch") } - revert.Add(func() { client.LogicalSwitchDelete(n.getIntSwitchName()) }) + + if !update { + revert.Add(func() { client.LogicalSwitchDelete(n.getIntSwitchName()) }) + } var excludeIPV4 []shared.IPRange if routerIntPortIPv4 != nil { @@ -1821,7 +1832,10 @@ func (n *ovn) setup(update bool) error { if err != nil { return errors.Wrapf(err, "Failed adding internal switch router port") } - revert.Add(func() { client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) }) + + if !update { + revert.Add(func() { client.LogicalSwitchPortDelete(n.getIntSwitchRouterPortName()) }) + } err = client.LogicalSwitchPortLinkRouter(n.getIntSwitchRouterPortName(), n.getRouterIntPortName()) if err != nil { From c58ccecb18c04fc973a879989dff9b49c77593ef Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:55:51 +0000 Subject: [PATCH 11/16] lxd/network/driver/ovn: Delete SNAT rules from route before adding new ones This ensures that during an update, old SNAT rules are removed. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index f9b5d47573..e4a39b519b 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1645,6 +1645,15 @@ func (n *ovn) setup(update bool) error { return errors.Wrapf(err, "Failed linking external switch provider port to external provider network") } + // Remove any existing SNAT rules on update. As currently these are only defined from the network + // config rather than from any instance NIC config, so we can re-create the active config below. + if update { + err = client.LogicalRouterSNATDeleteAll(n.getRouterName()) + if err != nil { + return errors.Wrapf(err, "Failed removing existing router SNAT rules") + } + } + // Add SNAT rules. if shared.IsTrue(n.config["ipv4.nat"]) && routerIntPortIPv4Net != nil && routerExtPortIPv4 != nil { err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, routerExtPortIPv4, update) From cb9db30dbd7848b2f4c14ce636ab4bbb9c5e2f51 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:56:24 +0000 Subject: [PATCH 12/16] lxd/network/driver/ovn: Improve SNAT failure errors Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index e4a39b519b..1c0439f3a1 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1658,14 +1658,14 @@ func (n *ovn) setup(update bool) error { if shared.IsTrue(n.config["ipv4.nat"]) && routerIntPortIPv4Net != nil && routerExtPortIPv4 != nil { err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv4Net, routerExtPortIPv4, update) if err != nil { - return err + return errors.Wrapf(err, "Failed adding router IPv4 SNAT rule") } } if shared.IsTrue(n.config["ipv6.nat"]) && routerIntPortIPv6Net != nil && routerExtPortIPv6 != nil { err = client.LogicalRouterSNATAdd(n.getRouterName(), routerIntPortIPv6Net, routerExtPortIPv6, update) if err != nil { - return err + return errors.Wrapf(err, "Failed adding router IPv6 SNAT rule") } } From 0455da20308446fa359d010aee1b301f58e6f14d Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:57:00 +0000 Subject: [PATCH 13/16] lxd/network/driver/ovn: Pass update to mayExists when setting up default routes And remove default routes when IP protocol address isn't enabled. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 1c0439f3a1..f386d3a6c9 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1669,19 +1669,31 @@ func (n *ovn) setup(update bool) error { } } - // Add default routes. + // Add or remove default routes as config dictates. + defaultIPv4Route := &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)} if uplinkNet.routerExtGwIPv4 != nil { - err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}, uplinkNet.routerExtGwIPv4, false) + err = client.LogicalRouterRouteAdd(n.getRouterName(), defaultIPv4Route, uplinkNet.routerExtGwIPv4, update) if err != nil { return errors.Wrapf(err, "Failed adding IPv4 default route") } + } else if update { + err = client.LogicalRouterRouteDelete(n.getRouterName(), defaultIPv4Route, nil) + if err != nil { + return errors.Wrapf(err, "Failed removing IPv4 default route") + } } + defaultIPv6Route := &net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)} if uplinkNet.routerExtGwIPv6 != nil { - err = client.LogicalRouterRouteAdd(n.getRouterName(), &net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}, uplinkNet.routerExtGwIPv6, false) + err = client.LogicalRouterRouteAdd(n.getRouterName(), defaultIPv6Route, uplinkNet.routerExtGwIPv6, update) if err != nil { return errors.Wrapf(err, "Failed adding IPv6 default route") } + } else if update { + err = client.LogicalRouterRouteDelete(n.getRouterName(), defaultIPv6Route, nil) + if err != nil { + return errors.Wrapf(err, "Failed removing IPv6 default route") + } } } From acf0f3da29e98fb94c67636786a1e395c35b454a Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 17:58:20 +0000 Subject: [PATCH 14/16] lxd/network/driver/ovn: Create internal router port before DHCP option setup Keeps DHCP setup steps together. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 60 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index f386d3a6c9..6ce441e752 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1722,6 +1722,38 @@ func (n *ovn) setup(update bool) error { return errors.Wrapf(err, "Failed setting IP allocation settings on internal switch") } + // Gather internal router port IPs (in CIDR format). + intRouterIPs := []*net.IPNet{} + + if routerIntPortIPv4Net != nil { + intRouterIPs = append(intRouterIPs, &net.IPNet{ + IP: routerIntPortIPv4, + Mask: routerIntPortIPv4Net.Mask, + }) + } + + if routerIntPortIPv6Net != nil { + intRouterIPs = append(intRouterIPs, &net.IPNet{ + IP: routerIntPortIPv6, + Mask: routerIntPortIPv6Net.Mask, + }) + } + + if len(intRouterIPs) <= 0 { + return fmt.Errorf("No internal IPs defined for network router") + } + + // Create internal router port. + err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterIntPortName(), routerMAC, intRouterIPs, update) + if err != nil { + return errors.Wrapf(err, "Failed adding internal router port") + } + + if !update { + revert.Add(func() { client.LogicalRouterPortDelete(n.getRouterIntPortName()) }) + } + + // Configure DHCP option sets. var dhcpv4UUID, dhcpv6UUID string dhcpV4Subnet := n.DHCPv4Subnet() dhcpV6Subnet := n.DHCPv6Subnet() @@ -1763,27 +1795,6 @@ func (n *ovn) setup(update bool) error { } } - // Internal router port IPs (in CIDR format). - intRouterIPs := []*net.IPNet{} - - if routerIntPortIPv4Net != nil { - intRouterIPs = append(intRouterIPs, &net.IPNet{ - IP: routerIntPortIPv4, - Mask: routerIntPortIPv4Net.Mask, - }) - } - - if routerIntPortIPv6Net != nil { - intRouterIPs = append(intRouterIPs, &net.IPNet{ - IP: routerIntPortIPv6, - Mask: routerIntPortIPv6Net.Mask, - }) - } - - if len(intRouterIPs) <= 0 { - return fmt.Errorf("No IPs defined for network router") - } - // Create DHCPv4 options for internal switch. if dhcpV4Subnet != nil { err = client.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, dhcpV4Subnet, &openvswitch.OVNDHCPv4Opts{ @@ -1812,13 +1823,6 @@ func (n *ovn) setup(update bool) error { } } - // Create internal router port. - err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterIntPortName(), routerMAC, intRouterIPs...) - if err != nil { - return errors.Wrapf(err, "Failed adding internal router port") - } - revert.Add(func() { client.LogicalRouterPortDelete(n.getRouterIntPortName()) }) - // Set IPv6 router advertisement settings. if dhcpV6Subnet != nil { adressMode := openvswitch.OVNIPv6AddressModeSLAAC From 2b3cf479b84ce250ea8b90890fb5ade64e3ff1db Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 18:12:33 +0000 Subject: [PATCH 15/16] lxd/network/driver/ovn: Modifies IPv6 RA settings and removes them entirely when IPv6 disabled Settings change to: - ipv6.dhcp = false RA with slaac - ipv6.dhcp = true RA with stateless DHCP - ipv6.dhcp = true and ipv6.dhcp.stateful = true RA with stateful DHCP Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 6ce441e752..630ae3c914 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1824,10 +1824,13 @@ func (n *ovn) setup(update bool) error { } // Set IPv6 router advertisement settings. - if dhcpV6Subnet != nil { + if routerIntPortIPv6Net != nil { adressMode := openvswitch.OVNIPv6AddressModeSLAAC - if shared.IsTrue(n.config["ipv6.dhcp.stateful"]) { - adressMode = openvswitch.OVNIPv6AddressModeDHCPStateful + if dhcpV6Subnet != nil { + adressMode = openvswitch.OVNIPv6AddressModeDHCPStateless + if shared.IsTrue(n.config["ipv6.dhcp.stateful"]) { + adressMode = openvswitch.OVNIPv6AddressModeDHCPStateful + } } var recursiveDNSServer net.IP @@ -1850,6 +1853,11 @@ func (n *ovn) setup(update bool) error { if err != nil { return errors.Wrapf(err, "Failed setting internal router port IPv6 advertisement settings") } + } else { + err = client.LogicalRouterPortDeleteIPv6Advertisements(n.getRouterIntPortName()) + if err != nil { + return errors.Wrapf(err, "Failed removing internal router port IPv6 advertisement settings") + } } // Create internal switch port and link to router port. From f486c839c6f9cc884ba40d3cc67031aab69dbe0f Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Fri, 18 Dec 2020 18:14:07 +0000 Subject: [PATCH 16/16] lxd/network/driver/ovn: Don't return DHCPv6 subnet if IPv6 prefix smaller than /64 Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 630ae3c914..6f2d9d7d39 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -2585,6 +2585,11 @@ func (n *ovn) DHCPv6Subnet() *net.IPNet { return nil } + ones, _ := subnet.Mask.Size() + if ones > 64 { + return nil // OVN only supports DHCPv6 allocated using EUI64 (which requires at least a /64). + } + return subnet }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel