Commit a5667e05 authored by Xavier Thompson's avatar Xavier Thompson

slapformat: Add IPv6 to tun

parent 8d2794d0
......@@ -58,7 +58,11 @@ import six
import lxml.etree
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
from slapos import version
from slapos import manager as slapmanager
......@@ -462,11 +466,25 @@ class Computer(object):
else:
tap = Tap(partition_dict['reference'])
if partition_dict.get('tun') is not None and partition_dict['tun'].get('ipv4_addr') is not None:
tun = Tun(partition_dict['tun']['name'], partition_index, partition_amount)
tun.ipv4_addr = partition_dict['tun']['ipv4_addr']
tun_dict = partition_dict.get('tun')
if tun_dict is None:
if config.create_tun:
tun = Tun("slaptun" + str(partition_index), partition_index, partition_amount, config.tun_ipv6)
else:
tun = None
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']
ipv6_range = partition_dict.get('ipv6_range', {})
......@@ -479,7 +497,7 @@ class Computer(object):
address_list=address_list,
ipv6_range=ipv6_range,
tap=tap,
tun=tun if config.create_tun else None,
tun=tun,
external_storage_list=external_storage_list,
)
......@@ -633,12 +651,10 @@ class Computer(object):
tap=partition.tap)
# construct ipv6_network (16 bit more than the computer network)
netmask_len = lenNetmaskIpv6(self.interface.getGlobalScopeAddressList()[0]['netmask']) + 16
prefix = binFromIpv6(partition.tap.ipv6_addr)[:netmask_len]
network_addr = ipv6FromBin(prefix)
partition.tap.ipv6_gateway = "{}1".format(network_addr) # address network::1 will be inside the VM
partition.tap.ipv6_gateway = ipv6FromBin(binFromIpv6(partition.tap.ipv6_gateway)) # correctly format the IPv6
partition.tap.ipv6_network = "{}/{}".format(network_addr, netmask_len)
prefixlen = lenNetmaskIpv6(self.interface.getGlobalScopeAddressList()[0]['netmask']) + 16
gateway_addr = getIpv6RangeFirstAddr(partition.tap.ipv6_addr, prefixlen)
partition.tap.ipv6_gateway = gateway_addr
partition.tap.ipv6_network = "{}/{}".format(gateway_addr, prefixlen)
else:
partition.tap.ipv6_addr = ''
partition.tap.ipv6_netmask = ''
......@@ -651,6 +667,13 @@ class Computer(object):
if partition.tun is not None:
# create TUN interface per partition as well
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()
# Reconstructing partition's address
......@@ -954,13 +977,14 @@ class Tun(Tap):
BASE_MASK = 12
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.
:param name: name which will appear in ``ip list`` afterwards
:param sequence: {int} position of this TUN among all ``partitions``
"""
super(Tun, self).__init__(name)
self._needs_ipv6 = needs_ipv6
if sequence is not None:
assert 0 <= sequence < partitions, "0 <= {} < {}".format(sequence, partitions)
# create base IPNetwork
......@@ -980,14 +1004,20 @@ class Tun(Tap):
"""Extend for physical addition of network address because TAP let this on external class."""
if self.ipv4_network:
# add an address
code, _ = callAndRead(['ip', 'addr', 'add', self.ipv4_network, 'dev', self.name],
raise_on_error=False)
code, _ = callAndRead(
['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:
# address added to the interface - wait
time.sleep(1)
else:
raise RuntimeError("Cannot setup address on interface {}. "
"Address is missing.".format(self.name))
class Interface(object):
......@@ -1291,7 +1321,7 @@ class Interface(object):
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.
......@@ -1312,7 +1342,10 @@ class Interface(object):
interface_addr_list = self.getGlobalScopeAddressList()
address_dict = interface_addr_list[0]
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['network'] = '%(addr)s/%(prefixlen)d' % ipv6_range
if self._tryReserveIpv6Range(ipv6_range['addr'], ipv6_range['prefixlen']):
......@@ -1389,7 +1422,7 @@ def parse_computer_definition(conf, definition_path):
tap = Tap(computer_definition.get(section, 'network_interface'))
tun = Tun("slaptun" + str(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'),
path=os.path.join(conf.instance_root,
computer_definition.get(section, 'pathname')),
......@@ -1461,7 +1494,7 @@ def parse_computer_xml(conf, xml_path):
address_list=None,
ipv6_range=None,
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)
......@@ -1549,11 +1582,12 @@ class FormatConfig(object):
ipv6_interface = None
partition_has_ipv6_range = True
create_tap = True
create_tun = False
tap_base_name = None
tap_ipv6 = True
tap_gateway_interface = ''
ipv4_local_network = None
create_tun = False
tun_ipv6 = True
# User options
alter_user = 'True' # modifiable by cmdline
......@@ -1612,7 +1646,7 @@ class FormatConfig(object):
raise UsageError(message)
# 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)
if isinstance(attr, str):
if attr.lower() == 'true':
......
......@@ -250,6 +250,14 @@ getPartitionIpv6Range = getIpv6RangeFactory(1, '0')
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):
"""Convert string represented netmask to its integer prefix"""
# 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