The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/8229
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) === Allows DHCP/RA to be disabled.
From 19b1f4ea200277bbcb3519e4ec630bee769b7156 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 13:58:55 +0000 Subject: [PATCH 1/7] lxd/network/openvswitch/ovn: Exports LogicalSwitchDHCPOptionsDelete and adds optional UUID filter for deletion Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/openvswitch/ovn.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lxd/network/openvswitch/ovn.go b/lxd/network/openvswitch/ovn.go index 643e6d7047..d7ad3079ee 100644 --- a/lxd/network/openvswitch/ovn.go +++ b/lxd/network/openvswitch/ovn.go @@ -325,7 +325,7 @@ func (o *OVN) LogicalSwitchDelete(switchName OVNSwitch) error { return err } - err = o.logicalSwitchDHCPOptionsDelete(switchName) + err = o.LogicalSwitchDHCPOptionsDelete(switchName) if err != nil { return err } @@ -549,8 +549,9 @@ func (o *OVN) LogicalSwitchDHCPOptionsGet(switchName OVNSwitch) ([]OVNDHCPOptsSe return dhcpOpts, nil } -// logicalSwitchDHCPOptionsDelete deletes any DHCP options defined for a switch. -func (o *OVN) logicalSwitchDHCPOptionsDelete(switchName OVNSwitch) error { +// LogicalSwitchDHCPOptionsDelete deletes any DHCP options defined for a switch. +// Optionally accepts one or more specific UUID records to delete (if they are associated to the specified switch). +func (o *OVN) LogicalSwitchDHCPOptionsDelete(switchName OVNSwitch, onlyUUID ...string) error { existingOpts, err := o.nbctl("--format=csv", "--no-headings", "--data=bare", "--colum=_uuid", "find", "dhcp_options", fmt.Sprintf("external_ids:lxd_switch=%s", string(switchName)), ) @@ -558,12 +559,28 @@ func (o *OVN) logicalSwitchDHCPOptionsDelete(switchName OVNSwitch) error { return err } + shouldDelete := func(existingUUID string) bool { + if len(onlyUUID) <= 0 { + return true // Delete all records if no UUID filter supplied. + } + + for _, uuid := range onlyUUID { + if existingUUID == uuid { + return true + } + } + + return false + } + existingOpts = strings.TrimSpace(existingOpts) if existingOpts != "" { for _, uuid := range strings.Split(existingOpts, "\n") { - _, err = o.nbctl("destroy", "dhcp_options", uuid) - if err != nil { - return err + if shouldDelete(uuid) { + _, err = o.nbctl("destroy", "dhcp_options", uuid) + if err != nil { + return err + } } } } From f893eb22808c247ac88fe0051bc53b91fc66dae8 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:02:45 +0000 Subject: [PATCH 2/7] lxc/network/driver/ovn: Adds ipv4.dhcp and ipv6.dhcp boolean settings Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index dc7668e853..4723a8445f 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -180,6 +180,7 @@ func (n *ovn) Validate(config map[string]string) error { return validate.Optional(validate.IsNetworkAddressCIDRV4)(value) }, + "ipv4.dhcp": validate.Optional(validate.IsBool), "ipv6.address": func(value string) error { if validate.IsOneOf(value, []string{"none", "auto"}) == nil { return nil @@ -187,6 +188,7 @@ func (n *ovn) Validate(config map[string]string) error { return validate.Optional(validate.IsNetworkAddressCIDRV6)(value) }, + "ipv6.dhcp": validate.Optional(validate.IsBool), "ipv6.dhcp.stateful": validate.Optional(validate.IsBool), "ipv4.nat": validate.Optional(validate.IsBool), "ipv6.nat": validate.Optional(validate.IsBool), From 9067bf591633532827a2708cccdc3d779f92c7cc Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:08:08 +0000 Subject: [PATCH 3/7] lxc/network/driver/ovn: Modifies setup to only activate DHCP/RA if its enabled on network Also removes old DHCP option records if DHCP is being disabled. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 61 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index 4723a8445f..d0c35a2a0d 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -1605,6 +1605,8 @@ func (n *ovn) setup(update bool) error { } var dhcpv4UUID, dhcpv6UUID string + dhcpV4Subnet := n.DHCPv4Subnet() + dhcpV6Subnet := n.DHCPv6Subnet() if update { // Find first existing DHCP options set for IPv4 and IPv6 and update them instead of adding sets. @@ -1613,25 +1615,60 @@ func (n *ovn) setup(update bool) error { return errors.Wrapf(err, "Failed getting existing DHCP settings for internal switch") } + var deleteDHCPRecords []string // DHCP option records to delete if DHCP is being disabled. + for _, existingOpt := range existingOpts { if existingOpt.CIDR.IP.To4() == nil { if dhcpv6UUID == "" { dhcpv6UUID = existingOpt.UUID + + if dhcpV6Subnet == nil { + deleteDHCPRecords = append(deleteDHCPRecords, dhcpv6UUID) + } } } else { if dhcpv4UUID == "" { dhcpv4UUID = existingOpt.UUID + + if dhcpV4Subnet == nil { + deleteDHCPRecords = append(deleteDHCPRecords, dhcpv4UUID) + } } } } + + if len(deleteDHCPRecords) > 0 { + err = client.LogicalSwitchDHCPOptionsDelete(n.getIntSwitchName(), deleteDHCPRecords...) + if err != nil { + return errors.Wrapf(err, "Failed deleting existing DHCP settings for internal switch") + } + } } // Internal router port IPs (in CIDR format). intRouterIPs := []*net.IPNet{} - // Create DHCPv4 options for internal switch. if routerIntPortIPv4Net != nil { - err = client.LogicalSwitchDHCPv4OptionsSet(n.getIntSwitchName(), dhcpv4UUID, routerIntPortIPv4Net, &openvswitch.OVNDHCPv4Opts{ + 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{ ServerID: routerIntPortIPv4, ServerMAC: routerMAC, Router: routerIntPortIPv4, @@ -1643,16 +1680,11 @@ func (n *ovn) setup(update bool) error { if err != nil { return errors.Wrapf(err, "Failed adding DHCPv4 settings for internal switch") } - - intRouterIPs = append(intRouterIPs, &net.IPNet{ - IP: routerIntPortIPv4, - Mask: routerIntPortIPv4Net.Mask, - }) } // Create DHCPv6 options for internal switch. - if routerIntPortIPv6Net != nil { - err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, routerIntPortIPv6Net, &openvswitch.OVNDHCPv6Opts{ + if dhcpV6Subnet != nil { + err = client.LogicalSwitchDHCPv6OptionsSet(n.getIntSwitchName(), dhcpv6UUID, dhcpV6Subnet, &openvswitch.OVNDHCPv6Opts{ ServerID: routerMAC, RecursiveDNSServer: uplinkNet.dnsIPv6, DNSSearchList: n.getDNSSearchList(), @@ -1660,18 +1692,9 @@ func (n *ovn) setup(update bool) error { if err != nil { return errors.Wrapf(err, "Failed adding DHCPv6 settings for internal switch") } - - intRouterIPs = append(intRouterIPs, &net.IPNet{ - IP: routerIntPortIPv6, - Mask: routerIntPortIPv6Net.Mask, - }) } // Create internal router port. - if len(intRouterIPs) <= 0 { - return fmt.Errorf("No IPs defined for network router") - } - err = client.LogicalRouterPortAdd(n.getRouterName(), n.getRouterIntPortName(), routerMAC, intRouterIPs...) if err != nil { return errors.Wrapf(err, "Failed adding internal router port") @@ -1679,7 +1702,7 @@ func (n *ovn) setup(update bool) error { revert.Add(func() { client.LogicalRouterPortDelete(n.getRouterIntPortName()) }) // Set IPv6 router advertisement settings. - if routerIntPortIPv6Net != nil { + if dhcpV6Subnet != nil { adressMode := openvswitch.OVNIPv6AddressModeSLAAC if shared.IsTrue(n.config["ipv6.dhcp.stateful"]) { adressMode = openvswitch.OVNIPv6AddressModeDHCPStateful From 1ba16cffc87d151eeece2fcacd548f09f8fdddb3 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:08:59 +0000 Subject: [PATCH 4/7] lxd/network/driver/ovn: Updates InstanceDevicePortAdd to respect DHCP options on network Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/network/driver_ovn.go | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/lxd/network/driver_ovn.go b/lxd/network/driver_ovn.go index d0c35a2a0d..d467867c10 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -2118,26 +2118,19 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, instanceName string, de return "", errors.Wrapf(err, "Failed to load uplink network %q", n.config["network"]) } - // Get DHCP options IDs. - if validate.IsOneOf(n.getRouterIntPortIPv4Net(), []string{"none", ""}) != nil { - _, routerIntPortIPv4Net, err := net.ParseCIDR(n.getRouterIntPortIPv4Net()) - if err != nil { - return "", err - } + dhcpv4Subnet := n.DHCPv4Subnet() + dhcpv6Subnet := n.DHCPv6Subnet() - dhcpV4ID, err = client.LogicalSwitchDHCPOptionsGetID(n.getIntSwitchName(), routerIntPortIPv4Net) + // Get DHCP options IDs. + if dhcpv4Subnet != nil { + dhcpV4ID, err = client.LogicalSwitchDHCPOptionsGetID(n.getIntSwitchName(), dhcpv4Subnet) if err != nil { return "", err } } - if validate.IsOneOf(n.getRouterIntPortIPv6Net(), []string{"none", ""}) != nil { - _, routerIntPortIPv6Net, err := net.ParseCIDR(n.getRouterIntPortIPv6Net()) - if err != nil { - return "", err - } - - dhcpv6ID, err = client.LogicalSwitchDHCPOptionsGetID(n.getIntSwitchName(), routerIntPortIPv6Net) + if dhcpv6Subnet != nil { + dhcpv6ID, err = client.LogicalSwitchDHCPOptionsGetID(n.getIntSwitchName(), dhcpv6Subnet) if err != nil { return "", err } @@ -2156,7 +2149,7 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, instanceName string, de } if !hasIPv6 { - eui64IP, err := eui64.ParseMAC(routerIntPortIPv6Net.IP, mac) + eui64IP, err := eui64.ParseMAC(dhcpv6Subnet.IP, mac) if err != nil { return "", errors.Wrapf(err, "Failed generating EUI64 for instance port %q", mac.String()) } From 33a6d4d8a6aac553bfbb7bbf15ad450e186fed3b Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:09:24 +0000 Subject: [PATCH 5/7] lxd/network/driver/ovn: Updates DHCPv4Subnet and DHCPv6Subnet to use IP helper functions 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 d467867c10..280482c4ac 100644 --- a/lxd/network/driver_ovn.go +++ b/lxd/network/driver_ovn.go @@ -2411,7 +2411,7 @@ func (n *ovn) DHCPv4Subnet() *net.IPNet { return nil } - _, subnet, err := net.ParseCIDR(n.config["ipv4.address"]) + _, subnet, err := net.ParseCIDR(n.getRouterIntPortIPv4Net()) if err != nil { return nil } @@ -2426,7 +2426,7 @@ func (n *ovn) DHCPv6Subnet() *net.IPNet { return nil } - _, subnet, err := net.ParseCIDR(n.config["ipv6.address"]) + _, subnet, err := net.ParseCIDR(n.getRouterIntPortIPv6Net()) if err != nil { return nil } From 0b8ae947101f75bbd1d7423cbf7e2c8c8707bb21 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:12:14 +0000 Subject: [PATCH 6/7] api: Adds network_ovn_dhcp extension Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- doc/api-extensions.md | 5 +++++ shared/version/api.go | 1 + 2 files changed, 6 insertions(+) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index c1645d4f86..92c63f2199 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -1242,3 +1242,8 @@ Adds `ovn.ingress_mode` setting for `physical` networks. Sets the method that OVN NIC external IPs will be advertised on uplink network. Either `l2proxy` (proxy ARP/NDP) or `routed`. + +## network\_ovn\_dhcp +Adds `ipv4.dhcp` and `ipv6.dhcp` settings for `ovn` networks. + +Allows DHCP (and RA for IPv6) to be disabled. Defaults to on. diff --git a/shared/version/api.go b/shared/version/api.go index ee1ee5a6a8..2c8b4d2176 100644 --- a/shared/version/api.go +++ b/shared/version/api.go @@ -240,6 +240,7 @@ var APIExtensions = []string{ "resources_network_usb", "resources_disk_address", "network_physical_ovn_ingress_mode", + "network_ovn_dhcp", } // APIExtensionsCount returns the number of available API extensions. From 567f795f599a26b30f5e06e43bc661a0152dbed9 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Wed, 9 Dec 2020 14:13:18 +0000 Subject: [PATCH 7/7] doc/networks: Adds ipv4.dhcp and ipv6.dhcp docs for OVN networks Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- doc/networks.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/networks.md b/doc/networks.md index cd06506e85..c0ead486b3 100644 --- a/doc/networks.md +++ b/doc/networks.md @@ -297,8 +297,10 @@ bridge.mtu | integer | - | 1442 dns.domain | string | - | lxd | Domain to advertise to DHCP clients and use for DNS resolution dns.search | string | - | - | Full comma separated domain search list, defaulting to `dns.domain` value ipv4.address | string | standard mode | auto (on create only) | IPv4 address for the bridge (CIDR notation). Use "none" to turn off IPv4 or "auto" to generate a new random unused subnet +ipv4.dhcp | boolean | ipv4 address | true | Whether to allocate addresses using DHCP ipv4.nat | boolean | ipv4 address | false | Whether to NAT (will default to true if unset and a random ipv4.address is generated) ipv6.address | string | standard mode | auto (on create only) | IPv6 address for the bridge (CIDR notation). Use "none" to turn off IPv6 or "auto" to generate a new random unused subnet +ipv6.dhcp | boolean | ipv6 address | true | Whether to provide additional network configuration over DHCP ipv6.dhcp.stateful | boolean | ipv6 dhcp | false | Whether to allocate addresses using DHCP ipv6.nat | boolean | ipv6 address | false | Whether to NAT (will default to true if unset and a random ipv6.address is generated) network | string | - | - | Uplink network to use for external network access
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel