296 lines
12 KiB
Diff
296 lines
12 KiB
Diff
From 5ded09d5acf4d653fe2cbd54814f53063d265489 Mon Sep 17 00:00:00 2001
|
|
From: Eduardo Otubo <otubo@redhat.com>
|
|
Date: Thu, 29 Oct 2020 15:05:42 +0100
|
|
Subject: [PATCH 1/3] Explicit set IPV6_AUTOCONF and IPV6_FORCE_ACCEPT_RA on
|
|
static6 (#634)
|
|
|
|
RH-Author: Eduardo Terrell Ferrari Otubo (eterrell)
|
|
RH-MergeRequest: 13: [RHEL-8.4.0] Add support for ipv6_autoconf on cloud-init-20.3
|
|
RH-Commit: [1/1] 41e61c35893f4487981a1ad31f9f97a9a740b397 (eterrell/cloud-init)
|
|
RH-Bugzilla: 1889635
|
|
|
|
commit b46e4a8cff667c8441622089cf7d57aeb88220cd
|
|
Author: Eduardo Otubo <otubo@redhat.com>
|
|
Date: Thu Oct 29 15:05:42 2020 +0100
|
|
|
|
Explicit set IPV6_AUTOCONF and IPV6_FORCE_ACCEPT_RA on static6 (#634)
|
|
|
|
The static and static6 subnet types for network_data.json were
|
|
being ignored by the Openstack handler, this would cause the code to
|
|
break and not function properly.
|
|
|
|
As of today, if a static6 configuration is chosen, the interface will
|
|
still eventually be available to receive router advertisements or be set
|
|
from NetworkManager to wait for them and cycle the interface in negative
|
|
case.
|
|
|
|
It is safe to assume that if the interface is manually configured to use
|
|
static ipv6 address, there's no need to wait for router advertisements.
|
|
This patch will set automatically IPV6_AUTOCONF and IPV6_FORCE_ACCEPT_RA
|
|
both to "no" in this case.
|
|
|
|
This patch fixes the specific behavior only for RHEL flavor and
|
|
sysconfig renderer. It also introduces new unit tests for the specific
|
|
case as well as adjusts some existent tests to be compatible with the
|
|
new options. This patch also addresses this problem by assigning the
|
|
appropriate subnet type for each case on the openstack handler.
|
|
|
|
rhbz: #1889635
|
|
rhbz: #1889635
|
|
|
|
Signed-off-by: Eduardo Otubo otubo@redhat.com
|
|
|
|
Signed-off-by: Eduardo Otubo otubo@redhat.com
|
|
---
|
|
cloudinit/net/network_state.py | 3 +-
|
|
cloudinit/net/sysconfig.py | 4 +
|
|
cloudinit/sources/helpers/openstack.py | 8 +-
|
|
tests/unittests/test_distros/test_netconfig.py | 2 +
|
|
tests/unittests/test_net.py | 100 +++++++++++++++++++++++++
|
|
5 files changed, 115 insertions(+), 2 deletions(-)
|
|
|
|
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
|
|
--
|
|
1.8.3.1
|
|
|