Cross connections (initial planetlab-side implementation following the tun protocol)
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Wed, 4 May 2011 08:13:34 +0000 (10:13 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Wed, 4 May 2011 08:13:34 +0000 (10:13 +0200)
src/nepi/core/execute.py
src/nepi/core/metadata.py
src/nepi/testbeds/planetlab/interfaces.py
src/nepi/testbeds/planetlab/metadata_v01.py

index de3e7e1..980053c 100644 (file)
@@ -726,7 +726,11 @@ class ExperimentController(object):
             cross_data[cross_testbed_guid] = dict()
             cross_testbed = self._testbeds[cross_testbed_guid]
             for cross_guid in guid_list:
-                elem_cross_data = dict()
+                elem_cross_data = dict(
+                    _guid = cross_guid,
+                    _testbed_guid = cross_testbed_guid,
+                    _testbed_id = cross_testbed.testbed_id,
+                    _testbed_version = cross_testbed.testbed_version)
                 cross_data[cross_testbed_guid][cross_guid] = elem_cross_data
                 attributes_list = cross_testbed.get_attribute_list(cross_guid)
                 for attr_name in attributes_list:
index fe92e05..0b30a41 100644 (file)
@@ -249,6 +249,31 @@ class Metadata(object):
     
     del DC
     
+    
+    STANDARD_ATTRIBUTE_BUNDLES = {
+            "tun_proto" : dict({
+                "name": "tun_proto", 
+                "help": "TUNneling protocol used",
+                "type": Attribute.STRING,
+                "flags": Attribute.Invisible | Attribute.ReadOnly,
+                "validation_function": validation.is_string,
+            }),
+            "tun_addr" : dict({
+                "name": "tun_addr", 
+                "help": "IP address of the tunnel endpoint",
+                "type": Attribute.STRING,
+                "flags": Attribute.Invisible | Attribute.ReadOnly,
+                "validation_function": validation.is_ip_address,
+            }),
+            "tun_port" : dict({
+                "name": "tun_port", 
+                "help": "IP port of the tunnel endpoint",
+                "type": Attribute.INTEGER,
+                "flags": Attribute.Invisible | Attribute.ReadOnly,
+                "validation_function": validation.is_integer,
+            }),
+    }
+    
 
     def __init__(self, testbed_id, version):
         self._version = version
@@ -372,7 +397,9 @@ class Metadata(object):
 
     def _add_attributes(self, factory, info, attr_key, box_attributes = False, attr_bundle = ()):
         if not attr_bundle and info and attr_key in info:
-            attr_bundle = [ (attr_id, self._metadata.attributes[attr_id])
+            definitions = self.STANDARD_ATTRIBUTE_BUNDLES.copy()
+            definitions.update(self._metadata.attributes)
+            attr_bundle = [ (attr_id, definitions[attr_id])
                             for attr_id in info[attr_key] ]
         for attr_id, attr_info in attr_bundle:
             name = attr_info["name"]
index cd0b7f0..8e2a401 100644 (file)
@@ -83,6 +83,12 @@ class NodeIface(object):
             raise RuntimeError, "All external interface devices must be connected to the Internet"
     
 
+class _CrossIface(object):
+    def __init__(self, proto, addr, port):
+        self.tun_proto = proto
+        self.tun_addr = addr
+        self.tun_port = port
+
 class TunIface(object):
     def __init__(self, api=None):
         if not api:
@@ -149,6 +155,12 @@ class TunIface(object):
             raise RuntimeError, "Misconfigured TUN iface - missing address"
     
     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))):
