diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py index b2f7d31..d9e7fd5 100644 --- a/cloudinit/net/network_state.py +++ b/cloudinit/net/network_state.py @@ -820,7 +820,8 @@ def _normalize_subnet(subnet): if subnet.get('type') in ('static', 'static6'): normal_subnet.update( - _normalize_net_keys(normal_subnet, address_keys=('address',))) + _normalize_net_keys(normal_subnet, address_keys=( + 'address', 'ip_address',))) normal_subnet['routes'] = [_normalize_route(r) for r in subnet.get('routes', [])] diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py index af093dd..c078898 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py @@ -451,6 +451,10 @@ class Renderer(renderer.Renderer): iface_cfg[mtu_key] = subnet['mtu'] else: iface_cfg[mtu_key] = subnet['mtu'] + + if subnet_is_ipv6(subnet) and flavor == 'rhel': + iface_cfg['IPV6_FORCE_ACCEPT_RA'] = False + iface_cfg['IPV6_AUTOCONF'] = False elif subnet_type == 'manual': if flavor == 'suse': LOG.debug('Unknown subnet type setting "%s"', subnet_type) diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py index 65e020c..3e6365f 100644 --- a/cloudinit/sources/helpers/openstack.py +++ b/cloudinit/sources/helpers/openstack.py @@ -602,11 +602,17 @@ def convert_net_json(network_json=None, known_macs=None): elif network['type'] in ['ipv6_slaac', 'ipv6_dhcpv6-stateless', 'ipv6_dhcpv6-stateful']: subnet.update({'type': network['type']}) - elif network['type'] in ['ipv4', 'ipv6']: + elif network['type'] in ['ipv4', 'static']: subnet.update({ 'type': 'static', 'address': network.get('ip_address'), }) + elif network['type'] in ['ipv6', 'static6']: + cfg.update({'accept-ra': False}) + subnet.update({ + 'type': 'static6', + 'address': network.get('ip_address'), + }) # Enable accept_ra for stateful and legacy ipv6_dhcp types if network['type'] in ['ipv6_dhcpv6-stateful', 'ipv6_dhcp']: diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py index 8d7b09c..f9fc3a1 100644 --- a/tests/unittests/test_distros/test_netconfig.py +++ b/tests/unittests/test_distros/test_netconfig.py @@ -514,7 +514,9 @@ class TestNetCfgDistroRedhat(TestNetCfgDistroBase): DEVICE=eth0 IPV6ADDR=2607:f0d0:1002:0011::2/64 IPV6INIT=yes + IPV6_AUTOCONF=no IPV6_DEFAULTGW=2607:f0d0:1002:0011::1 + IPV6_FORCE_ACCEPT_RA=no NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index 9985a97..d7a7a65 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -750,7 +750,9 @@ IPADDR=172.19.1.34 IPV6ADDR=2001:DB8::10/64 IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64" IPV6INIT=yes +IPV6_AUTOCONF=no IPV6_DEFAULTGW=2001:DB8::1 +IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.252.0 ONBOOT=yes TYPE=Ethernet @@ -1022,6 +1024,8 @@ NETWORK_CONFIGS = { IPADDR=192.168.14.2 IPV6ADDR=2001:1::1/64 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no NETMASK=255.255.255.0 ONBOOT=yes TYPE=Ethernet @@ -1247,6 +1251,33 @@ NETWORK_CONFIGS = { """), }, }, + 'static6': { + 'yaml': textwrap.dedent("""\ + version: 1 + config: + - type: 'physical' + name: 'iface0' + accept-ra: 'no' + subnets: + - type: 'static6' + address: 2001:1::1/64 + """).rstrip(' '), + 'expected_sysconfig_rhel': { + 'ifcfg-iface0': textwrap.dedent("""\ + BOOTPROTO=none + DEVICE=iface0 + IPV6ADDR=2001:1::1/64 + IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no + DEVICE=iface0 + NM_CONTROLLED=no + ONBOOT=yes + TYPE=Ethernet + USERCTL=no + """), + }, + }, 'dhcpv6_stateless': { 'expected_eni': textwrap.dedent("""\ auto lo @@ -1636,6 +1667,8 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true IPADDR=192.168.14.2 IPV6ADDR=2001:1::1/64 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no IPV6_DEFAULTGW=2001:4800:78ff:1b::1 MACADDR=bb:bb:bb:bb:bb:aa NETMASK=255.255.255.0 @@ -2158,6 +2191,8 @@ iface bond0 inet6 static IPADDR1=192.168.1.2 IPV6ADDR=2001:1::1/92 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no MTU=9000 NETMASK=255.255.255.0 NETMASK1=255.255.255.0 @@ -2259,6 +2294,8 @@ iface bond0 inet6 static IPADDR1=192.168.1.2 IPV6ADDR=2001:1::bbbb/96 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no IPV6_DEFAULTGW=2001:1::1 MTU=2222 NETMASK=255.255.255.0 @@ -2341,6 +2378,9 @@ iface bond0 inet6 static HWADDR=52:54:00:12:34:00 IPV6ADDR=2001:1::100/96 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no + NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet USERCTL=no @@ -2352,6 +2392,9 @@ iface bond0 inet6 static HWADDR=52:54:00:12:34:01 IPV6ADDR=2001:1::101/96 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no + NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet USERCTL=no @@ -3151,6 +3194,61 @@ USERCTL=no self._compare_files_to_expected(entry[self.expected_name], found) self._assert_headers(found) + def test_stattic6_from_json(self): + net_json = { + "services": [{"type": "dns", "address": "172.19.0.12"}], + "networks": [{ + "network_id": "dacd568d-5be6-4786-91fe-750c374b78b4", + "type": "ipv4", "netmask": "255.255.252.0", + "link": "tap1a81968a-79", + "routes": [{ + "netmask": "0.0.0.0", + "network": "0.0.0.0", + "gateway": "172.19.3.254", + }, { + "netmask": "0.0.0.0", # A second default gateway + "network": "0.0.0.0", + "gateway": "172.20.3.254", + }], + "ip_address": "172.19.1.34", "id": "network0" + }, { + "network_id": "mgmt", + "netmask": "ffff:ffff:ffff:ffff::", + "link": "interface1", + "mode": "link-local", + "routes": [], + "ip_address": "fe80::c096:67ff:fe5c:6e84", + "type": "static6", + "id": "network1", + "services": [], + "accept-ra": "false" + }], + "links": [ + { + "ethernet_mac_address": "fa:16:3e:ed:9a:59", + "mtu": None, "type": "bridge", "id": + "tap1a81968a-79", + "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f" + }, + ], + } + macs = {'fa:16:3e:ed:9a:59': 'eth0'} + render_dir = self.tmp_dir() + network_cfg = openstack.convert_net_json(net_json, known_macs=macs) + ns = network_state.parse_net_config_data(network_cfg, + skip_broken=False) + renderer = self._get_renderer() + with self.assertRaises(ValueError): + renderer.render_network_state(ns, target=render_dir) + self.assertEqual([], os.listdir(render_dir)) + + def test_static6_from_yaml(self): + entry = NETWORK_CONFIGS['static6'] + found = self._render_and_read(network_config=yaml.load( + entry['yaml'])) + self._compare_files_to_expected(entry[self.expected_name], found) + self._assert_headers(found) + def test_dhcpv6_reject_ra_config_v2(self): entry = NETWORK_CONFIGS['dhcpv6_reject_ra'] found = self._render_and_read(network_config=yaml.load( @@ -3268,6 +3366,8 @@ USERCTL=no IPADDR=192.168.42.100 IPV6ADDR=2001:db8::100/32 IPV6INIT=yes + IPV6_AUTOCONF=no + IPV6_FORCE_ACCEPT_RA=no IPV6_DEFAULTGW=2001:db8::1 NETMASK=255.255.255.0 NM_CONTROLLED=no