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 AF_INET, 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, interface):
24 switch.connect(interface)
26 #XXX: This connection function cannot be use to transfer a file descriptor
27 # to a remote tap device
28 def connect_fd_local(testbed_instance, tap, fdnd):
31 fd = tap.file_descriptor
32 address = fdnd.socket_address
33 sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
35 passfd.sendfd(sock, fd, '0')
36 # TODO: after succesful transfer, the tap device should close the fd
38 ### Creation functions ###
40 def create_node(testbed_instance, guid):
41 parameters = testbed_instance._get_parameters(guid)
43 if "forward_X11" in parameters:
44 forward_X11 = parameters["forward_X11"]
45 del parameters["forward_X11"]
46 element = testbed_instance.netns.Node(forward_X11 = forward_X11)
47 testbed_instance.elements[guid] = element
49 def create_p2piface(testbed_instance, guid):
50 if guid in testbed_instance.elements:
51 # The interface pair was already instantiated
53 # search for the node asociated with the p2piface
54 node1_guid = testbed_instance.get_connected(guid, "node", "devs")
55 if len(node1_guid) == 0:
56 raise RuntimeError("Can't instantiate interface %d outside netns \
58 node1 = testbed_instance.elements[node1_guid[0]]
59 # search for the pair p2piface
60 p2p_guid = testbed_instance.get_connected(guid, "p2p","p2p")
61 if len(p2p_guid) == 0:
62 raise RuntimeError("Can't instantiate p2p interface %d. \
63 Missing interface pair" % guid)
65 node2_guid = testbed_instance.get_connected(guid2, "node", "devs")
66 if len(node2_guid) == 0:
67 raise RuntimeError("Can't instantiate interface %d outside netns \
69 node2 = testbed_instance.elements[node2_guid[0]]
70 element1, element2 = testbed_instance.netns.P2PInterface.create_pair(
72 testbed_instance.elements[guid] = element1
73 testbed_instance.elements[guid2] = element2
75 def create_tapiface(testbed_instance, guid):
76 node_guid = testbed_instance.get_connected(guid, "node", "devs")
77 if len(node_guid) == 0:
78 raise RuntimeError("Can't instantiate interface %d outside netns \
80 node = testbed_instance.elements[node_guid[0]]
81 element = node.add_tap()
82 testbed_instance.elements[guid] = element
84 def create_nodeiface(testbed_instance, guid):
85 node_guid = testbed_instance.get_connected(guid, "node", "devs")
86 if len(node_guid) == 0:
87 raise RuntimeError("Can't instantiate interface %d outside netns \
89 node = testbed_instance.elements[node_guid[0]]
90 element = node.add_if()
91 testbed_instance.elements[guid] = element
93 def create_switch(testbed_instance, guid):
94 element = testbed_instance.netns.Switch()
95 testbed_instance.elements[guid] = element
97 def create_application(testbed_instance, guid):
98 testbed_instance.elements[guid] = None # Delayed construction
100 ### Start/Stop functions ###
102 def start_application(testbed_instance, guid):
103 parameters = testbed_instance._get_parameters(guid)
104 traces = testbed_instance._get_traces(guid)
105 user = parameters["user"]
106 command = parameters["command"]
107 stdout = stderr = None
108 if "stdout" in traces:
109 filename = testbed_instance.trace_filename(guid, "stdout")
110 stdout = open(filename, "wb")
111 testbed_instance.follow_trace("stdout", stdout)
112 if "stderr" in traces:
113 filename = testbed_instance.trace_filename(guid, "stderr")
114 stderr = open(filename, "wb")
115 testbed_instance.follow_trace("stderr", stderr)
117 node_guid = testbed_instance.get_connected(guid, "node", "apps")
118 if len(node_guid) == 0:
119 raise RuntimeError("Can't instantiate interface %d outside netns \
121 node = testbed_instance.elements[node_guid[0]]
122 element = node.Popen(command, shell = True, stdout = stdout,
123 stderr = stderr, user = user)
124 testbed_instance.elements[guid] = element
126 ### Status functions ###
128 def status_application(testbed_instance, guid):
129 if guid not in testbed_instance.elements.keys():
130 return STATUS_NOT_STARTED
131 app = testbed_instance.elements[guid]
132 if app.poll() == None:
133 return STATUS_RUNNING
134 return STATUS_FINISHED
136 ### Factory information ###
138 connector_types = dict({
140 "help": "Connector from node to applications",
146 "help": "Connector from node to network interfaces",
152 "help": "Connector to a Node",
158 "help": "Connector to a P2PInterface",
164 "help": "Connector to a network interface that can receive a file descriptor",
170 "help": "Connector to a switch",
179 "from": (TESTBED_ID, NODE, "devs"),
180 "to": (TESTBED_ID, P2PIFACE, "node"),
185 "from": (TESTBED_ID, NODE, "devs"),
186 "to": (TESTBED_ID, TAPIFACE, "node"),
191 "from": (TESTBED_ID, NODE, "devs"),
192 "to": (TESTBED_ID, NODEIFACE, "node"),
197 "from": (TESTBED_ID, P2PIFACE, "p2p"),
198 "to": (TESTBED_ID, P2PIFACE, "p2p"),
203 "from": (TESTBED_ID, TAPIFACE, "fd"),
204 "to": (NS3_TESTBED_ID, FDNETDEV, "fd"),
205 "code": connect_fd_local,
209 "from": (TESTBED_ID, SWITCH, "devs"),
210 "to": (TESTBED_ID, NODEIFACE, "switch"),
211 "code": connect_switch,
215 "from": (TESTBED_ID, NODE, "apps"),
216 "to": (TESTBED_ID, APPLICATION, "node"),
223 "forward_X11": dict({
224 "name": "forward_X11",
225 "help": "Forward x11 from main namespace to the node",
226 "type": Attribute.BOOL,
230 "flags": Attribute.DesignOnly,
231 "validation_function": validation.is_bool
235 "help": "Mac address",
236 "type": Attribute.STRING,
240 "flags": Attribute.DesignOnly,
241 "validation_function": validation.is_mac_address
246 "type": Attribute.BOOL,
250 "validation_function": validation.is_bool
252 "device_name": dict({
254 "help": "Device name",
255 "type": Attribute.STRING,
259 "flags": Attribute.DesignOnly,
260 "validation_function": validation.is_string
264 "help": "Maximum transmition unit for device",
265 "type": Attribute.INTEGER,
269 "validation_function": validation.is_integer
273 "help": "Broadcast address",
274 "type": Attribute.STRING,
278 "validation_function": validation.is_string # TODO: should be is address!
282 "help": "Multicast enabled",
283 "type": Attribute.BOOL,
287 "validation_function": validation.is_bool
291 "help": "ARP enabled",
292 "type": Attribute.BOOL,
296 "validation_function": validation.is_bool
300 "help": "Command line string",
301 "type": Attribute.STRING,
305 "flags": Attribute.DesignOnly,
306 "validation_function": validation.is_string
310 "help": "System user",
311 "type": Attribute.STRING,
315 "flags": Attribute.DesignOnly,
316 "validation_function": validation.is_string
320 "help": "Standard input",
321 "type": Attribute.STRING,
325 "flags": Attribute.DesignOnly,
326 "validation_function": validation.is_string
328 "max_addresses": dict({
329 "name": "MaxAddresses",
330 "help": "Maximum number of addresses allowed by the device",
331 "type": Attribute.INTEGER,
335 "flags": Attribute.Invisible,
336 "validation_function": validation.is_integer
340 "help": "IP address family",
341 "type": Attribute.INTEGER,
345 "flags": Attribute.Invisible,
346 "validation_function": validation.is_integer
353 "help": "Standard output stream"
357 "help": "Application standard error",
361 factories_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
364 factories_info = dict({
366 "allow_routes": True,
367 "help": "Emulated Node with virtualized network stack",
368 "category": "topology",
369 "create_function": create_node,
370 "start_function": None,
371 "stop_function": None,
372 "status_function": None,
373 "box_attributes": ["forward_X11"],
374 "connector_types": ["devs", "apps"]
377 "allow_addresses": True,
378 "help": "Point to point network interface",
379 "category": "devices",
380 "create_function": create_p2piface,
381 "start_function": None,
382 "stop_function": None,
383 "status_function": None,
384 "factory_attributes": ["family", "max_addresses"],
385 "box_attributes": ["lladdr", "up", "device_name", "mtu",
386 "multicast", "broadcast", "arp"],
387 "connector_types": ["node", "p2p"]
390 "allow_addresses": True,
391 "help": "Tap device network interface",
392 "category": "devices",
393 "create_function": create_tapiface,
394 "start_function": None,
395 "stop_function": None,
396 "status_function": None,
397 "factory_attributes": ["family", "max_addresses"],
398 "box_attributes": ["lladdr", "up", "device_name", "mtu",
399 "multicast", "broadcast", "arp"],
400 "connector_types": ["node", "fd"]
403 "allow_addresses": True,
404 "help": "Node network interface",
405 "category": "devices",
406 "create_function": create_nodeiface,
407 "start_function": None,
408 "stop_function": None,
409 "status_function": None,
410 "factory_attributes": ["family", "max_addresses"],
411 "box_attributes": ["lladdr", "up", "device_name", "mtu",
412 "multicast", "broadcast", "arp"],
413 "connector_types": ["node", "switch"]
416 "display_name": "Switch",
417 "help": "Switch interface",
418 "category": "devices",
419 "create_function": create_switch,
420 "start_function": None,
421 "stop_function": None,
422 "status_function": None,
423 "box_attributes": ["up", "device_name", "mtu", "multicast"],
424 #TODO: Add attribute ("Stp", help, type, value, range, allowed, readonly, validation_function),
425 #TODO: Add attribute ("ForwarddDelay", help, type, value, range, allowed, readonly, validation_function),
426 #TODO: Add attribute ("HelloTime", help, type, value, range, allowed, readonly, validation_function),
427 #TODO: Add attribute ("AgeingTime", help, type, value, range, allowed, readonly, validation_function),
428 #TODO: Add attribute ("MaxAge", help, type, value, range, allowed, readonly, validation_function)
429 "connector_types": ["devs"]
432 "help": "Generic executable command line application",
433 "category": "applications",
434 "create_function": create_application,
435 "start_function": start_application,
436 "stop_function": None,
437 "status_function": status_application,
438 "box_attributes": ["command", "user"],
439 "connector_types": ["node"],
440 "traces": ["stdout", "stderr"]
444 testbed_attributes = dict({
445 "enable_debug": dict({
446 "name": "enableDebug",
447 "help": "Enable netns debug output",
448 "type": Attribute.BOOL,
452 "validation_function": validation.is_bool
454 "home_directory": dict({
455 "name": "homeDirectory",
456 "help": "Path to the directory where traces and other files \
458 "type": Attribute.STRING,
462 "flags": Attribute.DesignOnly,
463 "validation_function": validation.is_string
467 class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
469 def connections_types(self):
470 return connection_types
473 def connections(self):
477 def attributes(self):
485 def factories_order(self):
486 return factories_order
489 def factories_info(self):
490 return factories_info
493 def testbed_attributes(self):
494 return testbed_attributes