[lxc-devel] [lxd/master] Network: Adds ipv4.dhcp and ipv6.dhcp settings for OVN networks
tomponline on Github
lxc-bot at linuxcontainers.org
Wed Dec 9 14:15:13 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 335 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201209/67f82fbe/attachment.bin>
-------------- next part --------------
From 19b1f4ea200277bbcb3519e4ec630bee769b7156 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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.parrott at 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
More information about the lxc-devel
mailing list