Blob Blame History Raw
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