Commit ca244b1c authored by Alina Quereilhac's avatar Alina Quereilhac

Added TapNodeInterface and test to test_core. This test is not working.

parent 2cd9d91a
...@@ -14,10 +14,10 @@ def usage(f): ...@@ -14,10 +14,10 @@ def usage(f):
f.write(" -s, --pktsize=BYTES Size of packet payload\n\n") f.write(" -s, --pktsize=BYTES Size of packet payload\n\n")
f.write("Topology configuration:\n") f.write("Topology configuration:\n")
f.write(" --use-p2p Use P2P links, to avoid bridging\n") f.write(" --use-p2p Use P2P switchs, to avoid bridging\n")
f.write(" --delay=SECS Add delay emulation in links\n") f.write(" --delay=SECS Add delay emulation in switchs\n")
f.write(" --jitter=PERCENT Add jitter emulation in links\n") f.write(" --jitter=PERCENT Add jitter emulation in switchs\n")
f.write(" --bandwidth=BPS Maximum bandwidth of links\n\n") f.write(" --bandwidth=BPS Maximum bandwidth of switchs\n\n")
f.write("How long should the benchmark run (defaults to -t 10):\n") f.write("How long should the benchmark run (defaults to -t 10):\n")
f.write(" -t, --time=SECS Stop after SECS seconds\n") f.write(" -t, --time=SECS Stop after SECS seconds\n")
...@@ -89,7 +89,7 @@ def main(): ...@@ -89,7 +89,7 @@ def main():
elif not pktsize: elif not pktsize:
error = "Missing mandatory --pktsize argument" error = "Missing mandatory --pktsize argument"
elif use_p2p and (delay or jitter or bandwidth): elif use_p2p and (delay or jitter or bandwidth):
error = "Cannot use link emulation with P2P links" error = "Cannot use switch emulation with P2P switchs"
if error: if error:
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), error)) sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), error))
...@@ -106,7 +106,7 @@ def main(): ...@@ -106,7 +106,7 @@ def main():
if not udp_perf: if not udp_perf:
raise RuntimeError("Cannot find `udp-perf'") raise RuntimeError("Cannot find `udp-perf'")
nodes, interfaces, links = create_topo(nr, use_p2p, delay, jitter, nodes, interfaces, switchs = create_topo(nr, use_p2p, delay, jitter,
bandwidth) bandwidth)
cmdline = [udp_perf, "--server"] cmdline = [udp_perf, "--server"]
...@@ -174,7 +174,7 @@ def dec2ip(dec): ...@@ -174,7 +174,7 @@ def dec2ip(dec):
def create_topo(n, p2p, delay, jitter, bw): def create_topo(n, p2p, delay, jitter, bw):
nodes = [] nodes = []
interfaces = [] interfaces = []
links = [] switchs = []
for i in range(n): for i in range(n):
nodes.append(netns.Node()) nodes.append(netns.Node())
if p2p: if p2p:
...@@ -197,12 +197,12 @@ def create_topo(n, p2p, delay, jitter, bw): ...@@ -197,12 +197,12 @@ def create_topo(n, p2p, delay, jitter, bw):
right = None right = None
interfaces.append((left, right)) interfaces.append((left, right))
for i in range(n - 1): for i in range(n - 1):
link = netns.Link(bandwidth = bw, delay = delay, switch = netns.Switch(bandwidth = bw, delay = delay,
delay_jitter = jitter) delay_jitter = jitter)
link.up = True switch.up = True
link.connect(interfaces[i][1]) switch.connect(interfaces[i][1])
link.connect(interfaces[i + 1][0]) switch.connect(interfaces[i + 1][0])
links.append(link) switchs.append(switch)
for i in range(n): for i in range(n):
for j in (0, 1): for j in (0, 1):
...@@ -222,7 +222,7 @@ def create_topo(n, p2p, delay, jitter, bw): ...@@ -222,7 +222,7 @@ def create_topo(n, p2p, delay, jitter, bw):
nexthop = dec2ip(ipbase + 4 * i + 2)) nexthop = dec2ip(ipbase + 4 * i + 2))
nodes[n - 1 - i].add_route(prefix = "10.0.0.0", prefix_len = 30, nodes[n - 1 - i].add_route(prefix = "10.0.0.0", prefix_len = 30,
nexthop = dec2ip(ipbase + (n - 2 - i) * 4 + 1)) nexthop = dec2ip(ipbase + (n - 2 - i) * 4 + 1))
return nodes, interfaces, links return nodes, interfaces, switchs
if __name__ == "__main__": if __name__ == "__main__":
main() main()
...@@ -29,9 +29,9 @@ if1 = b.add_if(mtu = 1492) ...@@ -29,9 +29,9 @@ if1 = b.add_if(mtu = 1492)
# for using with a tun device, to connect to the outside world # for using with a tun device, to connect to the outside world
if2 = b.import_if('tun0') if2 = b.import_if('tun0')
# each Link is a linux bridge, all the parameters are applied to the associated # each Switch is a linux bridge, all the parameters are applied to the associated
# interfaces as tc qdiscs. # interfaces as tc qdiscs.
link0 = netns.Link(bandwidth = 100 * 1024 * 1024, switch0 = netns.Switch(bandwidth = 100 * 1024 * 1024,
delay = 0.01, delay_jitter = 0.001, delay = 0.01, delay_jitter = 0.001,
delay_correlation = 0.25, delay_distribution = 'normal', delay_correlation = 0.25, delay_distribution = 'normal',
loss = 0.005, loss_correlation = 0.20, loss = 0.005, loss_correlation = 0.20,
...@@ -39,13 +39,13 @@ link0 = netns.Link(bandwidth = 100 * 1024 * 1024, ...@@ -39,13 +39,13 @@ link0 = netns.Link(bandwidth = 100 * 1024 * 1024,
corrupt = 0.005, corrupt_correlation = 0.25) corrupt = 0.005, corrupt_correlation = 0.25)
# connect to the bridge # connect to the bridge
link0.connect(if0) switch0.connect(if0)
link0.connect(if1) switch0.connect(if1)
# Should be experimented with Tom Geoff's patch to see if the bridge could be # 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 # avoided; but for that the API would be slightly different, as these would be
# point-to-point interfaces and links. # point-to-point interfaces and links.
# ppp0 = netns.PPPLink(a, b, bandwidth = ....) # ppp0 = netns.PPPSwitch(a, b, bandwidth = ....)
# if0 = ppp0.interface(a) # if0 = ppp0.interface(a)
# For now, we have simple P2P interfaces: # For now, we have simple P2P interfaces:
...@@ -54,9 +54,9 @@ link0.connect(if1) ...@@ -54,9 +54,9 @@ link0.connect(if1)
# Add and connect a tap device (as if a external router were plugged into a # Add and connect a tap device (as if a external router were plugged into a
# switch) # switch)
if2 = netns.ImportedInterface('tap0') if2 = netns.ImportedInterface('tap0')
link0.connect(if2) switch0.connect(if2)
link0.up = True switch0.up = True
if0.up = True if0.up = True
if1.up = True if1.up = True
...@@ -79,7 +79,7 @@ stats = if0.get_stats() ...@@ -79,7 +79,7 @@ stats = if0.get_stats()
routes = a.get_routes() routes = a.get_routes()
ifaces = a.get_interfaces() ifaces = a.get_interfaces()
nodes = netns.get_nodes() nodes = netns.get_nodes()
links = netns.get_links() switches = netns.get_switches()
stats = link0.get_stats() stats = link0.get_stats()
# Run a process in background # Run a process in background
...@@ -108,9 +108,9 @@ def setup_linear_topology(n, bd, delay): ...@@ -108,9 +108,9 @@ def setup_linear_topology(n, bd, delay):
if2 = nodes[i + 1].add_if() if2 = nodes[i + 1].add_if()
if1.add_v4_address(addr = ('10.0.%d.2' % i), prefix_len = 24) 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) if2.add_v4_address(addr = ('10.0.%d.1' % i), prefix_len = 24)
link = netns.Link(bandwidth = bd, delay = delay) switch = netns.Switch(bandwidth = bd, delay = delay)
link.connect(if1) switch.connect(if1)
link.connect(if2) switch.connect(if2)
for i in range(n): for i in range(n):
for j in range(n): for j in range(n):
......
...@@ -169,7 +169,7 @@ class P2PInterface(NSInterface): ...@@ -169,7 +169,7 @@ class P2PInterface(NSInterface):
self._slave = None self._slave = None
class ImportedNodeInterface(NSInterface): class ImportedNodeInterface(NSInterface):
"""Class to handle already existing interfaces inside a name spac: """Class to handle already existing interfaces inside a name space:
real devices, tun devices, etc. real devices, tun devices, etc.
The flag 'migrate' in the constructor indicates that the interface was migrated The flag 'migrate' in the constructor indicates that the interface was migrated
inside the name space. inside the name space.
...@@ -203,6 +203,30 @@ class ImportedNodeInterface(NSInterface): ...@@ -203,6 +203,30 @@ class ImportedNodeInterface(NSInterface):
netns.iproute.set_if(self._original_state) netns.iproute.set_if(self._original_state)
self._slave = None self._slave = None
class TapNodeInterface(NSInterface):
"""Class to create a tap interface inside a name space, it
can be connected to a Switch object with emulation of link
characteristics."""
def __init__(self, node):
"""Create a new tap interface. 'node' is the name space in which this
interface should be put."""
iface = netns.iproute.interface(name = self._gen_if_name())
self._fd = netns.iproute.create_tap(iface)
netns.iproute.change_netns(iface.name, node.pid)
iface = node.get_interface(iface.name)
super(TapNodeInterface, self).__init__(node, iface.index)
@property
def fd(self):
return self._fd
def destroy(self):
if self._fd:
try:
os.close(self._fd)
except:
pass
class ExternalInterface(Interface): class ExternalInterface(Interface):
"""Add user-facing methods for interfaces that run in the main namespace.""" """Add user-facing methods for interfaces that run in the main namespace."""
@property @property
...@@ -257,7 +281,7 @@ class ExternalInterface(Interface): ...@@ -257,7 +281,7 @@ class ExternalInterface(Interface):
return ret return ret
class SlaveInterface(ExternalInterface): class SlaveInterface(ExternalInterface):
"""Class to handle the main-name-space-facing couples of Nodeinterface. """Class to handle the main-name-space-facing half of NodeInterface.
Does nothing, just avoids any destroy code.""" Does nothing, just avoids any destroy code."""
def destroy(self): def destroy(self):
pass pass
......
# vim:ts=4:sw=4:et:ai:sts=4 # vim:ts=4:sw=4:et:ai:sts=4
import copy, os, re, socket, subprocess, sys import copy, os, re, socket, subprocess, sys, struct
from fcntl import ioctl
from netns.environ import * from netns.environ import *
# helpers # helpers
...@@ -895,3 +896,19 @@ def set_tc(iface, bandwidth = None, delay = None, delay_jitter = None, ...@@ -895,3 +896,19 @@ def set_tc(iface, bandwidth = None, delay = None, delay_jitter = None,
for c in commands: for c in commands:
execute(c) execute(c)
def create_tap(iface):
"""Creates a tap device and returns the associated file descriptor"""
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
TUNSETIFF = 0x400454ca
mode = IFF_TAP | IFF_NO_PI
fd = os.open("/dev/net/tun", os.O_RDWR)
if fd == -1:
raise RuntimeError("Could not open /dev/net/tun")
err = ioctl(fd, TUNSETIFF, struct.pack("16sH", iface.name, mode))
if err < 0:
os.close(fd)
raise RuntimeError("Could not configure device %s" % iface.name)
return fd
...@@ -96,6 +96,12 @@ class Node(object): ...@@ -96,6 +96,12 @@ class Node(object):
setattr(i, k, v) setattr(i, k, v)
return i return i
def add_tap(self, **kwargs):
i = netns.interface.TapNodeInterface(self)
for k, v in kwargs.items():
setattr(i, k, v)
return i
def import_if(self, interface): def import_if(self, interface):
return netns.interface.ImportedNodeInterface(self, interface) return netns.interface.ImportedNodeInterface(self, interface)
......
#!/usr/bin/env python #!/usr/bin/env python
# vim:ts=4:sw=4:et:ai:sts=4 # vim:ts=4:sw=4:et:ai:sts=4
import grp, os, pwd, time, unittest import grp, os, pwd, time, threading, unittest
import netns, test_util import netns, test_util
class TestConfigure(unittest.TestCase): class TestConfigure(unittest.TestCase):
...@@ -51,7 +51,7 @@ class TestGlobal(unittest.TestCase): ...@@ -51,7 +51,7 @@ class TestGlobal(unittest.TestCase):
i1 = n1.add_if() i1 = n1.add_if()
i2 = n2.add_if() i2 = n2.add_if()
i1.up = i2.up = True i1.up = i2.up = True
l = netns.Link() l = netns.Switch()
l.connect(i1) l.connect(i1)
l.connect(i2) l.connect(i2)
l.up = True l.up = True
...@@ -74,8 +74,8 @@ class TestGlobal(unittest.TestCase): ...@@ -74,8 +74,8 @@ class TestGlobal(unittest.TestCase):
i2b = n2.add_if() i2b = n2.add_if()
i3 = n3.add_if() i3 = n3.add_if()
i1.up = i2a.up = i2b.up = i3.up = True i1.up = i2a.up = i2b.up = i3.up = True
l1 = netns.Link() l1 = netns.Switch()
l2 = netns.Link() l2 = netns.Switch()
l1.connect(i1) l1.connect(i1)
l1.connect(i2a) l1.connect(i2a)
l2.connect(i2b) l2.connect(i2b)
...@@ -95,5 +95,64 @@ class TestGlobal(unittest.TestCase): ...@@ -95,5 +95,64 @@ class TestGlobal(unittest.TestCase):
self.assertEquals(a1.wait(), 0) self.assertEquals(a1.wait(), 0)
self.assertEquals(a2.wait(), 0) self.assertEquals(a2.wait(), 0)
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def test_run_ping_tap(self):
"""This test simulates a point to point connection between two hosts using two tap devices"""
class ChannelThread:
def __init__(self):
self.stop = False
self.thread = None
def _run(self, fd1, fd2):
while not self.stop:
s = os.read(fd1, 65536)
os.write(fd2, s)
def start(self, fd1, fd2):
self.thread = threading.Thread(target = self._run, args=[fd1, fd2])
self.thread.start()
n1 = netns.Node()
n2 = netns.Node()
i1 = n1.add_if()
tap1 = n1.add_tap()
tap2 = n2.add_tap()
i2 = n2.add_if()
i1.up = tap1.up = tap2.up = i2.up = True
i1.add_v4_address('10.0.0.1', 24)
tap1.add_v4_address('10.0.1.1', 24)
tap2.add_v4_address('10.0.1.2', 24)
i2.add_v4_address('10.0.2.2', 24)
n2.add_route(prefix = '10.0.0.0', prefix_len = 24, nexthop = '10.0.1.2')
n1.add_route(prefix = '10.0.2.0', prefix_len = 24, nexthop = '10.0.1.1')
# communication forth between the two taps
thread1 = ChannelThread()
thread1.start(tap1.fd, tap2.fd)
# communication back between the two taps
thread2 = ChannelThread()
thread2.start(tap2.fd, tap1.fd)
null = file('/dev/null', 'wb')
a = n1.Popen(['ping', '-qc1', '10.0.2.1'], stdout = null)
self.assertEquals(a.wait(), 0)
print 'jhola'
thread1.stop = True
thread2.stop = True
os.write(tap1.fd, "0")
os.write(tap2.fd, "0")
thread1.thread.join()
thread2.thread.join()
print 'lalala'
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -29,7 +29,7 @@ class TestInterfaces(unittest.TestCase): ...@@ -29,7 +29,7 @@ class TestInterfaces(unittest.TestCase):
devs = get_devs_netns(node0) devs = get_devs_netns(node0)
for i in range(5): for i in range(5):
self.assertFalse(devs['lo']['up']) self.assertTrue(devs['lo']['up'])
self.assertTrue(ifaces[i].name in devs) self.assertTrue(ifaces[i].name in devs)
node_devs = set(node0.get_interfaces()) node_devs = set(node0.get_interfaces())
......
...@@ -37,9 +37,9 @@ class TestNode(unittest.TestCase): ...@@ -37,9 +37,9 @@ class TestNode(unittest.TestCase):
b = netns.Node() b = netns.Node()
ifa = a.add_if() ifa = a.add_if()
ifb = b.add_if() ifb = b.add_if()
link = netns.Link() switch = netns.Switch()
link.connect(ifa) switch.connect(ifa)
link.connect(ifb) switch.connect(ifb)
# Test automatic destruction # Test automatic destruction
orig_devs = len(test_util.get_devs()) orig_devs = len(test_util.get_devs())
......
...@@ -4,20 +4,20 @@ ...@@ -4,20 +4,20 @@
import os, unittest import os, unittest
import netns, test_util, netns.environ import netns, test_util, netns.environ
class TestLink(unittest.TestCase): class TestSwitch(unittest.TestCase):
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges") @test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def setUp(self): def setUp(self):
n1 = netns.Node() n1 = netns.Node()
n2 = netns.Node() n2 = netns.Node()
i1 = n1.add_if() i1 = n1.add_if()
i2 = n2.add_if() i2 = n2.add_if()
l = netns.Link() l = netns.Switch()
l.connect(i1) l.connect(i1)
l.connect(i2) l.connect(i2)
self.stuff = (n1, n2, i1, i2, l) self.stuff = (n1, n2, i1, i2, l)
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges") @test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def test_link_base(self): def test_switch_base(self):
(n1, n2, i1, i2, l) = self.stuff (n1, n2, i1, i2, l) = self.stuff
l.mtu = 3000 l.mtu = 3000
ifdata = netns.iproute.get_if_data()[0] ifdata = netns.iproute.get_if_data()[0]
...@@ -40,7 +40,7 @@ class TestLink(unittest.TestCase): ...@@ -40,7 +40,7 @@ class TestLink(unittest.TestCase):
self.assertEquals(tcdata[i2.control.index], {"qdiscs": {}}) self.assertEquals(tcdata[i2.control.index], {"qdiscs": {}})
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges") @test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def test_link_changes(self): def test_switch_changes(self):
(n1, n2, i1, i2, l) = self.stuff (n1, n2, i1, i2, l) = self.stuff
# Test strange rules handling # Test strange rules handling
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment