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):
f.write(" -s, --pktsize=BYTES Size of packet payload\n\n")
f.write("Topology configuration:\n")
f.write(" --use-p2p Use P2P links, to avoid bridging\n")
f.write(" --delay=SECS Add delay emulation in links\n")
f.write(" --jitter=PERCENT Add jitter emulation in links\n")
f.write(" --bandwidth=BPS Maximum bandwidth of links\n\n")
f.write(" --use-p2p Use P2P switchs, to avoid bridging\n")
f.write(" --delay=SECS Add delay emulation in switchs\n")
f.write(" --jitter=PERCENT Add jitter emulation in switchs\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(" -t, --time=SECS Stop after SECS seconds\n")
......@@ -89,7 +89,7 @@ def main():
elif not pktsize:
error = "Missing mandatory --pktsize argument"
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:
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), error))
......@@ -106,7 +106,7 @@ def main():
if not 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)
cmdline = [udp_perf, "--server"]
......@@ -174,7 +174,7 @@ def dec2ip(dec):
def create_topo(n, p2p, delay, jitter, bw):
nodes = []
interfaces = []
links = []
switchs = []
for i in range(n):
nodes.append(netns.Node())
if p2p:
......@@ -197,12 +197,12 @@ def create_topo(n, p2p, delay, jitter, bw):
right = None
interfaces.append((left, right))
for i in range(n - 1):
link = netns.Link(bandwidth = bw, delay = delay,
switch = netns.Switch(bandwidth = bw, delay = delay,
delay_jitter = jitter)
link.up = True
link.connect(interfaces[i][1])
link.connect(interfaces[i + 1][0])
links.append(link)
switch.up = True
switch.connect(interfaces[i][1])
switch.connect(interfaces[i + 1][0])
switchs.append(switch)
for i in range(n):
for j in (0, 1):
......@@ -222,7 +222,7 @@ def create_topo(n, p2p, delay, jitter, bw):
nexthop = dec2ip(ipbase + 4 * i + 2))
nodes[n - 1 - i].add_route(prefix = "10.0.0.0", prefix_len = 30,
nexthop = dec2ip(ipbase + (n - 2 - i) * 4 + 1))
return nodes, interfaces, links
return nodes, interfaces, switchs
if __name__ == "__main__":
main()
......@@ -29,9 +29,9 @@ if1 = b.add_if(mtu = 1492)
# for using with a tun device, to connect to the outside world
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.
link0 = netns.Link(bandwidth = 100 * 1024 * 1024,
switch0 = netns.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,
......@@ -39,13 +39,13 @@ link0 = netns.Link(bandwidth = 100 * 1024 * 1024,
corrupt = 0.005, corrupt_correlation = 0.25)
# connect to the bridge
link0.connect(if0)
link0.connect(if1)
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 = netns.PPPLink(a, b, bandwidth = ....)
# ppp0 = netns.PPPSwitch(a, b, bandwidth = ....)
# if0 = ppp0.interface(a)
# For now, we have simple P2P interfaces:
......@@ -54,9 +54,9 @@ link0.connect(if1)
# Add and connect a tap device (as if a external router were plugged into a
# switch)
if2 = netns.ImportedInterface('tap0')
link0.connect(if2)
switch0.connect(if2)
link0.up = True
switch0.up = True
if0.up = True
if1.up = True
......@@ -79,7 +79,7 @@ stats = if0.get_stats()
routes = a.get_routes()
ifaces = a.get_interfaces()
nodes = netns.get_nodes()
links = netns.get_links()
switches = netns.get_switches()
stats = link0.get_stats()
# Run a process in background
......@@ -108,9 +108,9 @@ def setup_linear_topology(n, bd, delay):
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)
link = netns.Link(bandwidth = bd, delay = delay)
link.connect(if1)
link.connect(if2)
switch = netns.Switch(bandwidth = bd, delay = delay)
switch.connect(if1)
switch.connect(if2)
for i in range(n):
for j in range(n):
......
......@@ -169,7 +169,7 @@ class P2PInterface(NSInterface):
self._slave = None
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.
The flag 'migrate' in the constructor indicates that the interface was migrated
inside the name space.
......@@ -203,6 +203,30 @@ class ImportedNodeInterface(NSInterface):
netns.iproute.set_if(self._original_state)
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):
"""Add user-facing methods for interfaces that run in the main namespace."""
@property
......@@ -257,7 +281,7 @@ class ExternalInterface(Interface):
return ret
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."""
def destroy(self):
pass
......
# 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 *
# helpers
......@@ -895,3 +896,19 @@ def set_tc(iface, bandwidth = None, delay = None, delay_jitter = None,
for c in commands:
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):
setattr(i, k, v)
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):
return netns.interface.ImportedNodeInterface(self, interface)
......
#!/usr/bin/env python
# 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
class TestConfigure(unittest.TestCase):
......@@ -51,7 +51,7 @@ class TestGlobal(unittest.TestCase):
i1 = n1.add_if()
i2 = n2.add_if()
i1.up = i2.up = True
l = netns.Link()
l = netns.Switch()
l.connect(i1)
l.connect(i2)
l.up = True
......@@ -74,8 +74,8 @@ class TestGlobal(unittest.TestCase):
i2b = n2.add_if()
i3 = n3.add_if()
i1.up = i2a.up = i2b.up = i3.up = True
l1 = netns.Link()
l2 = netns.Link()
l1 = netns.Switch()
l2 = netns.Switch()
l1.connect(i1)
l1.connect(i2a)
l2.connect(i2b)
......@@ -95,5 +95,64 @@ class TestGlobal(unittest.TestCase):
self.assertEquals(a1.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__':
unittest.main()
......@@ -29,7 +29,7 @@ class TestInterfaces(unittest.TestCase):
devs = get_devs_netns(node0)
for i in range(5):
self.assertFalse(devs['lo']['up'])
self.assertTrue(devs['lo']['up'])
self.assertTrue(ifaces[i].name in devs)
node_devs = set(node0.get_interfaces())
......
......@@ -37,9 +37,9 @@ class TestNode(unittest.TestCase):
b = netns.Node()
ifa = a.add_if()
ifb = b.add_if()
link = netns.Link()
link.connect(ifa)
link.connect(ifb)
switch = netns.Switch()
switch.connect(ifa)
switch.connect(ifb)
# Test automatic destruction
orig_devs = len(test_util.get_devs())
......
......@@ -4,20 +4,20 @@
import os, unittest
import netns, test_util, netns.environ
class TestLink(unittest.TestCase):
class TestSwitch(unittest.TestCase):
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def setUp(self):
n1 = netns.Node()
n2 = netns.Node()
i1 = n1.add_if()
i2 = n2.add_if()
l = netns.Link()
l = netns.Switch()
l.connect(i1)
l.connect(i2)
self.stuff = (n1, n2, i1, i2, l)
@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
l.mtu = 3000
ifdata = netns.iproute.get_if_data()[0]
......@@ -40,7 +40,7 @@ class TestLink(unittest.TestCase):
self.assertEquals(tcdata[i2.control.index], {"qdiscs": {}})
@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
# 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