X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Ftestbeds%2Fplanetlab%2Finterfaces.py;h=f4df82f64ca92590d517956d976e8b495ff7b3d8;hb=1cf85539204432589217de408cd2eb37e3d68e6a;hp=8eace7b37875e19db26c8eff39ff6603b8ea14b0;hpb=b0670e6c643fea3b8308e479986e4074287e8f41;p=nepi.git diff --git a/src/nepi/testbeds/planetlab/interfaces.py b/src/nepi/testbeds/planetlab/interfaces.py index 8eace7b3..f4df82f6 100644 --- a/src/nepi/testbeds/planetlab/interfaces.py +++ b/src/nepi/testbeds/planetlab/interfaces.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- from constants import TESTBED_ID @@ -10,6 +9,7 @@ import os import os.path import random import ipaddr +import functools import tunproto @@ -60,9 +60,16 @@ class NodeIface(object): if self.node is None or self.node._node_id is None: raise RuntimeError, "Cannot pick interface without an assigned node" - + + # HACK: SFA doesnt give the node_id!! + if not isinstance(self.node._node_id, int): + node_data = self._api.GetNodes(filters={'hostname':self.node.hostname}, fields=('node_id',))[0] + node_id = node_data['node_id'] + else: + node_id = self.node._node_id + avail = self._api.GetInterfaces( - node_id=self.node._node_id, + node_id=node_id, is_primary=self.primary, fields=('interface_id','mac','netmask','ip') ) @@ -88,11 +95,17 @@ class NodeIface(object): class _CrossIface(object): - def __init__(self, proto, addr, port): + def __init__(self, proto, addr, port, cipher): self.tun_proto = proto self.tun_addr = addr self.tun_port = port - + self.tun_cipher = cipher + + # Attributes + self.address = None + self.netprefix = None + self.netmask = None + # Cannot access cross peers self.peer_proto_impl = None @@ -101,7 +114,8 @@ class _CrossIface(object): self.__class__.__name__, ( self.tun_proto, self.tun_addr, - self.tun_port ) + self.tun_port, + self.tun_cipher ) ) __repr__ = __str__ @@ -121,11 +135,12 @@ class TunIface(object): self.netmask = None self.up = None - self.device_name = None self.mtu = None self.snat = False - self.txqueuelen = None + self.txqueuelen = 1000 self.pointopoint = None + self.multicast = False + self.bwlimit = None # Enabled traces self.capture = False @@ -133,6 +148,10 @@ class TunIface(object): # These get initialized when the iface is connected to its node self.node = None + # These get initialized when the iface is connected to any filter + self.filter_module = None + self.multicast_forwarder = None + # These get initialized when the iface is configured self.external_iface = None @@ -140,6 +159,7 @@ class TunIface(object): # They're part of the TUN standard attribute set self.tun_port = None self.tun_addr = None + self.tun_cipher = "AES" # These get initialized when the iface is connected to its peer self.peer_iface = None @@ -147,6 +167,7 @@ class TunIface(object): self.peer_addr = None self.peer_port = None self.peer_proto_impl = None + self._delay_recover = False # same as peer proto, but for execute-time standard attribute lookups self.tun_proto = None @@ -178,6 +199,14 @@ class TunIface(object): if self.peer_proto_impl: return self.peer_proto_impl.if_name + def if_up(self): + if self.peer_proto_impl: + return self.peer_proto_impl.if_up() + + def if_down(self): + if self.peer_proto_impl: + return self.peer_proto_impl.if_down() + def routes_here(self, route): """ Returns True if the route should be attached to this interface @@ -185,16 +214,20 @@ class TunIface(object): """ if self.address and self.netprefix: addr, prefix = self.address, self.netprefix - if self.pointopoint: + pointopoint = self.pointopoint + if not pointopoint and self.peer_iface: + pointopoint = self.peer_iface.address + + if pointopoint: prefix = 32 - dest, destprefix, nexthop = route + dest, destprefix, nexthop, metric, device = route - myNet = ipaddr.IPNetwork("%s/%d" % (addr, prefix)) - gwIp = ipaddr.IPNetwork(nexthop) + myNet = ipaddr.IPv4Network("%s/%d" % (addr, prefix)) + gwIp = ipaddr.IPv4Network(nexthop) - if self.pointopoint: - peerIp = ipaddr.IPNetwork(self.pointopoint) + if pointopoint: + peerIp = ipaddr.IPv4Network(pointopoint) if gwIp == peerIp: return True @@ -207,7 +240,7 @@ class TunIface(object): if (self.address or self.netprefix or self.netmask) is not None: raise RuntimeError, "Cannot add more than one address to %s interfaces" % (self._KIND,) if broadcast: - raise ValueError, "%s interfaces cannot broadcast in PlanetLab" % (self._KIND,) + raise ValueError, "%s interfaces cannot broadcast in PlanetLab (%s)" % (self._KIND,broadcast) self.address = address self.netprefix = netprefix @@ -220,28 +253,43 @@ class TunIface(object): raise RuntimeError, "Unsupported tunnelling protocol: %s" % (self.peer_proto,) if not self.address or not self.netprefix or not self.netmask: raise RuntimeError, "Misconfigured %s iface - missing address" % (self._KIND,) + if self.filter_module and self.peer_proto not in ('udp','tcp',None): + raise RuntimeError, "Miscofnigured TUN: %s - filtered tunnels only work with udp or tcp links" % (self,) + if self.tun_cipher != 'PLAIN' and self.peer_proto not in ('udp','tcp',None): + raise RuntimeError, "Miscofnigured TUN: %s - ciphered tunnels only work with udp or tcp links" % (self,) - def _impl_instance(self, home_path, listening): + def _impl_instance(self, home_path): impl = self._PROTO_MAP[self.peer_proto]( - self, self.peer_iface, home_path, self.tun_key, listening) + self, self.peer_iface, home_path, self.tun_key) impl.port = self.tun_port + impl.cross_slice = not self.peer_iface or isinstance(self.peer_iface, _CrossIface) return impl - def prepare(self, home_path, listening): - if not self.peer_iface and (self.peer_proto and (listening or (self.peer_addr and self.peer_port))): + def recover(self): + if self.peer_proto: + self.peer_proto_impl = self._impl_instance( + self._home_path) + self.peer_proto_impl.recover() + else: + self._delay_recover = True + + def prepare(self, home_path): + if not self.peer_iface and (self.peer_proto and self.peer_addr): # Ad-hoc peer_iface self.peer_iface = _CrossIface( self.peer_proto, self.peer_addr, - self.peer_port) + self.peer_port, + self.peer_cipher) if self.peer_iface: if not self.peer_proto_impl: - self.peer_proto_impl = self._impl_instance(home_path, listening) - self.peer_proto_impl.prepare() + self.peer_proto_impl = self._impl_instance(home_path) + if self._delay_recover: + self.peer_proto_impl.recover() - def setup(self): + def launch(self): if self.peer_proto_impl: - self.peer_proto_impl.setup() + self.peer_proto_impl.launch() def cleanup(self): if self.peer_proto_impl: @@ -252,22 +300,26 @@ class TunIface(object): self.peer_proto_impl.destroy() self.peer_proto_impl = None - def async_launch_wait(self): + def wait(self): if self.peer_proto_impl: - self.peer_proto_impl.async_launch_wait() + self.peer_proto_impl.wait() - def sync_trace(self, local_dir, whichtrace): + def sync_trace(self, local_dir, whichtrace, tracemap = None): if self.peer_proto_impl: - return self.peer_proto_impl.sync_trace(local_dir, whichtrace) + return self.peer_proto_impl.sync_trace(local_dir, whichtrace, + tracemap) else: return None - def remote_trace_path(self, whichtrace): + def remote_trace_path(self, whichtrace, tracemap = None): if self.peer_proto_impl: - return self.peer_proto_impl.remote_trace_path(whichtrace) + return self.peer_proto_impl.remote_trace_path(whichtrace, tracemap) else: return None + def remote_trace_name(self, whichtrace): + return whichtrace + class TapIface(TunIface): _PROTO_MAP = tunproto.TAP_PROTO_MAP _KIND = 'TAP' @@ -339,6 +391,10 @@ class NetPipe(object): options = ' '.join(options) return (scope,options) + + def recover(self): + # Rules are safe on their nodes + self.configured = True def configure(self): # set up rule @@ -437,3 +493,116 @@ class NetPipe(object): return local_path +class TunFilter(object): + _TRACEMAP = { + # tracename : (remotename, localname) + } + + def __init__(self, api=None): + if not api: + api = plcapi.PLCAPI() + self._api = api + + # Attributes + self.module = None + self.args = None + + # These get initialised when the filter is connected + self.peer_guid = None + self.peer_proto = None + self.iface_guid = None + self.peer = None + self.iface = None + + def _get(what, self): + wref = self.iface + if wref: + wref = wref() + if wref: + return getattr(wref, what) + else: + return None + + def _set(what, self, val): + wref = self.iface + if wref: + wref = wref() + if wref: + setattr(wref, what, val) + + tun_proto = property( + functools.partial(_get, 'tun_proto'), + functools.partial(_set, 'tun_proto') ) + tun_addr = property( + functools.partial(_get, 'tun_addr'), + functools.partial(_set, 'tun_addr') ) + tun_port = property( + functools.partial(_get, 'tun_port'), + functools.partial(_set, 'tun_port') ) + tun_key = property( + functools.partial(_get, 'tun_key'), + functools.partial(_set, 'tun_key') ) + tun_cipher = property( + functools.partial(_get, 'tun_cipher'), + functools.partial(_set, 'tun_cipher') ) + + del _get + del _set + + def remote_trace_path(self, whichtrace): + iface = self.iface() + if iface is not None: + return iface.remote_trace_path(whichtrace, self._TRACEMAP) + return None + + def remote_trace_name(self, whichtrace): + iface = self.iface() + if iface is not None: + return iface.remote_trace_name(whichtrace, self._TRACEMAP) + return None + + def sync_trace(self, local_dir, whichtrace): + iface = self.iface() + if iface is not None: + return iface.sync_trace(local_dir, whichtrace, self._TRACEMAP) + return None + +class ClassQueueFilter(TunFilter): + _TRACEMAP = { + # tracename : (remotename, localname) + 'dropped_stats' : ('dropped_stats', 'dropped_stats') + } + + def __init__(self, api=None): + super(ClassQueueFilter, self).__init__(api) + # Attributes + self.module = "classqueue.py" + +class LoggingClassQueueFilter(ClassQueueFilter): + _TRACEMAP = ClassQueueFilter._TRACEMAP.copy() + _TRACEMAP.update({ + # tracename : (remotename, localname) + 'queue_stats_f' : ('queue_stats_f', 'queue_stats_f'), + 'queue_stats_b' : ('queue_stats_b', 'queue_stats_b'), + }) + + def __init__(self, api=None): + super(LoggingClassQueueFilter, self).__init__(api) + # Attributes + self.module = "loggingclassqueue.py classqueue.py" + + def _args_get(self): + # Inject outpath + args = dict(filter(lambda x:len(x)>1, map(lambda x:x.split('=',1),(self._args or "").split(',')))) + args["outpath"] = "queue_stats" + return ",".join(map("=".join, args.iteritems())) + def _args_set(self, value): + self._args = value + args = property(_args_get, _args_set) + +class ToSQueueFilter(TunFilter): + def __init__(self, api=None): + super(ToSQueueFilter, self).__init__(api) + # Attributes + self.module = "tosqueue.py" +