routing support added for ns3 testbed
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 25 Mar 2011 17:15:24 +0000 (18:15 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 25 Mar 2011 17:15:24 +0000 (18:15 +0100)
src/nepi/core/execute.py
src/nepi/core/metadata.py
src/nepi/core/testbed_impl.py
src/nepi/testbeds/netns/execute.py
src/nepi/testbeds/netns/metadata_v01.py
src/nepi/testbeds/ns3/execute.py
src/nepi/testbeds/ns3/factories_metadata_v3_9_RC3.py
src/nepi/testbeds/ns3/metadata_v3_9_RC3.py
test/lib/mock/metadata_v01.py
test/testbeds/ns3/execute.py [new file with mode: 0755]

index a796bc4..c37c6d3 100644 (file)
@@ -89,8 +89,8 @@ class ConnectorType(object):
 # need a definition!
 class Factory(AttributesMap):
     def __init__(self, factory_id, create_function, start_function, 
-            stop_function, status_function, allow_addresses = False, 
-            allow_routes = False):
+            stop_function, status_function, configure_function,
+            allow_addresses = False, allow_routes = False):
         super(Factory, self).__init__()
         self._factory_id = factory_id
         self._allow_addresses = (allow_addresses == True)
@@ -99,6 +99,7 @@ class Factory(AttributesMap):
         self._start_function = start_function
         self._stop_function = stop_function
         self._status_function = status_function
+        self._configure_function = configure_function
         self._connector_types = dict()
         self._traces = list()
         self._box_attributes = AttributesMap()
@@ -135,6 +136,10 @@ class Factory(AttributesMap):
     def status_function(self):
         return self._status_function
 
+    @property
+    def configure_function(self):
+        return self._configure_function
+
     @property
     def traces(self):
         return self._traces
index 8180e8e..b4fa746 100644 (file)
@@ -57,12 +57,19 @@ class VersionedMetadataInfo(object):
         raise NotImplementedError
 
     @property
-    def factories_order(self):
+    def create_order(self):
         """ list of factory ids that indicates the order in which the elements
         should be instantiated.
         """
         raise NotImplementedError
 
