#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from nepi.core.description import ExperimentDescription
-from nepi.testbeds import netns
+from nepi.core.design import ExperimentDescription, FactoriesProvider
exp_desc = ExperimentDescription()
testbed_version = "01"
-netns_provider = netns.TestbedFactoriesProvider(testbed_version)
+testbed_id = "netns"
+netns_provider = FactoriesProvider(testbed_id, testbed_version)
netns_desc = exp_desc.add_testbed_description(netns_provider)
node1 = netns_desc.create("Node")
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from nepi.core.decription import AF_INET
+from nepi.core.design import AF_INET
from nepi.testbeds import netns
-instance = netns.TestbedInstance(None)
+user = "alina"
+testbed_version = "01"
+config = netns.TestbedConfiguration()
+instance = netns.TestbedInstance(testbed_version, config)
-instance.create(2, "Node", [])
-instance.create(3, "Node", [])
-instance.create(4, "NodeInterface", [])
+instance.create(2, "Node")
+instance.create(3, "Node")
+instance.create(4, "NodeInterface")
instance.create_set(4, "up", True)
instance.connect(2, "devs", 4, "node")
-instance.add_adddress(4, AF_INET, "10.0.0.1", None, None)
-instance.create(5, "NodeInterface", [])
+instance.add_adddress(4, AF_INET, "10.0.0.1", 24, None)
+instance.create(5, "NodeInterface")
instance.create_set(5, "up", True)
instance.connect(3, "devs", 5, "node")
-instance.add_adddress(5, AF_INET, "10.0.0.2", None, None)
-instance.create(6, "Switch", [])
+instance.add_adddress(5, AF_INET, "10.0.0.2", 24, None)
+instance.create(6, "Switch")
instance.create_set(6, "up", True)
instance.connect(4, "switch", 6, "devs")
instance.connect(5, "switch", 6, "devs")
-instance.create(7, "Application", [])
+instance.create(7, "Application")
instance.create_set(7, "command", "ping -qc10 10.0.0.2")
+instance.create_set(7, "user", user)
instance.connect(7, "node", 2, "apps")
instance.do_create()
import time
time.sleep(5)
instance.stop()
+instance.shutdown()
+"""
+NEPI (Network Experiment Programming Interface) v 1.0.0 (22 Feb 2011)
+Licensed under #TODO: Check license
+
+Provides a uniform API to describe, deploy and control network experiments for heterogeneous experimentation platforms.
+"""
def set_attribute_value(self, name, value):
self._attributes[name].value = value
- def set_attribute_readonly(self, name, value):
- self._attributes[name].readonly = value
+ def set_attribute_readonly(self, name, readonly = True):
+ self._attributes[name].readonly = (readonly == True)
def get_attribute_value(self, name):
return self._attributes[name].value
def get_attribute_readonly(self, name):
return self._attributes[name].readonly
+ def get_attribute_visible(self, name):
+ return self._attributes[name].visible
+
def is_attribute_modified(self, name):
return self._attributes[name].modified
def add_attribute(self, name, help, type, value = None, range = None,
- allowed = None, readonly = False, validation_function = None):
+ allowed = None, readonly = False, visible = True,
+ validation_function = None):
if name in self._attributes:
raise AttributeError("Attribute %s already exists" % name)
attribute = Attribute(name, help, type, value, range, allowed, readonly,
- validation_function)
+ visible, validation_function)
self._attributes[name] = attribute
def del_attribute(self, name):
types = [STRING, BOOL, ENUM, DOUBLE, INTEGER]
def __init__(self, name, help, type, value = None, range = None,
- allowed = None, readonly = False, validation_function = None):
+ allowed = None, readonly = False, visible = True,
+ validation_function = None):
if not type in Attribute.types:
raise AttributeError("invalid type %s " % type)
self.name = name
self._help = help
self._value = value
self._validation_function = validation_function
+ # readonly attributes can be seen but not changed by users
self._readonly = (readonly == True)
+ # invisible attributes cannot be seen or changed by users
+ self._visible = (visible == True)
self._modified = False
# range: max and min possible values
self._range = range
def help(self):
return self._help
+ @property
+ def visible(self):
+ return self._visible
+
@property
def readonly(self):
return self._readonly
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+"""
+Experiment design API
+"""
+
from nepi.core.attributes import AttributesMap, Attribute
+from nepi.core.metadata import Metadata
from nepi.util import validation
+from nepi.util.constants import AF_INET, AF_INET6
from nepi.util.guid import GuidGenerator
from nepi.util.graphical_info import GraphicalInfo
from nepi.util.parser._xml import XmlExperimentParser
import sys
-AF_INET = 0
-AF_INET6 = 1
-
class ConnectorType(object):
- """A ConnectorType defines a kind of connector that can be used in an Object.
- """
- def __init__(self, connector_type_id, help, name, max = -1, min = 0):
+ def __init__(self, testbed_id, factory_id, name, help, max = -1, min = 0):
super(ConnectorType, self).__init__()
- """
- ConnectorType(name, help, display_name, max, min):
- - connector_type_id: (unique) identifier for this type.
- Typically: testbed_id + factory_id + name
- - name: descriptive name for the user
- - help: help text
- - max: amount of connections that this type support, -1 for no limit
- - min: minimum amount of connections to this type of connector
- """
if max == -1:
max = sys.maxint
elif max <= 0:
raise RuntimeError(
- 'The maximum number of connections allowed need to be more than 0')
+ "The maximum number of connections allowed need to be more than 0")
if min < 0:
raise RuntimeError(
- 'The minimum number of connections allowed needs to be at least 0')
- self._connector_type_id = connector_type_id
- self._help = help
+ "The minimum number of connections allowed needs to be at least 0")
+ # connector_type_id -- univoquely identifies a connector type
+ # across testbeds
+ self._connector_type_id = (testbed_id.lower(), factory_id.lower(),
+ name.lower())
+ # name -- display name for the connector type
self._name = name
+ # help -- help text
+ self._help = help
+ # max -- maximum amount of connections that this type support,
+ # -1 for no limit
self._max = max
+ # min -- minimum amount of connections required by this type of connector
self._min = min
- # list of connector_type_ids with which this connector_type is allowed
- # to connect
- self._allowed_connector_type_ids = list()
+ # allowed_connections -- keys in the dictionary correspond to the
+ # connector_type_id for possible connections. The value indicates if
+ # the connection is allowed accros different testbed instances
+ self._allowed_connections = dict()
@property
def connector_type_id(self):
def min(self):
return self._min
- def add_allowed_connector_type_id(self, connector_type_id):
- self._allowed_connector_type_ids.append(connector_type_id)
+ def add_allowed_connection(self, testbed_id, factory_id, name, can_cross):
+ self._allowed_connections[(testbed_id.lower(),
+ factory_id.lower(), name.lower())] = can_cross
- def can_connect(self, connector_type_id):
- return connector_type_id in self._allowed_connector_type_ids
+ def can_connect(self, connector_type_id, testbed_guid1, testbed_guid2):
+ if not connector_type_id in self._allowed_connections.keys():
+ return False
+ can_cross = self._allowed_connections[connector_type_id]
+ return can_cross or (testbed_guid1 == testbed_guid2)
class Connector(object):
"""A Connector sepcifies the connection points in an Object"""
super(Connector, self).__init__()
self._box = box
self._connector_type = connector_type
- self._connections = dict()
+ self._connections = list()
@property
def box(self):
@property
def connections(self):
- return self._connections.values()
+ return self._connections
def is_full(self):
- """Return True if the connector has the maximum number of connections"""
+ """Return True if the connector has the maximum number of connections
+ """
return len(self.connections) == self.connector_type.max
def is_complete(self):
- """Return True if the connector has the minimum number of connections"""
+ """Return True if the connector has the minimum number of connections
+ """
return len(self.connections) >= self.connector_type.min
def is_connected(self, connector):
- return connector._key in self._connections
+ return connector in self._connections
def connect(self, connector):
- if self.is_full() or connector.is_full():
- raise RuntimeError("Connector is full")
if not self.can_connect(connector) or not connector.can_connect(self):
raise RuntimeError("Could not connect.")
- self._connections[connector._key] = connector
- connector._connections[self._key] = self
+ self._connections.append(connector)
+ connector._connections.append(self)
def disconnect(self, connector):
- if connector._key not in self._connections or\
- self._key not in connector._connections:
+ if connector not in self._connections or\
+ self not in connector._connections:
raise RuntimeError("Could not disconnect.")
- del self._connections[connector._key]
- del connector._connections[self._key]
+ self._connections.remove(connector)
+ connector._connections.remove(self)
def can_connect(self, connector):
+ if self.is_full() or connector.is_full():
+ return False
+ if self.is_connected(connector):
+ return False
connector_type_id = connector.connector_type.connector_type_id
- return self.connector_type.can_connect(connector_type_id)
+ testbed_guid1 = self.box.testbed_guid
+ testbed_guid2 = connector.box.testbed_guid
+ return self.connector_type.can_connect(connector_type_id,
+ testbed_guid1, testbed_guid2)
def destroy(self):
for connector in self.connections:
self.disconnect(connector)
self._box = self._connectors = None
- @property
- def _key(self):
- return "%d_%s" % (self.box.guid,
- self.connector_type.connector_type_id)
-
class Trace(AttributesMap):
- def __init__(self, name, help, enabled = False):
+ def __init__(self, trace_id, help, enabled = False):
super(Trace, self).__init__()
- self._name = name
+ self._trace_id = trace_id
self._help = help
self.enabled = enabled
@property
- def name(self):
- return self._name
+ def trace_id(self):
+ return self._trace_id
@property
def help(self):
help = "Network prefix for the address",
type = Attribute.INTEGER,
range = prefix_range,
+ value = 24 if family == AF_INET else 64,
validation_function = validation.is_integer)
if family == AF_INET:
self.add_attribute(name = "Broadcast",
validation_function = address_validation)
class Box(AttributesMap):
- def __init__(self, guid, factory, container = None):
+ def __init__(self, guid, factory, testbed_guid, container = None):
super(Box, self).__init__()
- # general unique id
+ # guid -- global unique identifier
self._guid = guid
- # factory identifier or name
+ # factory_id -- factory identifier or name
self._factory_id = factory.factory_id
- # boxes can be nested inside other 'container' boxes
+ # testbed_guid -- parent testbed guid
+ self._testbed_guid = testbed_guid
+ # container -- boxes can be nested inside other 'container' boxes
self._container = container
- # traces for the box
+ # traces -- list of available traces for the box
self._traces = dict()
- # connectors for the box
+ # connectors -- list of available connectors for the box
self._connectors = dict()
- # factory attributes for box construction
+ # factory_attributes -- factory attributes for box construction
self._factory_attributes = list()
-
+ # graphical_info -- GUI position information
self.graphical_info = GraphicalInfo(str(self._guid))
for connector_type in factory.connector_types:
connector = Connector(self, connector_type)
self._connectors[connector_type.name] = connector
for trace in factory.traces:
- tr = Trace(trace.name, trace.help, trace.enabled)
- self._traces[trace.name] = tr
+ tr = Trace(trace.trace_id, trace.help, trace.enabled)
+ self._traces[trace.trace_id] = tr
for attr in factory.box_attributes:
self.add_attribute(attr.name, attr.help, attr.type, attr.value,
- attr.range, attr.allowed, attr.readonly,
+ attr.range, attr.allowed, attr.readonly, attr.visible,
attr.validation_function)
for attr in factory.attributes:
self._factory_attributes.append(attr)
def factory_id(self):
return self._factory_id
+ @property
+ def testbed_guid(self):
+ return self._testbed_guid
+
@property
def container(self):
return self._container
def connector(self, name):
return self._connectors[name]
- def trace(self, name):
- return self._traces[name]
+ def trace(self, trace_id):
+ return self._traces[trace_id]
def destroy(self):
super(Box, self).destroy()
self._connectors = self._traces = self._factory_attributes = None
class AddressableBox(Box):
- def __init__(self, guid, factory, family, max_addresses = 1, container = None):
- super(AddressableBox, self).__init__(guid, factory, container)
- self._family = family
+ def __init__(self, guid, factory, testbed_guid, container = None):
+ super(AddressableBox, self).__init__(guid, factory, testbed_guid,
+ container)
+ self._family = factory.get_attribute_value("Family")
# maximum number of addresses this box can have
- self._max_addresses = max_addresses
+ self._max_addresses = factory.get_attribute_value("MaxAddresses")
self._addresses = list()
@property
self.delete_route(route)
self._route = None
-class BoxFactory(AttributesMap):
- def __init__(self, factory_id, display_name, help = None, category = None):
- super(BoxFactory, self).__init__()
+class Factory(AttributesMap):
+ def __init__(self, factory_id, allow_addresses = False,
+ allow_routes = False, Help = None, category = None):
+ super(Factory, self).__init__()
self._factory_id = factory_id
+ self._allow_addresses = (allow_addresses == True)
+ self._allow_routes = (allow_routes == True)
self._help = help
self._category = category
- self._display_name = display_name
- self._connector_types = set()
+ self._connector_types = list()
self._traces = list()
self._box_attributes = list()
def factory_id(self):
return self._factory_id
+ @property
+ def allow_addresses(self):
+ return self._allow_addresses
+
+ @property
+ def allow_routes(self):
+ return self._allow_routes
+
@property
def help(self):
return self._help
def category(self):
return self._category
- @property
- def display_name(self):
- return self._display_name
-
@property
def connector_types(self):
return self._connector_types
def box_attributes(self):
return self._box_attributes
- def add_connector_type(self, connector_type_id, help, name, max = -1,
- min = 0, allowed_connector_type_ids = []):
- connector_type = ConnectorType(connector_type_id, help, name, max, min)
- for connector_type_id in allowed_connector_type_ids:
- connector_type.add_allowed_connector_type_id(connector_type_id)
- self._connector_types.add(connector_type)
+ def add_connector_type(self, connector_type):
+ self._connector_types.append(connector_type)
- def add_trace(self, name, help, enabled = False):
- trace = Trace(name, help, enabled)
+ def add_trace(self, trace_id, help, enabled = False):
+ trace = Trace(trace_id, help, enabled)
self._traces.append(trace)
def add_box_attribute(self, name, help, type, value = None, range = None,
- allowed = None, readonly = False, validation_function = None):
+ allowed = None, readonly = False, visible = True,
+ validation_function = None):
attribute = Attribute(name, help, type, value, range, allowed, readonly,
- validation_function)
+ visible, validation_function)
self._box_attributes.append(attribute)
def create(self, guid, testbed_description):
- return Box(guid, self)
+ if self._allow_addresses:
+ return AddressableBox(guid, self, testbed_description.guid)
+ elif self._allow_routes:
+ return RoutingTableBox(guid, self, testbed_description.guid)
+ else:
+ return Box(guid, self, testbed_description.guid)
def destroy(self):
- super(BoxFactory, self).destroy()
+ super(Factory, self).destroy()
self._connector_types = None
-class AddressableBoxFactory(BoxFactory):
- def __init__(self, factory_id, display_name, family, max_addresses = 1,
- help = None, category = None):
- super(AddressableBoxFactory, self).__init__(factory_id,
- display_name, help, category)
- self._family = family
- self._max_addresses = 1
-
- def create(self, guid, testbed_description):
- return AddressableBox(guid, self, self._family,
- self._max_addresses)
-
-class RoutingTableBoxFactory(BoxFactory):
- def create(self, guid, testbed_description):
- return RoutingTableBox(guid, self)
-
-class TestbedFactoriesProvider(object):
+class FactoriesProvider(object):
def __init__(self, testbed_id, testbed_version):
- super(TestbedFactoriesProvider, self).__init__()
+ super(FactoriesProvider, self).__init__()
self._testbed_id = testbed_id
self._testbed_version = testbed_version
self._factories = dict()
+ metadata = Metadata(testbed_id, testbed_version)
+ for factory in metadata.build_design_factories():
+ self.add_factory(factory)
+
@property
def testbed_id(self):
return self._testbed_id
for testbed_description in self.testbed_descriptions:
testbed_description.destroy()
+# TODO: When the experiment xml is passed to the controller to execute it
+# NetReferences in the xml need to be solved
+#
+#targets = re.findall(r"%target:(.*?)%", command)
+#for target in targets:
+# try:
+# (family, address, port) = resolve_netref(target, AF_INET,
+# self.server.experiment )
+# command = command.replace("%%target:%s%%" % target, address.address)
+# except:
+# continue
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from nepi.core.attributes import AttributesMap
+import sys
+
+class ConnectorType(object):
+ def __init__(self, testbed_id, factory_id, name, max = -1, min = 0):
+ super(ConnectorType, self).__init__()
+ if max == -1:
+ max = sys.maxint
+ elif max <= 0:
+ raise RuntimeError(
+ "The maximum number of connections allowed need to be more than 0")
+ if min < 0:
+ raise RuntimeError(
+ "The minimum number of connections allowed needs to be at least 0")
+ # connector_type_id -- univoquely identifies a connector type
+ # across testbeds
+ self._connector_type_id = (testbed_id.lower(), factory_id.lower(),
+ name.lower())
+ # name -- display name for the connector type
+ self._name = name
+ # max -- maximum amount of connections that this type support,
+ # -1 for no limit
+ self._max = max
+ # min -- minimum amount of connections required by this type of connector
+ self._min = min
+ # from_connections -- connections where the other connector is the "From"
+ # to_connections -- connections where the other connector is the "To"
+ # keys in the dictionary correspond to the
+ # connector_type_id for possible connections. The value is a tuple:
+ # (can_cross, connect)
+ # can_cross: indicates if the connection is allowed accros different
+ # testbed instances
+ # code: is the connection function to be invoked when the elements
+ # are connected
+ self._from_connections = dict()
+ self._to_connections = dict()
+
+ @property
+ def connector_type_id(self):
+ return self._connector_type_id
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def max(self):
+ return self._max
+
+ @property
+ def min(self):
+ return self._min
+
+ def add_from_connection(self, testbed_id, factory_id, name, can_cross, code):
+ self._from_connections[(testbed_id.lower(), factory_id.lower(),
+ name.lower())] = (can_cross, code)
+
+ def add_to_connection(self, testbed_id, factory_id, name, can_cross, code):
+ self._to_connections[(testbed_id.lower(), factory_id.lower(),
+ name.lower())] = (can_cross, code)
+
+ def can_connect(self, testbed_id, factory_id, name, count,
+ must_cross = False):
+ connector_type_id = (testbed_id.lower(), factory_id.lower(),
+ name.lower())
+ if connector_type_id in self._from_connections:
+ (can_cross, code) = self._from_connections[connector_type_id]
+ elif connector_type_id in self._to_connections:
+ (can_cross, code) = self._to_connections[connector_type_id]
+ else:
+ return False
+ return not must_cross or can_cross
+
+ def code_to_connect(self, testbed_id, factory_id, name):
+ connector_type_id = (testbed_id.lower(), factory_id.lower(),
+ name.lower())
+ if not connector_type_id in self._to_connections.keys():
+ return False
+ (can_cross, code) = self._to_connections[connector_type_id]
+ return code
+
+# TODO: create_function, start_function, stop_function, status_function
+# 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):
+ super(Factory, self).__init__()
+ self._factory_id = factory_id
+ self._allow_addresses = (allow_addresses == True)
+ self._allow_routes = (allow_routes == True)
+ self._create_function = create_function
+ self._start_function = start_function
+ self._stop_function = stop_function
+ self._status_function = status_function
+ self._connector_types = dict()
+ self._traces = list()
+
+ @property
+ def factory_id(self):
+ return self._factory_id
+
+ @property
+ def allow_addresses(self):
+ return self._allow_addresses
+
+ @property
+ def allow_routes(self):
+ return self._allow_routes
+
+ @property
+ def create_function(self):
+ return self._create_function
+
+ @property
+ def start_function(self):
+ return self._start_function
+
+ @property
+ def stop_function(self):
+ return self._stop_function
+
+ @property
+ def status_function(self):
+ return self._status_function
+
+ @property
+ def traces(self):
+ return self._traces
+
+ def connector_type(self, name):
+ return self._connector_types[name]
+
+ def add_connector_type(self, connector_type):
+ self._connector_types[connector_type.name] = connector_type
+
+ def add_trace(self, trace_id):
+ self._traces.append(trace_id)
+
+class TestbedConfiguration(AttributesMap):
+ pass
+
+class TestbedInstance(object):
+ def __init__(self, testbed_version, configuration):
+ pass
+
+ def create(self, guid, factory_id):
+ """Instructs creation of element """
+ raise NotImplementedError
+
+ def create_set(self, guid, name, value):
+ """Instructs setting an attribute on an element"""
+ raise NotImplementedError
+
+ def do_create(self):
+ """After do_create all instructed elements are created and
+ attributes setted"""
+ raise NotImplementedError
+
+ def connect(self, guid1, connector_type_name1, guid2,
+ connector_type_name2):
+ raise NotImplementedError
+
+ def cross_connect(self, guid, connector_type_name, cross_guid,
+ cross_testbed_id, cross_factory_id, cross_connector_type_name):
+ raise NotImplementedError
+
+ def do_connect(self):
+ raise NotImplementedError
+
+ def add_trace(self, guid, trace_id):
+ raise NotImplementedError
+
+ def add_adddress(self, guid, family, address, netprefix, broadcast):
+ raise NotImplementedError
+
+ def add_route(self, guid, family, destination, netprefix, nexthop,
+ interface):
+ raise NotImplementedError
+
+ def do_configure(self):
+ raise NotImplementedError
+
+ def do_cross_connect(self):
+ raise NotImplementedError
+
+ def set(self, time, guid, name, value):
+ raise NotImplementedError
+
+ def get(self, time, guid, name):
+ raise NotImplementedError
+
+ def start(self, time):
+ raise NotImplementedError
+
+ def action(self, time, guid, action):
+ raise NotImplementedError
+
+ def stop(self, time):
+ raise NotImplementedError
+
+ def status(self, guid):
+ raise NotImplementedError
+
+ def trace(self, guid, trace_id):
+ raise NotImplementedError
+
+ def shutdown(self):
+ raise NotImplementedError
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+
+class VersionedMetadataInfo(object):
+ @property
+ def connections_types(self):
+ """ dictionary of dictionaries with allowed connection information.
+ connector_id: dict({
+ "help": help text,
+ "name": connector type name,
+ "max": maximum number of connections allowed (-1 for no limit),
+ "min": minimum number of connections allowed
+ }),
+ """
+ raise NotImplementedError
+
+ @property
+ def connections(self):
+ """ array of dictionaries with allowed connection information.
+ dict({
+ "from": (testbed_id1, factory_id1, connector_type_name1),
+ "to": (testbed_id2, factory_id2, connector_type_name2),
+ "code": connection function to invoke upon connection creation
+ "can_cross": whether the connection can be done across testbed
+ instances
+ }),
+ """
+ raise NotImplementedError
+
+ @property
+ def attributes(self):
+ """ dictionary of dictionaries of all available attributes.
+ "attribute_id": dict({
+ "name": attribute name,
+ "help": help text,
+ "type": attribute type,
+ "value": default attribute value,
+ "range": (maximum, minimun) values else None if not defined,
+ "allowed": array of posible values,
+ "readonly": whether the attribute is read only for the user,
+ "visible": whether the attribute is visible for the user,
+ "validation_function": validation function for the attribute
+ })
+ """
+ raise NotImplementedError
+
+ @property
+ def traces(self):
+ """ dictionary of dictionaries of all available traces.
+ trace_id: dict({
+ "name": trace name,
+ "help": help text
+ })
+ """
+ raise NotImplementedError
+
+ @property
+ def factories_order(self):
+ """ list of factory ids that indicates the order in which the elements
+ should be instantiated.
+ """
+ raise NotImplementedError
+
+ @property
+ def factories_info(self):
+ """ dictionary of dictionaries of factory specific information
+ factory_id: dict({
+ "allow_addresses": whether the box allows adding IP addresses,
+ "allow_routes": wether the box allows adding routes,
+ "help": help text,
+ "category": category the element belongs to,
+ "create_function": function for element instantiation,
+ "start_function": function for element starting,
+ "stop_function": function for element stoping,
+ "status_function": function for retrieving element status,
+ "factory_attributes": list of references to attribute_ids,
+ "box_attributes": list of regerences to attribute_ids,
+ "traces": list of references to trace_id
+ "connector_types": list of references to connector_types
+ })
+ """
+ raise NotImplementedError
+
+class Metadata(object):
+ def __init__(self, testbed_id, version):
+ self._version = version
+ self._testbed_id = testbed_id
+ self._metadata = self._load_versioned_metadata_info()
+
+ @property
+ def factories_order(self):
+ return self._metadata.factories_order
+
+ def build_design_factories(self):
+ from nepi.core.design import Factory
+ factories = list()
+ for factory_id, info in self._metadata.factories_info.iteritems():
+ help = info["help"]
+ category = info["category"]
+ 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, allow_addresses, allow_routes,
+ help, category)
+ self._add_attributes(factory, info, "factory_attributes")
+ self._add_attributes(factory, info, "box_attributes", True)
+ self._add_design_traces(factory, info)
+ self._add_design_connector_types(factory, info)
+ factories.append(factory)
+ return factories
+
+ def build_execute_factories(self):
+ from nepi.core.execute import Factory
+ factories = list()
+ for factory_id, info in self._metadata.factories_info.iteritems():
+ create_function = info["create_function"]
+ start_function = info["start_function"]
+ stop_function = info["stop_function"]
+ status_function = info["status_function"]
+ 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)
+ self._add_attributes(factory, info, "factory_attributes")
+ self._add_attributes(factory, info, "box_attributes")
+ self._add_execute_traces(factory, info)
+ self._add_execute_connector_types(factory, info)
+ factories.append(factory)
+ return factories
+
+ def _load_versioned_metadata_info(self):
+ mod_name = "nepi.testbeds.%s.metadata_v%s" % (self._testbed_id.lower(),
+ self._version)
+ if not mod_name in sys.modules:
+ __import__(mod_name)
+ return sys.modules[mod_name]
+
+ def _add_attributes(self, factory, info, attributes_key,
+ box_attributes = False):
+ if attributes_key in info:
+ for attribute_id in info[attributes_key]:
+ attribute_info = self._metadata.attributes[attribute_id]
+ name = attribute_info["name"]
+ help = attribute_info["help"]
+ type = attribute_info["type"]
+ value = attribute_info["value"]
+ range = attribute_info["range"]
+ allowed = attribute_info["allowed"]
+ readonly = attribute_info["readonly"]
+ visible = attribute_info["visible"]
+ validation_function = attribute_info["validation_function"]
+ if box_attributes:
+ factory.add_box_attribute(name, help, type, value, range,
+ allowed, readonly, visible, validation_function)
+ else:
+ factory.add_attribute(name, help, type, value, range,
+ allowed, readonly, visible, validation_function)
+
+ def _add_design_traces(self, factory, info):
+ if "traces" in info:
+ for trace in info["traces"]:
+ trace_info = self._metadata.traces[trace]
+ trace_id = trace_info["name"]
+ help = trace_info["help"]
+ factory.add_trace(trace_id, help)
+
+ def _add_execute_traces(self, factory, info):
+ if "traces" in info:
+ for trace in info["traces"]:
+ trace_info = self._metadata.traces[trace]
+ trace_id = trace_info["name"]
+ factory.add_trace(trace_id)
+
+ def _add_design_connector_types(self, factory, info):
+ from nepi.core.design import ConnectorType
+ if "connector_types" in info:
+ connections = dict()
+ for connection in self._metadata.connections:
+ from_ = connection["from"]
+ to = connection["to"]
+ can_cross = connection["can_cross"]
+ if from_ not in connections:
+ connections[from_] = list()
+ if to not in connections:
+ connections[to] = list()
+ connections[from_].append((to, can_cross))
+ connections[to].append((from_, can_cross))
+ for connector_id in info["connector_types"]:
+ connector_type_info = self._metadata.connector_types[
+ connector_id]
+ name = connector_type_info["name"]
+ help = connector_type_info["help"]
+ max = connector_type_info["max"]
+ min = connector_type_info["min"]
+ testbed_id = self._testbed_id
+ factory_id = factory.factory_id
+ connector_type = ConnectorType(testbed_id, factory_id, name,
+ help, max, min)
+ for (to, can_cross) in connections[(testbed_id, factory_id,
+ name)]:
+ (testbed_id_to, factory_id_to, name_to) = to
+ connector_type.add_allowed_connection(testbed_id_to,
+ factory_id_to, name_to, can_cross)
+ factory.add_connector_type(connector_type)
+
+ def _add_execute_connector_types(self, factory, info):
+ from nepi.core.execute import ConnectorType
+ if "connector_types" in info:
+ from_connections = dict()
+ to_connections = dict()
+ for connection in self._metadata.connections:
+ from_ = connection["from"]
+ to = connection["to"]
+ can_cross = connection["can_cross"]
+ code = connection["code"]
+ if from_ not in from_connections:
+ from_connections[from_] = list()
+ if to not in to_connections:
+ to_connections[to] = list()
+ from_connections[from_].append((to, can_cross, code))
+ to_connections[to].append((from_, can_cross, code))
+ for connector_id in info["connector_types"]:
+ connector_type_info = self._metadata.connector_types[
+ connector_id]
+ name = connector_type_info["name"]
+ max = connector_type_info["max"]
+ min = connector_type_info["min"]
+ testbed_id = self._testbed_id
+ factory_id = factory.factory_id
+ connector_type = ConnectorType(testbed_id, factory_id, name,
+ max, min)
+ connector_key = (testbed_id, factory_id, name)
+ if connector_key in to_connections:
+ for (from_, can_cross, code) in to_connections[connector_key]:
+ (testbed_id_from, factory_id_from, name_from) = from_
+ connector_type.add_from_connection(testbed_id_from,
+ factory_id_from, name_from, can_cross, code)
+ if connector_key in from_connections:
+ for (to, can_cross, code) in from_connections[(testbed_id,
+ factory_id, name)]:
+ (testbed_id_to, factory_id_to, name_to) = to
+ connector_type.add_to_connection(testbed_id_to,
+ factory_id_to, name_to, can_cross, code)
+ factory.add_connector_type(connector_type)
+
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# PROTOCOL MESSAGES
-CREATE = 0
-CONNECT = 1
-SET = 2
-GET = 3
-START = 4
-STOP = 5
-STATUS = 6
-ENABLE_TRACE = 7
-DISABLE_TRACE = 8
-GET_TRACE = 9
-ADD_ADDRES = 10
-ADD_ROUTE = 11
-SHUTDOWN = 12
-
-tesbed_messages = {
- CREATE: "CREATE,%d,%d,%s,[%s]", # CREATE,time,guid,factory_id,parameters
- CONNECT: "CONNECT,%d,%d,%d,%d,%s,%s", # CONNECT,time,object1_guid,object2_guid,connector1_id,connector2_id
- SET: "%d,%d,%s,%s", # SET,time,guid,name,value
- GET: "%d,%d,%s", # GET,time,guid,name
- START: "%d,%d", # START,time,guid
- STOP: "%d,%d", # STOP,time,guid
- STATUS: "%d,%d", # STATUS,time,guid
- ENABLE_TRACE: "%d,%d,%s", # ENABLE_TRACE,time,guid,trace_id
- DISABLE_TRACE: "%d,%d,%s", # DISABLE_TRACE,time,guid,trace_id
- GET_TRACE: "%d,%d,%s", # GET_TRACE,time,guid,trace_id
- ADD_ADDRESSES: "%d,%d", # ADD_ADDRESSES,time,guid
- ADD_ROUTE: "%d,%d", # ADD_ROUTE,time,guid
- SHUTDOWN: "%d,%d" , # SHUTDOWN,time.guid
- }
-
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-from nepi.core.attributes import AttributesMap
-
-class TestbedConfiguration(AttributesMap):
- pass
-
-class TestbedInstance(object):
- def __init__(self, configuration):
- pass
-
- def create(self, guid, factory_id):
- """Instructs creation of element """
- raise NotImplementedError
-
- def create_set(self, guid, name, value):
- """Instructs setting an attribute on an element"""
- raise NotImplementedError
-
- def do_create(self):
- """After do_create all instructed elements are created and
- attributes setted"""
- raise NotImplementedError
-
- def connect(self, guid1, connector_type_name1, guid2,
- connector_type_name2):
- raise NotImplementedError
-
- def do_connect(self):
- raise NotImplementedError
-
- def add_trace(self, guid, trace_id):
- raise NotImplementedError
-
- def add_adddress(self, guid, family, address, netprefix, broadcast):
- raise NotImplementedError
-
- def add_route(self, guid, family, destination, netprefix, nexthop,
- interface):
- raise NotImplementedError
-
- def do_configure(self):
- raise NotImplementedError
-
- def do_cross_connect(self):
- raise NotImplementedError
-
- def set(self, time, guid, name, value):
- raise NotImplementedError
-
- def get(self, time, guid, name):
- raise NotImplementedError
-
- def start(self, time):
- raise NotImplementedError
-
- def action(self, time, guid, action):
- raise NotImplementedError
-
- def stop(self, time):
- raise NotImplementedError
-
- def status(self, guid):
- raise NotImplementedError
-
- def trace(self, guid, trace_id):
- raise NotImplementedError
-
- def shutdown(self):
- raise NotImplementedError
-
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from description import TestbedFactoriesProvider
-from testbed import TestbedInstance
+from constants import TESTBED_ID
+from execute import TestbedConfiguration, TestbedInstance
+
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+TESTBED_ID = "netns"
+
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from nepi.core import description
-import sys
-
-TESTBED_ID = "netns"
-
-def add_connector_types(factory, connector_types_metadata):
- for (connector_type_id, help, name, max, min,
- allowed_connector_type_ids) in connector_types_metadata:
- factory.add_connector_type(connector_type_id, help, name, max,
- min, allowed_connector_type_ids)
-
-def add_traces(factory, traces_metadata):
- for (name, help) in traces_metadata:
- factory.add_trace(name, help)
-
-def add_attributes(factory, attributes_metadata):
- for (name, help, type, value, range, allowed, readonly,
- validation_function) in attributes_metadata:
- factory.add_attribute(name, help, type, value, range, allowed,
- readonly, validation_function)
-
-def add_box_attributes(factory, box_attributes_metadata):
- for (name, help, type, value, range, allowed, readonly,
- validation_function) in box_attributes_metadata:
- factory.add_box_attribute(name, help, type, value, range,
- allowed, readonly, validation_function)
-
-def create_factory_from_metadata(factory_id, info):
- help = info["help"]
- category = info["category"]
- display_name = info["display_name"]
- factory_type = info["factory_type"] if "factory_type" in info else None
- if factory_type == "addressable":
- family = info["family"]
- max_addresses = info["max_addresses"]
- factory = description.AddressableBoxFactory(factory_id,
- display_name, family, max_addresses, help, category)
- elif factory_type == "routing":
- factory = description.RoutingTableBoxFactory(factory_id,
- display_name, help, category)
- else:
- factory = description.BoxFactory(factory_id, display_name, help, category)
- if "connector_types" in info:
- add_connector_types(factory, info["connector_types"])
- if "traces" in info:
- add_traces(factory, info["traces"])
- if "attributes" in info:
- add_attributes(factory, info["attributes"])
- if "box_attributes" in info:
- add_box_attributes(factory, info["box_attributes"])
- return factory
-
-def create_factories(version):
- factories = list()
- mod_name = "nepi.testbeds.netns.metadata_v%s" % (version)
- if not mod_name in sys.modules:
- __import__(mod_name)
- metadata = sys.modules[mod_name].get_metadata()
- for factory_id, info in metadata.iteritems():
- factory = create_factory_from_metadata(factory_id, info)
- factories.append(factory)
- return factories
-
-class TestbedFactoriesProvider(description.TestbedFactoriesProvider):
- def __init__(self, testbed_version):
- super(TestbedFactoriesProvider, self).__init__(TESTBED_ID,
- testbed_version)
- for factory in create_factories(testbed_version):
- self.add_factory(factory)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from constants import TESTBED_ID
+from nepi.core import execute
+from nepi.core.attributes import Attribute
+from nepi.core.metadata import Metadata
+from nepi.util import validation
+from nepi.util.constants import AF_INET, AF_INET6
+
+class TestbedConfiguration(execute.TestbedConfiguration):
+ def __init__(self):
+ super(TestbedConfiguration, self).__init__()
+ self.add_attribute("EnableDebug", "Enable netns debug output",
+ Attribute.BOOL, False, None, None, False, validation.is_bool)
+
+class TestbedInstance(execute.TestbedInstance):
+ def __init__(self, testbed_version, configuration):
+ self._configuration = configuration
+ self._testbed_id = TESTBED_ID
+ self._testbed_version = testbed_version
+ self._factories = dict()
+ self._elements = dict()
+ self._create = dict()
+ self._set = dict()
+ self._connect = dict()
+ self._cross_connect = dict()
+ self._add_trace = dict()
+ self._add_address = dict()
+ self._add_route = dict()
+
+ self._metadata = Metadata(self._testbed_id, self._testbed_version)
+ for factory in self._metadata.build_execute_factories():
+ self._factories[factory.factory_id] = factory
+
+ self._netns = self._load_netns_module(configuration)
+
+ @property
+ def elements(self):
+ return self._elements
+
+ @property
+ def netns(self):
+ return self._netns
+
+ def create(self, guid, factory_id):
+ if factory_id not in self._factories:
+ raise RuntimeError("Invalid element type %s for Netns version %s" %
+ (factory_id, self._testbed_version))
+ if guid in self._create:
+ raise RuntimeError("Cannot add elements with the same guid: %d" %
+ guid)
+ self._create[guid] = factory_id
+
+ def create_set(self, guid, name, value):
+ 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]
+ if not factory.has_attribute(name):
+ raise RuntimeError("Invalid attribute %s for element type %s" %
+ (name, factory_id))
+ factory.set_attribute_value(name, value)
+ if guid not in self._set:
+ self._set[guid] = dict()
+ self._set[guid][name] = value
+
+ def connect(self, guid1, connector_type_name1, guid2,
+ connector_type_name2):
+ factory_id1 = self._create[guid1]
+ factory_id2 = self._create[guid2]
+ count = self._get_connection_count(guid1, connector_type_name1)
+ factory1 = self._factories[factory_id1]
+ connector_type = factory1.connector_type(connector_type_name1)
+ connector_type.can_connect(self._testbed_id, factory_id2,
+ connector_type_name2, count)
+ if not guid1 in self._connect:
+ self._connect[guid1] = dict()
+ if not connector_type_name1 in self._connect[guid1]:
+ self._connect[guid1][connector_type_name1] = dict()
+ self._connect[guid1][connector_type_name1][guid2] = \
+ connector_type_name2
+ if not guid2 in self._connect:
+ self._connect[guid2] = dict()
+ if not connector_type_name2 in self._connect[guid2]:
+ self._connect[guid2][connector_type_name2] = dict()
+ self._connect[guid2][connector_type_name2][guid1] = \
+ connector_type_name1
+
+ def cross_connect(self, guid, connector_type_name, cross_guid,
+ cross_testbed_id, cross_factory_id, cross_connector_type_name):
+ factory_id = self._create[guid]
+ count = self._get_connection_count(guid, connector_type_name)
+ factory = self._factories[factory_id]
+ connector_type = factory.connector_type(connector_type_name)
+ connector_type.can_connect(cross_testbed_id, cross_factory_id,
+ cross_connector_type_name, count, must_cross = True)
+ if not guid in self._connect:
+ self._cross_connect[guid] = dict()
+ if not connector_type_name in self._cross_connect[guid]:
+ self._cross_connect[guid][connector_type_name] = dict()
+ self._cross_connect[guid][connector_type_name] = \
+ (cross_guid, cross_testbed_id, cross_factory_id,
+ cross_connector_type_name)
+
+ def add_trace(self, guid, trace_id):
+ 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]
+ if not trace_id in factory_traces:
+ raise RuntimeError("Element type %s doesn't support trace %s" %
+ (factory_id, trace_id))
+ if not guid in self._add_trace:
+ self._add_trace[guid] = list()
+ self._add_trace[guid].append(trace_id)
+
+ def add_adddress(self, guid, family, address, netprefix, broadcast):
+ 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]
+ if not factory.allow_addresses:
+ raise RuntimeError("Element type %s doesn't support addresses" %
+ factory_id)
+ max_addresses = factory.get_attribute_value("MaxAddresses")
+ if guid in self._add_address:
+ count_addresses = len(self._add_address[guid])
+ if max_addresses == count_addresses:
+ raise RuntimeError("Element guid %d of type %s can't accept \
+ more addresses" % (guid, family_id))
+ else:
+ self._add_address[guid] = list()
+ self._add_address[guid].append((family, address, netprefix, broadcast))
+
+ def add_route(self, guid, family, destination, netprefix, nexthop,
+ interface):
+ 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]
+ if not factory.allow_routes:
+ raise RuntimeError("Element type %s doesn't support routes" %
+ factory_id)
+ if not guid in self._add_route:
+ self._add_route[guid] = list()
+ self._add_route[guid].append((family, destination, netprefix, nexthop,
+ interface))
+
+ def do_create(self):
+ guids = dict()
+ for guid, factory_id in self._create.iteritems():
+ if not factory_id in guids:
+ guids[factory_id] = list()
+ guids[factory_id].append(guid)
+ for factory_id in self._metadata.factories_order:
+ if factory_id not in guids:
+ continue
+ factory = self._factories[factory_id]
+ for guid in guids[factory_id]:
+ parameters = dict() if guid not in self._set else \
+ self._set[guid]
+ factory.create_function(self, guid, parameters)
+ element = self._elements[guid]
+ if element:
+ for name, value in parameters.iteritems():
+ setattr(element, name, value)
+
+ def do_connect(self):
+ for guid1, connections in self._connect.iteritems():
+ element1 = self._elements[guid1]
+ factory_id1 = self._create[guid1]
+ factory1 = self._factories[factory_id1]
+ for connector_type_name1, connections2 in connections.iteritems():
+ connector_type1 = factory1.connector_type(connector_type_name1)
+ for guid2, connector_type_name2 in connections2.iteritems():
+ element2 = self._elements[guid2]
+ factory_id2 = self._create[guid2]
+ # Connections are executed in a "From -> To" direction only
+ # This explicitly ignores the "To -> From" (mirror)
+ # connections of every connection pair.
+ code_to_connect = connector_type1.code_to_connect(
+ self._testbed_id, factory_id2,
+ connector_type_name2)
+ if code_to_connect:
+ code_to_connect(element1, element2)
+
+ def do_configure(self):
+ # TODO: add traces!
+ # add 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)
+ # add routes
+ for guid, routes in self._add_route.iteritems():
+ element = self._elements[guid]
+ for route in routes:
+ # TODO: family and interface not used!!!!!
+ (family, destination, netprefix, nexthop, interfaces) = routes
+ element.add_route(prefix = destination, prefix_len = netprefix,
+ nexthop = nexthop)
+
+ def do_cross_connect(self):
+ for guid, cross_connections in self._cross_connect.iteritems():
+ element = self._elements[guid]
+ factory_id = self._create[guid]
+ factory = self._factories[factory_id]
+ for connector_type_name, cross_connection in \
+ cross_connections.iteritems():
+ connector_type = factory.connector_type(connector_type_name)
+ (cross_testbed_id, cross_factory_id,
+ cross_connector_type_name) = cross_connection
+ code_to_connect = connector_type.code_to_connect(
+ cross_guid, cross_testbed_id, cross_factory_id,
+ cross_conector_type_name)
+ if code_to_connect:
+ code_to_connect(element, cross_guid)
+
+ def set(self, time, guid, name, value):
+ # TODO: take on account schedule time for the task
+ element = self._elements[guid]
+ setattr(element, name, value)
+
+ def get(self, time, guid, name):
+ # TODO: take on account schedule time for the task
+ element = self._elements[guid]
+ return getattr(element, name)
+
+ def start(self, time = "0s"):
+ for guid, factory_id in self._create.iteritems():
+ 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._set else \
+ self._set[guid]
+ start_function(self, guid, parameters, traces)
+
+ def action(self, time, guid, action):
+ raise NotImplementedError
+
+ def stop(self, time = "0s"):
+ for guid, factory_id in self._create.iteritems():
+ 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)
+
+ 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:
+ result = status_function(self, guid)
+
+ def trace(self, guid, trace_id):
+ raise NotImplementedError
+
+ def shutdown(self):
+ for element in self._elements.values():
+ element.destroy()
+
+ def get_connected(self, guid, connector_type_name,
+ other_connector_type_name):
+ """searchs the connected elements for the specific connector_type_name
+ pair"""
+ if guid not in self._connect:
+ return []
+ # all connections for all connectors for guid
+ all_connections = self._connect[guid]
+ if connector_type_name not in all_connections:
+ return []
+ # all connections for the specific connector
+ connections = all_connections[connector_type_name]
+ specific_connections = [otr_guid for otr_guid, otr_connector_type_name \
+ in connections.iteritems() if \
+ otr_connector_type_name == other_connector_type_name]
+ return specific_connections
+
+ def _load_netns_module(self, configuration):
+ # TODO: Do something with the configuration!!!
+ import sys
+ __import__("netns")
+ netns_mod = sys.modules["netns"]
+ # enable debug
+ enable_debug = configuration.get_attribute_value("EnableDebug")
+ if enable_debug:
+ netns_mod.environ.set_log_level(netns_mod.environ.LOG_DEBUG)
+ return netns_mod
+
+ def _get_connection_count(self, guid, connection_type_name):
+ count = 0
+ cross_count = 0
+ if guid in self._connect and connection_type_name in \
+ self._connect[guid]:
+ count = len(self._connect[guid][connection_type_name])
+ if guid in self._cross_connect and connection_type_name in \
+ self._cross_connect[guid]:
+ cross_count = len(self._cross_connect[guid][connection_type_name])
+ return count + cross_count
+
+
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-from nepi.core.description import AF_INET
+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
+
+NODE = "Node"
+P2PIFACE = "P2PInterface"
+TAPIFACE = "TapNodeInterface"
+NODEIFACE = "NodeInterface"
+SWITCH = "Switch"
+APPLICATION = "Application"
+
+NS3_TESTBED_ID = "ns3"
+FDNETDEV = "ns3::FileDescriptorNetDevice"
+
+### Connection functions ####
+
+def connect_switch(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):
+ import passfd
+ import socket
+ fd = tap.file_descriptor
+ address = fdnd.socket_address
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+ sock.connect(address)
+ passfd.sendfd(sock, fd, '0')
+ # TODO: after succesful transfer, the tap device should close the fd
+
+### Creation functions ###
+
+def create_node(testbed_instance, guid, parameters):
+ forward_X11 = False
+ if "forward_X11" in parameters:
+ forward_X11 = parameters["forward_X11"]
+ del parameters["forward_X11"]
+ element = testbed_instance.netns.Node(forward_X11 = forward_X11)
+ testbed_instance.elements[guid] = element
+
+def create_p2piface(testbed_instance, guid, parameters):
+ # search for the node asociated with the p2piface
+ node1_guid = testbed_instance.get_connected(guid, "node", "devs")
+ if len(node1_guid) == 0:
+ raise RuntimeError("Can't instantiate interface %d outside netns \
+ node" % guid)
+ node1 = testbed_instance.elements[node1_guid[0]]
+ # search for the pair p2piface
+ p2p_guid = testbed_instance.get_connected(guid, "p2p","p2p")
+ if len(p2p_guid) == 0:
+ raise RuntimeError("Can't instantiate p2p interface %d. \
+ Missing interface pair" % guid)
+ guid2 = p2p_guid[0]
+ node2_guid = testbed_instance.get_connected(guid2, "node", "devs")
+ if len(node2_guid) == 0:
+ raise RuntimeError("Can't instantiate interface %d outside netns \
+ node" % guid2)
+ node2 = testbed_instance.elements[node2_guid[0]]
+ element1, element2 = testbed_instance.netns.P2PInterface.create_pair(
+ node1, node2)
+ testbed_instance.elements[guid] = element1
+ testbed_instance.elements[guid2] = element2
+
+def create_tapiface(testbed_instance, guid, parameters):
+ 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]]
+ element = node.add_tap()
+ testbed_instance.elements[guid] = element
+
+def create_nodeiface(testbed_instance, guid, parameters):
+ 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]]
+ element = node.add_if()
+ testbed_instance.elements[guid] = element
+
+def create_switch(testbed_instance, guid, parameters):
+ element = testbed_instance.netns.Switch()
+ testbed_instance.elements[guid] = element
+
+def create_application(testbed_instance, guid, parameters):
+ testbed_instance.elements[guid] = None # Delayed construction
+
+### Start/Stop functions ###
+
+def start_application(testbed_instance, guid, parameters, traces):
+ user = parameters["user"]
+ command = parameters["command"]
+ stdout = stderr = None
+ if "stdout" in traces:
+ filename = "%d_%s" % (guid, "stdout")
+ stdout = open(filename, "wb")
+ if "stderr" in traces:
+ filename = "%d_%s" % (guid, "stderr")
+ stderr = open(filename, "wb")
+
+ node_guid = testbed_instance.get_connected(guid, "node", "apps")
+ if len(node_guid) == 0:
+ raise RuntimeError("Can't instantiate interface %d outside netns \
+ node" % guid)
+ node = testbed_instance.elements[node_guid[0]]
+ element = node.Popen(command, shell = True, stdout = stdout,
+ stderr = stderr, user = user)
+ testbed_instance.elements[guid] = element
+
+### Status functions ###
+
+def status_application(testbed_instance, guid):
+ if guid not in testbed_instance.elements.keys():
+ return None
+ app = testbed.elements[guid]
+ return app.poll()
+
+### Factory information ###
+
+connector_types = dict({
+ "apps": dict({
+ "help": "Connector from node to applications",
+ "name": "apps",
+ "max": -1,
+ "min": 0
+ }),
+ "devs": dict({
+ "help": "Connector from node to network interfaces",
+ "name": "devs",
+ "max": -1,
+ "min": 0
+ }),
+ "node": dict({
+ "help": "Connector to a Node",
+ "name": "node",
+ "max": 1,
+ "min": 1
+ }),
+ "p2p": dict({
+ "help": "Connector to a P2PInterface",
+ "name": "p2p",
+ "max": 1,
+ "min": 0
+ }),
+ "fd": dict({
+ "help": "Connector to a network interface that can receive a file descriptor",
+ "name": "fd",
+ "max": 1,
+ "min": 0
+ }),
+ "switch": dict({
+ "help": "Connector to a switch",
+ "name": "switch",
+ "max": 1,
+ "min": 0
+ })
+ })
+
+connections = [
+ dict({
+ "from": (TESTBED_ID, NODE, "devs"),
+ "to": (TESTBED_ID, P2PIFACE, "node"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, NODE, "devs"),
+ "to": (TESTBED_ID, TAPIFACE, "node"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, NODE, "devs"),
+ "to": (TESTBED_ID, NODEIFACE, "node"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, P2PIFACE, "p2p"),
+ "to": (TESTBED_ID, P2PIFACE, "p2p"),
+ "code": None,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, TAPIFACE, "fd"),
+ "to": (NS3_TESTBED_ID, FDNETDEV, "fd"),
+ "code": connect_fd_local,
+ "can_cross": True
+ }),
+ dict({
+ "from": (TESTBED_ID, SWITCH, "devs"),
+ "to": (TESTBED_ID, NODEIFACE, "switch"),
+ "code": connect_switch,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, NODE, "apps"),
+ "to": (TESTBED_ID, APPLICATION, "node"),
+ "code": None,
+ "can_cross": False
+ })
+]
+
+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,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_bool
+ }),
+ "lladdr": dict({
+ "name": "lladdr",
+ "help": "Mac address",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_mac_address
+ }),
+ "up": dict({
+ "name": "up",
+ "help": "Link up",
+ "type": Attribute.BOOL,
+ "value": False,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_bool
+ }),
+ "device_name": dict({
+ "name": "name",
+ "help": "Device name",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_string
+ }),
+ "mtu": dict({
+ "name": "mtu",
+ "help": "Maximum transmition unit for device",
+ "type": Attribute.INTEGER,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_integer
+ }),
+ "broadcast": dict({
+ "name": "broadcast",
+ "help": "Broadcast address",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_string # TODO: should be is address!
+ }),
+ "multicast": dict({
+ "name": "multicast",
+ "help": "Multicast enabled",
+ "type": Attribute.BOOL,
+ "value": False,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_bool
+ }),
+ "arp": dict({
+ "name": "arp",
+ "help": "ARP enabled",
+ "type": Attribute.BOOL,
+ "value": False,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_bool
+ }),
+ "command": dict({
+ "name": "command",
+ "help": "Command line string",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_string
+ }),
+ "user": dict({
+ "name": "user",
+ "help": "System user",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_string
+ }),
+ "stdin": dict({
+ "name": "stdin",
+ "help": "Standard input",
+ "type": Attribute.STRING,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": False,
+ "visible": True,
+ "validation_function": validation.is_string
+ }),
+ "max_addresses": dict({
+ "name": "MaxAddresses",
+ "help": "Maximum number of addresses allowed by the device",
+ "type": Attribute.INTEGER,
+ "value": None,
+ "range": None,
+ "allowed": None,
+ "readonly": True,
+ "visible": False,
+ "validation_function": validation.is_integer
+ }),
+ "family": dict({
+ "name": "Family",
+ "help": "IP address family",
+ "type": Attribute.INTEGER,
+ "value": AF_INET,
+ "range": None,
+ "allowed": None,
+ "readonly": True,
+ "visible": False,
+ "validation_function": validation.is_integer
+ }),
+
+ })
+
+traces = dict({
+ "stdout": dict({
+ "name": "StdoutTrace",
+ "help": "Standard output stream"
+ }),
+ "stderr": dict({
+ "name": "StderrTrace",
+ "help": "Application standard error",
+ })
+ })
+
+factories_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+ APPLICATION ]
+
+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"]
+ }),
+ P2PIFACE: dict({
+ "allow_addresses": True,
+ "help": "Point to point network interface",
+ "category": "devices",
+ "create_function": create_p2piface,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "factory_attributes": ["family", "max_addresses"],
+ "box_attributes": ["lladdr", "up", "device_name", "mtu",
+ "multicast", "broadcast", "arp"],
+ "connector_types": ["node", "p2p"]
+ }),
+ TAPIFACE: dict({
+ "allow_addresses": True,
+ "help": "Tap device network interface",
+ "category": "devices",
+ "create_function": create_tapiface,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "factory_attributes": ["family", "max_addresses"],
+ "box_attributes": ["lladdr", "up", "device_name", "mtu",
+ "multicast", "broadcast", "arp"],
+ "connector_types": ["node", "fd"]
+ }),
+ NODEIFACE: dict({
+ "allow_addresses": True,
+ "help": "Node network interface",
+ "category": "devices",
+ "create_function": create_nodeiface,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "factory_attributes": ["family", "max_addresses"],
+ "box_attributes": ["lladdr", "up", "device_name", "mtu",
+ "multicast", "broadcast", "arp"],
+ "connector_types": ["node", "switch"]
+ }),
+ SWITCH: dict({
+ "display_name": "Switch",
+ "help": "Switch interface",
+ "category": "devices",
+ "create_function": create_switch,
+ "start_function": None,
+ "stop_function": None,
+ "status_function": None,
+ "box_attributes": ["up", "device_name", "mtu", "multicast"],
+ #TODO: Add attribute ("Stp", help, type, value, range, allowed, readonly, validation_function),
+ #TODO: Add attribute ("ForwarddDelay", help, type, value, range, allowed, readonly, validation_function),
+ #TODO: Add attribute ("HelloTime", help, type, value, range, allowed, readonly, validation_function),
+ #TODO: Add attribute ("AgeingTime", help, type, value, range, allowed, readonly, validation_function),
+ #TODO: Add attribute ("MaxAge", help, type, value, range, allowed, readonly, validation_function)
+ "connector_types": ["devs"]
+ }),
+ APPLICATION: dict({
+ "help": "Generic executable command line application",
+ "category": "applications",
+ "create_function": create_application,
+ "start_function": start_application,
+ "stop_function": None,
+ "status_function": status_application,
+ "box_attributes": ["command", "user"],
+ "connector_types": ["node"],
+ "traces": ["stdout", "stderr"]
+ }),
+})
+
+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
-def get_metadata():
- return dict({
- "Node": dict({
- "factory_type": "routing",
- "display_name": "Node",
- "help": "Node",
- "category": "topology",
- "connector_types": [
- ("netns_node_apps",
- "Connector from node to applications",
- "apps", -1, 0,
- ["netns_application_node"]),
- ("netns_node_devs",
- "Connector from node to network interfaces",
- "devs", -1, 0,
- [
- "netns_nodeiface_node",
- "netns_tapiface_node",
- "netns_p2piface_node"
- ])
- ],
- "box_attributes": [
- ("forward_X11",
- "Forward x11 from main namespace to the node",
- Attribute.BOOL,
- False, None, None, False,
- validation.is_bool)
- ]
- }),
- "P2PInterface": dict({
- "factory_type": "addressable",
- "family": AF_INET,
- "max_addresses": 1,
- "display_name": "P2PInterface",
- "help": "Point to point network interface",
- "category": "devices",
- "connector_types": [
- ("netns_p2piface_node",
- "Connector from P2PInterface to Node",
- "node", 1, 1,
- ["netns_node_devs"]),
- ("netns_p2piface_p2p",
- "Connector to another P2PInterface",
- "p2p", 1, 0,
- ["netns_p2piface_p2p"])
- ],
- "box_attributes": [
- ("lladdr", "Mac address", Attribute.STRING,
- None, None, None, False,
- validation.is_mac_address),
- ("up", "Link up", Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("name", "Device name", Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("mtu", "Maximmum transmition unit for device",
- Attribute.INTEGER,
- None, None, None, False,
- validation.is_integer),
- ("broadcast", "Broadcast address",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("multicast", "Is multicast enabled",
- Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("arp", "Is ARP enabled", Attribute.BOOL,
- True, None, None, False,
- validation.is_bool),
- ]
- }),
- "TapNodeInterface": dict({
- "factory_type": "addressable",
- "family": AF_INET,
- "max_addresses": 1,
- "display_name": "TapNodeInterface",
- "help": "Tap device network interface",
- "category": "devices",
- "connector_types": [
- ("netns_tapiface_node",
- "Connector to a Node",
- "node", 1, 1,
- ["netns_node_devs"]),
- ("netns_tapiface_fd",
- "Connector to a network interface that can receive a file descriptor",
- "fd", 1, 0,
- # TODO: Doesn't exist yet!
- ["ns3_fdnetdev_fd"])
- ],
- "box_attributes": [
- ("lladdr", "Mac address", Attribute.STRING,
- None, None, None, False,
- validation.is_mac_address),
- ("up", "Link up", Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("name", "Device name", Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("mtu", "Maximmum transmition unit for device",
- Attribute.INTEGER,
- None, None, None, False,
- validation.is_integer),
- ("broadcast", "Broadcast address",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("multicast", "Is multicast enabled",
- Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("arp", "Is ARP enabled", Attribute.BOOL,
- True, None, None, False,
- validation.is_bool),
- ]
- }),
- "NodeInterface": dict({
- "factory_type": "addressable",
- "family": AF_INET,
- "max_addresses": 1,
- "display_name": "NodeInterface",
- "help": "Node network interface",
- "category": "devices",
- "connector_types": [
- ("netns_nodeiface_node", "Connector to a node",
- "node", 1, 1,
- ["netns_node_devs"]),
- ("netns_nodeiface_switch", "Connector to a switch",
- "switch", 1, 0,
- ["netns_switch_devs"])
- ],
- "box_attributes": [
- ("lladdr", "Mac address", Attribute.STRING,
- None, None, None, False,
- validation.is_mac_address),
- ("up", "Link up", Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("name", "Device name", Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("mtu", "Maximmum transmition unit for device",
- Attribute.INTEGER,
- None, None, None, False,
- validation.is_integer),
- ("broadcast", "Broadcast address",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("multicast", "Is multicast enabled",
- Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("arp", "Is ARP enabled", Attribute.BOOL,
- True, None, None, False,
- validation.is_bool),
- ]
- }),
- "Switch": dict({
- "display_name": "Switch",
- "help": "Switch interface",
- "category": "devices",
- "connector_types": [
- ("netns_switch_devs", "Connector to network interfaces",
- "devs", -1, 0,
- ["netns_nodeiface_switch"])
- ],
- "box_attributes": [
- ("up", "Link up", Attribute.BOOL,
- False, None, None, False,
- validation.is_bool),
- ("name", "Device name", Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("mtu", "Maximmum transmition unit for device",
- Attribute.INTEGER,
- None, None, None, False,
- validation.is_integer),
- ("multicast", "Is multicast enabled",
- Attribute.BOOL,
- None, None, None, False,
- validation.is_bool),
- #TODO:("Stp", help, type, value, range, allowed, readonly, validation_function),
- #TODO:("ForwarddDelay", help, type, value, range, allowed, readonly, validation_function),
- #TODO:("HelloTime", help, type, value, range, allowed, readonly, validation_function),
- #TODO:("AgeingTime", help, type, value, range, allowed, readonly, validation_function),
- #TODO:("MaxAge", help, type, value, range, allowed, readonly, validation_function)
- ]
- }),
- "Application": dict({
- "display_name": "Application",
- "help": "Generic executable command line application",
- "category": "applications",
- "connector_types": [
- ("netns_application_node", "Connector to a node",
- "node", 1, 1,
- ["netns_node_apps"])
- ],
- "traces": [
- ("StdoutTrace", "Standard output"),
- ("StderrTrace", "Standard error")
- ],
- "box_attributes": [
- ("command", "Command line",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("user", "System user",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string),
- ("stdin", "Standard input",
- Attribute.STRING,
- None, None, None, False,
- validation.is_string)
- ]
- }),
- })
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from nepi.core import testbed
-
-CREATE = 0
-SET = 1
-CONNECT = 2
-ADD_TRACE = 3
-ADD_ADDRESS = 4
-ADD_ROUTE = 5
-
-class TestbedConfiguration(testbed.TestbedConfiguration):
- pass
-
-class TestbedInstance(testbed.TestbedInstance):
- def __init__(self, configuration):
- self._netns = self._load_netns_module(configuration)
- self._elements = dict()
- self._configuration = configuration
- self._instructions = dict({
- CREATE: dict(),
- SET: dict(),
- CONNECT: dict(),
- ADD_TRACE: dict(),
- ADD_ADDRESS: dict(),
- ADD_ROUTE: dict()
- })
- self._factories = dict({
- "Node": list(),
- "P2PInterface": list(),
- "TapNodeInterface": list(),
- "NodeInterface": list(),
- "Switch": list(),
- "Application": list()
- })
- self._connections = list()
-
- def create(self, guid, factory_id):
- if guid in self._instructions[CREATE]:
- # XXX: Validation
- raise RuntimeError("cannot add two elements with the same guid")
- if factory_id not in self._factories:
- # XXX: Validation
- raise RuntimeError("%s is not an allowed factory_id" % factory_id)
- self._instructions[CREATE][guid] = factory_id
- self._factories[factory_id].append(guid)
-
- def create_set(self, guid, name, value):
- if guid not in self._instructions[SET]:
- self._instructions[SET][guid] = dict()
- self._instructions[SET][guid][name] = value
-
- def connect(self, guid1, connector_type_name1, guid2,
- connector_type_name2):
- if not guid1 in self._instructions[CONNECT]:
- self._instructions[CONNECT] = dict()
- if not connector_type_name1 in self._instructions[CONNECT][guid1]:
- self._instructions[CONNECT][guid1][connector_type_name1] = dict()
- self._instructions[CONNECT][guid1][connector_type_name1][guid2] = \
- connector_type_name2
- self._connections.append((guid1, connector_type_name1, guid2,
- connector_type_name2))
-
- def add_trace(self, guid, trace_id):
- if not guid in self._instructions[ADD_TRACE]:
- self._instructions[ADD_TRACE][guid] = list()
- self._instructions[ADD_TRACE][guid].append(trace_id)
-
- def add_adddress(self, guid, family, address, netprefix, broadcast):
- if not guid in self._instructions[ADD_ADDRESS]:
- self._instructions[ADD_ADDRESS][guid] = list()
- self._instructions[ADD_ADDRESS][guid].append((guid, family, address,
- netprefix, broadcast))
-
- def add_route(self, guid, family, destination, netprefix, nexthop,
- interface):
- if not guid in self._instructions[ADD_ROUTE]:
- self._instructions[ADD_ROUTE][guid] = list()
- self._instructions[ADD_ROUTE][guid].append((family, destination,
- netprefix, nexthop, interface))
-
- def do_create(self):
- # nodes need to be created first
- factories_order = ["Node", "P2PInterface", "TapNodeInterface",
- "NodeInterface", "Switch", "Application"]
- for guid in self._factories[factory_id] \
- for factory_id in factories_order:
- self._create_element(guid, factory_id)
- # free self._factories as it is not going to be used further
- # TODO: Check if this methods frees everithing...
- # maybe there are still some references!
- self._factories = None
-
- def do_connect(self):
- cross_connections = list()
- for (guid1, connector_type_name1, guid2, connector_type_name2) \
- in self._connections:
- if guid1 not in self._elements or guid2 not in self._elements:
- # at least one of the elements does not belong to this
- # TestbedIntsance and so it needs to be treated as a cross
- # testbed connection
- cross_connections.append(guid1, connector_type_name1, guid2,
- connector_type_name2)
- else:
- # TODO: do Whatever is needed to connect
- pass
- self._connections = cross_connections
-
- def do_configure(self):
- raise NotImplementedError
- #self._object.add_route(
- # prefix = destination,
- # prefix_len = netprefix,
- # nexthop = nexthop)
-
- def do_cross_connect(self):
- for (guid1, connector_type_name1, guid2, connector_type_name2) \
- in self._connections:
- # TODO: do Whatever is needed to connect
- pass
- # free connections list as is not going to be used further
- self._connections = None
-
- def set(self, time, guid, name, value):
- raise NotImplementedError
-
- def get(self, time, guid, name):
- raise NotImplementedError
-
- def start(self, time):
- raise NotImplementedError
-
- def action(self, time, guid, action):
- raise NotImplementedError
-
- def stop(self, time):
- raise NotImplementedError
-
- def status(self, guid):
- raise NotImplementedError
-
- def trace(self, guid, trace_id):
- raise NotImplementedError
-
- def shutdown(self):
- raise NotImplementedError
-
- def _netns_module(self, configuration):
- # TODO: Do something with the configuration!!!
- import sys
- __import__("netns")
- return sys.modules["netns"]
-
- def _create_element(self, guid, factory_id):
- paremeters = dict()
- if guid in self._instructions[SET]:
- parameters = self._instructions[SET][guid]
- if guid not in self._elements.keys():
- if factory_id == "Node":
- self._create_node_element(guid, parameters)
- elif factory_id == "P2PInterface":
- self._create_p2piface_element(guid, parameters)
- self._set_attributes(guid, parameters)
-
- def _create_node_element(self, guid, parameters):
- forward_X11 = False
- if "forward_X11" in paremeters:
- forward_X11 = parameters["forward_X11"]
- del parameters["forward_X11"]
- element = self._netns.Node(forward_X11 = forward_X11)
- self._elements[guid] = element
-
- def _create_p2piface_element(self, guid, parameters):
- # search in the connections the node asociated with this
- # P2PInterface and the other P2PInterface to which it is
- # connected
- connection =
- node1 =
- node2 =
- element1, element2 = self._netns.P2PInterface.create_pair(
- node1, node2)
- self._elements[guid] = element1
- self._elements[guid2] = element2
-
- def _set_attributes(self, guid, paramenters):
- for name, value in parameters:
- # TODO: Validate attribute does not exist!!!
- setattr(element, name, value)
-
-def connect_switch(switch_connector, interface_connector):
- switch = switch_connector.container_element
- interface = interface_connector.container_element
- if switch.is_installed() and interface.is_installed():
- switch._object.connect(interface._object)
- return True
- return False
-
-#XXX: This connection function cannot be use to transfer a file descriptor
-# to a remote tap device
-def connect_fd_local(tap_connector, fdnd_connector):
- tap = tap_connector.container_element
- fdnd = fdnd_connector.container_element
- if fdnd.is_installed() and tap.is_installed():
- socket = tap.server.modules.socket
- passfd = tap.server.modules.passfd
- fd = tap.file_descriptor
- address = fdnd.socket_address
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
- sock.connect(address)
- passfd.sendfd(sock, fd, '0')
- # TODO: after succesful transfer, the tap device should close the fd
- return True
- return False
-
-connections = [
- dict({
- 'from' : [ "netns", "Node", "devs" ],
- 'to' : [ "netns", "P2PInterface", "node" ],
- 'code' : do_nothing,
- 'can_cross' : False
- }),
- dict({
- 'from' : [ "netns", "Node", "devs" ],
- 'to' : [ "netns", "TapNodeInterface", "node" ],
- 'code' : do_nothing,
- 'can_cross' : False
- }),
- dict({
- 'from' : [ "netns", "Node", "devs" ],
- 'to' : [ "netns", "NodeInterface", "node" ],
- 'code' : do_nothing,
- 'can_cross' : False
- }),
- dict({
- 'from' : [ "netns", "P2PInterface", "p2p" ],
- 'to' : [ "netns", "P2PInterface", "p2p" ],
- 'code' : do_nothing,
- 'can_cross' : False
- }),
- dict({
- 'from' : [ "netns", "TapNodeInterface", "fd" ],
- 'to' : [ "ns3", "ns3::FileDescriptorNetDevice", "fd" ],
- 'code' : connect_fd_local,
- 'can_cross' : True
- }),
- dict({
- 'from' : [ "netns", "Switch", "devs" ],
- 'to' : [ "netns", "NodeInterface", "switch" ],
- 'code' : connect_switch,
- 'can_cross' : False
- }),
- dict({
- 'from' : [ "netns", "Node", "apps" ],
- 'to' : [ "netns", "Application", "node" ],
- 'code' : do_nothing,
- 'can_cross' : False
- })
-]
-
-class TapNodeInterface(object):
- def __init__(self):
- # GET THE NODE!
- self._object = node._object.add_tap()
-
-class NodeInterface(object):
- def __init__(self):
- # GET NODE
- self._object = n.add_if()
-
-class Switch(Topo_ChannelMixin, NetnsElement):
- def __init__(self, factory, server, container = None):
- self._object = self.server.modules.netns.Switch()
-
-class NetnsApplication(NetnsElement):
- def __init__(self, factory, server, container = None):
- super(NetnsApplication, self).__init__(factory, server, container)
- # attributes
- self.add_string_attribute(name = "command",
- help = "Command name")
- self.add_string_attribute(name = "user",
- help = "system user")
- self.add_string_attribute(name = "stdin",
- help = "Standard input")
- #traces
- stdout = StdTrace(
- name='StdoutTrace',
- help='Application standard output',
- filename='stdout.txt',
- element=self)
- stderr = StdTrace(
- name='StderrTrace',
- help='Application standard error',
- filename='stderr.txt',
- element=self)
- self._add_trace(stdout)
- self._add_trace(stderr)
-
- def start(self):
- user = self.get_attribute("user").value
-
- stdin = stdout = stderr = None
- if self.get_attribute('stdin').value:
- filename = self.get_attribute('stdin')
- stdin = self.server.modules.__builtin__.open(filename, 'rb')
-
- trace = self.get_trace("StdoutTrace")
- if trace.is_enabled:
- filename = trace.real_filepath
- stdout = self.server.modules.__builtin__.open(filename, 'wb')
-
- trace = self.get_trace("StderrTrace")
- if trace.is_enabled:
- filename = trace.real_filepath
- stderr = self.server.modules.__builtin__.open(filename, 'wb')
-
- cnctr = self.connector("node")
- node = iter(cnctr.connections).next().get_other(cnctr)\
- .container_element
- force_install(node)
- n = node._object
- command = self.get_attribute('command').value
- targets = re.findall(r"%target:(.*?)%", command)
- for target in targets:
- try:
- (family, address, port) = resolve_netref(target, AF_INET,
- self.server.experiment )
- command = command.replace("%%target:%s%%" % target, address.address)
- except:
- continue
-
- self._object = n.Popen(command, shell = True, stdout = stdout, stdin = stdin,
- stderr = stderr, user = user)
-
- def is_completed(self):
- if self._object is not None:
- returncode = self._object.poll()
- if returncode is not None:
- return True
- return False
-
-class StdTrace(Trace):
- def install(self):
- pass
-
- @property
- def real_filepath(self):
- filename = self.get_attribute("Filename").value
- return self.element.server.get_trace_filepath(filename)
-
- def read_trace(self):
- filename = self.get_attribute("Filename").value
- return self.element.server.read_trace(filename)
-
-def force_install(object):
- if not object.is_installed():
- object.install()
-
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+AF_INET = 0
+AF_INET6 = 1
+
self.connections_from_data(experiment_description, box_guids, data)
def testbed_from_data(self, experiment_description, guid, data):
+ from nepi.core.design import FactoriesProvider
(testbed_id, testbed_version) = data.get_testbed_data(guid)
- mod_name = 'nepi.testbeds.%s' % testbed_id
- if not mod_name in sys.modules:
- __import__(mod_name)
- testbed_mod = sys.modules[mod_name]
- provider = testbed_mod.TestbedFactoriesProvider(testbed_version)
+ provider = FactoriesProvider(testbed_id, testbed_version)
experiment_description.add_testbed_description(provider)
testbed_description = experiment_description.testbed_description(guid)
self.attributes_from_data(testbed_description, data)
if not connector.is_connected(other_connector):
connector.connect(other_connector)
-