Commit 79d8788b authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼 Committed by Rafael Monnerat

Fix IPv6 on taps: the IPs were not added during format if they existed in the config file.

/reviewed-on nexedi/slapos.core!71
parent b0cac659
...@@ -56,10 +56,7 @@ from urllib2 import urlopen ...@@ -56,10 +56,7 @@ from urllib2 import urlopen
import lxml.etree import lxml.etree
import xml_marshaller.xml_marshaller import xml_marshaller.xml_marshaller
import slapos.util from slapos.util import mkdir_p, ipv6FromBin, binFromIpv6, lenNetmaskIpv6
from slapos.util import mkdir_p
from slapos.util import ipv6FromBin
from slapos.util import binFromIpv6
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
...@@ -566,11 +563,7 @@ class Computer(object): ...@@ -566,11 +563,7 @@ class Computer(object):
self.interface.addIPv6Address(self.address, self.netmask) self.interface.addIPv6Address(self.address, self.netmask)
if use_unique_local_address_block: if use_unique_local_address_block:
if self.ipv6_interface: self._addUniqueLocalAddressIpv6(self.ipv6_interface or self.interface.name)
network_interface_name = self.ipv6_interface
else:
network_interface_name = self.interface.name
self._addUniqueLocalAddressIpv6(network_interface_name)
if create_tap: if create_tap:
if self.tap_gateway_interface: if self.tap_gateway_interface:
...@@ -619,12 +612,23 @@ class Computer(object): ...@@ -619,12 +612,23 @@ class Computer(object):
partition.tap.ipv4_network = gateway_addr_dict['network'] partition.tap.ipv4_network = gateway_addr_dict['network']
if not partition.tap.ipv6_addr: if not partition.tap.ipv6_addr:
# create a new IPv6 randomly for the tap
ipv6_dict = self.interface.addIPv6Address(tap=partition.tap) ipv6_dict = self.interface.addIPv6Address(tap=partition.tap)
partition.tap.ipv6_addr = ipv6_dict['addr'] partition.tap.ipv6_addr = ipv6_dict['addr']
partition.tap.ipv6_netmask = ipv6_dict['netmask'] partition.tap.ipv6_netmask = ipv6_dict['netmask']
partition.tap.ipv6_gateway = "" else:
partition.tap.ipv6_network = "" # make sure the tap has its IPv6
self.interface.addIPv6Address(
addr=partition.tap.ipv6_addr,
netmask=partition.tap.ipv6_netmask,
tap=partition.tap)
# construct ipv6_network and create routes
netmask_len = lenNetmaskIpv6(partition.tap.ipv6_netmask)
prefix = binFromIpv6(partition.tap.ipv6_addr)[:netmask_len]
network_addr = ipv6FromBin(prefix)
partition.tap.ipv6_gateway = partition.tap.ipv6_addr
partition.tap.ipv6_network = "{}/{}".format(network_addr, netmask_len)
partition.tap.createRoutes() partition.tap.createRoutes()
if partition.tun is not None: if partition.tun is not None:
...@@ -973,10 +977,7 @@ class Interface(object): ...@@ -973,10 +977,7 @@ class Interface(object):
def getGlobalScopeAddressList(self, tap=None): def getGlobalScopeAddressList(self, tap=None):
"""Returns currently configured global scope IPv6 addresses""" """Returns currently configured global scope IPv6 addresses"""
if self.ipv6_interface: interface_name = self.ipv6_interface or self.name
interface_name = self.ipv6_interface
else:
interface_name = self.name
try: try:
address_list = [ address_list = [
q q
...@@ -1020,10 +1021,7 @@ class Interface(object): ...@@ -1020,10 +1021,7 @@ class Interface(object):
if ipv6: if ipv6:
address_string = '%s/%s' % (address, netmaskToPrefixIPv6(netmask)) address_string = '%s/%s' % (address, netmaskToPrefixIPv6(netmask))
af = socket.AF_INET6 af = socket.AF_INET6
if self.ipv6_interface: interface_name = self.ipv6_interface or self.name
interface_name = self.ipv6_interface
else:
interface_name = self.name
else: else:
af = socket.AF_INET af = socket.AF_INET
address_string = '%s/%s' % (address, netmaskToPrefixIPv4(netmask)) address_string = '%s/%s' % (address, netmaskToPrefixIPv4(netmask))
...@@ -1038,6 +1036,8 @@ class Interface(object): ...@@ -1038,6 +1036,8 @@ class Interface(object):
address_dict = netifaces.ifaddresses(interface) address_dict = netifaces.ifaddresses(interface)
if af in address_dict: if af in address_dict:
if address in [q['addr'].split('%')[0] for q in address_dict[af]]: if address in [q['addr'].split('%')[0] for q in address_dict[af]]:
self._logger.warning('Cannot add address %s to %s as it already exists on interface %s.' % \
(address, interface_name, interface))
return False return False
if not af in netifaces.ifaddresses(interface_name) \ if not af in netifaces.ifaddresses(interface_name) \
...@@ -1129,33 +1129,34 @@ class Interface(object): ...@@ -1129,33 +1129,34 @@ class Interface(object):
NoAddressOnInterface: There's no address on the interface to construct NoAddressOnInterface: There's no address on the interface to construct
an address with. an address with.
""" """
interface_name = self.ipv6_interface or self.name
# Getting one address of the interface as base of the next addresses # Getting one address of the interface as base of the next addresses
if self.ipv6_interface:
interface_name = self.ipv6_interface
else:
interface_name = self.name
interface_addr_list = self.getGlobalScopeAddressList() interface_addr_list = self.getGlobalScopeAddressList()
# No address found # No address found
if len(interface_addr_list) == 0: if len(interface_addr_list) == 0:
raise NoAddressOnInterface(interface_name) raise NoAddressOnInterface(interface_name)
address_dict = interface_addr_list[0] address_dict = interface_addr_list[0]
if addr is not None: if addr is not None:
if dict(addr=addr, netmask=netmask) in interface_addr_list: dict_addr_netmask = dict(addr=addr, netmask=netmask)
if dict_addr_netmask in interface_addr_list or \
(tap and dict_addr_netmask in self.getGlobalScopeAddressList(tap=tap)):
# confirmed to be configured # confirmed to be configured
return dict(addr=addr, netmask=netmask) return dict_addr_netmask
if netmask == address_dict['netmask']: if netmask == address_dict['netmask'] or \
(tap and lenNetmaskIpv6(netmask) == lenNetmaskIpv6(address_dict['netmask']) + 16):
# same netmask, so there is a chance to add good one # same netmask, so there is a chance to add good one
interface_network = netaddr.ip.IPNetwork('%s/%s' % (address_dict['addr'], interface_network = netaddr.ip.IPNetwork('%s/%s' % (address_dict['addr'],
netmaskToPrefixIPv6(address_dict['netmask']))) netmaskToPrefixIPv6(address_dict['netmask'])))
requested_network = netaddr.ip.IPNetwork('%s/%s' % (addr, requested_network = netaddr.ip.IPNetwork('%s/%s' % (addr,
netmaskToPrefixIPv6(netmask))) netmaskToPrefixIPv6(address_dict['netmask'])))
if interface_network.network == requested_network.network: if interface_network.network == requested_network.network:
# same network, try to add # same network, try to add
if self._addSystemAddress(addr, netmask, tap=tap): if self._addSystemAddress(addr, netmask, tap=tap):
# succeed, return it # succeed, return it
return dict(addr=addr, netmask=netmask) self._logger.info('Successfully added IPv6 %s to %s.' % (addr, tap.name or interface_name))
return dict_addr_netmask
else: else:
self._logger.warning('Impossible to add old public IPv6 %s. ' self._logger.warning('Impossible to add old public IPv6 %s. '
'Generating new IPv6 address.' % addr) 'Generating new IPv6 address.' % addr)
...@@ -1164,15 +1165,14 @@ class Interface(object): ...@@ -1164,15 +1165,14 @@ class Interface(object):
try_num = 10 try_num = 10
netmask = address_dict['netmask'] netmask = address_dict['netmask']
if tap: if tap:
netmask_len = len(binFromIpv6(netmask).rstrip('0')) netmask_len = lenNetmaskIpv6(netmask)
prefix = binFromIpv6(address_dict['addr'])[:netmask_len] prefix = binFromIpv6(address_dict['addr'])[:netmask_len]
netmask_len += 16 netmask_len += 16
# we generate a subnetwork for the tap # we generate a subnetwork for the tap
# the subnetwork has 16 bits more than the interface network # the subnetwork has 16 bits more than the interface network
# make sure we have at least 2 IPs in the subnetwork # make sure we have at least 2 IPs in the subnetwork
if netmask_len >= 128: if netmask_len >= 128:
self._logger.error('Interface {} has netmask {} which is too big for generating IPv6 on taps.'.format( self._logger.error('Interface %s has netmask %s which is too big for generating IPv6 on taps.' % (interface_name, netmask))
interface_name, netmask))
raise AddressGenerationError(addr) raise AddressGenerationError(addr)
netmask = ipv6FromBin('1'*netmask_len) netmask = ipv6FromBin('1'*netmask_len)
......
...@@ -135,3 +135,6 @@ def ipv6FromBin(ip, suffix=''): ...@@ -135,3 +135,6 @@ 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 lenNetmaskIpv6(netmask):
return len(binFromIpv6(netmask).rstrip('0'))
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