Commit 546472f4 authored by Martín Ferrari's avatar Martín Ferrari

many fixes to the routing code, seems to work

parent 3006f202
...@@ -224,38 +224,38 @@ class route(object): ...@@ -224,38 +224,38 @@ class route(object):
prefix = property(_make_getter("_prefix"), prefix = property(_make_getter("_prefix"),
_make_setter("_prefix", _non_empty_str)) _make_setter("_prefix", _non_empty_str))
prefix_len = property(_make_getter("_plen"), prefix_len = property(_make_getter("_plen"),
_make_setter("_plen", int)) lambda s, v: setattr(s, '_plen', int(v or 0)))
nexthop = property(_make_getter("_nexthop"), nexthop = property(_make_getter("_nexthop"),
_make_setter("_nexthop", _non_empty_str)) _make_setter("_nexthop", _non_empty_str))
interface = property(_make_getter("_interface"),
_make_setter("_interface", _positive))
metric = property(_make_getter("_metric"), metric = property(_make_getter("_metric"),
_make_setter("_metric", int)) lambda s, v: setattr(s, '_metric', int(v or 0)))
device = property(_make_getter("_device"),
_make_setter("_device", _positive))
def __init__(self, tipe = 'unicast', prefix = None, prefix_len = 0, def __init__(self, tipe = 'unicast', prefix = None, prefix_len = 0,
nexthop = None, device = None, metric = 0): nexthop = None, interface = None, metric = 0):
self.tipe = tipe self.tipe = tipe
self.prefix = prefix self.prefix = prefix
self.prefix_len = prefix_len self.prefix_len = prefix_len
self.nexthop = nexthop self.nexthop = nexthop
self.device = device self.interface = interface
self.metric = metric self.metric = metric
assert nexthop or device assert nexthop or interface
def __repr__(self): def __repr__(self):
s = "%s.%s(tipe = %s, prefix = %s, prefix_len = %s, nexthop = %s, " s = "%s.%s(tipe = %s, prefix = %s, prefix_len = %s, nexthop = %s, "
s += "device = %s, metric = %s)" s += "interface = %s, metric = %s)"
return s % (self.__module__, self.__class__.__name__, return s % (self.__module__, self.__class__.__name__,
self.tipe.__repr__(), self.prefix.__repr__(), self.tipe.__repr__(), self.prefix.__repr__(),
self.prefix_len.__repr__(), self.nexthop.__repr__(), self.prefix_len.__repr__(), self.nexthop.__repr__(),
self.device.__repr__(), self.metric.__repr__()) self.interface.__repr__(), self.metric.__repr__())
def __eq__(self, o): def __eq__(self, o):
if not isinstance(o, route): if not isinstance(o, route):
return False return False
return (self.tipe == o.tipe and self.prefix == o.prefix and return (self.tipe == o.tipe and self.prefix == o.prefix and
self.prefix_len == o.prefix_len and self.nexthop == o.nexthop self.prefix_len == o.prefix_len and self.nexthop == o.nexthop
and self.device == o.device and self.metric == o.metric) and self.interface == o.interface and self.metric == o.metric)
# helpers # helpers
def _execute(cmd): def _execute(cmd):
...@@ -614,19 +614,23 @@ def get_all_route_data(): ...@@ -614,19 +614,23 @@ def get_all_route_data():
continue continue
match = re.match(r'(?:(unicast|local|broadcast|multicast|throw|' + match = re.match(r'(?:(unicast|local|broadcast|multicast|throw|' +
r'unreachable|prohibit|blackhole|nat) )?' + r'unreachable|prohibit|blackhole|nat) )?' +
r'(\S+)(?: via (\S+))? dev (\S+)', line) r'(\S+)(?: via (\S+))? dev (\S+).*(?: metric (\d+))?', line)
if not match: if not match:
raise RuntimeError("Invalid output from `ip route'") raise RuntimeError("Invalid output from `ip route': `%s'" % line)
tipe = match.group(1) or 'unicast' tipe = match.group(1) or 'unicast'
prefix = match.group(2) prefix = match.group(2)
nexthop = match.group(3) nexthop = match.group(3)
device = ifdata[match.group(4)] interface = ifdata[match.group(4)]
metric = match.group(5)
if prefix == 'default' or re.search(r'/0$', prefix): if prefix == 'default' or re.search(r'/0$', prefix):
prefix = None prefix = None
prefix_len = 0 prefix_len = 0
else: else:
prefix, foo, prefix_len = prefix.partition('/') match = re.match(r'([0-9a-f:.]+)(?:/(\d+))?$', prefix)
ret.append(route(tipe, prefix, prefix_len, nexthop, device.index)) prefix = match.group(1)
prefix_len = int(match.group(2) or 32)
ret.append(route(tipe, prefix, prefix_len, nexthop, interface.index,
metric))
return ret return ret
def get_route_data(): def get_route_data():
...@@ -653,6 +657,6 @@ def _add_del_route(action, route): ...@@ -653,6 +657,6 @@ def _add_del_route(action, route):
cmd += ['default'] cmd += ['default']
if route.nexthop: if route.nexthop:
cmd += ['via', route.nexthop] cmd += ['via', route.nexthop]
if route.device: if route.interface:
cmd += ['dev', _get_if_name(route.device)] cmd += ['dev', _get_if_name(route.interface)]
_execute(cmd) _execute(cmd)
...@@ -85,8 +85,8 @@ class Node(object): ...@@ -85,8 +85,8 @@ class Node(object):
def del_if(self, iface): def del_if(self, iface):
"""Doesn't destroy the interface if it wasn't created by us.""" """Doesn't destroy the interface if it wasn't created by us."""
iface.destroy()
del self._interfaces[iface.index] del self._interfaces[iface.index]
iface.destroy()
def get_interfaces(self): def get_interfaces(self):
ifaces = self._slave.get_if_data() ifaces = self._slave.get_if_data()
...@@ -105,19 +105,24 @@ class Node(object): ...@@ -105,19 +105,24 @@ class Node(object):
return sorted(ret, key = lambda x: x.index) return sorted(ret, key = lambda x: x.index)
def route(self, tipe = 'unicast', prefix = None, prefix_len = 0,
nexthop = None, interface = None, metric = 0):
return netns.iproute.route(tipe, prefix, prefix_len, nexthop,
interface.index if interface else None, metric)
def add_route(self, *args, **kwargs): def add_route(self, *args, **kwargs):
# Accepts either a route object or all its constructor's parameters # Accepts either a route object or all its constructor's parameters
if len(args) == 1 and not kwargs: if len(args) == 1 and not kwargs:
r = args[0] r = args[0]
else: else:
r = netns.iproute.route(*args, **kwargs) r = self.route(*args, **kwargs)
return self._slave.add_route(r) return self._slave.add_route(r)
def del_route(self, *args, **kwargs): def del_route(self, *args, **kwargs):
if len(args) == 1 and not kwargs: if len(args) == 1 and not kwargs:
r = args[0] r = args[0]
else: else:
r = netns.iproute.route(*args, **kwargs) r = self.route(*args, **kwargs)
return self._slave.del_route(r) return self._slave.del_route(r)
def get_routes(self): def get_routes(self):
......
...@@ -382,13 +382,13 @@ class Server(object): ...@@ -382,13 +382,13 @@ class Server(object):
def do_ROUT_ADD(self, cmdname, tipe, prefix, prefixlen, nexthop, ifnr, def do_ROUT_ADD(self, cmdname, tipe, prefix, prefixlen, nexthop, ifnr,
metric): metric):
netns.iproute.add_route(netns.iproute.route(tipe, prefix, prefixlen, netns.iproute.add_route(netns.iproute.route(tipe, prefix, prefixlen,
nexthop, ifnr, metric)) nexthop, ifnr or None, metric))
self.reply(200, "Done.") self.reply(200, "Done.")
def do_ROUT_DEL(self, cmdname, tipe, prefix, prefixlen, nexthop, ifnr, def do_ROUT_DEL(self, cmdname, tipe, prefix, prefixlen, nexthop, ifnr,
metric): metric):
netns.iproute.del_route(netns.iproute.route(tipe, prefix, prefixlen, netns.iproute.del_route(netns.iproute.route(tipe, prefix, prefixlen,
nexthop, ifnr, metric)) nexthop, ifnr or None, metric))
self.reply(200, "Done.") self.reply(200, "Done.")
# ============================================================================ # ============================================================================
...@@ -598,8 +598,8 @@ class Client(object): ...@@ -598,8 +598,8 @@ class Client(object):
def _add_del_route(self, action, route): def _add_del_route(self, action, route):
args = ["ROUT", action, _b64(route.tipe), _b64(route.prefix), args = ["ROUT", action, _b64(route.tipe), _b64(route.prefix),
route.prefix_len, _b64(route.nexthop), route.device, route.prefix_len or 0, _b64(route.nexthop),
route.metric] route.interface or 0, route.metric or 0]
self._send_cmd(*args) self._send_cmd(*args)
self._read_and_check_reply() self._read_and_check_reply()
......
...@@ -10,15 +10,20 @@ class TestRouting(unittest.TestCase): ...@@ -10,15 +10,20 @@ class TestRouting(unittest.TestCase):
routes = node.get_routes() routes = node.get_routes()
if(len(routes)): if(len(routes)):
self.assertRaises(ValueError, node.add_route, routes[0]) self.assertRaises(ValueError, node.add_route, routes[0])
routes[0].device += 1 # should be enough to make it unique routes[0].interface += 1 # should be enough to make it unique
self.assertRaises(ValueError, node.del_route, routes[0]) self.assertRaises(ValueError, node.del_route, routes[0])
@test_util.skipUnless(os.getuid() == 0, "Test requires root privileges") @test_util.skipUnless(os.getuid() == 0, "Test requires root privileges")
def test_routing(self): def test_routing(self):
node = netns.Node() node = netns.Node()
self.assertEquals(len(node.get_routes()), 0)
if0 = node.add_if() if0 = node.add_if()
if0.add_v4_address('10.0.0.1', 24) if0.add_v4_address('10.0.0.1', 24)
node.add_default_route(nexthop = '10.0.0.2') if0.up = True
self.assertEquals(len(node.get_routes()), 1)
node.add_route(nexthop = '10.0.0.2') # default route
node.add_route(prefix = '10.1.0.0', prefix_len = 16, node.add_route(prefix = '10.1.0.0', prefix_len = 16,
nexthop = '10.0.0.3') nexthop = '10.0.0.3')
node.add_route(prefix = '11.1.0.1', prefix_len = 32, interface = if0) node.add_route(prefix = '11.1.0.1', prefix_len = 32, interface = if0)
......
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