adding ns3 testbed: ongoing development! tests DON'T run OK!
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 18 Mar 2011 14:53:21 +0000 (15:53 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 18 Mar 2011 14:53:21 +0000 (15:53 +0100)
src/nepi/core/attributes.py
src/nepi/core/testbed_impl.py
src/nepi/testbeds/netns/metadata_v01.py
src/nepi/testbeds/ns3/__init__.py [new file with mode: 0644]
src/nepi/testbeds/ns3/constants.py [new file with mode: 0644]
src/nepi/testbeds/ns3/execute.py [new file with mode: 0644]
src/nepi/testbeds/ns3/metadata_v3.9.RC3.py [new file with mode: 0644]
src/nepi/util/server.py
src/nepi/util/validation.py
test/core/integration.py
test/lib/test_util.py

index e57ba19..f82fbae 100644 (file)
@@ -3,9 +3,19 @@
 
 class Attribute(object):
     ### Attribute types
-    STRING, BOOL, ENUM, DOUBLE, INTEGER = (
-               "STRING", "BOOL", "ENUM", "DOUBLE", "INTEGER")
-    types = [STRING, BOOL, ENUM, DOUBLE, INTEGER]
+    STRING  = "STRING"
+    BOOL    = "BOOL"
+    ENUM    = "ENUM"
+    DOUBLE  = "DOUBLE"
+    INTEGER = "INTEGER"
+
+    types = [
+        STRING, 
+        BOOL, 
+        ENUM, 
+        DOUBLE, 
+        INTEGER
+    ]
 
     ### Attribute Flags
     NoFlags     = 0x00
index 5452531..0f35a1e 100644 (file)
@@ -54,7 +54,7 @@ class TestbedInstance(execute.TestbedInstance):
 
     def create(self, guid, factory_id):
         if factory_id not in self._factories:
-            raise RuntimeError("Invalid element type %s for Netns version %s" %
+            raise RuntimeError("Invalid element type %s for testbed version %s" %
                     (factory_id, self._testbed_version))
         if guid in self._create:
             raise RuntimeError("Cannot add elements with the same guid: %d" %
@@ -184,10 +184,9 @@ class TestbedInstance(execute.TestbedInstance):
                 continue
             factory = self._factories[factory_id]
             for guid in guids[factory_id]:
-                parameters = dict() if guid not in self._create_set else \
-                        self._create_set[guid]
+                parameters = self._get_parameters(guid)
                 factory_parameters = dict() if guid not in \
-                        self._factory_set else self._create_set[guid]
+                        self._factory_set else self._factory_set[guid]
                 factory.create_function(self, guid, parameters, 
                         factory_parameters)
                 for name, value in parameters.iteritems():
@@ -210,7 +209,7 @@ class TestbedInstance(execute.TestbedInstance):
                             self._testbed_id, factory_id2, 
                             connector_type_name2)
                     if code_to_connect:
-                        code_to_connect(element1, element2)
+                        code_to_connect(self, element1, element2)
 
     def do_configure(self):
         raise NotImplementedError
@@ -256,10 +255,8 @@ class TestbedInstance(execute.TestbedInstance):
             factory = self._factories[factory_id]
             start_function = factory.start_function
             if start_function:
-                traces = [] if guid not in self._add_trace else \
-                        self._add_trace[guid]
-                parameters = dict() if guid not in self._create_set else \
-                        self._create_set[guid]
+                traces = self._traces(guid)
+                parameters = self._parameters(guid)
                 start_function(self, guid, parameters, traces)
         self._started = True
 
@@ -271,16 +268,18 @@ class TestbedInstance(execute.TestbedInstance):
             factory = self._factories[factory_id]
             stop_function = factory.stop_function
             if stop_function:
-                traces = [] if guid not in self._add_trace else \
-                        self._add_trace[guid]
-                stop_function(self, guid, traces)
+                traces = self._traces(guid)
+                parameters = self._parameters(guid)
+                stop_function(self, guid, parameters, traces)
 
     def status(self, guid):
-        for guid, factory_id in self._create.iteritems():
-            factory = self._factories[factory_id]
-            status_function = factory.status_function
-            if status_function:
-                return status_function(self, guid)
+        if not guid in self._create:
+            raise RuntimeError("Element guid %d doesn't exist" % guid)
+        factory_id = self._create[guid]
+        factory = self._factories[factory_id]
+        status_function = factory.status_function
+        if status_function:
+            return status_function(self, guid, parameters, traces)
         return STATUS_UNDETERMINED
 
     def trace(self, guid, trace_id):
@@ -317,3 +316,10 @@ class TestbedInstance(execute.TestbedInstance):
             cross_count = len(self._cross_connect[guid][connection_type_name])
         return count + cross_count
 
+    def _get_traces(self, guid):
+        return [] if guid not in self._add_trace else self._add_trace[guid]
+
+    def _get_parameters(self, guid):
+        return dict() if guid not in self._create_set else \
+                self._create_set[guid]
+
index 58cab37..2006245 100644 (file)
@@ -20,12 +20,12 @@ FDNETDEV = "ns3::FileDescriptorNetDevice"
 
 ### Connection functions ####
 
-def connect_switch(switch, interface):
+def connect_switch(testbed_instance, switch, interface):
     switch.connect(interface)
    
 #XXX: This connection function cannot be use to transfer a file descriptor
 # to a remote tap device
-def connect_fd_local(tap, fdnd):
+def connect_fd_local(testbed_instance, tap, fdnd):
     import passfd
     import socket
     fd = tap.file_descriptor
@@ -122,7 +122,7 @@ def start_application(testbed_instance, guid, parameters, traces):
 
 ### Status functions ###
 
-def status_application(testbed_instance, guid):
+def status_application(testbed_instance, guid, parameters, traces):
     if guid not in testbed_instance.elements.keys():
         return STATUS_NOT_STARTED
     app = testbed_instance.elements[guid]
diff --git a/src/nepi/testbeds/ns3/__init__.py b/src/nepi/testbeds/ns3/__init__.py
new file mode 100644 (file)
index 0000000..3b3f853
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from execute import TestbedInstance 
+
diff --git a/src/nepi/testbeds/ns3/constants.py b/src/nepi/testbeds/ns3/constants.py
new file mode 100644 (file)
index 0000000..fe891bf
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+TESTBED_ID = "ns3"
+
diff --git a/src/nepi/testbeds/ns3/execute.py b/src/nepi/testbeds/ns3/execute.py
new file mode 100644 (file)
index 0000000..bb2816f
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from nepi.core import testbed_impl
+from nepi.util.constants import AF_INET, AF_INET6
+import os
+
+class TestbedInstance(testbed_impl.TestbedInstance):
+    def __init__(self, testbed_version):
+        super(TestbedInstance, self).__init__(TESTBED_ID, testbed_version)
+        self._ns3 = None
+        self._home_directory = None
+        self._traces = dict()
+
+    @property
+    def home_directory(self):
+        return self._home_directory
+
+    @property
+    def ns3(self):
+        return self._ns3
+
+    def do_setup(self):
+        self._home_directory = self._attributes.\
+            get_attribute_value("homeDirectory")
+        self._ns3 = self._load_ns3_module()
+
+    def do_configure(self):
+        # TODO: add traces!
+        # configure addressess
+        for guid, addresses in self._add_address.iteritems():
+            element = self._elements[guid]
+            for address in addresses:
+                (family, address, netprefix, broadcast) = address
+                if family == AF_INET:
+                    element.add_v4_address(address, netprefix)
+        # configure routes
+        for guid, routes in self._add_route.iteritems():
+            element = self._elements[guid]
+            for route in routes:
+                (destination, netprefix, nexthop) = route
+                element.add_route(prefix = destination, prefix_len = netprefix,
+                        nexthop = nexthop)
+
+    def set(self, time, guid, name, value):
+        super(TestbedInstance, self).set(time, guid, name, value)
+        factory_id = self._crerate[guid]
+        element = self._elements[guid]
+        self._set(element, factory_id, name, value)
+
+    def get(self, time, guid, name):
+        raise NotImplementedError
+        # TODO: take on account schedule time for the task
+        #element = self._elements[guid]
+        #return getattr(element, name)
+
+    def action(self, time, guid, action):
+        raise NotImplementedError
+
+    def trace(self, guid, trace_id):
+        fd = open("%s" % self.trace_filename(guid, trace_id), "r")
+        content = fd.read()
+        fd.close()
+        return content
+
+    def shutdown(self):
+        for trace in self._traces.values():
+            trace.close()
+        for element in self._elements.values():
+            element.destroy()
+
+    def trace_filename(self, guid, trace_id):
+        # TODO: Need to be defined inside a home!!!! with and experiment id_code
+        return os.path.join(self.home_directory, "%d_%s" % (guid, trace_id))
+
+    def follow_trace(self, trace_id, trace):
+        self._traces[trace_id] = trace
+
+    def _set(self, element, factory_id, name, value):
+        TypeId = self.ns3.TypeId()
+        typeId = TypeId.LookupByName(factory_id)
+        index = None
+        attr_count = typeId.GetAttributeN()
+        for idx in range(attr_count):
+            if name == typeId.GetAttributeName(idx)
+                index = idx
+                break
+        checker = typeid.GetAttributeChecker(index)
+        ns3_value = attribute_checker.Create()
+        value = str(value)
+        if isinstance(value, bool):
+            value = value.lower()
+        ns3_value.DeserializeFromString(value, checker)
+        element.Set(name, ns3_value)
+
+    def _load_ns3_module(self):
+        import ctypes
+        import imp
+
+        bindings = self._attributes.get_attribute_value("ns3Bindings")
+        libfile = self._attributes.get_attribute_value("ns3Library")
+        simu_impl_type = self._attributes.get_attribute_value(
+                "SimulatorImplementationType")
+        checksum = self._attributes.get_attribute_value("ChecksumEnabled")
+
+        if libfile:
+            ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
+
+        path = [ os.path.dirname(__file__) ] + sys.path
+        if bindings:
+            path = [ bindings ] + path
+
+        module = imp.find_module ('ns3', path)
+        mod = imp.load_module ('ns3', *module)
+    
+        if simu_impl_type:
+            value = mod.StringValue(simu_impl_type)
+            mod.GlobalValue.Bind ("SimulatorImplementationType", value)
+        if checksum:
+            value = mod.BooleanValue(checksum)
+            mod.GlobalValue.Bind ("ChecksumEnabled", value)
+        return mod
+
diff --git a/src/nepi/testbeds/ns3/metadata_v3.9.RC3.py b/src/nepi/testbeds/ns3/metadata_v3.9.RC3.py
new file mode 100644 (file)
index 0000000..8edbe2e
--- /dev/null
@@ -0,0 +1,643 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from nepi.core import metadata
+from nepi.core.attributes import Attribute
+from nepi.util import validation
+from nepi.util.constants import AF_INET, STATUS_NOT_STARTED, STATUS_RUNNING, \
+        STATUS_FINISHED
+
+wifi_standards = dict({
+    "WIFI_PHY_STANDARD_holland": 5,
+    "WIFI_PHY_STANDARD_80211p_SCH": 7,
+    "WIFI_PHY_STANDARD_80211_5Mhz": 4,
+    "WIFI_PHY_UNKNOWN": 8,
+    "WIFI_PHY_STANDARD_80211_10Mhz": 3,
+    "WIFI_PHY_STANDARD_80211g": 2,
+    "WIFI_PHY_STANDARD_80211p_CCH": 6,
+    "WIFI_PHY_STANDARD_80211a": 0,
+    "WIFI_PHY_STANDARD_80211b": 1
+})
+
+### Connection functions ####
+
+def connect_node_device(testbed_instance, node, device):
+    node.AddDevice(device)
+
+def connect_queue_device(testbed_instance, queue, device):
+    device.SetQueue(queue)
+
+def connect_manager_device(testbed_instance, manager, device):
+    device.SetRemoteStationManager(manager)
+
+def connect_phy_device(testbed_instance, phy, device):
+    device.SetPhy(phy)
+    phy.SetDevice(device)
+    # search for the node asociated with the device
+    node_guid = testbed_instance.get_connected(guid, "node", "devs")
+    if len(node_guid) == 0:
+        raise RuntimeError("Can't instantiate interface %d outside netns \
+                node" % guid)
+    node = testbed_instance.elements[node_guid[0]]
+    phy.SetMobility(node)
+
+def connect_mac_device(testbed_instance, mac, device):
+    device.SetMac(mac)
+
+def connect_errormodel_device(testbed_instance, model, device):
+    device.SetReceiveErrorModel(model)
+
+def connect_errormodel_phy(testbed_instance, err, phy):
+    phy.SetErrorRateModel(err)
+
+def connect_channel_device(testbed_instance, channel, device):
+    device.Attach(channel)
+
+def connect_simple_channel_device(testbed_instance, channel, device):
+    device.SetChannel(channel)
+
+def connect_loss_channel(testbed_instance, loss, channel):
+    channel.SetPropagationLossModel(loss)
+
+def connect_next_loss(testbed_instance, prev, next):
+    prev.SetNext(next)
+
+def connect_delay_channel(testbed_instance, delay, channel):
+    channel.SetPropagationDelayModel(delay)
+
+def connect_node_application(testbed_instance, node, application):
+    node.AddApplication(application)
+# works for ArpL3Protocol, Ipv4L3Protocol, UdpL4Protocol, TcpL4Protocol,
+# NscTcpL4Protocol, MobilityModel (every subclass), 
+# RoutingProtocol (every subclass)
+
+def connect_node_other(tesbed_instance, node, other):
+    node.AggregateObject(other)
+### Creation functions ###
+
+def create_element(testbed_instance, guid, parameters, factory_parameters):
+    element_factory = testbed_instance.ns3.ObjectFactory()
+    factory_id = testbed_instance._create[guid]
+    element_factory.SetTypeId(factory_id) 
+    for name, value in factory_parameters.iteritems():
+        testbed_instance._set(element_factory, factory_id, name, value)
+    element = element_factory.Create()
+    testbed_instance._elements[guid] = element
+
+def create_node(testbed_instance, guid, parameters, factory_parameters):
+    create_element(testbed_instance, guid, parameters, factory_parameters)
+    element = testbed_instance._elements[guid]
+    element.AggregateObject(testbed_instance.PacketSocketFactory())
+
+def create_dev(testbed_instance, guid, parameters, factory_parameters):
+    create_element(testbed_instance, guid, parameters, factory_parameters)
+    element = testbed_instance._elements[guid]
+    if "macAddress" in parameters:
+        address = parameters["macAddress"]
+        macaddr = testbed_instance.ns3.Mac48Address(address)
+    else:
+        macaddr = testbed_instance.ns3.Mac48Address.Allocate()
+    element.SetAddress(macaddr)
+
+def create_wifi_standard_model(testbed_instance, guid, parameters, 
+        factory_parameters):
+    create_element(testbed_instance, guid, parameters, factory_parameters)
+    element = testbed_instance._elements[guid]
+    if "standard" in parameters:
+        standard = parameters["standard"]
+        if standard:
+            elements.ConfigureStandard(wifi_standards[standard])
+
+def create_ipv4stack(testbed_instance, guid, parameters, factory_parameters):
+    create_element(testbed_instance, guid, parameters, factory_parameters)
+    element = testbed_instance._elements[guid]
+    list_routing = testbed_instance.ns3.Ipv4ListRouting()
+    element.SetRoutingProtocol(list_routing)
+    static_routing = testbed_instance.ns3.Ipv4StaticRouting()
+    list_routing.AddRoutingProtocol(static_routing, 1)
+
+### Start/Stop functions ###
+
+def start_application(testbed_instance, guid, parameters, traces):
+    element = testbed_instance.elements[guid]
+    element.Start()
+
+def stop_application(testbed_instance, guid, parameters, traces):
+    element = testbed_instance.elements[guid]
+    element.Stop()
+
+### Status functions ###
+
+def status_application(testbed_instance, guid, parameters, traces):
+    if guid not in testbed_instance.elements.keys():
+        return STATUS_NOT_STARTED
+    app = testbed_instance.elements[guid]
+    if "stopTime" in parameters:
+        stop = parameters["stopTime"]
+        if stop:
+            simTime = testbed_instance.ns3.Simulator.Now()
+            if simTime.Compare(stopTime) > 0:
+                return STATUS_RUNNING
+    return STATUS_FINISHED
+
+### Factory information ###
+
+connector_types = dict({
+    "node": dict({
+                "help": "Connector to a ns3::Node object (mandatory)",
+                "name": "node",
+                "max": 1,
+                "min": 1
+            }),
+    "devs": dict({
+                "help": "Connector to network interfaces",
+                "name": "devs",
+                "max": -1,
+                "min": 0
+            }),
+    "dev2": dict({
+                "help": "Connector to exactly two network interfaces (mandatory)",
+                "name": "dev2",
+                "max": 2,
+                "min": 2
+            }),
+    "dev": dict({
+                "help": "Connector to exactly one network interface (mandatory)",
+                "name": "dev",
+                "max": 1,
+                "min": 1
+            }),
+    "apps": dict({
+                "help": "Connector to applications", 
+                "name": "apps",
+                "max": -1,
+                "min": 0
+            }),
+    "protos": dict({
+                "help": "Connector to network stacks and protocols", 
+                "name": "protos",
+                "max": -1,
+                "min": 0
+            }),
+    "chan": dict({
+                "help": "Connector to a channel for the device (mandatory)", 
+                "name": "chan",
+                "max": 1,
+                "min": 1
+            }),
+    "queue": dict({
+                "help": "Connector to a queueing discipline (mandatory)", 
+                "name": "queue",
+                "max": 1,
+                "min": 1
+            }),
+    "err": dict({
+                "help": "Connector to an error model for the device", 
+                "name": "err",
+                "max": 1,
+                "min": 0
+            }),
+    "fd": dict({
+                "help": "Connector to interconnect devices with file descriptors",
+                "name": "fd",
+                "max": 1,
+                "min": 0
+            }),
+    "phy": dict({
+                "help": "Connector to interconnect elements with a PHY wifi model", 
+                "name": "phy",
+                "max": 1,
+                "min": 0
+            }),
+    "phys": dict({
+                "help": "Connector to interconnect a wifi channel with PHY wifi models", 
+                "name": "phys",
+                "max": -1,
+                "min": 0
+            }),
+    "mac": dict({
+                "help": "Connector to interconnect a device with a MAC wifi model", 
+                "name": "mac",
+                "max": 1,
+                "min": 0
+            }),
+    "manager": dict({
+                "help": "Connector to interconnect a wifi device with a wifi manager", 
+                "name": "manager",
+                "max": 1,
+                "min": 0
+            }),
+    "delay": dict({
+                "help": "Connector to a delay model", 
+                "name": "delay",
+                "max": 1,
+                "min": 0
+            }),
+    "loss": dict({
+                "help": "Connector to a loss model", 
+                "name": "loss",
+                "max": 1,
+                "min": 0
+            }),
+    "prev": dict({
+                "help": "Connector to the previous loss model", 
+                "name": "prev",
+                "max": 1,
+                "min": 0
+            }),
+    "next": dict({
+                "help": "Connector to the next loss model", 
+                "name": "next",
+                "max": 1,
+                "min": 0
+            }),
+    "mobility": dict({
+                "help": "Connector to a mobility model for the node", 
+                "name": "mobility",
+                "max": 1,
+                "min": 0
+            }),
+    })
+
+connections = [
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::BridgeNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::CsmaNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::EmuNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::PointToPointNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::SimpleNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::FileDescriptorNetDevice", "node" ),
+            "code": connect_node_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::Node", "devs" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "node" ),
+            "code": connect_node_device,   
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::DropTailQueue", "dev" ),
+            "to":   ( "ns3", "ns3::CsmaNetDevice", "queue" ),
+            "code": connect_queue_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::DropTailQueue", "dev" ),
+            "to":   ( "ns3", "ns3::EmuNetDevice", "queue" ),
+            "code": connect_queue_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::DropTailQueue", "dev" ),
+            "to":   ( "ns3", "ns3::PointToPointNetDevice", "queue" ),
+            "code": connect_queue_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::ArfWifiManager", "dev" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "manager" ),  
+            "code": connect_manager_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::ConstantRateWifiManager", "dev" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "manager" ),  
+            "code": connect_manager_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::YansWifiPhy", "dev" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "phy" ),  
+            "code": connect_phy_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::QapWifiMac", "dev" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "mac" ),
+            "code": connect_mac_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::QstaWifiMac", "dev" ),
+            "to":   ( "ns3", "ns3::WifiNetDevice", "mac" ),
+            "code": connect_mac_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::RateErrorModel", "dev" ),
+            "to":   ( "ns3", "ns3::CsmaNetDevice", "err" ),
+            "code": connect_errormodel_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::RateErrorModel", "dev" ),
+            "to":   ( "ns3", "ns3::PointToPointNetDevice", "err" ),
+            "code": connect_errormodel_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::ListErrorModel", "dev" ),
+            "to":   ( "ns3", "ns3::CsmaNetDevice", "err" ),
+            "code": connect_errormodel_device,
+            "can_cross": False
+    }),
+    dict({
+            "from": ( "ns3", "ns3::ListErrorModel", "dev" ),
+            "to":   ( "ns3", "ns3::PointToPointNetDevice", "err" ),
+            "code": connect_errormodel_device,
+            "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::NistErrorRateModel", "phy" ),        
+        "to":   ( "ns3", "ns3::YansWifiPhy", "err" ),
+        "code": connect_errormodel_phy,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::CsmaChannel", "devs" ),
+        "to":   ( "ns3", "ns3::CsmaNetDevice", "chan" ),
+        "code": connect_channel_device,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::PointToPointChannel", "dev2" ),
+        "to":   ( "ns3", "ns3::PointToPointNetDevice", "chan" ),
+        "code": connect_channel_device,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::SimpleChannel", "devs" ),
+        "to":   ( "ns3", "ns3::SimpleNetDevice", "chan" ),
+        "code": connect_simple_channel_device,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::YansWifiChannel", "phys" ),
+        "to":   ( "ns3", "ns3::YansWifiPhy", "chan" ),  
+        "code": connect_simple_channel_device,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::LogDistancePropagationLossModel", "prev" ),
+        "to":   ( "ns3", "ns3::YansWifiChannel", "loss" ),  
+        "code": connect_loss_channel,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::LogDistancePropagationLossModel", "prev" ),
+        "to":   ( "ns3", "ns3::LogDistancePropagationLossModel", "next" ),  
+        "code": connect_next_loss,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::ConstantSpeedPropagationDelayModel", "chan" ),
+        "to":   ( "ns3", "ns3::YansWifiChannel", "delay" ),  
+        "code": connect_delay_channel,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "apps" ),
+        "to":   ( "ns3", "ns3::OnOffApplication", "node" ),
+        "code": connect_node_application,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "apps" ),
+        "to":   ( "ns3", "ns3::PacketSink", "node" ),
+        "code": connect_node_application,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "apps" ),
+        "to":   ( "ns3", "ns3::UdpEchoClient", "node" ),
+        "code": connect_node_application,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "apps" ),
+        "to":   ( "ns3", "ns3::UdpEchoServer", "node" ),
+        "code": connect_node_application,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "apps" ),
+        "to":   ( "ns3", "ns3::V4Ping", "node" ),
+        "code": connect_node_application,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "protos" ),
+        "to":   ( "ns3", "ns3::ArpL3Protocol", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "protos" ),
+        "to":   ( "ns3", "ns3::Icmpv4L4Protocol", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "protos" ),
+        "to":   ( "ns3", "ns3::Ipv4L3Protocol", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "protos" ),
+        "to":   ( "ns3", "ns3::UdpL4Protocol", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "protos" ),
+        "to":   ( "ns3", "ns3::TcpL4Protocol", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::ConstantAccelerationMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::ConstantPositionMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::ConstantVelocityMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::HierarchicalMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::RandomDirection2dMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::RandomWalk2dMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    }),
+    dict({
+        "from": ( "ns3", "ns3::Node", "mobility" ),
+        "to":   ( "ns3", "ns3::RandomWaypointMobilityModel", "node" ),
+        "code": connect_node_other,
+        "can_cross": False
+    })
+]
+
+# TODO!
+attributes = dict({
+    "forward_X11": dict({      
+                "name": "forward_X11",
+                "help": "Forward x11 from main namespace to the node",
+                "type": Attribute.BOOL, 
+                "value": False,
+                "range": None,
+                "allowed": None,
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_bool
+            }),
+    })
+
+# TODO!
+traces = dict({
+    "stdout": dict({
+                "name": "stdout",
+                "help": "Standard output stream"
+              }),
+    })
+
+# TODO!
+factories_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+        APPLICATION ]
+
+# TODO!
+factories_info = dict({
+    NODE: dict({
+            "allow_routes": True,
+            "help": "Emulated Node with virtualized network stack",
+            "category": "topology",
+            "create_function": create_node,
+            "start_function": None,
+            "stop_function": None,
+            "status_function": None,
+            "box_attributes": ["forward_X11"],
+            "connector_types": ["devs", "apps"]
+       }),
+ })
+
+testbed_attributes = dict({
+        "ns3_bindings": dict({
+                "name": "ns3Bindings",
+                "help": "Location of the ns-3 python binding",
+                "type": Attribute.STRING,
+                "value": None,
+                "range": None,
+                "allowed": None,
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_string # TODO: validation.is_path
+            }),
+         "ns3_library": dict({
+                "name": "ns3Library",
+                "help": "Location of the ns-3 library .so file",
+                "type": Attribute.STRING,
+                "value": None,
+                "range": None,
+                "allowed": None,
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_string # TODO: validation.is_path
+            }),
+         "simu_impl_type": dict({
+                "name": "SimulatorImplementationType",
+                "help": "The object class to use as the simulator implementation",
+                "type": Attribute.STRING,
+                "value": None,
+                "range": None,
+                "allowed": None,
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_string
+            }),
+          "checksum": dict({
+                "name": "ChecksumEnabled",
+                "help": "A global switch to enable all checksums for all protocols",
+                "type": Attribute.BOOL,
+                "value": False,
+                "range": None,
+                "allowed": None,
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_bool
+            })
+ })
+
+class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
+    @property
+    def connections_types(self):
+        return connection_types
+
+    @property
+    def connections(self):
+        return connections
+
+    @property
+    def attributes(self):
+        return attributes
+
+    @property
+    def traces(self):
+        return traces
+
+    @property
+    def factories_order(self):
+        return factories_order
+
+    @property
+    def factories_info(self):
+        return factories_info
+
+    @property
+    def testbed_attributes(self):
+        return testbed_attributes
+
index 2e02c74..e1f68c1 100644 (file)
@@ -195,7 +195,7 @@ class Forwarder(object):
 
     def write_data(self, data):
         sys.stdout.write(data)
