aboutsummaryrefslogtreecommitdiffstats
path: root/vicn/resource/central.py
diff options
context:
space:
mode:
Diffstat (limited to 'vicn/resource/central.py')
-rw-r--r--vicn/resource/central.py248
1 files changed, 101 insertions, 147 deletions
diff --git a/vicn/resource/central.py b/vicn/resource/central.py
index 6f3c680b..1013d1a5 100644
--- a/vicn/resource/central.py
+++ b/vicn/resource/central.py
@@ -22,7 +22,6 @@ import os
from netmodel.model.type import String
from netmodel.util.misc import pairwise
-from vicn.core.address_mgr import AddressManager
from vicn.core.attribute import Attribute
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import Resource
@@ -34,9 +33,9 @@ from vicn.resource.icn.forwarder import Forwarder
from vicn.resource.icn.face import L2Face, L4Face, FaceProtocol
from vicn.resource.icn.producer import Producer
from vicn.resource.icn.route import Route as ICNRoute
-from vicn.resource.linux.file import TextFile
from vicn.resource.lxd.lxc_container import LxcContainer
from vicn.resource.node import Node
+from vicn.resource.ip_assignment import Ipv4Assignment, Ipv6Assignment
log = logging.getLogger(__name__)
@@ -47,7 +46,7 @@ CMD_CONTAINER_SET_DNS = 'echo "nameserver {ip_dns}" | ' \
# For host
CMD_NAT = '\n'.join([
- 'iptables -t nat -A POSTROUTING -o {bridge_name} -s {network} ' \
+ 'iptables -t nat -A POSTROUTING -o {interface_name} -s {network} ' \
'! -d {network} -j MASQUERADE',
'echo 1 > /proc/sys/net/ipv4/ip_forward'
])
@@ -208,90 +207,6 @@ def _get_icn_graph(manager):
#-------------------------------------------------------------------------------
-class IPAssignment(Resource):
- """
- Resource: IPAssignment
- """
-
- #--------------------------------------------------------------------------
- # Resource lifecycle
- #--------------------------------------------------------------------------
-
- def __after__(self):
- return ('Interface',)
-
- @inline_task
- def __get__(self):
- raise ResourceNotFound
-
- def __subresources__(self):
- basedir = os.path.dirname(self._state.manager._base)
- self.host_file = TextFile(node = None,
- filename = os.path.join(basedir, HOST_FILE),
- overwrite = True)
- return self.host_file
-
- def __create__(self):
- """
- IP assignment strategy /32: assign /32 IP address to each interface
-
- We might use different subnets for resources involved in experiment,
- and supporting resources, and to minimize routing tables.
- """
- log.info('Assigment of IP addresses')
- tasks = EmptyTask()
-
- # We sort nodes by names for IP assignment. This code ensures that
- # interfaces on the same channel get consecutive IP addresses. That
- # way, we can assign /31 on p2p channels.
- channels = sorted(self._state.manager.by_type(Channel),
- key = lambda x : x.get_sortable_name())
- channels.extend(sorted(self._state.manager.by_type(Node),
- key = lambda node : node.name))
-
- host_file_content = ""
-
- # Dummy code to start IP addressing on an even number for /31
- ip = AddressManager().get_ip(None)
- if int(ip[-1]) % 2 == 0:
- ip = AddressManager().get_ip("dummy object")
-
- for channel in channels:
- # Sort interfaces in a deterministic order to ensure consistent
- # addressing across restarts of the tool
- interfaces = sorted(channel.interfaces,
- key = lambda x : x.device_name)
-
- for interface in interfaces:
- if interface.ip_address is None:
- ip = AddressManager().get_ip(interface)
-
- @async_task
- async def set_ip(interface, ip):
- await interface.async_set('ip_address', ip)
-
- if interface.managed:
- tasks = tasks | set_ip(interface, ip)
- else:
- ip = interface.ip_address
-
- # Note: interface.ip_address should still be None at this stage
- # since we have not made the assignment yet
-
- if isinstance(channel, Node):
- host_file_content += '# {} {} {}\n'.format(
- interface.node.name, interface.device_name, ip)
- if interface == interface.node.host_interface:
- host_file_content += '{} {}\n'.format(ip,
- interface.node.name)
- self.host_file.content = host_file_content
-
- return tasks
-
- __delete__ = None
-
-#-------------------------------------------------------------------------------
-
class IPRoutes(Resource):
"""
Resource: IPRoutes
@@ -331,7 +246,9 @@ class IPRoutes(Resource):
if not node_uuid in origins:
origins[node_uuid] = list()
for interface in node.interfaces:
- origins[node_uuid].append(interface.ip_address)
+ origins[node_uuid].append(interface.ip4_address)
+ if interface.ip6_address: #Control interfaces have no v6 address
+ origins[node_uuid].append(interface.ip6_address)
return origins
def _get_ip_routes(self):
@@ -370,37 +287,44 @@ class IPRoutes(Resource):
if prefix in ip_routes[src_node]:
continue
- if prefix == next_hop_ingress.ip_address:
+ #FIXME: should test for IP format
+ ip_version = 6 if ":" in prefix else 4
+ next_hop_ingress_ip = (next_hop_ingress.ip6_address if ip_version is 6 else
+ next_hop_ingress.ip4_address)
+ if prefix == next_hop_ingress_ip:
# Direct route on src_node.name :
# route add [prefix] dev [next_hop_interface_.device_name]
- route = IPRoute(node = src_node,
+ route4 = IPRoute(node = src_node,
managed = False,
owner = self,
ip_address = prefix,
mac_address = mac_addr,
+ ip_version = ip_version,
interface = next_hop_interface)
else:
# We need to be sure we have a route to the gw from the node
- if not next_hop_ingress.ip_address in ip_routes[src_node]:
- pre_route = IPRoute(node = src_node,
- managed = False,
- owner = self,
- ip_address = next_hop_ingress.ip_address,
+ if not next_hop_ingress_ip in ip_routes[src_node]:
+ pre_route = IPRoute(node = src_node,
+ managed = False,
+ owner = self,
+ ip_address = next_hop_ingress_ip,
+ ip_version = ip_version,
mac_address = mac_addr,
- interface = next_hop_interface)
- ip_routes[src_node].append(next_hop_ingress.ip_address)
+ interface = next_hop_interface)
+ ip_routes[src_node].append(next_hop_ingress_ip)
pre_routes.append(pre_route)
# Route on src_node.name:
# route add [prefix] dev [next_hop_interface_.device_name]
# via [next_hop_ingress.ip_address]
- route = IPRoute(node = src_node,
- managed = False,
- owner = self,
- ip_address = prefix,
- interface = next_hop_interface,
+ route = IPRoute(node = src_node,
+ managed = False,
+ owner = self,
+ ip_address = prefix,
+ ip_version = ip_version,
+ interface = next_hop_interface,
mac_address = mac_addr,
- gateway = next_hop_ingress.ip_address)
+ gateway = next_hop_ingress_ip)
ip_routes[src_node].append(prefix)
routes.append(route)
return pre_routes, routes
@@ -420,16 +344,24 @@ class IPRoutes(Resource):
dst = self._state.manager.by_uuid(map_[dst_node_uuid])
log.debug('[IP ROUTE] NODES {}/{}/{} -> {}/{}/{}'.format(
- src_node.name, src.device_name, src.ip_address,
- dst_node.name, dst.device_name, dst.ip_address))
+ src_node.name, src.device_name, src.ip4_address,
+ dst_node.name, dst.device_name, dst.ip4_address))
log.debug('[IP ROUTE] NODES {}/{}/{} -> {}/{}/{}'.format(
- dst_node.name, dst.device_name, dst.ip_address,
- src_node.name, src.device_name, src.ip_address))
+ dst_node.name, dst.device_name, dst.ip4_address,
+ src_node.name, src.device_name, src.ip4_address))
route = IPRoute(node = src_node,
managed = False,
owner = self,
- ip_address = dst.ip_address,
+ ip_address = dst.ip4_address,
+ mac_address = dst.mac_address,
+ interface = src)
+ routes.append(route)
+ route = IPRoute(node = src_node,
+ managed = False,
+ owner = self,
+ ip_address = dst.ip6_address,
+ ip_version = 6,
mac_address = dst.mac_address,
interface = src)
routes.append(route)
@@ -437,7 +369,15 @@ class IPRoutes(Resource):
route = IPRoute(node = dst_node,
managed = False,
owner = self,
- ip_address = src.ip_address,
+ ip_address = src.ip4_address,
+ mac_address = src.mac_address,
+ interface = dst)
+ routes.append(route)
+ route = IPRoute(node = dst_node,
+ managed = False,
+ owner = self,
+ ip_address = src.ip6_address,
+ ip_version = 6,
mac_address = src.mac_address,
interface = dst)
routes.append(route)
@@ -513,15 +453,15 @@ class ICNFaces(Resource):
src_face = L4Face(node = src_node,
owner = self,
protocol = protocol,
- src_ip = src.ip_address,
- dst_ip = dst.ip_address,
+ src_ip = src.ip4_address,
+ dst_ip = dst.ip4_address,
src_port = TMP_DEFAULT_PORT,
dst_port = TMP_DEFAULT_PORT)
dst_face = L4Face(node = dst_node,
owner = self,
protocol = protocol,
- src_ip = dst.ip_address,
- dst_ip = src.ip_address,
+ src_ip = dst.ip4_address,
+ dst_ip = src.ip4_address,
src_port = TMP_DEFAULT_PORT,
dst_port = TMP_DEFAULT_PORT)
else:
@@ -649,38 +589,9 @@ class ContainerSetup(Resource):
def __subresources__(self):
- # a) routes: host -> container
- # . container interfaces
- # . container host (main) interface
- # route add -host {ip_address} dev {bridge_name}
- route = IPRoute(node = self.container.node,
- managed = False,
- owner = self,
- ip_address = self.container.host_interface.ip_address,
- interface = self.container.node.bridge)
- route.node.routing_table.routes << route
-
- # b) route: container -> host
- # route add {ip_gateway} dev {interface_name}
- # route add default gw {ip_gateway} dev {interface_name}
- route = IPRoute(node = self.container,
- owner = self,
- managed = False,
- ip_address = self.container.node.bridge.ip_address,
- interface = self.container.host_interface)
- route.node.routing_table.routes << route
- route_gw = IPRoute(node = self.container,
- managed = False,
- owner = self,
- ip_address = 'default',
- interface = self.container.host_interface,
- gateway = self.container.node.bridge.ip_address)
- route_gw.node.routing_table.routes << route_gw
-
- # c) dns
dns_server_entry = DnsServerEntry(node = self.container,
owner = self,
- ip_address = self.container.node.bridge.ip_address,
+ ip_address = self.container.node.bridge.ip4_address,
interface_name = self.container.host_interface.device_name)
return dns_server_entry
@@ -690,6 +601,44 @@ class ContainerSetup(Resource):
raise ResourceNotFound
def __create__(self):
+ #If no IP has been given on the host interface (e.g., through DHCP)
+ #We need to assign one
+ if not self.container.host_interface.ip4_address:
+ # a) get the IP
+ assign=self._state.manager.by_type(Ipv4Assignment)[0]
+ ip4_addr = assign.get_control_address(self.container.host_interface)
+ self.container.host_interface.ip4_address = ip4_addr
+
+
+ # a) routes: host -> container
+ # . container interfaces
+ # . container host (main) interface
+ # route add -host {ip_address} dev {bridge_name}
+ route = IPRoute(node = self.container.node,
+ managed = False,
+ owner = self,
+ ip_address = ip4_addr,
+ interface = self.container.node.bridge)
+ route.node.routing_table.routes << route
+
+ # b) route: container -> host
+ # route add {ip_gateway} dev {interface_name}
+ # route add default gw {ip_gateway} dev {interface_name}
+ route = IPRoute(node = self.container,
+ owner = self,
+ managed = False,
+ ip_address = self.container.node.bridge.ip4_address,
+ interface = self.container.host_interface)
+ route.node.routing_table.routes << route
+ route_gw = IPRoute(node = self.container,
+ managed = False,
+ owner = self,
+ ip_address = 'default',
+ interface = self.container.host_interface,
+ gateway = self.container.node.bridge.ip4_address)
+ route_gw.node.routing_table.routes << route_gw
+
+
return BashTask(self.container.node, CMD_IP_FORWARD)
#------------------------------------------------------------------------------
@@ -729,21 +678,26 @@ class CentralIP(Resource):
ip_routing_strategy = Attribute(String, description = 'IP routing strategy',
default = 'pair') # spt, pair
+ ip6_data_prefix = Attribute(String, description="Prefix for IPv6 forwarding", mandatory=True)
+ ip4_data_prefix = Attribute(String, description="Prefix for IPv4 forwarding", mandatory=True)
+ ip4_control_prefix = Attribute(String, description="Prefix for IPv4 control", mandatory=True)
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
- def __after_init__(self):
- return ('Node', 'Channel', 'Interface')
+ #def __after_init__(self):
+ # return ('Node', 'Channel', 'Interface')
def __subresources__(self):
- ip_assign = IPAssignment(owner=self)
+ ip4_assign = Ipv4Assignment(prefix=self.ip4_data_prefix,
+ control_prefix=self.ip4_control_prefix)
+ ip6_assign = Ipv6Assignment(prefix=self.ip6_data_prefix)
containers_setup = ContainersSetup(owner=self)
ip_routes = IPRoutes(owner = self,
routing_strategy = self.ip_routing_strategy)
- return ip_assign > (ip_routes | containers_setup)
+ return (ip4_assign | ip6_assign) > (ip_routes | containers_setup)
@inline_task
def __get__(self):