Commit 00a3553e authored by Łukasz Nowak's avatar Łukasz Nowak

Implement ipv6_interface.

This supports configuration, when bridge cannot be attached with IPv6 capable
interface (like a lot of WLAN interfaces and IPv6 tunnels).

Thanks to setting ipv6_interface in slapformat configuration file, IPv6
generation will be done there, but IPv4 will be still available on bridge.
parent 99c8bb98
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* slapconsole: Simplify usage and use configuration file. You can now * slapconsole: Simplify usage and use configuration file. You can now
just run slapconsole and type things like "request(kvm, 'mykvm')". just run slapconsole and type things like "request(kvm, 'mykvm')".
[Cedric de Saint Martin] [Cedric de Saint Martin]
* slapformat: Allow to have IPv6 only interface, with bridge still supporting
local IPv4 stack. [Łukasz Nowak]
0.8 (2011-06-27) 0.8 (2011-06-27)
================ ================
......
...@@ -170,7 +170,8 @@ class AddressGenerationError(Error): ...@@ -170,7 +170,8 @@ class AddressGenerationError(Error):
class Computer: class Computer:
"Object representing the computer" "Object representing the computer"
def __init__(self, reference, bridge=None, addr = None, netmask = None): def __init__(self, reference, bridge=None, addr = None, netmask = None,
ipv6_interface=None):
""" """
Attributes: Attributes:
reference: String, the reference of the computer. reference: String, the reference of the computer.
...@@ -181,6 +182,7 @@ class Computer: ...@@ -181,6 +182,7 @@ class Computer:
self.partition_list = [] self.partition_list = []
self.address = addr self.address = addr
self.netmask = netmask self.netmask = netmask
self.ipv6_interface = ipv6_interface
def __getinitargs__(self): def __getinitargs__(self):
return (self.reference, self.bridge) return (self.reference, self.bridge)
...@@ -244,7 +246,7 @@ class Computer: ...@@ -244,7 +246,7 @@ class Computer:
output_file.close() output_file.close()
@classmethod @classmethod
def load(cls, path_to_xml, reference): def load(cls, path_to_xml, reference, ipv6_interface):
""" """
Create a computer object from a valid xml file. Create a computer object from a valid xml file.
...@@ -264,6 +266,7 @@ class Computer: ...@@ -264,6 +266,7 @@ class Computer:
reference = reference, reference = reference,
addr = dumped_dict['address'], addr = dumped_dict['address'],
netmask = dumped_dict['netmask'], netmask = dumped_dict['netmask'],
ipv6_interface=ipv6_interface,
) )
for partition_dict in dumped_dict['partition_list']: for partition_dict in dumped_dict['partition_list']:
...@@ -577,7 +580,7 @@ class Tap: ...@@ -577,7 +580,7 @@ class Tap:
class Bridge: class Bridge:
"Bridge represent a bridge on the system" "Bridge represent a bridge on the system"
def __init__(self, name, ipv4_local_network): def __init__(self, name, ipv4_local_network, ipv6_interface):
""" """
Attributes: Attributes:
name: String, the name of the bridge name: String, the name of the bridge
...@@ -585,6 +588,7 @@ class Bridge: ...@@ -585,6 +588,7 @@ class Bridge:
self.name = str(name) self.name = str(name)
self.ipv4_local_network = ipv4_local_network self.ipv4_local_network = ipv4_local_network
self.ipv6_interface = ipv6_interface
# Attach to TAP network interface, only if the bridge interface does not # Attach to TAP network interface, only if the bridge interface does not
# report carrier # report carrier
...@@ -605,12 +609,16 @@ class Bridge: ...@@ -605,12 +609,16 @@ class Bridge:
def getGlobalScopeAddressList(self): def getGlobalScopeAddressList(self):
"""Returns currently configured global scope IPv6 addresses""" """Returns currently configured global scope IPv6 addresses"""
if self.ipv6_interface:
interface_name = self.ipv6_interface
else:
interface_name = self.name
try: try:
address_list = [q for q in netifaces.ifaddresses(self.name)[socket.AF_INET6] address_list = [q for q in netifaces.ifaddresses(interface_name)[socket.AF_INET6]
if isGlobalScopeAddress(q['addr'].split('%')[0])] if isGlobalScopeAddress(q['addr'].split('%')[0])]
except KeyError: except KeyError:
raise ValueError("%s must have at least one IPv6 address assigned" % \ raise ValueError("%s must have at least one IPv6 address assigned" % \
self.name) interface_name)
# XXX: Missing implementation of Unique Local IPv6 Unicast Addresses as # XXX: Missing implementation of Unique Local IPv6 Unicast Addresses as
# defined in http://www.rfc-editor.org/rfc/rfc4193.txt # defined in http://www.rfc-editor.org/rfc/rfc4193.txt
# XXX: XXX: XXX: IT IS DISALLOWED TO IMPLEMENT link-local addresses as # XXX: XXX: XXX: IT IS DISALLOWED TO IMPLEMENT link-local addresses as
...@@ -659,30 +667,36 @@ class Bridge: ...@@ -659,30 +667,36 @@ class Bridge:
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
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))
interface_name = self.name
# check if address is already took by any other interface # check if address is already took by any other interface
for interface in netifaces.interfaces(): for interface in netifaces.interfaces():
if interface != self.name: if interface != interface_name:
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]]:
return False return False
if not af in netifaces.ifaddresses(self.name) or not address in [q['addr'].split('%')[0] for q in netifaces.ifaddresses(self.name)[af]]: if not af in netifaces.ifaddresses(interface_name) or not address in [q['addr'].split('%')[0] for q in netifaces.ifaddresses(interface_name)[af]]:
# add an address # add an address
callAndRead(['ip', 'addr', 'add', address_string, 'dev', self.name]) callAndRead(['ip', 'addr', 'add', address_string, 'dev', interface_name])
# wait few moments # wait few moments
time.sleep(2) time.sleep(2)
# check existence on interface # check existence on interface
returncode, result = callAndRead(['ip', 'addr', 'list', self.name]) returncode, result = callAndRead(['ip', 'addr', 'list', interface_name])
for l in result.split('\n'): for l in result.split('\n'):
if address in l: if address in l:
if 'tentative' in l: if 'tentative' in l:
# duplicate, remove # duplicate, remove
callAndRead(['ip', 'addr', 'del', address_string, 'dev', self.name]) callAndRead(['ip', 'addr', 'del', address_string, 'dev',
interface_name])
return False return False
# found and clean # found and clean
return True return True
...@@ -742,11 +756,15 @@ class Bridge: ...@@ -742,11 +756,15 @@ class Bridge:
an address with. an address with.
""" """
# Getting one address of the bridge as base of the next addresses # Getting one address of the bridge as base of the next addresses
if self.ipv6_interface:
interface_name = self.ipv6_interface
else:
interface_name = self.name
bridge_addr_list = self.getGlobalScopeAddressList() bridge_addr_list = self.getGlobalScopeAddressList()
# No address found # No address found
if len(bridge_addr_list) == 0: if len(bridge_addr_list) == 0:
raise NoAddressOnBridge(self.name) raise NoAddressOnBridge(interface_name)
address_dict = bridge_addr_list[0] address_dict = bridge_addr_list[0]
if addr is not None: if addr is not None:
...@@ -848,12 +866,14 @@ def run(config): ...@@ -848,12 +866,14 @@ def run(config):
address, netmask = computer_definition.get('computer', 'address').split('/') address, netmask = computer_definition.get('computer', 'address').split('/')
if config.alter_network and config.bridge_name is not None \ if config.alter_network and config.bridge_name is not None \
and config.ipv4_local_network is not None: and config.ipv4_local_network is not None:
bridge = Bridge(config.bridge_name, config.ipv4_local_network) bridge = Bridge(config.bridge_name, config.ipv4_local_network,
config.ipv6_interface)
computer = Computer( computer = Computer(
reference=config.computer_id, reference=config.computer_id,
bridge=bridge, bridge=bridge,
addr=address, addr=address,
netmask=netmask, netmask=netmask,
ipv6_interface=config.ipv6_interface
) )
partition_list = [] partition_list = []
for partition_number in range(int(config.partition_amount)): for partition_number in range(int(config.partition_amount)):
...@@ -875,17 +895,20 @@ def run(config): ...@@ -875,17 +895,20 @@ def run(config):
# no definition file, figure out computer # no definition file, figure out computer
if os.path.exists(config.computer_xml): if os.path.exists(config.computer_xml):
config.logger.info('Loading previous computer data from %r' % config.computer_xml) config.logger.info('Loading previous computer data from %r' % config.computer_xml)
computer = Computer.load(config.computer_xml, reference=config.computer_id) computer = Computer.load(config.computer_xml, reference=config.computer_id, ipv6_interface=config.ipv6_interface)
# Connect to the bridge interface defined by the configuration # Connect to the bridge interface defined by the configuration
computer.bridge = Bridge(config.bridge_name, config.ipv4_local_network) computer.bridge = Bridge(config.bridge_name, config.ipv4_local_network,
config.ipv6_interface)
else: else:
# If no pre-existent configuration found, creating a new computer object # If no pre-existent configuration found, creating a new computer object
config.logger.warning('Creating new data computer with id %r' % config.computer_id) config.logger.warning('Creating new data computer with id %r' % config.computer_id)
computer = Computer( computer = Computer(
reference=config.computer_id, reference=config.computer_id,
bridge=Bridge(config.bridge_name, config.ipv4_local_network), bridge=Bridge(config.bridge_name, config.ipv4_local_network,
config.ipv6_interface),
addr=None, addr=None,
netmask=None, netmask=None,
ipv6_interface=config.ipv6_interface
) )
partition_amount = int(config.partition_amount) partition_amount = int(config.partition_amount)
...@@ -990,7 +1013,7 @@ class Config: ...@@ -990,7 +1013,7 @@ class Config:
# setup some nones # setup some nones
for parameter in ['bridge_name', 'partition_base_name', 'user_base_name', for parameter in ['bridge_name', 'partition_base_name', 'user_base_name',
'tap_base_name', 'ipv4_local_network']: 'tap_base_name', 'ipv4_local_network', 'ipv6_interface']:
if getattr(self, parameter, None) is None: if getattr(self, parameter, None) is None:
setattr(self, parameter, None) setattr(self, parameter, None)
......
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