Merge "Implement multipath routing in route commands"

This commit is contained in:
Zuul 2021-05-06 06:42:49 +00:00 committed by Gerrit Code Review
commit 9e9488be86
2 changed files with 69 additions and 7 deletions

View File

@ -295,6 +295,11 @@ def _run_iproute_addr(command, device, namespace, **kwargs):
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
def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope,
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 cidr: (string) source IP or CIDR address (IPv4, IPv6)
: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 metric: (int) route metric
:param scope: (int) route scope
@ -713,16 +719,29 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table,
args['scope'] = scope
if cidr:
args['dst'] = cidr
if device:
args['oif'] = get_link_id(device, namespace)
if via:
args['gateway'] = via
if table:
args['table'] = int(table)
if metric:
args['priority'] = int(metric)
if 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

View File

@ -476,6 +476,34 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
self.device = ip_lib.IPDevice(self.device_name, self.namespace)
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,
scope=None, proto='static'):
table = table or iproute_linux.DEFAULT_TABLE
@ -499,8 +527,7 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
self.assertEqual(
priv_ip_lib._IP_VERSION_FAMILY_MAP[ip_version],
route['family'])
self.assertEqual(gateway,
ip_lib.get_attr(route, 'RTA_GATEWAY'))
self._check_gateway_or_multipath(route, gateway)
self.assertEqual(metric,
ip_lib.get_attr(route, 'RTA_PRIORITY'))
self.assertEqual(scope, route['scope'])
@ -616,6 +643,22 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
device=self.device_name, via=_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):