Merge "Implement multipath routing in route commands"
This commit is contained in:
commit
9e9488be86
|
@ -295,6 +295,11 @@ def _run_iproute_addr(command, device, namespace, **kwargs):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.default.entrypoint
|
||||||
|
def privileged_get_link_id(device, namespace, raise_exception=True):
|
||||||
|
return get_link_id(device, namespace, raise_exception=raise_exception)
|
||||||
|
|
||||||
|
|
||||||
@privileged.default.entrypoint
|
@privileged.default.entrypoint
|
||||||
def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope,
|
def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope,
|
||||||
broadcast=None):
|
broadcast=None):
|
||||||
|
@ -698,7 +703,8 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table,
|
||||||
:param ip_version: (int) [4, 6]
|
:param ip_version: (int) [4, 6]
|
||||||
:param cidr: (string) source IP or CIDR address (IPv4, IPv6)
|
:param cidr: (string) source IP or CIDR address (IPv4, IPv6)
|
||||||
:param device: (string) input interface name
|
:param device: (string) input interface name
|
||||||
:param via: (string) gateway IP address
|
:param via: (string) gateway IP address or (list of dicts) for multipath
|
||||||
|
definition.
|
||||||
:param table: (string, int) table number or name
|
:param table: (string, int) table number or name
|
||||||
:param metric: (int) route metric
|
:param metric: (int) route metric
|
||||||
:param scope: (int) route scope
|
:param scope: (int) route scope
|
||||||
|
@ -713,16 +719,29 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table,
|
||||||
args['scope'] = scope
|
args['scope'] = scope
|
||||||
if cidr:
|
if cidr:
|
||||||
args['dst'] = cidr
|
args['dst'] = cidr
|
||||||
if device:
|
|
||||||
args['oif'] = get_link_id(device, namespace)
|
|
||||||
if via:
|
|
||||||
args['gateway'] = via
|
|
||||||
if table:
|
if table:
|
||||||
args['table'] = int(table)
|
args['table'] = int(table)
|
||||||
if metric:
|
if metric:
|
||||||
args['priority'] = int(metric)
|
args['priority'] = int(metric)
|
||||||
if protocol:
|
if protocol:
|
||||||
args['proto'] = protocol
|
args['proto'] = protocol
|
||||||
|
if isinstance(via, (list, tuple)):
|
||||||
|
args['multipath'] = []
|
||||||
|
for mp in via:
|
||||||
|
multipath = {}
|
||||||
|
if mp.get('device'):
|
||||||
|
multipath['oif'] = get_link_id(mp['device'], namespace)
|
||||||
|
if mp.get('via'):
|
||||||
|
multipath['gateway'] = mp['via']
|
||||||
|
if mp.get('weight'):
|
||||||
|
multipath['hops'] = mp['weight'] - 1
|
||||||
|
args['multipath'].append(multipath)
|
||||||
|
else:
|
||||||
|
if via:
|
||||||
|
args['gateway'] = via
|
||||||
|
if device:
|
||||||
|
args['oif'] = get_link_id(device, namespace)
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -476,6 +476,34 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
|
||||||
self.device = ip_lib.IPDevice(self.device_name, self.namespace)
|
self.device = ip_lib.IPDevice(self.device_name, self.namespace)
|
||||||
self.device.link.set_up()
|
self.device.link.set_up()
|
||||||
|
|
||||||
|
def _check_gateway_or_multipath(self, route, gateway):
|
||||||
|
if gateway is None or isinstance(gateway, str):
|
||||||
|
self.assertEqual(gateway, ip_lib.get_attr(route, 'RTA_GATEWAY'))
|
||||||
|
return
|
||||||
|
|
||||||
|
rta_multipath = ip_lib.get_attr(route, 'RTA_MULTIPATH')
|
||||||
|
self.assertEqual(len(gateway), len(rta_multipath))
|
||||||
|
for nexthop in gateway:
|
||||||
|
to_check = {'hops': 0}
|
||||||
|
if nexthop.get('device'):
|
||||||
|
to_check['oif'] = priv_ip_lib.privileged_get_link_id(
|
||||||
|
nexthop['device'], self.namespace)
|
||||||
|
if nexthop.get('weight'):
|
||||||
|
to_check['hops'] = nexthop['weight'] - 1
|
||||||
|
if nexthop.get('via'):
|
||||||
|
to_check['gateway'] = nexthop['via']
|
||||||
|
|
||||||
|
for mp in rta_multipath:
|
||||||
|
mp['gateway'] = ip_lib.get_attr(mp, 'RTA_GATEWAY')
|
||||||
|
for key in to_check:
|
||||||
|
if to_check[key] != mp[key]:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.fail('Route nexthops %s do not match with defined ones '
|
||||||
|
'%s' % (rta_multipath, gateway))
|
||||||
|
|
||||||
def _check_routes(self, cidrs, table=None, gateway=None, metric=None,
|
def _check_routes(self, cidrs, table=None, gateway=None, metric=None,
|
||||||
scope=None, proto='static'):
|
scope=None, proto='static'):
|
||||||
table = table or iproute_linux.DEFAULT_TABLE
|
table = table or iproute_linux.DEFAULT_TABLE
|
||||||
|
@ -499,8 +527,7 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
priv_ip_lib._IP_VERSION_FAMILY_MAP[ip_version],
|
priv_ip_lib._IP_VERSION_FAMILY_MAP[ip_version],
|
||||||
route['family'])
|
route['family'])
|
||||||
self.assertEqual(gateway,
|
self._check_gateway_or_multipath(route, gateway)
|
||||||
ip_lib.get_attr(route, 'RTA_GATEWAY'))
|
|
||||||
self.assertEqual(metric,
|
self.assertEqual(metric,
|
||||||
ip_lib.get_attr(route, 'RTA_PRIORITY'))
|
ip_lib.get_attr(route, 'RTA_PRIORITY'))
|
||||||
self.assertEqual(scope, route['scope'])
|
self.assertEqual(scope, route['scope'])
|
||||||
|
@ -616,6 +643,22 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
|
||||||
device=self.device_name, via=_ip)
|
device=self.device_name, via=_ip)
|
||||||
self._check_gateway(_ip)
|
self._check_gateway(_ip)
|
||||||
|
|
||||||
|
def test_add_multipath_route(self):
|
||||||
|
self.device_name2 = 'test_device2'
|
||||||
|
ip_lib.IPWrapper(self.namespace).add_dummy(self.device_name2)
|
||||||
|
self.device2 = ip_lib.IPDevice(self.device_name2, self.namespace)
|
||||||
|
self.device2.link.set_up()
|
||||||
|
self.device.addr.add('10.1.0.1/24')
|
||||||
|
self.device2.addr.add('10.2.0.1/24')
|
||||||
|
multipath = [
|
||||||
|
{'device': self.device_name, 'via': '10.1.0.100', 'weight': 10},
|
||||||
|
{'device': self.device_name2, 'via': '10.2.0.100', 'weight': 20},
|
||||||
|
{'via': '10.2.0.101', 'weight': 30},
|
||||||
|
{'via': '10.2.0.102'}]
|
||||||
|
priv_ip_lib.add_ip_route(self.namespace, '192.168.0.0/24',
|
||||||
|
n_cons.IP_VERSION_4, via=multipath)
|
||||||
|
self._check_routes(['192.168.0.0/24'], gateway=multipath)
|
||||||
|
|
||||||
|
|
||||||
class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
|
class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue