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"
### 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
+ flags = struct.unpack("I",
+ fcntl.ioctl(tap.fd, TUNGETIFF, struct.pack("I",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
+
+
### Creation functions ###
def create_node(testbed_instance, guid):
return STATUS_RUNNING
return STATUS_FINISHED
+### Configure functions ###
+
+def configure_device(testbed_instance, guid):
+ element = testbed_instance._elements[guid]
+ if not guid in testbed_instance._add_address:
+ return
+ addresses = testbed_instance._add_address[guid]
+ for address in addresses:
+ (address, netprefix, broadcast) = address
+ # TODO: Decide if we should add a ipv4 or ipv6 address
+ element.add_v4_address(address, netprefix)
+
+def configure_node(testbed_instance, guid):
+ element = testbed_instance._elements[guid]
+ if not guid in testbed_instance._add_route:
+ return
+ routes = testbed_instance._add_route[guid]
+ for route in routes:
+ (destination, netprefix, nexthop) = route
+ element.add_route(prefix = destination, prefix_len = netprefix,
+ nexthop = nexthop)
+
+
### Factory information ###
connector_types = dict({
"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({
})
})
-factories_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE, SWITCH,
+create_order = [ NODE, P2PIFACE, NODEIFACE, TAPIFACE,
+ TUNCHANNEL, SWITCH,
APPLICATION ]
+configure_order = [ P2PIFACE, NODEIFACE, TAPIFACE,
+ TUNCHANNEL, SWITCH,
+ NODE, APPLICATION ]
+
factories_info = dict({
NODE: dict({
"allow_routes": True,
"help": "Emulated Node with virtualized network stack",
"category": "topology",
"create_function": create_node,
+ "configure_function": configure_node,
"box_attributes": ["forward_X11"],
"connector_types": ["devs", "apps"]
}),
"help": "Point to point network interface",
"category": "devices",
"create_function": create_p2piface,
+ "configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
"connector_types": ["node", "p2p"]
"help": "Tap device network interface",
"category": "devices",
"create_function": create_tapiface,
+ "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,
"help": "Node network interface",
"category": "devices",
"create_function": create_nodeiface,
+ "configure_function": configure_device,
"box_attributes": ["lladdr", "up", "device_name", "mtu",
"multicast", "broadcast", "arp"],
"connector_types": ["node", "switch"]
"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({
"value": False,
"validation_function": validation.is_bool
}),
- "home_directory": dict({
- "name": "homeDirectory",
- "help": "Path to the directory where traces and other files \
- will be stored",
- "type": Attribute.STRING,
- "value": False,
- "flags": Attribute.DesignOnly,
- "validation_function": validation.is_string
- })
})
class VersionedMetadataInfo(metadata.VersionedMetadataInfo):
return traces
@property
- def factories_order(self):
- return factories_order
+ def create_order(self):
+ return create_order
+
+ @property
+ def configure_order(self):
+ return configure_order
@property
def factories_info(self):