2 # -*- coding: utf-8 -*-
4 from constants import TESTBED_ID
5 from nepi.core import metadata
6 from nepi.core.attributes import Attribute
7 from nepi.util import validation
8 from nepi.util.constants import STATUS_NOT_STARTED, STATUS_RUNNING, \
12 P2PIFACE = "P2PNodeInterface"
13 TAPIFACE = "TapNodeInterface"
14 NODEIFACE = "NodeInterface"
16 APPLICATION = "Application"
18 NS3_TESTBED_ID = "ns3"
19 FDNETDEV = "ns3::FileDescriptorNetDevice"
21 ### Connection functions ####
23 def connect_switch(testbed_instance, switch_guid, interface_guid):
24 switch = testbed_instance._elements[switch_guid]
25 interface = testbed_instance._elements[interface_guid]
26 switch.connect(interface)
28 def connect_fd(testbed_instance, tap_guid, cross_data):
31 tap = testbed_instance._elements[tap_guid]
32 fd = tap.file_descriptor
33 address = cross_data["LinuxSocketAddress"]
34 sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
36 passfd.sendfd(sock, fd, '0')
37 # TODO: after succesful transfer, the tap device should close the fd
39 ### Creation functions ###
41 def create_node(testbed_instance, guid):
42 parameters = testbed_instance._get_parameters(guid)
44 if "forward_X11" in parameters:
45 forward_X11 = parameters["forward_X11"]
46 del parameters["forward_X11"]
47 element = testbed_instance.netns.Node(forward_X11 = forward_X11)
48 testbed_instance.elements[guid] = element
50 def create_p2piface(testbed_instance, guid):
51 if guid in testbed_instance.elements:
52 # The interface pair was already instantiated
54 # search for the node asociated with the p2piface
55 node1_guid = testbed_instance.get_connected(guid, "node", "devs")
56 if len(node1_guid) == 0:
57 raise RuntimeError("Can't instantiate interface %d outside netns \
59 node1 = testbed_instance.elements[node1_guid[0]]
60 # search for the pair p2piface
61 p2p_guid = testbed_instance.get_connected(guid, "p2p","p2p")
62 if len(p2p_guid) == 0:
63 raise RuntimeError("Can't instantiate p2p interface %d. \
64 Missing interface pair" % guid)
66 node2_guid = testbed_instance.get_connected(guid2, "node", "devs")
67 if len(node2_guid) == 0:
68 raise RuntimeError("Can't instantiate interface %d outside netns \
70 node2 = testbed_instance.elements[node2_guid[0]]
71 element1, element2 = testbed_instance.netns.P2PInterface.create_pair(
73 testbed_instance.elements[guid] = element1
74 testbed_instance.elements[guid2] = element2
76 def create_tapiface(testbed_instance, guid):
77 node_guid = testbed_instance.get_connected(guid, "node", "devs")
78 if len(node_guid) == 0:
79 raise RuntimeError("Can't instantiate interface %d outside netns \
81 node = testbed_instance.elements[node_guid[0]]
82 element = node.add_tap()
83 testbed_instance.elements[guid] = element
85 def create_nodeiface(testbed_instance, guid):
86 node_guid = testbed_instance.get_connected(guid, "node", "devs")
87 if len(node_guid) == 0:
88 raise RuntimeError("Can't instantiate interface %d outside netns \
90 node = testbed_instance.elements[node_guid[0]]
91 element = node.add_if()
92 testbed_instance.elements[guid] = element
94 def create_switch(testbed_instance, guid):
95 element = testbed_instance.netns.Switch()
96 testbed_instance.elements[guid] = element
98 def create_application(testbed_instance, guid):
99 testbed_instance.elements[guid] = None # Delayed construction
101 ### Start/Stop functions ###
103 def start_application(testbed_instance, guid):
104 parameters = testbed_instance._get_parameters(guid)
105 traces = testbed_instance._get_traces(guid)
106 user = parameters["user"]
107 command = parameters["command"]
108 stdout = stderr = None
109 if "stdout" in traces:
110 filename = testbed_instance.trace_filename(guid, "stdout")
111 stdout = open(filename, "wb")
112 testbed_instance.follow_trace("stdout", stdout)
113 if "stderr" in traces:
114 filename = testbed_instance.trace_filename(guid, "stderr")
115 stderr = open(filename, "wb")
116 testbed_instance.follow_trace("stderr", stderr)
118 node_guid = testbed_instance.get_connected(guid, "node", "apps")
119 if len(node_guid) == 0:
120 raise RuntimeError("Can't instantiate interface %d outside netns \
122 node = testbed_instance.elements[node_guid[0]]
123 element = node.Popen(command, shell = True, stdout = stdout,
124 stderr = stderr, user = user)
125 testbed_instance.elements[guid] = element
127 ### Status functions ###
129 def status_application(testbed_instance, guid):
130 if guid not in testbed_instance.elements.keys():
131 return STATUS_NOT_STARTED
132 app = testbed_instance.elements[guid]
133 if app.poll() == None:
134 return STATUS_RUNNING
135 return STATUS_FINISHED
137 ### Configure functions ###
139 def configure_device(testbed_instance, guid):
140 element = testbed_instance._elements[guid]
141 if not guid in testbed_instance._add_address:
143 addresses = testbed_instance._add_address[guid]
144 for address in addresses:
145 (address, netprefix, broadcast) = address
146 # TODO: Decide if we should add a ipv4 or ipv6 address
147 element.add_v4_address(address, netprefix)
149 def configure_node(testbed_instance, guid):
150 element = testbed_instance._elements[guid]
151 if not guid in testbed_instance._add_route:
153 routes = testbed_instance._add_route[guid]
155 (destination, netprefix, nexthop) = route
156 element.add_route(prefix = destination, prefix_len = netprefix,
159 ### Factory information ###
161 connector_types = dict({
163 "help": "Connector from node to applications",
169 "help": "Connector from node to network interfaces",
175 "help": "Connector to a Node",
181 "help": "Connector to a P2PInterface",
187 "help": "Connector to a network interface that can receive a file descriptor",
193 "help": "Connector to a switch",
202 "from": (TESTBED_ID, NODE, "devs"),
203 "to": (TESTBED_ID, P2PIFACE, "node"),
207 "from": (TESTBED_ID, NODE, "devs"),
208 "to": (TESTBED_ID, TAPIFACE, "node"),
212 "from": (TESTBED_ID, NODE, "devs"),
213 "to": (TESTBED_ID, NODEIFACE, "node"),
217 "from": (TESTBED_ID, P2PIFACE, "p2p"),
218 "to": (TESTBED_ID, P2PIFACE, "p2p"),
222 "from": (TESTBED_ID, TAPIFACE, "fd"),
223 "to": (NS3_TESTBED_ID, FDNETDEV, "fd"),
224 "compl_code": connect_fd,
228 "from": (TESTBED_ID, SWITCH, "devs"),
229 "to": (TESTBED_ID, NODEIFACE, "switch"),
230 "init_code": connect_switch,
234 "from": (TESTBED_ID, NODE, "apps"),
235 "to": (TESTBED_ID, APPLICATION, "node"),
241 "forward_X11": dict({
242 "name": "forward_X11",
243 "help": "Forward x11 from main namespace to the node",
244 "type": Attribute.BOOL,
246 "flags": Attribute.DesignOnly,
247 "validation_function": validation.is_bool
251 "help": "Mac address",
252 "type": Attribute.STRING,
253 "flags": Attribute.DesignOnly,
254 "validation_function": validation.is_mac_address
259 "type": Attribute.BOOL,
261 "validation_function": validation.is_bool
263 "device_name": dict({
265 "help": "Device name",
266 "type": Attribute.STRING,
267 "flags": Attribute.DesignOnly,
268 "validation_function": validation.is_string
272 "help": "Maximum transmition unit for device",
273 "type": Attribute.INTEGER,
274 "validation_function": validation.is_integer
278 "help": "Broadcast address",
279 "type": Attribute.STRING,
280 "validation_function": validation.is_string # TODO: should be is address!
284 "help": "Multicast enabled",
285 "type": Attribute.BOOL,
287 "validation_function": validation.is_bool
291 "help": "ARP enabled",
292 "type": Attribute.BOOL,
294 "validation_function": validation.is_bool
298 "help": "Command line string",
299 "type": Attribute.STRING,
300 "flags": Attribute.DesignOnly,
301 "validation_function": validation.is_string
305 "help": "System user",
306 "type": Attribute.STRING,
307 "flags": Attribute.DesignOnly,
308 "validation_function": validation.is_string
312 "help": "Standard input",
313 "type": Attribute.STRING,
314 "flags": Attribute.DesignOnly,
315 "validation_function": validation.is_string
322 "help": "Standard output stream"
326 "help": "Application standard error",
330 create_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
333 configure_order = [ P2PIFACE, NODEIFACE, TAPIFACE, SWITCH, NODE,
336 factories_info = dict({
338 "allow_routes": True,
339 "help": "Emulated Node with virtualized network stack",
340 "category": "topology",
341 "create_function": create_node,
342 "configure_function": configure_node,
343 "box_attributes": ["forward_X11"],
344 "connector_types": ["devs", "apps"]
347 "allow_addresses": True,
348 "help": "Point to point network interface",
349 "category": "devices",
350 "create_function": create_p2piface,
351 "configure_function": configure_device,
352 "box_attributes": ["lladdr", "up", "device_name", "mtu",
353 "multicast", "broadcast", "arp"],
354 "connector_types": ["node", "p2p"]
357 "allow_addresses": True,
358 "help": "Tap device network interface",
359 "category": "devices",
360 "create_function": create_tapiface,
361 "configure_function": configure_device,
362 "box_attributes": ["lladdr", "up", "device_name", "mtu",
363 "multicast", "broadcast", "arp"],
364 "connector_types": ["node", "fd"]
367 "allow_addresses": True,
368 "help": "Node network interface",
369 "category": "devices",
370 "create_function": create_nodeiface,
371 "configure_function": configure_device,
372 "box_attributes": ["lladdr", "up", "device_name", "mtu",
373 "multicast", "broadcast", "arp"],
374 "connector_types": ["node", "switch"]
377 "display_name": "Switch",
378 "help": "Switch interface",
379 "category": "devices",
380 "create_function": create_switch,
381 "box_attributes": ["up", "device_name", "mtu", "multicast"],
382 #TODO: Add attribute ("Stp", help, type, value, range, allowed, readonly, validation_function),
383 #TODO: Add attribute ("ForwarddDelay", help, type, value, range, allowed, readonly, validation_function),
384 #TODO: Add attribute ("HelloTime", help, type, value, range, allowed, readonly, validation_function),
385 #TODO: Add attribute ("AgeingTime", help, type, value, range, allowed, readonly, validation_function),
386 #TODO: Add attribute ("MaxAge", help, type, value, range, allowed, readonly, validation_function)
387 "connector_types": ["devs"]
390 "help": "Generic executable command line application",
391 "category": "applications",
392 "create_function": create_application,
393 "start_function": start_application,
394 "status_function": status_application,
395 "box_attributes": ["command", "user"],
396 "connector_types": ["node"],
397 "traces": ["stdout", "stderr"]
401 testbed_attributes = dict({
402 "enable_debug": dict({
403 "name": "enableDebug",
404 "help": "Enable netns debug output",
405 "type": Attribute.BOOL,
407 "validation_function": validation.is_bool
411 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
413 def connector_types(self):
414 return connector_types
417 def connections(self):
421 def attributes(self):
429 def create_order(self):
433 def configure_order(self):
434 return configure_order
437 def factories_info(self):
438 return factories_info
441 def testbed_attributes(self):
442 return testbed_attributes