From bfbe8099b98bb97cfd96385fe31c023548734cbf Mon Sep 17 00:00:00 2001 From: Shraddha Pandhe Date: Fri, 21 Nov 2014 18:32:30 +0000 Subject: Add IPv6 Support for Rhel. This patch does the following: 1. Adds support to process network config with IPv6 2. Adds support to display 'ifconfig -a' information for IPv6 3. Adds support to display routing information for IPv6 --- cloudinit/distros/net_util.py | 60 ++++++++++++++++++++++++++++--------------- cloudinit/distros/rhel.py | 11 ++++++++ 2 files changed, 51 insertions(+), 20 deletions(-) (limited to 'cloudinit/distros') diff --git a/cloudinit/distros/net_util.py b/cloudinit/distros/net_util.py index b9bcfd8b..f56f6ccd 100644 --- a/cloudinit/distros/net_util.py +++ b/cloudinit/distros/net_util.py @@ -113,6 +113,10 @@ def translate_network(settings): for info in ifaces: if 'iface' not in info: continue + use_ipv6 = False + # Check if current device has an ipv6 IP + if 'inet6' in info['iface']: + use_ipv6 = True iface_details = info['iface'].split(None) dev_name = None if len(iface_details) >= 1: @@ -122,6 +126,7 @@ def translate_network(settings): if not dev_name: continue iface_info = {} + iface_info['ipv6'] = {} if len(iface_details) >= 3: proto_type = iface_details[2].strip().lower() # Seems like this can be 'loopback' which we don't @@ -129,26 +134,39 @@ def translate_network(settings): if proto_type in ['dhcp', 'static']: iface_info['bootproto'] = proto_type # These can just be copied over - for k in ['netmask', 'address', 'gateway', 'broadcast']: - if k in info: - val = info[k].strip().lower() - if val: - iface_info[k] = val - # Name server info provided?? - if 'dns-nameservers' in info: - iface_info['dns-nameservers'] = info['dns-nameservers'].split() - # Name server search info provided?? - if 'dns-search' in info: - iface_info['dns-search'] = info['dns-search'].split() - # Is any mac address spoofing going on?? - if 'hwaddress' in info: - hw_info = info['hwaddress'].lower().strip() - hw_split = hw_info.split(None, 1) - if len(hw_split) == 2 and hw_split[0].startswith('ether'): - hw_addr = hw_split[1] - if hw_addr: - iface_info['hwaddress'] = hw_addr - real_ifaces[dev_name] = iface_info + if use_ipv6: + for k in ['address', 'gateway']: + if k in info: + val = info[k].strip().lower() + if val: + iface_info['ipv6'][k] = val + else: + for k in ['netmask', 'address', 'gateway', 'broadcast']: + if k in info: + val = info[k].strip().lower() + if val: + iface_info[k] = val + # Name server info provided?? + if 'dns-nameservers' in info: + iface_info['dns-nameservers'] = info['dns-nameservers'].split() + # Name server search info provided?? + if 'dns-search' in info: + iface_info['dns-search'] = info['dns-search'].split() + # Is any mac address spoofing going on?? + if 'hwaddress' in info: + hw_info = info['hwaddress'].lower().strip() + hw_split = hw_info.split(None, 1) + if len(hw_split) == 2 and hw_split[0].startswith('ether'): + hw_addr = hw_split[1] + if hw_addr: + iface_info['hwaddress'] = hw_addr + + # If ipv6 is enabled, device will have multiple IPs. + # Update the dictionary instead of overwriting it + if dev_name in real_ifaces: + real_ifaces[dev_name].update(iface_info) + else: + real_ifaces[dev_name] = iface_info # Check for those that should be started on boot via 'auto' for (cmd, args) in entries: if cmd == 'auto': @@ -160,4 +178,6 @@ def translate_network(settings): dev_name = args[0].strip().lower() if dev_name in real_ifaces: real_ifaces[dev_name]['auto'] = True + if cmd == 'iface' and 'inet6' in args: + real_ifaces[dev_name]['inet6'] = True return real_ifaces diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py index 1a269e08..fa3ccb38 100644 --- a/cloudinit/distros/rhel.py +++ b/cloudinit/distros/rhel.py @@ -71,6 +71,7 @@ class Distro(distros.Distro): nameservers = [] searchservers = [] dev_names = entries.keys() + use_ipv6 = False for (dev, info) in entries.iteritems(): net_fn = self.network_script_tpl % (dev) net_cfg = { @@ -83,6 +84,13 @@ class Distro(distros.Distro): 'MACADDR': info.get('hwaddress'), 'ONBOOT': _make_sysconfig_bool(info.get('auto')), } + if info.get('inet6'): + use_ipv6 = True + net_cfg.update({ + 'IPV6INIT': _make_sysconfig_bool(True), + 'IPV6ADDR': info.get('ipv6').get('address'), + 'IPV6_DEFAULTGW': info.get('ipv6').get('gateway'), + }) rhel_util.update_sysconfig_file(net_fn, net_cfg) if 'dns-nameservers' in info: nameservers.extend(info['dns-nameservers']) @@ -95,6 +103,9 @@ class Distro(distros.Distro): net_cfg = { 'NETWORKING': _make_sysconfig_bool(True), } + # If IPv6 interface present, enable ipv6 networking + if use_ipv6: + net_cfg['NETWORKING_IPV6'] = _make_sysconfig_bool(True) rhel_util.update_sysconfig_file(self.network_conf_fn, net_cfg) return dev_names -- cgit v1.2.3 From 563467f2d62def448dbb8bacf33ae25782b2849e Mon Sep 17 00:00:00 2001 From: Shraddha Pandhe Date: Fri, 21 Nov 2014 22:17:26 +0000 Subject: Added unittests for IPv6 support for RHEL --- cloudinit/distros/rhel.py | 1 + tests/unittests/test_distros/test_netconfig.py | 93 ++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) (limited to 'cloudinit/distros') diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py index fa3ccb38..13335df5 100644 --- a/cloudinit/distros/rhel.py +++ b/cloudinit/distros/rhel.py @@ -106,6 +106,7 @@ class Distro(distros.Distro): # If IPv6 interface present, enable ipv6 networking if use_ipv6: net_cfg['NETWORKING_IPV6'] = _make_sysconfig_bool(True) + net_cfg['IPV6_AUTOCONF'] = _make_sysconfig_bool(False) rhel_util.update_sysconfig_file(self.network_conf_fn, net_cfg) return dev_names diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py index 35cc1f43..cb385da7 100644 --- a/tests/unittests/test_distros/test_netconfig.py +++ b/tests/unittests/test_distros/test_netconfig.py @@ -30,6 +30,24 @@ auto eth1 iface eth1 inet dhcp ''' +BASE_NET_CFG_IPV6 = ''' +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet static + address 192.168.1.5 + netmask 255.255.255.0 + network 192.168.0.0 + broadcast 192.168.1.0 + gateway 192.168.1.254 + +iface eth0 inet6 static + address 2607:f0d0:1002:0011::2 + netmask 64 + gateway 2607:f0d0:1002:0011::1 +''' + class WriteBuffer(object): def __init__(self): @@ -174,6 +192,81 @@ NETWORKING=yes self.assertCfgEquals(expected_buf, str(write_buf)) self.assertEquals(write_buf.mode, 0644) + def test_write_ipv6_rhel(self): + rh_distro = self._get_distro('rhel') + write_mock = self.mocker.replace(util.write_file, + spec=False, passthrough=False) + load_mock = self.mocker.replace(util.load_file, + spec=False, passthrough=False) + exists_mock = self.mocker.replace(os.path.isfile, + spec=False, passthrough=False) + + write_bufs = {} + + def replace_write(filename, content, mode=0644, omode="wb"): + buf = WriteBuffer() + buf.mode = mode + buf.omode = omode + buf.write(content) + write_bufs[filename] = buf + + exists_mock(mocker.ARGS) + self.mocker.count(0, None) + self.mocker.result(False) + + load_mock(mocker.ARGS) + self.mocker.count(0, None) + self.mocker.result('') + + for _i in range(0, 2): + write_mock(mocker.ARGS) + self.mocker.call(replace_write) + + write_mock(mocker.ARGS) + self.mocker.call(replace_write) + + self.mocker.replay() + rh_distro.apply_network(BASE_NET_CFG_IPV6, False) + + self.assertEquals(len(write_bufs), 3) + self.assertIn('/etc/sysconfig/network-scripts/ifcfg-lo', write_bufs) + write_buf = write_bufs['/etc/sysconfig/network-scripts/ifcfg-lo'] + expected_buf = ''' +DEVICE="lo" +ONBOOT=yes +''' + self.assertCfgEquals(expected_buf, str(write_buf)) + self.assertEquals(write_buf.mode, 0644) + + self.assertIn('/etc/sysconfig/network-scripts/ifcfg-eth0', write_bufs) + write_buf = write_bufs['/etc/sysconfig/network-scripts/ifcfg-eth0'] + expected_buf = ''' +DEVICE="eth0" +BOOTPROTO="static" +NETMASK="255.255.255.0" +IPADDR="192.168.1.5" +ONBOOT=yes +GATEWAY="192.168.1.254" +BROADCAST="192.168.1.0" +IPV6INIT=yes +IPV6ADDR="2607:f0d0:1002:0011::2" +IPV6_DEFAULTGW="2607:f0d0:1002:0011::1" +''' + self.assertCfgEquals(expected_buf, str(write_buf)) + self.assertEquals(write_buf.mode, 0644) + + self.assertIn('/etc/sysconfig/network', write_bufs) + write_buf = write_bufs['/etc/sysconfig/network'] + expected_buf = ''' +# Created by cloud-init v. 0.7 +NETWORKING=yes +NETWORKING_IPV6=yes +IPV6_AUTOCONF=no +''' + self.assertCfgEquals(expected_buf, str(write_buf)) + self.assertEquals(write_buf.mode, 0644) + + def test_simple_write_freebsd(self): fbsd_distro = self._get_distro('freebsd') util_mock = self.mocker.replace(util.write_file, -- cgit v1.2.3 From 4dfba8913a24da7254bf47017a264b28c7a49cd2 Mon Sep 17 00:00:00 2001 From: Shraddha Pandhe Date: Mon, 24 Nov 2014 19:36:18 +0000 Subject: IPv6 support for rhel distro - Saw an issue in my earlier commit with multiple NICs. This commit fixes that issue, along with the indentation issue --- cloudinit/distros/net_util.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'cloudinit/distros') diff --git a/cloudinit/distros/net_util.py b/cloudinit/distros/net_util.py index f56f6ccd..f8c34846 100644 --- a/cloudinit/distros/net_util.py +++ b/cloudinit/distros/net_util.py @@ -169,15 +169,16 @@ def translate_network(settings): real_ifaces[dev_name] = iface_info # Check for those that should be started on boot via 'auto' for (cmd, args) in entries: + args = args.split(None) + if not args: + continue + dev_name = args[0].strip().lower() if cmd == 'auto': # Seems like auto can be like 'auto eth0 eth0:1' so just get the # first part out as the device name - args = args.split(None) - if not args: - continue - dev_name = args[0].strip().lower() if dev_name in real_ifaces: real_ifaces[dev_name]['auto'] = True if cmd == 'iface' and 'inet6' in args: - real_ifaces[dev_name]['inet6'] = True + real_ifaces[dev_name]['inet6'] = True return real_ifaces + -- cgit v1.2.3