from nepi.util.constants import STATUS_NOT_STARTED, STATUS_RUNNING, \
STATUS_FINISHED
+from nepi.util.tunchannel_impl import \
+ preconfigure_tunchannel, postconfigure_tunchannel, \
+ wait_tunchannel, create_tunchannel, \
+ crossconnect_tunchannel_peer_init, \
+ crossconnect_tunchannel_peer_compl
+
+import functools
+
NODE = "Node"
P2PIFACE = "P2PNodeInterface"
TAPIFACE = "TapNodeInterface"
NODEIFACE = "NodeInterface"
SWITCH = "Switch"
APPLICATION = "Application"
+TUNCHANNEL = "TunChannel"
NS3_TESTBED_ID = "ns3"
FDNETDEV = "ns3::FileDescriptorNetDevice"
+def _follow_trace(testbed_instance, guid, trace_id, filename):
+ filepath = testbed_instance.trace_filepath(guid, trace_id, filename)
+ trace = open(filepath, "wb")
+ testbed_instance.follow_trace(guid, trace_id, trace, filename)
+ return trace
+
### Connection functions ####
-def connect_switch(testbed_instance, switch, interface):
+def connect_switch(testbed_instance, switch_guid, interface_guid):
+ switch = testbed_instance._elements[switch_guid]
+ interface = testbed_instance._elements[interface_guid]
switch.connect(interface)
-#XXX: This connection function cannot be use to transfer a file descriptor
-# to a remote tap device
-def connect_fd_local(testbed_instance, tap, fdnd):
+def connect_fd(testbed_instance, tap_guid, cross_data):
import passfd
import socket
- fd = tap.file_descriptor
- address = fdnd.socket_address
+ tap = testbed_instance._elements[tap_guid]
+ address = cross_data["tun_addr"]
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.connect(address)
- passfd.sendfd(sock, fd, '0')
+ passfd.sendfd(sock, tap.fd, '0')
# TODO: after succesful transfer, the tap device should close the fd
+def connect_tunchannel_tap(testbed_instance, chan_guid, tap_guid):
+ tap = testbed_instance._elements[tap_guid]
+ chan = testbed_instance._elements[chan_guid]
+
+ # Create a file object for the tap's interface device
+ # and send it to the channel. It should comply with all the
+ # requirements for the channel's tun_socket.
+ import os
+ chan.tun_socket = os.fdopen(tap.fd)
+
+ # Set the channel to ethernet mode (it's a tap)
+ chan.ethernet_mode = True
+
+ # Check to see if the device uses PI headers
+ # It's normally so
+ with_pi = True
+ try:
+ import fcntl
+ import struct
+ TUNGETIFF = 0x800454d2
+ IFF_NO_PI = 0x00001000
+ struct_ifreq = "x"*16+"H"+"x"*22
+ flags = struct.unpack(struct_ifreq,
+ fcntl.ioctl(tap.fd, TUNGETIFF, struct.pack(struct_ifreq,0)) )
+ with_pi = (0 == (flags & IFF_NO_PI))
+ except:
+ # maybe the kernel doesn't support the IOCTL,
+ # in which case, we assume it uses PI headers (as is usual)
+ pass
+ chan.with_pi = with_pi
+
+### Trace functions ###
+
+def nodepcap_trace(testbed_instance, guid, trace_id):
+ node = testbed_instance._elements[guid]
+ parameters = testbed_instance._get_parameters(guid)
+ filename = "%d-pcap.stdout" % guid
+ stdout = _follow_trace(testbed_instance, guid, "pcap_stdout", filename)
+ filename = "%d-pcap.stderr" % guid
+ stderr = _follow_trace(testbed_instance, guid, "pcap_stderr", filename)
+ filename = "%d-node.pcap" % guid
+ filepath = testbed_instance.trace_filepath(guid, trace_id, filename)
+ command = "tcpdump -i 'any' -w %s" % filepath
+ user = "root"
+ trace = node.Popen(command, shell = True, stdout = stdout,
+ stderr = stderr, user = user)
+ testbed_instance.follow_trace(guid, trace_id, trace, filename)
+
+trace_functions = dict({
+ "pcap": nodepcap_trace,
+ })
+
### Creation functions ###
def create_node(testbed_instance, guid):
def start_application(testbed_instance, guid):
parameters = testbed_instance._get_parameters(guid)
traces = testbed_instance._get_traces(guid)
- user = parameters["user"]
command = parameters["command"]
+ user = None
+ if "user" in parameters:
+ user = parameters["user"]
stdout = stderr = None
if "stdout" in traces:
- filename = testbed_instance.trace_filename(guid, "stdout")
- stdout = open(filename, "wb")
- testbed_instance.follow_trace("stdout", stdout)
+ filename = "%d-stdout.trace" % guid
+ stdout = _follow_trace(testbed_instance, guid, "stdout", filename)
if "stderr" in traces:
- filename = testbed_instance.trace_filename(guid, "stderr")
- stderr = open(filename, "wb")
- testbed_instance.follow_trace("stderr", stderr)
-
+ filename = "%d-stderr.trace" % guid
+ stderr = _follow_trace(testbed_instance, guid, "stderr", filename)
node_guid = testbed_instance.get_connected(guid, "node", "apps")
if len(node_guid) == 0:
raise RuntimeError("Can't instantiate interface %d outside netns \
stderr = stderr, user = user)
testbed_instance.elements[guid] = element
+def stop_application(testbed_instance, guid):
+ #app = testbed_instance.elements[guid]
+ #app.signal()
+ pass
+
### Status functions ###
def status_application(testbed_instance, guid):
### Configure functions ###
+def configure_traces(testbed_instance, guid):
+ traces = testbed_instance._get_traces(guid)
+ for trace_id in traces:
+ if trace_id not in trace_functions:
+ continue
+ trace_func = trace_functions[trace_id]
+ trace_func(testbed_instance, guid, trace_id)
+
def configure_device(testbed_instance, guid):
+ configure_traces(testbed_instance, guid)
element = testbed_instance._elements[guid]
if not guid in testbed_instance._add_address:
return
element.add_v4_address(address, netprefix)
def configure_node(testbed_instance, guid):
+ configure_traces(testbed_instance, guid)
element = testbed_instance._elements[guid]
if not guid in testbed_instance._add_route:
return
"max": 1,
"min": 0
}),
- "fd": dict({
- "help": "Connector to a network interface that can receive a file descriptor",
- "name": "fd",
- "max": 1,
+ "->fd": dict({
+ "help": "File descriptor receptor for devices with file descriptors",
+ "name": "->fd",
+ "max": 1,
+ "min": 0
+ }),
+ "fd->": dict({
+ "help": "File descriptor provider for devices with file descriptors",
+ "name": "fd->",
+ "max": 1,
"min": 0
}),
"switch": dict({
"name": "switch",
"max": 1,
"min": 0
- })
+ }),
+ "tcp": dict({
+ "help": "ip-ip tunneling over TCP link",
+ "name": "tcp",
+ "max": 1,
+ "min": 0
+ }),
+ "udp": dict({
+ "help": "ip-ip tunneling over UDP datagrams",
+ "name": "udp",
+ "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,
+ "from": (TESTBED_ID, TAPIFACE, "fd->"),
+ "to": (None, None, "->fd"),
+ "compl_code": connect_fd,
"can_cross": True
}),
dict({
"from": (TESTBED_ID, SWITCH, "devs"),
"to": (TESTBED_ID, NODEIFACE, "switch"),
- "code": connect_switch,
+ "init_code": connect_switch,
"can_cross": False
}),
dict({
"from": (TESTBED_ID, NODE, "apps"),
"to": (TESTBED_ID, APPLICATION, "node"),
- "code": None,
"can_cross": False
- })
+ }),
+ dict({
+ "from": (TESTBED_ID, TUNCHANNEL, "->fd" ),
+ "to": (TESTBED_ID, TAPIFACE, "fd->" ),
+ "init_code": connect_tunchannel_tap,
+ "can_cross": False
+ }),
+ dict({
+ "from": (TESTBED_ID, TUNCHANNEL, "tcp"),
+ "to": (None, None, "tcp"),
+ "init_code": functools.partial(crossconnect_tunchannel_peer_init,"tcp"),
+ "compl_code": functools.partial(crossconnect_tunchannel_peer_compl,"tcp"),
+ "can_cross": True
+ }),
+ dict({
+ "from": (TESTBED_ID, TUNCHANNEL, "udp"),
+ "to": (None, None, "udp"),
+ "init_code": functools.partial(crossconnect_tunchannel_peer_init,"udp"),
+ "compl_code": functools.partial(crossconnect_tunchannel_peer_compl,"udp"),
+ "can_cross": True
+ }),
]
attributes = dict({
"stderr": dict({
"name": "stderr",
"help": "Application standard error",
+ }),
+ "node_pcap": dict({
+ "name": "pcap",
+ "help": "tcpdump at all node interfaces",
})
})
-create_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+create_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE,
+ TUNCHANNEL, SWITCH,
APPLICATION ]
-configure_order = [ P2PIFACE, NODEIFACE, TAPIFACE, SWITCH, NODE,
- APPLICATION ]
+configure_order = [ P2PIFACE, NODEIFACE, TAPIFACE,
+ TUNCHANNEL, SWITCH,
+ NODE, APPLICATION ]
factories_info = dict({
NODE: dict({
"create_function": create_node,
"configure_function": configure_node,
"box_attributes": ["forward_X11"],
- "connector_types": ["devs", "apps"]
+ "connector_types": ["devs", "apps"],
+ "traces": ["node_pcap"]
}),
P2PIFACE: dict({
"allow_addresses": True,
"configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
- "connector_types": ["node", "fd"]
+ "connector_types": ["node", "fd->"]
}),
NODEIFACE: dict({
"allow_addresses": True,
"category": "applications",
"create_function": create_application,
"start_function": start_application,
+ "stop_function": stop_application,
"status_function": status_application,
"box_attributes": ["command", "user"],
"connector_types": ["node"],
"traces": ["stdout", "stderr"]
}),
+ TUNCHANNEL : dict({
+ "category": "Channel",
+ "create_function": create_tunchannel,
+ "preconfigure_function": preconfigure_tunchannel,
+ "configure_function": postconfigure_tunchannel,
+ "start_function": wait_tunchannel,
+ "help": "Channel to forward "+TAPIFACE+" data to "
+ "other TAP interfaces supporting the NEPI tunneling protocol.",
+ "connector_types": ["->fd", "udp", "tcp"],
+ "allow_addresses": False,
+ "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"]
+ }),
})
testbed_attributes = dict({