#/usr/bin/env python # vim:ts=4:sw=4:et:ai:sts=4 import nemu import signal # run_as: user to setuid() to before running applications (this is assumed to # run as root) nemu.config.run_as = 'nobody' # Clean-up is essential to avoid leaving bridge devices all over the place # (luckily, the veths die automatically). This installs signals and exit # handlers. nemu.set_cleanup_hooks(on_exit = True, on_signals = [signal.SIGTERM, signal.SIGINT]) # each Node is a netns a = nemu.Node() b = nemu.Node() print "Nodes started with pids: %d and %d" % (a.pid, b.pid) # interface object maps to a veth pair with one end in a netns if0 = a.add_if(lladdr = '42:71:e0:90:ca:42') # This is equivalent #if0 = nemu.NodeInterface(a) #if0.lladdr = '42:71:e0:90:ca:42' if1 = b.add_if(mtu = 1492) # for using with a tun device, to connect to the outside world if2 = b.import_if('tun0') # each Switch is a linux bridge, all the parameters are applied to the # associated interfaces as tc qdiscs. switch0 = nemu.Switch(bandwidth = 100 * 1024 * 1024, delay = 0.01, delay_jitter = 0.001, delay_correlation = 0.25, delay_distribution = 'normal', loss = 0.005, loss_correlation = 0.20, dup = 0.005, dup_correlation = 0.25, corrupt = 0.005, corrupt_correlation = 0.25) # connect to the bridge switch0.connect(if0) switch0.connect(if1) # Should be experimented with Tom Geoff's patch to see if the bridge could be # avoided; but for that the API would be slightly different, as these would be # point-to-point interfaces and links. # ppp0 = nemu.PPPSwitch(a, b, bandwidth = ....) # if0 = ppp0.interface(a) # For now, we have simple P2P interfaces: (pppa, pppb) = nemu.P2PInterface.create_pair(a, b) # Add and connect a tap device (as if a external router were plugged into a # switch) if2 = nemu.ImportedInterface('tap0') switch0.connect(if2) switch0.up = True if0.up = True if1.up = True # addresses as iproute if0.add_v4_address(addr = '10.0.0.1', prefix_len = 24) if0.add_v6_address(addr = 'fe80::222:19ff:fe22:615d', prefix_len = 64) if1.add_v4_address(addr = '10.0.0.2', prefix_len = 24, broadcast = '10.1.0.255') # ditto #a.add_route(prefix = '0', prefix_len = 0, nexthop = '10.0.0.2') a.add_default_route(nexthop = '10.0.0.2') b.add_route(prefix = '10.1.0.0', prefix_len = 16, nexthop = '10.0.0.1') b.add_route(prefix = '11.1.0.1', prefix_len = 32, device = if1) # Some inspection methods: they will not read internal data but query the # kernel addrs = if0.get_addresses() stats = if0.get_stats() routes = a.get_routes() ifaces = a.get_interfaces() nodes = nemu.get_nodes() switches = nemu.get_switches() stats = link0.get_stats() # Run a process in background import subprocess app0 = a.Popen("ping -c 3 10.0.0.2", shell = True, stdout = subprocess.PIPE) print app0.stdout.readline() app0.wait() # Run, capture output and wait() stdout = a.backticks(["ping", "-c", "3", "10.0.0.2"]) # Run an process with a pseudo-tty associated to it; provide a UNIX socket to # interact with the process app2 = a.start_tty_process("/bin/bash") # app2.sockname, app2.sockfd app2.wait() # Example to set up a linear topology def setup_linear_topology(n, bd, delay): nodes = [] for i in range(n): nodes.append(nemu.Node()) for i in range(n - 1): if1 = nodes[i].add_if() if2 = nodes[i + 1].add_if() if1.add_v4_address(addr = ('10.0.%d.2' % i), prefix_len = 24) if2.add_v4_address(addr = ('10.0.%d.1' % i), prefix_len = 24) switch = nemu.Switch(bandwidth = bd, delay = delay) switch.connect(if1) switch.connect(if2) for i in range(n): for j in range(n): if abs(i - j) <= 1: continue nodes[i].add_route(prefix = ('10.0.%d.0' % j), prefix_len = 24, nexthop = ('10.0.%d.%d' % ((i, 1) if i < j else (i - 1, 2))) ) return nodes