Commit a5667e05 authored by Xavier Thompson's avatar Xavier Thompson

slapformat: Add IPv6 to tun

parent 8d2794d0
...@@ -58,7 +58,11 @@ import six ...@@ -58,7 +58,11 @@ import six
import lxml.etree import lxml.etree
import xml_marshaller.xml_marshaller import xml_marshaller.xml_marshaller
from slapos.util import dumps, mkdir_p, ipv6FromBin, binFromIpv6, lenNetmaskIpv6, getPartitionIpv6Addr, getPartitionIpv6Range, getTapIpv6Range, netmaskFromLenIPv6 from slapos.util import (dumps, mkdir_p, ipv6FromBin, binFromIpv6,
lenNetmaskIpv6, getPartitionIpv6Addr,
getPartitionIpv6Range, getTapIpv6Range,
getTunIpv6Range, netmaskFromLenIPv6,
getIpv6RangeFirstAddr)
import slapos.slap as slap import slapos.slap as slap
from slapos import version from slapos import version
from slapos import manager as slapmanager from slapos import manager as slapmanager
...@@ -462,11 +466,25 @@ class Computer(object): ...@@ -462,11 +466,25 @@ class Computer(object):
else: else:
tap = Tap(partition_dict['reference']) tap = Tap(partition_dict['reference'])
if partition_dict.get('tun') is not None and partition_dict['tun'].get('ipv4_addr') is not None: tun_dict = partition_dict.get('tun')
tun = Tun(partition_dict['tun']['name'], partition_index, partition_amount) if tun_dict is None:
tun.ipv4_addr = partition_dict['tun']['ipv4_addr'] if config.create_tun:
tun = Tun("slaptun" + str(partition_index), partition_index, partition_amount, config.tun_ipv6)
else:
tun = None
else: else:
tun = Tun("slaptun" + str(partition_index), partition_index, partition_amount) ipv4_addr = tun_dict.get('ipv4_addr')
ipv6_addr = tun_dict.get('ipv6_addr')
needs_ipv6 = not ipv6_addr and config.tun_ipv6
tun = Tun(tun_dict['name'], partition_index, partition_amount, needs_ipv6)
if ipv4_addr:
tun.ipv4_addr = ipv4_addr
tun.ipv4_netmask = tun_dict['ipv4_netmask']
tun.ipv4_network = tun_dict['ipv4_network']
if ipv6_addr:
tun.ipv6_addr = ipv6_addr
tun.ipv6_netmask = tun_dict['ipv6_netmask']
tun.ipv6_network = tun_dict['ipv6_network']
address_list = partition_dict['address_list'] address_list = partition_dict['address_list']
ipv6_range = partition_dict.get('ipv6_range', {}) ipv6_range = partition_dict.get('ipv6_range', {})
...@@ -479,7 +497,7 @@ class Computer(object): ...@@ -479,7 +497,7 @@ class Computer(object):
address_list=address_list, address_list=address_list,
ipv6_range=ipv6_range, ipv6_range=ipv6_range,
tap=tap, tap=tap,
tun=tun if config.create_tun else None, tun=tun,
external_storage_list=external_storage_list, external_storage_list=external_storage_list,
) )
...@@ -633,12 +651,10 @@ class Computer(object): ...@@ -633,12 +651,10 @@ class Computer(object):
tap=partition.tap) tap=partition.tap)
# construct ipv6_network (16 bit more than the computer network) # construct ipv6_network (16 bit more than the computer network)
netmask_len = lenNetmaskIpv6(self.interface.getGlobalScopeAddressList()[0]['netmask']) + 16 prefixlen = lenNetmaskIpv6(self.interface.getGlobalScopeAddressList()[0]['netmask']) + 16
prefix = binFromIpv6(partition.tap.ipv6_addr)[:netmask_len] gateway_addr = getIpv6RangeFirstAddr(partition.tap.ipv6_addr, prefixlen)
network_addr = ipv6FromBin(prefix) partition.tap.ipv6_gateway = gateway_addr
partition.tap.ipv6_gateway = "{}1".format(network_addr) # address network::1 will be inside the VM partition.tap.ipv6_network = "{}/{}".format(gateway_addr, prefixlen)
partition.tap.ipv6_gateway = ipv6FromBin(binFromIpv6(partition.tap.ipv6_gateway)) # correctly format the IPv6
partition.tap.ipv6_network = "{}/{}".format(network_addr, netmask_len)
else: else:
partition.tap.ipv6_addr = '' partition.tap.ipv6_addr = ''
partition.tap.ipv6_netmask = '' partition.tap.ipv6_netmask = ''
...@@ -651,6 +667,13 @@ class Computer(object): ...@@ -651,6 +667,13 @@ class Computer(object):
if partition.tun is not None: if partition.tun is not None:
# create TUN interface per partition as well # create TUN interface per partition as well
partition.tun.createWithOwner(owner) partition.tun.createWithOwner(owner)
if partition.tun._needs_ipv6:
ipv6_dict = self.interface.generateIPv6Range(partition_index, tun=True)
prefixlen = ipv6_dict['prefixlen']
ipv6_addr = getIpv6RangeFirstAddr(ipv6_dict['addr'], prefixlen)
partition.tun.ipv6_addr = ipv6_addr
partition.tun.ipv6_netmask = ipv6_dict['netmask']
partition.tun.ipv6_network = "%s/%d" % (ipv6_addr, prefixlen)
partition.tun.createRoutes() partition.tun.createRoutes()
# Reconstructing partition's address # Reconstructing partition's address
...@@ -954,13 +977,14 @@ class Tun(Tap): ...@@ -954,13 +977,14 @@ class Tun(Tap):
BASE_MASK = 12 BASE_MASK = 12
BASE_NETWORK = "172.16.0.0" BASE_NETWORK = "172.16.0.0"
def __init__(self, name, sequence=None, partitions=None): def __init__(self, name, sequence=None, partitions=None, needs_ipv6=False):
"""Create TUN interface with subnet according to the optional ``sequence`` number. """Create TUN interface with subnet according to the optional ``sequence`` number.
:param name: name which will appear in ``ip list`` afterwards :param name: name which will appear in ``ip list`` afterwards
:param sequence: {int} position of this TUN among all ``partitions`` :param sequence: {int} position of this TUN among all ``partitions``
""" """
super(Tun, self).__init__(name) super(Tun, self).__init__(name)
self._needs_ipv6 = needs_ipv6
if sequence is not None: if sequence is not None:
assert 0 <= sequence < partitions, "0 <= {} < {}".format(sequence, partitions) assert 0 <= sequence < partitions, "0 <= {} < {}".format(sequence, partitions)
# create base IPNetwork # create base IPNetwork
...@@ -980,14 +1004,20 @@ class Tun(Tap): ...@@ -980,14 +1004,20 @@ class Tun(Tap):
"""Extend for physical addition of network address because TAP let this on external class.""" """Extend for physical addition of network address because TAP let this on external class."""
if self.ipv4_network: if self.ipv4_network:
# add an address # add an address
code, _ = callAndRead(['ip', 'addr', 'add', self.ipv4_network, 'dev', self.name], code, _ = callAndRead(
raise_on_error=False) ['ip', 'addr', 'add', self.ipv4_network, 'dev', self.name],
raise_on_error=False)
if code == 0:
# address added to the interface - wait
time.sleep(1)
if self.ipv6_network:
# add an address
code, _ = callAndRead(
['ip', 'addr', 'add', self.ipv6_network, 'dev', self.name],
raise_on_error=False)
if code == 0: if code == 0:
# address added to the interface - wait # address added to the interface - wait
time.sleep(1) time.sleep(1)
else:
raise RuntimeError("Cannot setup address on interface {}. "
"Address is missing.".format(self.name))
class Interface(object): class Interface(object):
...@@ -1291,7 +1321,7 @@ class Interface(object): ...@@ -1291,7 +1321,7 @@ class Interface(object):
raise AddressGenerationError(addr) raise AddressGenerationError(addr)
def generateIPv6Range(self, i): def generateIPv6Range(self, i, tun=False):
""" """
Generate an IPv6 range included in the IPv6 range of the interface. The IPv6 range depends on the partition index i. Generate an IPv6 range included in the IPv6 range of the interface. The IPv6 range depends on the partition index i.
...@@ -1312,7 +1342,10 @@ class Interface(object): ...@@ -1312,7 +1342,10 @@ class Interface(object):
interface_addr_list = self.getGlobalScopeAddressList() interface_addr_list = self.getGlobalScopeAddressList()
address_dict = interface_addr_list[0] address_dict = interface_addr_list[0]
address_dict['prefixlen'] = lenNetmaskIpv6(address_dict['netmask']) address_dict['prefixlen'] = lenNetmaskIpv6(address_dict['netmask'])
ipv6_range = getPartitionIpv6Range(address_dict, i) if tun:
ipv6_range = getTunIpv6Range(address_dict, i)
else:
ipv6_range = getPartitionIpv6Range(address_dict, i)
ipv6_range['netmask'] = netmaskFromLenIPv6(ipv6_range['prefixlen']) ipv6_range['netmask'] = netmaskFromLenIPv6(ipv6_range['prefixlen'])
ipv6_range['network'] = '%(addr)s/%(prefixlen)d' % ipv6_range ipv6_range['network'] = '%(addr)s/%(prefixlen)d' % ipv6_range
if self._tryReserveIpv6Range(ipv6_range['addr'], ipv6_range['prefixlen']): if self._tryReserveIpv6Range(ipv6_range['addr'], ipv6_range['prefixlen']):
...@@ -1389,7 +1422,7 @@ def parse_computer_definition(conf, definition_path): ...@@ -1389,7 +1422,7 @@ def parse_computer_definition(conf, definition_path):
tap = Tap(computer_definition.get(section, 'network_interface')) tap = Tap(computer_definition.get(section, 'network_interface'))
tun = Tun("slaptun" + str(partition_number), tun = Tun("slaptun" + str(partition_number),
partition_number, partition_number,
int(conf.partition_amount)) if conf.create_tun else None int(conf.partition_amount, conf.tun_ipv6)) if conf.create_tun else None
partition = Partition(reference=computer_definition.get(section, 'pathname'), partition = Partition(reference=computer_definition.get(section, 'pathname'),
path=os.path.join(conf.instance_root, path=os.path.join(conf.instance_root,
computer_definition.get(section, 'pathname')), computer_definition.get(section, 'pathname')),
...@@ -1461,7 +1494,7 @@ def parse_computer_xml(conf, xml_path): ...@@ -1461,7 +1494,7 @@ def parse_computer_xml(conf, xml_path):
address_list=None, address_list=None,
ipv6_range=None, ipv6_range=None,
tap=Tap('%s%s' % (conf.tap_base_name, i)), tap=Tap('%s%s' % (conf.tap_base_name, i)),
tun=Tun('slaptun' + str(i), i, partition_amount) if conf.create_tun else None tun=Tun('slaptun' + str(i), i, partition_amount, conf.tun_ipv6) if conf.create_tun else None
) )
computer.partition_list.append(partition) computer.partition_list.append(partition)
...@@ -1549,11 +1582,12 @@ class FormatConfig(object): ...@@ -1549,11 +1582,12 @@ class FormatConfig(object):
ipv6_interface = None ipv6_interface = None
partition_has_ipv6_range = True partition_has_ipv6_range = True
create_tap = True create_tap = True
create_tun = False
tap_base_name = None tap_base_name = None
tap_ipv6 = True tap_ipv6 = True
tap_gateway_interface = '' tap_gateway_interface = ''
ipv4_local_network = None ipv4_local_network = None
create_tun = False
tun_ipv6 = True
# User options # User options
alter_user = 'True' # modifiable by cmdline alter_user = 'True' # modifiable by cmdline
...@@ -1612,7 +1646,7 @@ class FormatConfig(object): ...@@ -1612,7 +1646,7 @@ class FormatConfig(object):
raise UsageError(message) raise UsageError(message)
# Convert strings to booleans # Convert strings to booleans
for option in ['alter_network', 'alter_user', 'partition_has_ipv6_range', 'create_tap', 'create_tun', 'tap_ipv6']: for option in ['alter_network', 'alter_user', 'partition_has_ipv6_range', 'create_tap', 'create_tun', 'tap_ipv6', 'tun_ipv6']:
attr = getattr(self, option) attr = getattr(self, option)
if isinstance(attr, str): if isinstance(attr, str):
if attr.lower() == 'true': if attr.lower() == 'true':
......
...@@ -250,6 +250,14 @@ getPartitionIpv6Range = getIpv6RangeFactory(1, '0') ...@@ -250,6 +250,14 @@ getPartitionIpv6Range = getIpv6RangeFactory(1, '0')
getTapIpv6Range = getIpv6RangeFactory(2, '1') getTapIpv6Range = getIpv6RangeFactory(2, '1')
getTunIpv6Range = getIpv6RangeFactory(3, '0')
def getIpv6RangeFirstAddr(addr, prefixlen):
addr_1 = "%s1" % ipv6FromBin(binFromIpv6(addr)[:prefixlen])
return ipv6FromBin(binFromIpv6(addr_1)) # correctly format the IPv6
def lenNetmaskIpv6(netmask): def lenNetmaskIpv6(netmask):
"""Convert string represented netmask to its integer prefix""" """Convert string represented netmask to its integer prefix"""
# Since version 0.10.7 of netifaces, the netmask is something like "ffff::/16", # Since version 0.10.7 of netifaces, the netmask is something like "ffff::/16",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment