From 8cad8c1df2fa9a25d7a24399e81253f7ff01efed Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 31 Jul 2023 16:33:21 +0530 Subject: [PATCH] net: fix ipv6_dhcpv6_stateful configuration for rhel When network type is ipv6_dhcpv6-stateful, cloud-init seems to enable dhcp for both ipv4 and ipv6. Network manager prefers dhcp over ipv4 and hence dhcp6 is not used to obtain the IP address. This is incorrect. For ipv6_dhcpv6-stateful networks, we should set: ipv4.method = disabled // disables all ipv4 dhcp ipv6.method = dhcp ipv6.may-fail = no // dhcp6 must succeed. For ifcfg files (sysconfig renderer), the corresponding changes should be: BOOTPROTO = none // instead of dhcp so that dhcp4 is disabled. IPV6_FAILURE_FATAL = yes // so that dhcp6 should succeed. This patch fixes this. This patch has been tested by Red Hat QE and it seems to fix the above issue. RHBZ: 2227767 fixes: f550c8765ca03d ("Adding BOOTPROTO = dhcp to render sysconfig dhcp6 stateful on RHEL (#685)") Signed-off-by: Ani Sinha --- cloudinit/net/network_manager.py | 15 +++++++++++++-- cloudinit/net/sysconfig.py | 3 ++- tests/unittests/test_net.py | 3 ++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cloudinit/net/network_manager.py b/cloudinit/net/network_manager.py index 8047f79690d..39277cc3ec0 100644 --- a/cloudinit/net/network_manager.py +++ b/cloudinit/net/network_manager.py @@ -36,7 +36,7 @@ class NMConnection: """Represents a NetworkManager connection profile.""" - def __init__(self, con_id): + def __init__(self, con_id, cloud_config=None): """ Initializes the connection with some very basic properties, notably the UUID so that the connection can be referred to. @@ -49,6 +49,8 @@ def __init__(self, con_id): # Identity option name mapping, to achieve case sensitivity self.config.optionxform = str + self.cloud_config = {} if not cloud_config else cloud_config + self.config["connection"] = { "id": f"cloud-init {con_id}", "uuid": str(uuid.uuid5(CI_NM_UUID, con_id)), @@ -105,6 +107,12 @@ def _set_ip_method(self, family, subnet_type): if self.config[family]["method"] == "auto" and method == "manual": return + flavor = self.cloud_config.get("flavor", "rhel") + if flavor == "rhel" and subnet_type == "ipv6_dhcpv6-stateful": + # set ipv4 method to 'disabled' so that dhcp4 is turned off and + # the setting aligns with sysconfig renderer + self._set_default("ipv4", "method", "disabled") + self.config[family]["method"] = method self._set_default(family, "may-fail", "false") @@ -342,6 +350,7 @@ class Renderer(renderer.Renderer): def __init__(self, config=None): self.connections = {} + self.config = config def get_conn(self, con_id): return self.connections[con_id] @@ -363,7 +372,9 @@ def render_network_state( # interfaces that have UUIDs that can be linked to from related # interfaces for iface in network_state.iter_interfaces(): - self.connections[iface["name"]] = NMConnection(iface["name"]) + self.connections[iface["name"]] = NMConnection( + iface["name"], self.config + ) # Now render the actual interface configuration for iface in network_state.iter_interfaces(): diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py index f5fd2acfea2..ef613778afa 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py @@ -439,10 +439,11 @@ def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor): elif ( flavor == "rhel" and subnet_type == "ipv6_dhcpv6-stateful" ): - iface_cfg["BOOTPROTO"] = "dhcp" + iface_cfg["BOOTPROTO"] = "none" iface_cfg["DHCPV6C"] = True iface_cfg["IPV6INIT"] = True iface_cfg["IPV6_AUTOCONF"] = False + iface_cfg["IPV6_FAILURE_FATAL"] = True else: iface_cfg["IPV6INIT"] = True # Configure network settings using DHCPv6 diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index da82b15a70a..959d8de36bd 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -2091,11 +2091,12 @@ "expected_sysconfig_rhel": { "ifcfg-iface0": textwrap.dedent( """\ - BOOTPROTO=dhcp + BOOTPROTO=none DEVICE=iface0 DHCPV6C=yes IPV6INIT=yes IPV6_AUTOCONF=no + IPV6_FAILURE_FATAL=yes IPV6_FORCE_ACCEPT_RA=yes DEVICE=iface0 NM_CONTROLLED=no