slapformat: Allow customising IPv6 range sizes
Showing
... | @@ -1024,7 +1024,7 @@ class Tun(Tap): | ... | @@ -1024,7 +1024,7 @@ class Tun(Tap): |
class Interface(object): | class Interface(object): | ||
"""Represent a network interface on the system""" | """Represent a network interface on the system""" | ||
def __init__(self, logger, name, ipv4_local_network, ipv6_interface=None): | def __init__(self, logger, name, ipv4_local_network, ipv6_interface=None, ipv6_prefixshift=16): | ||
""" | """ | ||
Attributes: | Attributes: | ||
name: String, the name of the interface | name: String, the name of the interface | ||
... | @@ -1036,6 +1036,8 @@ class Interface(object): | ... | @@ -1036,6 +1036,8 @@ class Interface(object): |
self.ipv6_interface = ipv6_interface or name | self.ipv6_interface = ipv6_interface or name | ||
self._ipv6_ranges = set() | self._ipv6_ranges = set() | ||
self.ipv6_prefixshift = ipv6_prefixshift | |||
# XXX no __getinitargs__, as instances of this class are never deserialized. | # XXX no __getinitargs__, as instances of this class are never deserialized. | ||
def getIPv4LocalAddressList(self): | def getIPv4LocalAddressList(self): | ||
... | @@ -1292,7 +1294,7 @@ class Interface(object): | ... | @@ -1292,7 +1294,7 @@ class Interface(object): |
# Try to use the IPv6 mapping based on partition index | # Try to use the IPv6 mapping based on partition index | ||
address_dict['prefixlen'] = lenNetmaskIpv6(address_dict['netmask']) | address_dict['prefixlen'] = lenNetmaskIpv6(address_dict['netmask']) | ||
if tap: | if tap: | ||
result_addr = getTapIpv6Range(address_dict, partition_index) | result_addr = getTapIpv6Range(address_dict, partition_index, self.ipv6_prefixshift) | ||
# the netmask of the tap itself is always 128 bits | # the netmask of the tap itself is always 128 bits | ||
result_addr['netmask'] = netmaskFromLenIPv6(128) | result_addr['netmask'] = netmaskFromLenIPv6(128) | ||
else: | else: | ||
... | @@ -1304,6 +1306,17 @@ class Interface(object): | ... | @@ -1304,6 +1306,17 @@ class Interface(object): |
self._reserveIpv6Range(result_addr['addr'], result_addr['prefixlen']) | self._reserveIpv6Range(result_addr['addr'], result_addr['prefixlen']) | ||
return result_addr | return result_addr | ||
if self._ipv6_prefixshift != 16: | |||
|
|||
self._logger.error( | |||
"Address %s/%s for partition %s is already taken;" | |||
" aborting because IPv6 prefixshift is %s != 16" % ( | |||
result_addr['addr'], | |||
result_addr['prefixlen'], | |||
'%s tap' % partition_index if tap else partition_index, | |||
self._ipv6_prefixshift, | |||
)) | |||
raise AddressGenerationError(addr) | |||
self._logger.warning( | self._logger.warning( | ||
"Falling back to random address selection for partition %s" | "Falling back to random address selection for partition %s" | ||
" because %s/%s is already taken" % ( | " because %s/%s is already taken" % ( | ||
... | @@ -1350,14 +1363,24 @@ class Interface(object): | ... | @@ -1350,14 +1363,24 @@ class Interface(object): |
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']) | ||
if tun: | if tun: | ||
ipv6_range = getTunIpv6Range(address_dict, i) | ipv6_range = getTunIpv6Range(address_dict, i, self.ipv6_prefixshift) | ||
else: | else: | ||
ipv6_range = getPartitionIpv6Range(address_dict, i) | ipv6_range = getPartitionIpv6Range(address_dict, i, self.ipv6_prefixshift) | ||
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']): | ||
return ipv6_range | return ipv6_range | ||
if self._ipv6_prefixshift != 16: | |||
self._logger.error( | |||
"Address % for partition %s is already taken;" | |||
" aborting because IPv6 prefixshift is %s != 16" % ( | |||
ipv6_range['network'], | |||
'%s tun' % i if tun else i, | |||
self._ipv6_prefixshift, | |||
)) | |||
raise AddressGenerationError(ipv6_range['addr']) | |||
self._logger.warning( | self._logger.warning( | ||
"Falling back to random IPv6 range selection for partition %s" | "Falling back to random IPv6 range selection for partition %s" | ||
" because %s is already taken" % ( | " because %s is already taken" % ( | ||
... | @@ -1406,7 +1429,8 @@ def parse_computer_definition(conf, definition_path): | ... | @@ -1406,7 +1429,8 @@ def parse_computer_definition(conf, definition_path): |
interface = Interface(logger=conf.logger, | interface = Interface(logger=conf.logger, | ||
name=conf.interface_name, | name=conf.interface_name, | ||
ipv4_local_network=conf.ipv4_local_network, | ipv4_local_network=conf.ipv4_local_network, | ||
ipv6_interface=conf.ipv6_interface) | ipv6_interface=conf.ipv6_interface, | ||
ipv6_prefixshift=conf.ipv6_prefixshift) | |||
computer = Computer( | computer = Computer( | ||
reference=conf.computer_id, | reference=conf.computer_id, | ||
interface=interface, | interface=interface, | ||
... | @@ -1455,7 +1479,8 @@ def parse_computer_xml(conf, xml_path): | ... | @@ -1455,7 +1479,8 @@ def parse_computer_xml(conf, xml_path): |
interface = Interface(logger=conf.logger, | interface = Interface(logger=conf.logger, | ||
name=conf.interface_name, | name=conf.interface_name, | ||
ipv4_local_network=conf.ipv4_local_network, | ipv4_local_network=conf.ipv4_local_network, | ||
ipv6_interface=conf.ipv6_interface) | ipv6_interface=conf.ipv6_interface, | ||
ipv6_prefixshift=conf.ipv6_prefixshift) | |||
if os.path.exists(xml_path): | if os.path.exists(xml_path): | ||
conf.logger.debug('Loading previous computer data from %r' % xml_path) | conf.logger.debug('Loading previous computer data from %r' % xml_path) | ||
... | @@ -1597,6 +1622,7 @@ class FormatConfig(object): | ... | @@ -1597,6 +1622,7 @@ class FormatConfig(object): |
interface_name = None | interface_name = None | ||
ipv6_interface = None | ipv6_interface = None | ||
partition_has_ipv6_range = True | partition_has_ipv6_range = True | ||
ipv6_prefixshift = 16 | |||
create_tap = True | create_tap = True | ||
tap_base_name = None | tap_base_name = None | ||
tap_ipv6 = True | tap_ipv6 = True | ||
... | @@ -1697,6 +1723,15 @@ class FormatConfig(object): | ... | @@ -1697,6 +1723,15 @@ class FormatConfig(object): |
file_location) | file_location) | ||
sys.exit(1) | sys.exit(1) | ||
# Sanity check for prefixshift | |||
self.ipv6_prefixshift = ipv6_prefixshift = int(self.ipv6_prefixshift) | |||
if (1 << ipv6_prefixshift) < 4 * int(self.partition_amount): | |||
# Each partition needs at least 4 IPv6, for IPv6 address, range, tap and tun | |||
self.logger.fatal( | |||
'ipv6_prefixshift %s is too small for partition_amount %s', | |||
ipv6_prefixshift, self.partition_amount) | |||
sys.exit(1) | |||
self.logger.debug('Started.') | self.logger.debug('Started.') | ||
if self.dry_run: | if self.dry_run: | ||
self.logger.info("Dry-run mode enabled.") | self.logger.info("Dry-run mode enabled.") | ||
... | ... |