From: Alina Quereilhac Date: Fri, 18 Mar 2011 14:53:21 +0000 (+0100) Subject: adding ns3 testbed: ongoing development! tests DON'T run OK! X-Git-Tag: nepi_v2~183 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=40df7aa3807fbfe23a83e78dd054922e1cf0e97c;p=nepi.git adding ns3 testbed: ongoing development! tests DON'T run OK! --- diff --git a/src/nepi/core/attributes.py b/src/nepi/core/attributes.py index e57ba190..f82fbae6 100644 --- a/src/nepi/core/attributes.py +++ b/src/nepi/core/attributes.py @@ -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 diff --git a/src/nepi/core/testbed_impl.py b/src/nepi/core/testbed_impl.py index 54525319..0f35a1e5 100644 --- a/src/nepi/core/testbed_impl.py +++ b/src/nepi/core/testbed_impl.py @@ -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] + diff --git a/src/nepi/testbeds/netns/metadata_v01.py b/src/nepi/testbeds/netns/metadata_v01.py index 58cab378..20062458 100644 --- a/src/nepi/testbeds/netns/metadata_v01.py +++ b/src/nepi/testbeds/netns/metadata_v01.py @@ -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 index 00000000..3b3f8534 --- /dev/null +++ b/src/nepi/testbeds/ns3/__init__.py @@ -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 index 00000000..fe891bf0 --- /dev/null +++ b/src/nepi/testbeds/ns3/constants.py @@ -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 index 00000000..bb2816f1 --- /dev/null +++ b/src/nepi/testbeds/ns3/execute.py @@ -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 index 00000000..8edbe2e1 --- /dev/null +++ b/src/nepi/testbeds/ns3/metadata_v3.9.RC3.py @@ -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 + diff --git a/src/nepi/util/server.py b/src/nepi/util/server.py index 2e02c74a..e1f68c1f 100644 --- a/src/nepi/util/server.py +++ b/src/nepi/util/server.py @@ -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): diff --git a/src/nepi/util/validation.py b/src/nepi/util/validation.py index 6f8a25b1..1c899ee5 100644 --- a/src/nepi/util/validation.py +++ b/src/nepi/util/validation.py @@ -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) diff --git a/test/core/integration.py b/test/core/integration.py index 3830f03d..726b885d 100755 --- a/test/core/integration.py +++ b/test/core/integration.py @@ -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() diff --git a/test/lib/test_util.py b/test/lib/test_util.py index bdedb9bb..25fc0cc1 100644 --- a/test/lib/test_util.py +++ b/test/lib/test_util.py @@ -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(