+            # Ad-hoc peer_iface
+            self.peer_iface = CrossIface(
+                self.peer_proto,
+                self.peer_addr,
+                self.peer_port)
         if self.peer_iface:
             if not self.peer_proto_impl:
                 self.peer_proto_impl = tunproto.PROTO_MAP[self.peer_proto](
@@ -157,7 +169,7 @@ class TunIface(object):
             self.peer_proto_impl.prepare()
     
     def setup(self):
-        if self.peer_iface:
+        if self.peer_proto_impl:
             self.peer_proto_impl.setup()
     
     def cleanup(self):
index 27d9679..6cb15c7 100644 (file)
@@ -103,6 +103,19 @@ def connect_tun_iface_peer(proto, testbed_instance, iface_guid, peer_iface_guid)
     iface.peer_proto = \
     iface.tun_proto = proto
 
+def crossconnect_tun_iface_peer_init(proto, testbed_instance, iface_guid, peer_iface_data):
+    iface = testbed_instance._elements[iface_guid]
+    iface.peer_iface = None
+    iface.peer_addr = peer_iface_data.get("tun_addr")
+    iface.peer_proto = peer_iface_data.get("tun_proto")
+    iface.peer_port = peer_iface_data.get("tun_port")
+    iface.tun_proto = proto
+    
+    preconfigure_tuniface(testbed_instance, iface_guid)
+
+def crossconnect_tun_iface_peer_compl(proto, testbed_instance, iface_guid, peer_iface_data):
+    postconfigure_tuniface(testbed_instance, iface_guid)
+
 def connect_dep(testbed_instance, node_guid, app_guid):
     node = testbed_instance._elements[node_guid]
     app = testbed_instance._elements[app_guid]
@@ -268,8 +281,9 @@ def preconfigure_tuniface(testbed_instance, guid):
             break
 
     # Set standard TUN attributes
-    element.tun_addr = element.external_iface.address
-    element.tun_port = 15000 + int(guid)
+    if (not element.tun_addr or not element.tun_port) and element.external_iface:
+        element.tun_addr = element.external_iface.address
+        element.tun_port = 15000 + int(guid)
 
     # Set enabled traces
     traces = testbed_instance._get_traces(guid)
@@ -279,9 +293,23 @@ def preconfigure_tuniface(testbed_instance, guid):
     element.validate()
     
     # First-phase setup
-    element.prepare( 
-        'tun-%s' % (guid,),
-        id(element) < id(element.peer_iface) )
+    if element.peer_proto:
+        if element.peer_iface and isinstance(element.peer_iface, testbed_instance._interfaces.TunIface):
+            # intra tun
+            listening = id(element) < id(element.peer_iface)
+        else:
+            # cross tun
+            if not element.tun_addr or not element.tun_port:
+                listening = True
+            elif not element.peer_addr or not element.peer_port:
+                listening = True
+            else:
+                # both have addresses...
+                # ...the one with the lesser address listens
+                listening = element.tun_addr < element.peer_addr
+        element.prepare( 
+            'tun-%s' % (guid,),
+             listening)
 
 def postconfigure_tuniface(testbed_instance, guid):
     element = testbed_instance._elements[guid]
@@ -463,6 +491,20 @@ connections = [
         "init_code": functools.partial(connect_tun_iface_peer,"udp"),
         "can_cross": False
     }),
+    dict({
+        "from": (TESTBED_ID, TUNIFACE, "tcp"),
+        "to":   (None, None, "tcp"),
+        "init_code": functools.partial(crossconnect_tun_iface_peer_init,"tcp"),
+        "compl_code": functools.partial(crossconnect_tun_iface_peer_compl,"tcp"),
+        "can_cross": True
+    }),
+    dict({
+        "from": (TESTBED_ID, TUNIFACE, "udp"),
+        "to":   (None, None, "udp"),
+        "init_code": functools.partial(crossconnect_tun_iface_peer_init,"udp"),
+        "compl_code": functools.partial(crossconnect_tun_iface_peer_compl,"udp"),
+        "can_cross": True
+    }),
 ]
 
 attributes = dict({
@@ -823,7 +865,8 @@ factories_info = dict({
             "configure_function": postconfigure_tuniface,
             "box_attributes": [
                 "up", "device_name", "mtu", "snat",
-                "txqueuelen"
+                "txqueuelen",
+                "tun_proto", "tun_addr", "tun_port"
             ],
             "traces": ["packets"],
             "connector_types": ["node","udp","tcp"]