+    @property
+    def configure_order(self):
+        """ list of factory ids that indicates the order in which the elements
+        should be configured.
+        """
+        raise NotImplementedError
+
     @property
     def factories_info(self):
         """ dictionary of dictionaries of factory specific information
@@ -75,6 +82,7 @@ class VersionedMetadataInfo(object):
                 "start_function": function for element starting,
                 "stop_function": function for element stoping,
                 "status_function": function for retrieving element status,
+                "configure_function": function for element configuration,
                 "factory_attributes": list of references to attribute_ids,
                 "box_attributes": list of regerences to attribute_ids,
                 "traces": list of references to trace_id
@@ -108,8 +116,12 @@ class Metadata(object):
         self._metadata = metadata_module.VersionedMetadataInfo()
 
     @property
-    def factories_order(self):
-        return self._metadata.factories_order
+    def create_order(self):
+        return self._metadata.create_order
+
+    @property
+    def configure_order(self):
+        return self._metadata.configure_order
 
     def testbed_attributes(self):
         attributes = AttributesMap()
@@ -158,13 +170,15 @@ class Metadata(object):
                     if "stop_function" in info else None
             status_function = info["status_function"] \
                     if "status_function" in info else None
+            configure_function = info["configure_function"] \
+                    if "configure_function" in info else None
             allow_addresses = info["allow_addresses"] \
                     if "allow_addresses" in info else False
             allow_routes = info["allow_routes"] \
                     if "allow_routes" in info else False
             factory = Factory(factory_id, create_function, start_function,
-                    stop_function, status_function, allow_addresses, 
-                    allow_routes)
+                    stop_function, status_function, configure_function,
+                    allow_addresses, allow_routes)
             self._add_attributes(factory, info, "factory_attributes")
             self._add_attributes(factory, info, "box_attributes", True)
             self._add_execute_traces(factory, info)
index 36e8b1f..f669817 100644 (file)
@@ -178,7 +178,7 @@ class TestbedInstance(execute.TestbedInstance):
                guids[factory_id] = list()
             guids[factory_id].append(guid)
         # create elements following the factory_id order
-        for factory_id in self._metadata.factories_order:
+        for factory_id in self._metadata.create_order:
             # omit the factories that have no element to create
             if factory_id not in guids:
                 continue
@@ -209,7 +209,22 @@ class TestbedInstance(execute.TestbedInstance):
                         code_to_connect(self, element1, element2)
 
     def do_configure(self):
-        raise NotImplementedError
+        guids = dict()
+        # order guids (elements) according to factory_id
+        for guid, factory_id in self._create.iteritems():
+            if not factory_id in guids:
+               guids[factory_id] = list()
+            guids[factory_id].append(guid)
+        # configure elements following the factory_id order
+        for factory_id in self._metadata.configure_order:
+            # omit the factories that have no element to create
+            if factory_id not in guids:
+                continue
+            factory = self._factories[factory_id]
+            if not factory.configure_function:
+                continue
+            for guid in guids[factory_id]:
+                factory.configure_function(self, guid)
 
     def do_cross_connect(self):
         for guid, cross_connections in self._cross_connect.iteritems():
index 70a64b4..c6fa941 100644 (file)
@@ -25,23 +25,6 @@ class TestbedInstance(testbed_impl.TestbedInstance):
             get_attribute_value("homeDirectory")
         self._netns = self._load_netns_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:
-                (address, netprefix, broadcast) = address
-                # TODO: Decide if we should add a ipv4 or ipv6 address
-                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)
         # TODO: take on account schedule time for the task 
index fd0ce4f..4672c35 100644 (file)
@@ -133,6 +133,28 @@ def status_application(testbed_instance, guid):
         return STATUS_RUNNING
     return STATUS_FINISHED
 
+### Configure functions ###
+
+def configure_device(testbed_instance, guid):
+    element = testbed_instance._elements[guid]
+    if not guid in testbed_instance._add_address:
+        return
+    addresses = testbed_instance._add_address[guid]
+    for address in addresses:
+        (address, netprefix, broadcast) = address
+        # TODO: Decide if we should add a ipv4 or ipv6 address
+        element.add_v4_address(address, netprefix)
+
+def configure_node(testbed_instance, guid):
+    element = testbed_instance._elements[guid]
+    if not guid in testbed_instance._add_route:
+        return
+    routes = testbed_instance._add_route[guid]
+    for route in routes:
+        (destination, netprefix, nexthop) = route
+        element.add_route(prefix = destination, prefix_len = netprefix,
+            nexthop = nexthop)
+
 ### Factory information ###
 
 connector_types = dict({
@@ -309,7 +331,10 @@ traces = dict({
         }) 
     })
 
-factories_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+create_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+        APPLICATION ]
+
+configure_order = [ P2PIFACE, NODEIFACE, TAPIFACE, SWITCH, NODE,
         APPLICATION ]
 
 factories_info = dict({
@@ -318,6 +343,7 @@ factories_info = dict({
             "help": "Emulated Node with virtualized network stack",
             "category": "topology",
             "create_function": create_node,
+            "configure_function": configure_node,
             "box_attributes": ["forward_X11"],
             "connector_types": ["devs", "apps"]
        }),
@@ -326,6 +352,7 @@ factories_info = dict({
             "help": "Point to point network interface",
             "category": "devices",
             "create_function": create_p2piface,
+            "configure_function": configure_device,
             "box_attributes": ["lladdr", "up", "device_name", "mtu", 
                 "multicast", "broadcast", "arp"],
             "connector_types": ["node", "p2p"]
@@ -335,6 +362,7 @@ factories_info = dict({
             "help": "Tap device network interface",
             "category": "devices",
             "create_function": create_tapiface,
+            "configure_function": configure_device,
             "box_attributes": ["lladdr", "up", "device_name", "mtu", 
                 "multicast", "broadcast", "arp"],
             "connector_types": ["node", "fd"]
@@ -344,6 +372,7 @@ factories_info = dict({
             "help": "Node network interface",
             "category": "devices",
             "create_function": create_nodeiface,
+            "configure_function": configure_device,
             "box_attributes": ["lladdr", "up", "device_name", "mtu", 
                 "multicast", "broadcast", "arp"],
             "connector_types": ["node", "switch"]
@@ -386,7 +415,7 @@ testbed_attributes = dict({
                 "help": "Path to the directory where traces and other files \
                         will be stored",
                 "type": Attribute.STRING,
-                "value": False,
+                "value": "",
                 "flags": Attribute.DesignOnly,
                 "validation_function": validation.is_string
             })
@@ -410,8 +439,12 @@ class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
         return traces
 
     @property
-    def factories_order(self):
-        return factories_order
+    def create_order(self):
+        return create_order
+
+    @property
+    def configure_order(self):
+        return configure_order
 
     @property
     def factories_info(self):
index c7aebea..2a8cc0a 100644 (file)
@@ -5,6 +5,8 @@ from constants import TESTBED_ID
 from nepi.core import testbed_impl
 from nepi.core.attributes import Attribute
 import os
+import sys
+import threading
 
 class TestbedInstance(testbed_impl.TestbedInstance):
     def __init__(self, testbed_version):
@@ -12,6 +14,8 @@ class TestbedInstance(testbed_impl.TestbedInstance):
         self._ns3 = None
         self._home_directory = None
         self._traces = dict()
+        self._simulator_thread = None
+        self._condition = None
 
     @property
     def home_directory(self):
@@ -26,74 +30,18 @@ class TestbedInstance(testbed_impl.TestbedInstance):
             get_attribute_value("homeDirectory")
         self._ns3 = self._load_ns3_module()
 
-    def do_configure(self):
-        # configure addressess
-        for guid, addresses in self._add_address.iteritems():
-            element = self._elements[guid]
-            for address in addresses:
-                (address, netprefix, broadcast) = address
-                # TODO!!!
-        # configure routes
-        for guid, routes in self._add_route.iteritems():
-            element = self._elements[guid]
-            for route in routes:
-                (destination, netprefix, nexthop) = route
-                # TODO!!
-        """
-        context = self.server.modules.ns3
-        ipv4 = self._object
-        for interface in self._interface2addr:
-            ifindex = ipv4.AddInterface(interface._object)
-            for addr in self._interface2addr[interface]:
-                inaddr = context.Ipv4InterfaceAddress(
-                        context.Ipv4Address(
-                            addr.get_attribute("Address").value),
-                        context.Ipv4Mask(
-                            addr.get_attribute("NetPrefix").value))
-                ipv4.AddAddress(ifindex, inaddr)
-                ipv4.SetMetric(ifindex, 1)
-                ipv4.SetUp(ifindex)
-                self._interface_addrs[addr] = inaddr
-                self._interfaces[interface] = ifindex
-        for entry in self.get_node().routing_table.get_entries(self._af):
-            self._rt_add(entry)
-
-        def _rt_add(self, entry):
-        # Called both at install-time (by NS3Ipv4Stack.post_install) and at
-        # run-time (by RoutingTable.add_entry).
-        context = self.server.modules.ns3
-        ifindex = self._interfaces[entry.interface]
-        prefixlen = entry.prefixlen
-        # print "rt_add %s %s %s %d"% (prefix, prefixlen, entry.nexthop, ifindex)        
-        if entry.nexthop:
-            self._static_routing.AddNetworkRouteTo(
-                    context.Ipv4Address(entry.prefix.address),
-                    context.Ipv4Mask(entry.mask.address),
-                    context.Ipv4Address(entry.nexthop.address),
-                    ifindex)
-        else:
-            self._static_routing.AddNetworkRouteTo(
-                    context.Ipv4Address(entry.prefix.address),
-                    context.Ipv4Mask(entry.mask.address),
-                    ifindex)
-        """
+    def start(self):
+        super(TestbedInstance, self).start()
+        self._condition = threading.Condition()
+        self._simulator_thread = threading.Thread(target = self._simulator_run,
+                args = [self._condition])
+        self._simulator_thread.start()
 
     def set(self, time, guid, name, value):
         super(TestbedInstance, self).set(time, guid, name, value)
         # TODO: take on account schedule time for the task
-        factory_id = self._crerate[guid]
         element = self._elements[guid]
-        TypeId = self.ns3.TypeId()
-        typeid = TypeId.LookupByName(factory_id)
-        info = TypeId.AttributeInfo()
-        if not typeid.LookupAttributeByName(name, info):
-            raise RuntimeError("Attribute %s doesn't belong to element %s" \
-                   % (name, factory_id))
-        value = str(value)
-        if isinstance(value, bool):
-            value = value.lower()
-        ns3_value = info.checker.Create()
-        ns3_value.DeserializeFromString(value, checker)
+        ns3_value = self._to_ns3_value(guid, name, value) 
         element.SetAttribute(name, ns3_value)
 
     def get(self, time, guid, name):
@@ -131,7 +79,7 @@ class TestbedInstance(testbed_impl.TestbedInstance):
 
     def trace_filename(self, guid, trace_id):
         # TODO: Need to be defined inside a home!!!! with and experiment id_code
-        filename = self._trace_filenames[guid][trace_id]
+        filename = self._traces[guid][trace_id]
         return os.path.join(self.home_directory, filename)
 
     def follow_trace(self, guid, trace_id, filename):
@@ -143,6 +91,61 @@ class TestbedInstance(testbed_impl.TestbedInstance):
         for element in self._elements.values():
             element = None
 
+    def _simulator_run(self, condition):
+        # Run simulation
+        self.ns3.Simulator.Run()
+        # Signal condition on simulation end to notify waiting threads
+        condition.acquire()
+        condition.notifyAll()
+        condition.release()
+
+    def _schedule_event(self, condition, func, *args):
+        """Schedules event on running experiment"""
+        def execute_event(condition, has_event_occurred, func, *args):
+            # exec func
+            func(*args)
+            # flag event occured
+            has_event_occurred[0] = True
+            # notify condition indicating attribute was set
+            condition.acquire()
+            condition.notifyAll()
+            condition.release()
+
+        # contextId is defined as general context
+        contextId = long(0xffffffff)
+        # delay 0 means that the event is expected to execute inmediately
+        delay = self.ns3.Seconds(0)
+        # flag to indicate that the event occured
+        # because bool is an inmutable object in python, in order to create a
+        # bool flag, a list is used as wrapper
+        has_event_occurred = [False]
+        condition.acquire()
+        if not self.ns3.Simulator.IsFinished():
+            self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event,
+                 condition, has_event_occurred, func, *args)
+            while not has_event_occurred[0] and not self.ns3.Simulator.IsFinished():
+                condition.wait()
+                condition.release()
+                if not has_event_occurred[0]:
+                    raise RuntimeError('Event could not be scheduled : %s %s ' \
+                    % (repr(func), repr(args)))
+
+    def _to_ns3_value(self, guid, name, value):
+        factory_id = self._create[guid]
+        TypeId = self.ns3.TypeId()
+        typeid = TypeId.LookupByName(factory_id)
+        info = TypeId.AttributeInfo()
+        if not typeid.LookupAttributeByName(name, info):
+            raise RuntimeError("Attribute %s doesn't belong to element %s" \
+                   % (name, factory_id))
+        str_value = str(value)
+        if isinstance(value, bool):
+            str_value = str_value.lower()
+        checker = info.checker
+        ns3_value = checker.Create()
+        ns3_value.DeserializeFromString(str_value, checker)
+        return ns3_value
+
     def _load_ns3_module(self):
         import ctypes
         import imp
@@ -177,7 +180,7 @@ class TestbedInstance(testbed_impl.TestbedInstance):
         factory_id = self._create[guid]
         TypeId = self.ns3.TypeId()
         typeid = TypeId.LookupByName(factory_id)
-        for name, value in params:
+        for name, value in params.iteritems():
             info = self.ns3.TypeId.AttributeInfo()
             typeid.LookupAttributeByName(name, info)
             if info.flags & TypeId.ATTR_CONSTRUCT == TypeId.ATTR_CONSTRUCT:
index 0b9b8dc..9021e54 100644 (file)
@@ -1,8 +1,261 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-from metadata_v3_9_RC3 import create_device, create_element, create_ipv4protocol, \
-        create_node, create_wifi_standard_model, start_application, \
-        stop_application, status_application
+
+from nepi.util.constants import AF_INET, STATUS_NOT_STARTED, STATUS_RUNNING, \
+        STATUS_FINISHED, STATUS_UNDETERMINED
+
+def _get_ipv4_protocol_guid(testbed_instance, node_guid):
+    # search for the Ipv4L3Protocol asociated with the device
+    protos_guids = testbed_instance.get_connected(node_guid, "protos", "node")
+    if len(protos_guids) == 0:
+        raise RuntimeError("No protocols where found for the node %d" % node_guid)
+    ipv4_guid = None
+    for proto_guid in protos_guids:
+        proto_factory_id = testbed_instance._create[proto_guid]
+        if proto_factory_id == "ns3::Ipv4L3Protocol":
+            ipv4_guid = proto_guid
+            break
+    if not ipv4_guid:
+        raise RuntimeError("No Ipv4L3Protocol associated to node %d. \
+                can't add Ipv4 addresses" % node_guid)
+    return ipv4_guid
+
+def _get_node_guid(testbed_instance, guid):
+    # search for the node asociated with the device
+    node_guids = testbed_instance.get_connected(guid, "node", "devs")
+    if len(node_guids) == 0:
+        raise RuntimeError("Can't instantiate interface %d outside netns \
+                node" % guid)
+    node_guid = node_guids[0]
+    return node_guid
+
+def _get_dev_number(testbed_instance, guid):
+    dev_guids = testbed_instance.get_connected(guid, "devs", "node")
+    interface_number = 0
+    for guid_ in dev_guids:
+        if guid_ == guid:
+            break
+        inteface_number += 1
+    return interface_number
+
+### create traces functions ###
+
+def p2ppcap_trace(testbed_instance, guid, trace_id):
+    node_guid = _get_node_guid(testbed_instance, guid)
+    interface_number = _get_dev_number(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    filename = "trace-p2p-node-%d-dev-%d.pcap" % (node_guid, interface_number)
+    testbed_instance.follow_trace(guid, trace_id, filename)
+    filepath = testbed_instance.trace_filename(guid, trace_id)
+    helper = testbed_instance.ns3.PointToPointHelper()
+    helper.EnablePcap(filepath, element, explicitFilename = True)
+
+def _csmapcap_trace(testbed_instance, guid, trace_id, promisc):
+    node_guid = _get_node_guid(testbed_instance, guid)
+    interface_number = _get_dev_number(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    filename = "trace-csma-node-%d-dev-%d.pcap" % (node_name, interface_number)
+    testbed_instance.follow_trace(guid, trace_id, filename)
+    filepath = testbed_instance.trace_filename(guid, trace_id)
+    helper = testbed_instance.ns3.CsmaHelper()
+    helper.EnablePcap(filepath, element, promiscuous = promisc, 
+            explicitFilename = True)
+
+def csmapcap_trace(testbed_instance, guid, trace_id):
+    promisc = False
+    _csmapcap_trace(testbed_instance, guid, trace_id, promisc)
+
+def csmapcap_promisc_trace(testbed_instance, guid, trace_id):
+    promisc = True
+    _csmapcap_trace(testbed_instance, guid, trace_id, promisc)
+
+def fdpcap_trace(testbed_instance, guid, trace_id):
+    node_guid = _get_node_guid(testbed_instance, guid)
+    interface_number = _get_dev_number(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    filename = "trace-fd-node-%d-dev-%d.pcap" % (node_name, interface_number)
+    testbed_instance.follow_trace(guid, trace_id, filename)
+    filepath = testbed_instance.trace_filename(guid, trace_id)
+    helper = testbed_instance.ns3.FileDescriptorHelper()
+    helper.EnablePcap(filepath, element, explicitFilename = True)
+
+def yanswifipcap_trace(testbed_instance, guid, trace_id):
+    dev_guid = testbed_instance.get_connected(guid, "dev", "phy")[0]
+    node_guid = _get_node_guid(testbed_instance, dev_guid)
+    interface_number = _get_dev_number(testbed_instance, dev_guid)
+    element = testbed_instance._elements[dev_guid]
+    filename = "trace-yanswifi-node-%d-dev-%d.pcap" % (node_name, interface_number)
+    testbed_instance.follow_trace(guid, trace_id, filename)
+    filepath = testbed_instance.trace_filename(guid, trace_id)
+    helper = testbed_instance.ns3.YansWifiPhyHelper()
+    helper.EnablePcap(filepath, element, explicitFilename = True)
+
+trace_functions = dict({
+    "P2PPcapTrace": p2ppcap_trace,
+    "CsmaPcapTrace": csmapcap_trace,
+    "CsmaPcapPromiscTrace": csmapcap_promisc_trace,
+    "FileDescriptorPcapTrace": fdpcap_trace,
+    "YansWifiPhyPcapTrace": yanswifipcap_trace
+    })
+
+### Creation functions ###
+
+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
+})
+
+def create_element(testbed_instance, guid):
+    element_factory = testbed_instance.ns3.ObjectFactory()
+    factory_id = testbed_instance._create[guid]
+    element_factory.SetTypeId(factory_id) 
+    construct_parameters = testbed_instance._get_construct_parameters(guid)
+    for name, value in construct_parameters.iteritems():
+        ns3_value = testbed_instance._to_ns3_value(guid, name, value)
+        element_factory.Set(name, ns3_value)
+    element = element_factory.Create()
+    testbed_instance._elements[guid] = element
+    traces = testbed_instance._get_traces(guid)
+    for trace_id in traces:
+        trace_func = trace_functions[trace_id]
+        trace_func(testbed_instance, guid, trace_id)
+
+def create_node(testbed_instance, guid):
+    create_element(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    element.AggregateObject(testbed_instance.ns3.PacketSocketFactory())
+
+def create_device(testbed_instance, guid):
+    create_element(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    parameters = testbed_instance._get_parameters(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):
+    create_element(testbed_instance, guid)
+    element = testbed_instance._elements[guid]
+    parameters = testbed_instance._get_parameters(guid)
+    if "standard" in parameters:
+        standard = parameters["standard"]
+        if standard:
+            elements.ConfigureStandard(wifi_standards[standard])
+
+def create_ipv4protocol(testbed_instance, guid):
+    create_element(testbed_instance, guid)
+    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):
+    element = testbed_instance.elements[guid]
+    # BUG: without doing this explicit call it doesn't start!!!
+    # Shouldn't be enough to set the StartTime?
+    element.Start()
+
+def stop_application(testbed_instance, guid):
+    element = testbed_instance.elements[guid]
+    now = testbed_instance.ns3.Simulator.Now()
+    element.SetStopTime(now)
+
+### Status functions ###
+
+def status_application(testbed_instance, guid):
+    if guid not in testbed_instance.elements.keys():
+        raise RuntimeError("Can't get status on guid %d" % guid )
+    now = testbed_instance.ns3.Simulator.Now()
+    if now.IsZero():
+        return STATUS_NOT_STARTED
+    app = testbed_instance.elements[guid]
+    parameters = testbed_instance._get_parameters(guid)
+    if "StartTime" in parameters and parameters["StartTime"]:
+        start_value = parameters["StartTime"]
+        start_time = testbed_instance.ns3.Time(start_value)
+        if now.Compare(start_time) < 0:
+            return STATUS_NOT_RUNNING
+    if "StopTime" in parameters and parameters["StopTime"]:
+        stop_value = parameters["StopTime"]
+        stop_time = testbed_instance.ns3.Time(stop_value)
+        if now.Compare(stop_time) < 0:
+            return STATUS_RUNNING
+        else:
+            return STATUS_FINISHED
+    return STATUS_UNDETERMINED
+
+### Configure functions ###
+
+def configure_device(testbed_instance, guid):
+    element = testbed_instance._elements[guid]
+    if not guid in testbed_instance._add_address:
+        return
+    # search for the node asociated with the device
+    node_guid = _get_node_guid(testbed_instance, guid)
+    node = testbed_instance.elements[node_guid]
+    # search for the Ipv4L3Protocol asociated with the device
+    ipv4_guid = _get_ipv4_protocol_guid(testbed_instance, node_guid)
+    ipv4 = testbed_instance._elements[ipv4_guid]
+    ns3 = testbed_instance.ns3
+    # add addresses 
+    addresses = testbed_instance._add_address[guid]
+    for address in addresses:
+        (address, netprefix, broadcast) = address
+        # TODO: missing IPV6 addresses!!
+        ifindex = ipv4.AddInterface(element)
+        inaddr = ns3.Ipv4InterfaceAddress(ns3.Ipv4Address(address),
+                ns3.Ipv4Mask("/%d" % netprefix))
+        ipv4.AddAddress(ifindex, inaddr)
+        ipv4.SetMetric(ifindex, 1)
+        ipv4.SetUp(ifindex)
+
+def configure_node(testbed_instance, guid):
+    element = testbed_instance._elements[guid]
+    if not guid in testbed_instance._add_route:
+        return
+    # search for the Ipv4L3Protocol asociated with the device
+    ipv4_guid = _get_ipv4_protocol_guid(testbed_instance, guid)
+    ipv4 = testbed_instance._elements[ipv4_guid]
+    list_routing = ipv4.GetRoutingProtocol()
+    (static_routing, priority) = list_routing.GetRoutingProtocol(0)
+    ns3 = testbed_instance.ns3
+    routes = testbed_instance._add_route[guid]
+    for route in routes:
+        (destination, netprefix, nexthop) = route
+        address = ns3.Ipv4Address(destination)
+        mask = ns3.Ipv4Mask("/%d" % netprefix) 
+        if nexthop:
+            nexthop_address = ns3.Ipv4Address(nexthop)
+            ifindex = -1
+            # TODO: HACKISH way of getting the ifindex... improve this
+            nifaces = ipv4.GetNInterfaces()
+            for ifidx in range(nifaces):
+                iface = ipv4.GetInterface(ifidx)
+                naddress = iface.GetNAddresses()
+                for addridx in range(naddress):
+                    ifaddr = iface.GetAddress(addridx)
+                    ifmask = ifaddr.GetMask()
+                    ifindex = ipv4.GetInterfaceForPrefix(nexthop_address, ifmask)
+                    if ifindex == ifidx:
+                        break
+            static_routing.AddNetworkRouteTo(address, mask, nexthop_address, 
+                    ifindex) 
+        else:
+            ifindex = ipv4.GetInterfaceForPrefix(address, mask)
+            static_routing.AddNetworkRouteTo(address, mask, ifindex) 
 
 factories_info = dict({
     "ns3::Ping6": dict({
@@ -41,6 +294,7 @@ factories_info = dict({
      "ns3::Node": dict({
         "category": "Topology",
         "create_function": create_node,
+        "configure_function": configure_node,
         "help": "",
         "connector_types": ["devs", "apps", "protos", "mobility"],
         "allow_routes": True,
@@ -123,6 +377,7 @@ factories_info = dict({
      "ns3::PointToPointNetDevice": dict({
         "category": "Device",
         "create_function": create_device,
+        "configure_function": configure_device,
         "help": "",
         "connector_types": ["node", "err", "queue", "chan"],
         "allow_addresses": True,
@@ -322,6 +577,7 @@ factories_info = dict({
      "ns3::FileDescriptorNetDevice": dict({
         "category": "Device",
         "create_function": create_device,
+        "configure_function": configure_device,
         "help": "Network interface associated to a file descriptor",
         "connector_types": ["node", "fd"],
         "allow_addresses": True,
@@ -331,6 +587,7 @@ factories_info = dict({
      "ns3::CsmaNetDevice": dict({
         "category": "Device",
         "create_function": create_device,
+        "configure_function": configure_device,
         "help": "CSMA (carrier sense, multiple access) interface",
         "connector_types": ["node", "chan", "err", "queue"],
         "allow_addresses": True,
@@ -671,6 +928,7 @@ factories_info = dict({
      "ns3::BaseStationNetDevice": dict({
         "category": "Device",
         "create_function": create_device,
+        "configure_function": configure_device,
         "help": "",
         "connector_types": [],
         "allow_addresses": True,
@@ -776,7 +1034,6 @@ factories_info = dict({
         "create_function": create_element,
         "help": "",
         "connector_types": [],
-        "allow_addresses": True,
         "box_attributes": ["Address",
             "Mtu"],
     }),
@@ -790,6 +1047,7 @@ factories_info = dict({
      "ns3::WifiNetDevice": dict({
         "category": "Device",
         "create_function": create_device,
+        "configure_function": configure_device,
         "help": "",
         "connector_types": ["node", "mac", "phy", "manager"],
         "allow_addresses": True,
index 2ad786d..bb51495 100644 (file)
@@ -5,20 +5,6 @@ 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 ####
 
@@ -79,160 +65,7 @@ def connect_fd_tap(tesbed_instance, fd, tap):
     # TODO!
     pass
 
- ### create traces functions ###
-
-def get_node_guid(testbed_instance, guid):
-    node_guid = testbed_instance.get_connected(guid, "node", "devs")[0]
-    return node_guid
-
-def get_dev_number(testbed_instance, guid):
-    dev_guids = testbed_instance.get_connected(node_guid, "devs", "node")
-    interface_number = 0
-    for guid_ in dev_guids:
-        if guid_ == guid:
-            break
-        inteface_number += 1
-    return interface_number
-
-def p2ppcap_trace(testbed_instance, guid):
-    trace_id = "p2ppcap"
-    node_guid = get_node_guid(testbed_instance, guid)
-    interface_number = get_dev_number(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    filename = "trace-p2p-node-%d-dev-%d.pcap" % (node_name, interface_number)
-    testbed_instance.follow_trace(guid, trace_id, filename)
-    filepath = testbed_instance.trace_filename(self, guid, trace_id)
-    helper = testbed_instance.ns3.PointToPointHelper()
-    helper.EnablePcap(filepath, element, explicitFilename = True)
-
-def _csmapcap_trace(testbed_instance, guid, trace_id, promisc):
-    node_guid = get_node_guid(testbed_instance, guid)
-    interface_number = get_dev_number(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    filename = "trace-csma-node-%d-dev-%d.pcap" % (node_name, interface_number)
-    testbed_instance.follow_trace(guid, trace_id, filename)
-    filepath = testbed_instance.trace_filename(self, guid, trace_id)
-    helper = testbed_instance.ns3.CsmaHelper()
-    helper.EnablePcap(filepath, element, promiscuous = promisc, 
-            explicitFilename = True)
-
-def csmapcap_trace(testbed_instance, guid):
-    trace_id = "csmapcap"
-    promisc = False
-    _csmapcap_trace(testbed_instance, guid, trace_id, promisc)
-
-def csmapcap_promisc_trace(testbed_instance, guid):
-    trace_id = "csmapcap_promisc"
-    promisc = True
-    _csmapcap_trace(testbed_instance, guid, trace_id, promisc)
-
-def fdpcap_trace(testbed_instance, guid):
-    trace_id = "fdpcap"
-    node_guid = get_node_guid(testbed_instance, guid)
-    interface_number = get_dev_number(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    filename = "trace-fd-node-%d-dev-%d.pcap" % (node_name, interface_number)
-    testbed_instance.follow_trace(guid, trace_id, filename)
-    filepath = testbed_instance.trace_filename(self, guid, trace_id)
-    helper = testbed_instance.ns3.FileDescriptorHelper()
-    helper.EnablePcap(filepath, element, explicitFilename = True)
-
-def yanswifipcap_trace(testbed_instance, guid):
-    trace_id = "yanswifipcap"
-    dev_guid = testbed_instance.get_connected(guid, "dev", "phy")[0]
-    node_guid = get_node_guid(testbed_instance, dev_guid)
-    interface_number = get_dev_number(testbed_instance, dev_guid)
-    element = testbed_instance._elements[dev_guid]
-    filename = "trace-yanswifi-node-%d-dev-%d.pcap" % (node_name, interface_number)
-    testbed_instance.follow_trace(guid, trace_id, filename)
-    filepath = testbed_instance.trace_filename(self, guid, trace_id)
-    helper = testbed_instance.ns3.YansWifiPhyHelper()
-    helper.EnablePcap(filepath, element, explicitFilename = True)
-
-trace_functions = dict({
-    "p2ppcap": p2ppcap_trace,
-    "csmapcap": csmapcap_trace,
-    "csmapcap_promisc": csmapcap_promisc_trace,
-    "fdpcap": fdpcap_trace,
-    "yanswifipcap": yanswifipcap_trace
-    })
-
-### Creation functions ###
-
-def create_element(testbed_instance, guid):
-    element_factory = testbed_instance.ns3.ObjectFactory()
-    factory_id = testbed_instance._create[guid]
-    element_factory.SetTypeId(factory_id) 
-    construct_parameters = testbed_instance._get_construct_parameters(guid)
-    for name, value in construct_parameters.iteritems():
-        ns3_value = testbed_instance._to_ns3_value(factory_id, name, value)
-        element_factory.Set(name, ns3_value)
-    element = element_factory.Create()
-    testbed_instance._elements[guid] = element
-    traces = testbed_instance._get_traces(guid)
-    for trace_id in traces:
-        trace_func = trace_functions[trace_id]
-        trace_func(testbed_instance, guid)
-
-def create_node(testbed_instance, guid):
-    create_element(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    element.AggregateObject(testbed_instance.PacketSocketFactory())
-
-def create_device(testbed_instance, guid):
-    create_element(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    parameters = testbed_instance._get_parameters(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):
-    create_element(testbed_instance, guid)
-    element = testbed_instance._elements[guid]
-    parameters = testbed_instance._get_parameters(guid)
-    if "standard" in parameters:
-        standard = parameters["standard"]
-        if standard:
-            elements.ConfigureStandard(wifi_standards[standard])
-
-def create_ipv4protocol(testbed_instance, guid):
-    create_element(testbed_instance, guid)
-    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):
-    element = testbed_instance.elements[guid]
-    element.Start()
-
-def stop_application(testbed_instance, guid):
-    element = testbed_instance.elements[guid]
-    element.Stop()
-
-### Status functions ###
-
-def status_application(testbed_instance, guid):
-    if guid not in testbed_instance.elements.keys():
-        return STATUS_NOT_STARTED
-    app = testbed_instance.elements[guid]
-    parameters = testbed_instance._get_parameters(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 information ###
 
 connector_types = dict({
     "node": dict({
@@ -827,8 +660,17 @@ testbed_attributes = dict({
                 "value": False,
                 "flags": Attribute.DesignOnly,
                 "validation_function": validation.is_bool
+            }),
+          "home_directory": dict({
+                "name": "homeDirectory",
+                "help": "Path to the directory where traces and other files \
+                        will be stored",
+                "type": Attribute.STRING,
+                "value": "",
+                "flags": Attribute.DesignOnly,
+                "validation_function": validation.is_string
             })
- })
+})
 
 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
     @property
@@ -849,7 +691,11 @@ class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
         return traces
 
     @property
-    def factories_order(self):
+    def create_order(self):
+        return factories_order
+
+    @property
+    def configure_order(self):
         return factories_order
 
     @property
index bb175cb..ffbb633 100644 (file)
@@ -170,7 +170,11 @@ class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
         return traces
 
     @property
-    def factories_order(self):
+    def create_order(self):
+        return factories_order
+
+    @property
+    def configure_order(self):
         return factories_order
 
     @property
diff --git a/test/testbeds/ns3/execute.py b/test/testbeds/ns3/execute.py
new file mode 100755 (executable)
index 0000000..5e2f01f
--- /dev/null
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.util.constants import STATUS_FINISHED
+from nepi.testbeds import ns3
+import os
+import shutil
+import tempfile
+import test_util
+import time
+import unittest
+
+class Ns3ExecuteTestCase(unittest.TestCase):
+    def setUp(self):
+        self.root_dir = tempfile.mkdtemp()
+
+    def test_run_ping_if(self):
+        testbed_version = "3_9_RC3"
+        instance = ns3.TestbedInstance(testbed_version)
+        instance.configure("homeDirectory", self.root_dir)
+        instance.create(2, "ns3::Node")
+        instance.create(3, "ns3::Ipv4L3Protocol")
+        instance.create(4, "ns3::ArpL3Protocol")
+        instance.create(5, "ns3::Icmpv4L4Protocol")
+        instance.create(6, "ns3::UdpL4Protocol")
+        instance.connect(2, "protos", 3, "node")
+        instance.connect(2, "protos", 4, "node")
+        instance.connect(2, "protos", 5, "node")
+        instance.connect(2, "protos", 6, "node")
+        instance.create(7, "ns3::PointToPointNetDevice")
+        instance.create(8, "ns3::DropTailQueue")
+        instance.connect(2, "devs", 7, "node")
+        instance.connect(7, "queue", 8, "dev")
+        instance.add_trace(7, "P2PPcapTrace")
+        instance.add_address(7, "10.0.0.1", 24, None)
+
+        instance.create(9, "ns3::Node")
+        instance.create(10, "ns3::Ipv4L3Protocol")
+        instance.create(11, "ns3::ArpL3Protocol")
+        instance.create(12, "ns3::Icmpv4L4Protocol")
+        instance.create(13, "ns3::UdpL4Protocol")
+        instance.connect(9, "protos", 10, "node")
+        instance.connect(9, "protos", 11, "node")
+        instance.connect(9, "protos", 12, "node")
+        instance.connect(9, "protos", 13, "node")
+        instance.create(14, "ns3::PointToPointNetDevice")
+        instance.create(15, "ns3::DropTailQueue")
+        instance.connect(9, "devs", 14, "node")
+        instance.connect(14, "queue", 15, "dev")
+        instance.add_trace(14, "P2PPcapTrace")
+        instance.add_address(14, "10.0.0.2", 24, None)
+
+        instance.create(16, "ns3::PointToPointChannel")
+        instance.connect(7, "chan", 16, "dev2")
+        instance.connect(14, "chan", 16, "dev2")
+
+        instance.create(17, "ns3::V4Ping")
+        instance.create_set(17, "Remote", "10.0.0.2")
+        instance.create_set(17, "StartTime", "0s")
+        instance.create_set(17, "StopTime", "10s")
+        instance.create_set(17, "Verbose", True)
+        instance.connect(17, "node", 2, "apps")
+
+        instance.do_setup()
+        instance.do_create()
+        instance.do_connect()
+        instance.do_configure()
+        instance.start()
+        while instance.status(17) != STATUS_FINISHED:
+            time.sleep(0.1)
+        comp_result = """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
+
+--- 10.0.0.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+"""
+        #self.assertTrue(ping_result.startswith(comp_result))
+        instance.stop()
+        instance.shutdown()
+
+    def test_run_ping_routing(self):
+        testbed_version = "3_9_RC3"
+        instance = ns3.TestbedInstance(testbed_version)
+        instance.configure("homeDirectory", self.root_dir)
+        instance.create(2, "ns3::Node")
+        instance.create(3, "ns3::Ipv4L3Protocol")
+        instance.create(4, "ns3::ArpL3Protocol")
+        instance.create(5, "ns3::Icmpv4L4Protocol")
+        instance.create(6, "ns3::UdpL4Protocol")
+        instance.connect(2, "protos", 3, "node")
+        instance.connect(2, "protos", 4, "node")
+        instance.connect(2, "protos", 5, "node")
+        instance.connect(2, "protos", 6, "node")
+        instance.create(7, "ns3::PointToPointNetDevice")
+        instance.create(8, "ns3::DropTailQueue")
+        instance.connect(2, "devs", 7, "node")
+        instance.connect(7, "queue", 8, "dev")
+        instance.add_trace(7, "P2PPcapTrace")
+        instance.add_address(7, "10.0.0.1", 24, None)
+
+        instance.create(9, "ns3::Node")
+        instance.create(10, "ns3::Ipv4L3Protocol")
+        instance.create(11, "ns3::ArpL3Protocol")
+        instance.create(12, "ns3::Icmpv4L4Protocol")
+        instance.create(13, "ns3::UdpL4Protocol")
+        instance.connect(9, "protos", 10, "node")
+        instance.connect(9, "protos", 11, "node")
+        instance.connect(9, "protos", 12, "node")
+        instance.connect(9, "protos", 13, "node")
+        instance.create(14, "ns3::PointToPointNetDevice")
+        instance.create(15, "ns3::DropTailQueue")
+        instance.connect(9, "devs", 14, "node")
+        instance.connect(14, "queue", 15, "dev")
+        instance.add_trace(14, "P2PPcapTrace")
+        instance.add_address(14, "10.0.0.2", 24, None)
+
+        instance.create(16, "ns3::PointToPointChannel")
+        instance.connect(7, "chan", 16, "dev2")
+        instance.connect(14, "chan", 16, "dev2")
+
+        instance.create(17, "ns3::PointToPointNetDevice")
+        instance.create(18, "ns3::DropTailQueue")
+        instance.connect(9, "devs", 17, "node")
+        instance.connect(17, "queue", 18, "dev")
+        instance.add_trace(17, "P2PPcapTrace")
+        instance.add_address(17, "10.0.1.1", 24, None)
+
+        instance.create(19, "ns3::Node")
+        instance.create(20, "ns3::Ipv4L3Protocol")
+        instance.create(21, "ns3::ArpL3Protocol")
+        instance.create(22, "ns3::Icmpv4L4Protocol")
+        instance.create(23, "ns3::UdpL4Protocol")
+        instance.connect(19, "protos", 20, "node")
+        instance.connect(19, "protos", 21, "node")
+        instance.connect(19, "protos", 22, "node")
+        instance.connect(19, "protos", 23, "node")
+        instance.create(24, "ns3::PointToPointNetDevice")
+        instance.create(25, "ns3::DropTailQueue")
+        instance.connect(19, "devs", 24, "node")
+        instance.connect(24, "queue", 25, "dev")
+        instance.add_trace(24, "P2PPcapTrace")
+        instance.add_address(24, "10.0.1.2", 24, None)
+
+        instance.create(26, "ns3::PointToPointChannel")
+        instance.connect(17, "chan", 26, "dev2")
+        instance.connect(24, "chan", 26, "dev2")
+
+        instance.create(27, "ns3::V4Ping")
+        instance.create_set(27, "Remote", "10.0.1.2")
+        instance.create_set(27, "StartTime", "0s")
+        instance.create_set(27, "StopTime", "10s")
+        instance.create_set(27, "Verbose", True)
+        instance.connect(27, "node", 2, "apps")
+
+        instance.add_route(2, "10.0.1.0", 24, "10.0.0.2")
+        instance.add_route(19, "10.0.0.0", 24, "10.0.1.1")
+
+        instance.do_setup()
+        instance.do_create()
+        instance.do_connect()
+        instance.do_configure()
+        instance.start()
+        while instance.status(27) != STATUS_FINISHED:
+            time.sleep(0.1)
+        comp_result = """PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
+
+--- 10.0.0.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+"""
+        #self.assertTrue(ping_result.startswith(comp_result))
+        instance.stop()
+        instance.shutdown()
+
+    def tearDown(self):
+        #shutil.rmtree(self.root_dir)
+        pass
+
+if __name__ == '__main__':
+    unittest.main()
+