Commit b21e68ff authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

slapos.core: introduce ipv6_range for each partition

parent 839ac0ef
...@@ -32,6 +32,7 @@ tap_ipv6 = true ...@@ -32,6 +32,7 @@ tap_ipv6 = true
# You can choose any other local network which does not conflict with your # You can choose any other local network which does not conflict with your
# current machine configuration # current machine configuration
ipv4_local_network = 10.0.0.0/16 ipv4_local_network = 10.0.0.0/16
partition_has_ipv6_range = true
# to enable, change to [firewall] # to enable, change to [firewall]
[disabled-firewall] [disabled-firewall]
......
This diff is collapsed.
...@@ -59,11 +59,23 @@ from .interface.slap import IRequester ...@@ -59,11 +59,23 @@ from .interface.slap import IRequester
from ..grid.slapgrid import SLAPGRID_PROMISE_FAIL from ..grid.slapgrid import SLAPGRID_PROMISE_FAIL
from .slap import slap from .slap import slap
from ..util import dumps, rmtree from ..util import dumps, rmtree, getPartitionIpv6Addr, getPartitionIpv6Range
from ..grid.svcbackend import getSupervisorRPC from ..grid.svcbackend import getSupervisorRPC
from ..grid.svcbackend import _getSupervisordSocketPath from ..grid.svcbackend import _getSupervisordSocketPath
def _getPartitionIpv6(ipv6_address, i):
# returns (single_ipv6_address, ipv6_range) for a partition
# ipv6_address can be either a range or a single IPv6 address (with no /)
if '/' in ipv6_address:
addr,netmask = ipv6_address.split('/')
single_ipv6_address = getPartitionIpv6Addr({'addr':addr, 'netmask':int(netmask)}, i)['addr']
ipv6_range = getPartitionIpv6Range({'addr':addr, 'netmask':int(netmask)}, i)
else:
ipv6_range = None
single_ipv6_address = ipv6_address
return (single_ipv6_address, ipv6_range)
@zope.interface.implementer(IException) @zope.interface.implementer(IException)
class SlapOSNodeCommandError(Exception): class SlapOSNodeCommandError(Exception):
...@@ -287,9 +299,7 @@ class SlapformatDefinitionWriter(ConfigWriter): ...@@ -287,9 +299,7 @@ class SlapformatDefinitionWriter(ConfigWriter):
""" """
def writeConfig(self, path): def writeConfig(self, path):
ipv4 = self._standalone_slapos._ipv4_address ipv4 = self._standalone_slapos._ipv4_address
ipv6 = self._standalone_slapos._ipv6_address
ipv4_cidr = ipv4 + '/255.255.255.255' if ipv4 else '' ipv4_cidr = ipv4 + '/255.255.255.255' if ipv4 else ''
ipv6_cidr = ipv6 + '/64' if ipv6 else ''
user = pwd.getpwuid(os.getuid()).pw_name user = pwd.getpwuid(os.getuid()).pw_name
partition_base_name = self._standalone_slapos._partition_base_name partition_base_name = self._standalone_slapos._partition_base_name
with open(path, 'w') as f: with open(path, 'w') as f:
...@@ -300,11 +310,15 @@ class SlapformatDefinitionWriter(ConfigWriter): ...@@ -300,11 +310,15 @@ class SlapformatDefinitionWriter(ConfigWriter):
address = {ipv4_cidr}\n address = {ipv4_cidr}\n
""").format(**locals())) """).format(**locals()))
for i in range(self._standalone_slapos._partition_count): for i in range(self._standalone_slapos._partition_count):
print(i)
single_ipv6_address, ipv6_range = _getPartitionIpv6(self._standalone_slapos._ipv6_address, i)
ipv6_range_network= '{addr}/{netmask}'.format(**ipv6_range)
f.write( f.write(
textwrap.dedent( textwrap.dedent(
""" """
[partition_{i}] [partition_{i}]
address = {ipv6_cidr} {ipv4_cidr} address = {single_ipv6_address}/128 {ipv4_cidr}
ipv6_range = {ipv6_range_network}
pathname = {partition_base_name}{i} pathname = {partition_base_name}{i}
user = {user} user = {user}
network_interface =\n network_interface =\n
...@@ -594,8 +608,12 @@ class StandaloneSlapOS(object): ...@@ -594,8 +608,12 @@ class StandaloneSlapOS(object):
partition_base_name="slappart"): partition_base_name="slappart"):
"""Creates `partition_count` partitions. """Creates `partition_count` partitions.
All partitions have the same `ipv4_address` and `ipv6_address` and All partitions have the same `ipv4_address` and use the current system
use the current system user. user.
`ipv6_address` can be a single address (in this case all partitions have
the same address) or a range in the form IPV6/CIDR (in this case each
partition has a subrange).
When calling this a second time with a lower `partition_count` or with When calling this a second time with a lower `partition_count` or with
different `partition_base_name` will delete existing partitions. different `partition_base_name` will delete existing partitions.
...@@ -628,6 +646,7 @@ class StandaloneSlapOS(object): ...@@ -628,6 +646,7 @@ class StandaloneSlapOS(object):
if not (os.path.exists(partition_path)): if not (os.path.exists(partition_path)):
os.mkdir(partition_path) os.mkdir(partition_path)
os.chmod(partition_path, 0o750) os.chmod(partition_path, 0o750)
single_ipv6_address, ipv6_range = _getPartitionIpv6(ipv6_address, i)
partition_list.append({ partition_list.append({
'address_list': [ 'address_list': [
{ {
...@@ -635,10 +654,11 @@ class StandaloneSlapOS(object): ...@@ -635,10 +654,11 @@ class StandaloneSlapOS(object):
'netmask': '255.255.255.255' 'netmask': '255.255.255.255'
}, },
{ {
'addr': ipv6_address, 'addr': single_ipv6_address,
'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' 'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
}, },
], ],
'ipv6_range' : ipv6_range,
'path': partition_path, 'path': partition_path,
'reference': partition_reference, 'reference': partition_reference,
'tap': { 'tap': {
......
...@@ -199,6 +199,69 @@ def ipv6FromBin(ip, suffix=''): ...@@ -199,6 +199,69 @@ def ipv6FromBin(ip, suffix=''):
return socket.inet_ntop(socket.AF_INET6, return socket.inet_ntop(socket.AF_INET6,
struct.pack('>QQ', int(ip[:64], 2), int(ip[64:], 2))) struct.pack('>QQ', int(ip[:64], 2), int(ip[64:], 2)))
def getPartitionIpv6Addr(ipv6_range, partition_index):
"""
from a IPv6 range in the form
{
'addr' : addr,
'natmask' : CIDR
}
returns the IPv6 addr
addr::(partition_index+2) (address 1 is is used by re6st)
"""
addr = ipv6_range['addr']
netmask = ipv6_range['netmask']
prefix = binFromIpv6(addr)[:netmask]
return dict(addr = ipv6FromBin(prefix + bin(partition_index+2)[2:].zfill(128 - netmask)), netmask = netmask)
def getPartitionIpv6Range(ipv6_range, partition_index):
"""
from a IPv6 range in the form
{
'addr' : addr,
'natmask' : CIDR
}
returns the IPv6 range
{
'addr' : addr:(partition_index+1)
'netmask : CIDR+16
}
"""
addr = ipv6_range['addr']
netmask = ipv6_range['netmask']
prefix = binFromIpv6(addr)[:netmask]
# we generate a subnetwork for the partition
# the subnetwork has 16 bits more than our IPv6 range
# make sure we have at least 2 IPs in the subnetwork
netmask += 16
if netmask >= 128:
raise ValueError('The IPv6 range has netmask {} which is too big for generating IPv6 range for partitions.'.format(netmask))
return dict(addr = ipv6FromBin(prefix + bin(partition_index+1)[2:].zfill(16) + '0' * (128 - netmask)), netmask=netmask)
def getTapIpv6Range(ipv6_range, partition_index):
"""
from a IPv6 range in the form
{
'addr' : addr,
'natmask' : CIDR
}
returns the IPv6 range
{
'addr' : addr:(2^15 + partition_index+1)
'netmask : CIDR+16
}
"""
addr = ipv6_range['addr']
netmask = ipv6_range['netmask']
prefix = binFromIpv6(addr)[:netmask]
# we generate a subnetwork for the partition
# the subnetwork has 16 bits more than our IPv6 range
# make sure we have at least 2 IPs in the subnetwork
netmask += 16
if netmask >= 128:
raise ValueError('The IPv6 range has netmask {} which is too big for generating IPv6 range for partitions.'.format(netmask))
return dict(addr = ipv6FromBin(prefix + bin(2^15 + partition_index+1)[2:].zfill(16) + '0' * (128 - netmask)), netmask=netmask)
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",
...@@ -209,6 +272,10 @@ def lenNetmaskIpv6(netmask): ...@@ -209,6 +272,10 @@ def lenNetmaskIpv6(netmask):
except ValueError: except ValueError:
return netaddr.IPNetwork(netmask).prefixlen return netaddr.IPNetwork(netmask).prefixlen
def netmaskFromLenIPv6(netmask_len):
""" opposite of lenNetmaskIpv6"""
return ipv6FromBin('1' * netmask_len)
# Used for Python 2-3 compatibility # Used for Python 2-3 compatibility
if str is bytes: if str is bytes:
bytes2str = str2bytes = lambda s: s bytes2str = str2bytes = lambda s: s
......
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