IPv6 support for rhel distro

When the ubuntu networking info file has ipv6 addresses inside
it we need to make sure that we parse that information out and
place it (at least) in the rhel network configuration writing.

In later patches the other distros that use this parsed network
configuration will likely also need to be updated (ubuntu and
debian already should function as expected with regard to ipv6
support).
This commit is contained in:
Joshua Harlow 2014-11-24 16:30:00 -08:00
commit a189df34f3
4 changed files with 228 additions and 33 deletions

View File

@ -114,6 +114,10 @@ def translate_network(settings):
if 'iface' not in info:
continue
iface_details = info['iface'].split(None)
# Check if current device *may* have an ipv6 IP
use_ipv6 = False
if 'inet6' in iface_details:
use_ipv6 = True
dev_name = None
if len(iface_details) >= 1:
dev = iface_details[0].strip().lower()
@ -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,35 +134,50 @@ 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, so we need to
# 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:
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
return real_ifaces

View File

@ -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,10 @@ 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)
net_cfg['IPV6_AUTOCONF'] = _make_sysconfig_bool(False)
rhel_util.update_sysconfig_file(self.network_conf_fn, net_cfg)
return dev_names

View File

@ -72,6 +72,7 @@ def netdev_info(empty=""):
"bcast:": "bcast", "broadcast": "bcast",
"mask:": "mask", "netmask": "mask",
"hwaddr": "hwaddr", "ether": "hwaddr",
"scope": "scope",
}
for origfield, field in ifconfigfields.items():
target = "%s%s" % (field, fieldpost)
@ -96,7 +97,12 @@ def netdev_info(empty=""):
def route_info():
(route_out, _err) = util.subp(["netstat", "-rn"])
routes = []
(route_out6, _err6) = util.subp(["netstat", "-A inet6", "-n"])
routes = {}
routes['ipv4'] = []
routes['ipv6'] = []
entries = route_out.splitlines()[1:]
for line in entries:
if not line:
@ -132,7 +138,26 @@ def route_info():
'iface': toks[7],
}
routes.append(entry)
routes['ipv4'].append(entry)
entries6 = route_out6.splitlines()[1:]
for line in entries6:
if not line:
continue
toks = line.split()
if (len(toks) < 6 or toks[0] == "Kernel" or
toks[0] == "Proto" or toks[0] == "Active"):
continue
entry = {
'proto': toks[0],
'recv-q': toks[1],
'send-q': toks[2],
'local address': toks[3],
'foreign address': toks[4],
'state': toks[5],
}
routes['ipv6'].append(entry)
return routes
@ -156,10 +181,12 @@ def netdev_pformat():
lines.append(util.center("Net device info failed", '!', 80))
netdev = None
if netdev is not None:
fields = ['Device', 'Up', 'Address', 'Mask', 'Hw-Address']
fields = ['Device', 'Up', 'Address', 'Mask', 'Scope', 'Hw-Address']
tbl = PrettyTable(fields)
for (dev, d) in netdev.iteritems():
tbl.add_row([dev, d["up"], d["addr"], d["mask"], d["hwaddr"]])
tbl.add_row([dev, d["up"], d["addr"], d["mask"], ".", d["hwaddr"]])
if d["addr6"]:
tbl.add_row([dev, d["up"], d["addr6"], ".", d["scope6"], d["hwaddr"]])
netdev_s = tbl.get_string()
max_len = len(max(netdev_s.splitlines(), key=len))
header = util.center("Net device info", "+", max_len)
@ -176,15 +203,30 @@ def route_pformat():
util.logexc(LOG, "Route info failed: %s" % e)
routes = None
if routes is not None:
fields = ['Route', 'Destination', 'Gateway',
fields_v4 = ['Route', 'Destination', 'Gateway',
'Genmask', 'Interface', 'Flags']
tbl = PrettyTable(fields)
for (n, r) in enumerate(routes):
if routes.get('ipv6') is not None:
fields_v6 = ['Route', 'Proto', 'Recv-Q', 'Send-Q', 'Local Address',
'Foreign Address', 'State']
tbl_v4 = PrettyTable(fields_v4)
for (n, r) in enumerate(routes.get('ipv4')):
route_id = str(n)
tbl.add_row([route_id, r['destination'],
tbl_v4.add_row([route_id, r['destination'],
r['gateway'], r['genmask'],
r['iface'], r['flags']])
route_s = tbl.get_string()
route_s = tbl_v4.get_string()
if fields_v6:
tbl_v6 = PrettyTable(fields_v6)
for (n, r) in enumerate(routes.get('ipv6')):
route_id = str(n)
tbl_v6.add_row([route_id, r['proto'],
r['recv-q'], r['send-q'],
r['local address'], r['foreign address'],
r['state']])
route_s = route_s + tbl_v6.get_string()
max_len = len(max(route_s.splitlines(), key=len))
header = util.center("Route info", "+", max_len)
lines.extend([header, route_s])

View File

@ -30,6 +30,36 @@ 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
iface eth1 inet static
address 192.168.1.6
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.1.0
gateway 192.168.1.254
iface eth1 inet6 static
address 2607:f0d0:1002:0011::3
netmask 64
gateway 2607:f0d0:1002:0011::1
'''
class WriteBuffer(object):
def __init__(self):
@ -174,6 +204,97 @@ 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, 3):
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), 4)
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-scripts/ifcfg-eth1', write_bufs)
write_buf = write_bufs['/etc/sysconfig/network-scripts/ifcfg-eth1']
expected_buf = '''
DEVICE="eth1"
BOOTPROTO="static"
NETMASK="255.255.255.0"
IPADDR="192.168.1.6"
ONBOOT=no
GATEWAY="192.168.1.254"
BROADCAST="192.168.1.0"
IPV6INIT=yes
IPV6ADDR="2607:f0d0:1002:0011::3"
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,