-        # sys.stdout.write is buffered, for this we need to do a flush()
+        # sys.stdout.write is buffered, this is why we need to do a flush()
         sys.stdout.flush()
 
     def send_to_server(self, data):
index 6f8a25b..1c899ee 100644 (file)
@@ -10,12 +10,19 @@ def is_enum(attribute, value):
 def is_bool(attribute, value):
     return isinstance(value, bool)
 
+def is_float(attribute, value):
+    return isinstance(value, float)
+
 def is_integer(attribute, value):
     return isinstance(value, int)
 
 def is_string(attribute, value):
     return isinstance(value, str)
 
+def is_time(attribute, value):
+    return isinstance(value, str) # TODO: Missing validation!
+
+# TODO: Allow netrefs!
 def is_ip4_address(attribute, value):
     try:
         ipaddr.IPv4Address(value)
@@ -23,6 +30,7 @@ def is_ip4_address(attribute, value):
         return False
     return True
 
+# TODO: Allow netrefs!
 def is_ip6_address(attribute, value):
     try:
         ipaddr.IPv6Address(value)
index 3830f03..726b885 100755 (executable)
@@ -186,7 +186,7 @@ class ExecuteTestCase(unittest.TestCase):
         controller.shutdown()
 
     def TODO_test_ssh_daemonized_all_integration(self):
-        # This test doesn't run because
+        # TODO: This test doesn't run because
         # sys.modules["nepi.testbeds.mock"] = mock
         # is not set in the ssh process
         exp_desc = ExperimentDescription()
index bdedb9b..25fc0cc 100644 (file)
@@ -134,6 +134,12 @@ class test_environment(object):
         if 'PYTHONPATH' in os.environ:
             environ['PYTHONPATH'] = ":".join(map(os.path.realpath, 
                 os.environ['PYTHONPATH'].split(":")))
+        if 'NEPI_NS3BINDINGS' in os.environ:
+            environ['NEPI_NS3BINDINGS'] = \
+                    os.path.realpath(os.environ['NEPI_NS3BINDINGS'])
+        if 'NEPI_NS3LIBRARY' in os.environ:
+            environ['NEPI_NS3LIBRARY'] = \
+                    os.path.realpath(os.environ['NEPI_NS3LIBRARY'])
 
         self.dir = tempfile.mkdtemp()
         self.server_keypair = gen_ssh_keypair(