From: Alina Quereilhac Date: Fri, 25 Mar 2011 17:15:24 +0000 (+0100) Subject: routing support added for ns3 testbed X-Git-Tag: nepi_v2~178 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=567d3b33963de9ad6e28e325618fdd81acb3aefa;p=nepi.git routing support added for ns3 testbed --- diff --git a/src/nepi/core/execute.py b/src/nepi/core/execute.py index a796bc4f..c37c6d3d 100644 --- a/src/nepi/core/execute.py +++ b/src/nepi/core/execute.py @@ -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 diff --git a/src/nepi/core/metadata.py b/src/nepi/core/metadata.py index 8180e8e8..b4fa746c 100644 --- a/src/nepi/core/metadata.py +++ b/src/nepi/core/metadata.py @@ -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) diff --git a/src/nepi/core/testbed_impl.py b/src/nepi/core/testbed_impl.py index 36e8b1ff..f6698178 100644 --- a/src/nepi/core/testbed_impl.py +++ b/src/nepi/core/testbed_impl.py @@ -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(): diff --git a/src/nepi/testbeds/netns/execute.py b/src/nepi/testbeds/netns/execute.py index 70a64b4d..c6fa941a 100644 --- a/src/nepi/testbeds/netns/execute.py +++ b/src/nepi/testbeds/netns/execute.py @@ -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 diff --git a/src/nepi/testbeds/netns/metadata_v01.py b/src/nepi/testbeds/netns/metadata_v01.py index fd0ce4ff..4672c353 100644 --- a/src/nepi/testbeds/netns/metadata_v01.py +++ b/src/nepi/testbeds/netns/metadata_v01.py @@ -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): diff --git a/src/nepi/testbeds/ns3/execute.py b/src/nepi/testbeds/ns3/execute.py index c7aebeaa..2a8cc0a8 100644 --- a/src/nepi/testbeds/ns3/execute.py +++ b/src/nepi/testbeds/ns3/execute.py @@ -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: diff --git a/src/nepi/testbeds/ns3/factories_metadata_v3_9_RC3.py b/src/nepi/testbeds/ns3/factories_metadata_v3_9_RC3.py index 0b9b8dc4..9021e549 100644 --- a/src/nepi/testbeds/ns3/factories_metadata_v3_9_RC3.py +++ b/src/nepi/testbeds/ns3/factories_metadata_v3_9_RC3.py @@ -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, diff --git a/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py b/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py index 2ad786dc..bb514954 100644 --- a/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py +++ b/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py @@ -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 diff --git a/test/lib/mock/metadata_v01.py b/test/lib/mock/metadata_v01.py index bb175cb3..ffbb6331 100644 --- a/test/lib/mock/metadata_v01.py +++ b/test/lib/mock/metadata_v01.py @@ -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 index 00000000..5e2f01f5 --- /dev/null +++ b/test/testbeds/ns3/execute.py @@ -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() +