Merge "Replace "get_routing_table" with "list_ip_routes"" into stable/wallaby

This commit is contained in:
Zuul 2023-02-17 00:33:51 +00:00 committed by Gerrit Code Review
commit 60b249b9f1
5 changed files with 74 additions and 59 deletions

View File

@ -1574,12 +1574,24 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None,
'source_prefix': get_attr(route, 'RTA_PREFSRC'),
'cidr': cidr,
'scope': IP_ADDRESS_SCOPE[int(route['scope'])],
'device': get_device(int(get_attr(route, 'RTA_OIF')), devices),
'via': get_attr(route, 'RTA_GATEWAY'),
'metric': metric,
'proto': proto,
}
multipath = get_attr(route, 'RTA_MULTIPATH')
if multipath:
value['device'] = None
mp_via = []
for mp in multipath:
mp_via.append({'device': get_device(int(mp['oif']), devices),
'via': get_attr(mp, 'RTA_GATEWAY'),
'weight': int(mp['hops']) + 1})
value['via'] = mp_via
else:
value['device'] = get_device(int(get_attr(route, 'RTA_OIF')),
devices)
value['via'] = get_attr(route, 'RTA_GATEWAY')
ret.append(value)
if scope:

View File

@ -40,7 +40,7 @@ NETNS_RUN_DIR = '/var/run/netns'
NUD_STATES = {state[1]: state[0] for state in ndmsg.states.items()}
def _get_scope_name(scope):
def get_scope_name(scope):
"""Return the name of the scope (given as a number), or the scope number
if the name is unknown.
@ -142,7 +142,6 @@ def _make_route_dict(destination, nexthop, device, scope):
@privileged.default.entrypoint
def get_routing_table(ip_version, namespace=None):
"""Return a list of dictionaries, each representing a route.
:param ip_version: IP version of routes to return, for example 4
:param namespace: The name of the namespace from which to get the routes
:return: a list of dictionaries, each representing a route.
@ -168,8 +167,7 @@ def get_routing_table(ip_version, namespace=None):
dst = route['dst']
nexthop = route.get('gateway')
oif = route.get('oif')
scope = _get_scope_name(route['scope'])
scope = get_scope_name(route['scope'])
# If there is not a valid outgoing interface id, check if
# this is a multipath route (i.e. same destination with
# multiple outgoing interfaces)
@ -313,7 +311,7 @@ def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope,
mask=prefixlen,
family=family,
broadcast=broadcast,
scope=_get_scope_name(scope))
scope=get_scope_name(scope))
except netlink_exceptions.NetlinkError as e:
if e.code == errno.EEXIST:
raise IpAddressAlreadyExists(ip=ip, device=device)
@ -755,7 +753,7 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table,
args = {'family': _IP_VERSION_FAMILY_MAP[ip_version]}
if not scope:
scope = 'global' if via else 'link'
scope = _get_scope_name(scope)
scope = get_scope_name(scope)
if scope:
args['scope'] = scope
if cidr:

View File

@ -575,9 +575,9 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
def _assert_extra_routes(self, router, namespace=None, enable_gw=True):
if namespace is None:
namespace = router.ns_name
routes = ip_lib.get_routing_table(4, namespace=namespace)
routes = [{'nexthop': route['nexthop'],
'destination': route['destination']} for route in routes]
routes = ip_lib.list_ip_routes(namespace, constants.IP_VERSION_4)
routes = [{'nexthop': route['via'],
'destination': route['cidr']} for route in routes]
for extra_route in router.router['routes']:
check = self.assertIn if enable_gw else self.assertNotIn
@ -588,17 +588,16 @@ class L3AgentTestFramework(base.BaseSudoTestCase):
ns_name = namespace or router.ns_name
routes = []
for ip_version in ip_versions:
_routes = ip_lib.get_routing_table(ip_version,
namespace=ns_name)
_routes = ip_lib.list_ip_routes(ns_name, ip_version)
routes.extend(_routes)
routes = set(route['destination'] for route in routes)
routes = set(route['cidr'] for route in routes)
ex_gw_port = router.get_ex_gw_port()
if not ex_gw_port:
if not enable_gw:
return
self.fail('GW port is enabled but not present in the router')
extra_subnets = ex_gw_port['extra_subnets']
extra_subnets = router.get_ex_gw_port()['extra_subnets']
for extra_subnet in (route['cidr'] for route in extra_subnets):
self.assertIn(extra_subnet, routes)

View File

@ -387,49 +387,6 @@ class IpLibTestCase(IpLibTestFramework):
self.assertIsNone(
device.route.get_gateway(ip_version=ip_version))
def test_get_routing_table(self):
attr = self.generate_device_details(
ip_cidrs=["%s/24" % TEST_IP, "fd00::1/64"]
)
device = self.manage_device(attr)
device_ip = attr.ip_cidrs[0].split('/')[0]
destination = '8.8.8.0/24'
device.route.add_route(destination, device_ip)
destination6 = 'fd01::/64'
device.route.add_route(destination6, "fd00::2")
expected_routes = [{'nexthop': device_ip,
'device': attr.name,
'destination': destination,
'scope': 'universe'},
{'nexthop': None,
'device': attr.name,
'destination': str(
netaddr.IPNetwork(attr.ip_cidrs[0]).cidr),
'scope': 'link'}]
routes = ip_lib.get_routing_table(4, namespace=attr.namespace)
self.assertCountEqual(expected_routes, routes)
self.assertIsInstance(routes, list)
expected_routes6 = [{'nexthop': "fd00::2",
'device': attr.name,
'destination': destination6,
'scope': 'universe'},
{'nexthop': None,
'device': attr.name,
'destination': str(
netaddr.IPNetwork(attr.ip_cidrs[1]).cidr),
'scope': 'universe'}]
routes6 = ip_lib.get_routing_table(6, namespace=attr.namespace)
self.assertCountEqual(expected_routes6, routes6)
self.assertIsInstance(routes6, list)
def test_get_routing_table_no_namespace(self):
with testtools.ExpectedException(ip_lib.NetworkNamespaceNotFound):
ip_lib.get_routing_table(4, namespace="nonexistent-netns")
def test_get_neigh_entries(self):
attr = self.generate_device_details(
ip_cidrs=["%s/24" % TEST_IP, "fd00::1/64"]
@ -1158,3 +1115,52 @@ class IpLinkCommandTestCase(IpLibTestFramework):
device.link.create()
namespace = self.useFixture(net_helpers.NamespaceFixture())
device.link.set_netns(namespace.name)
class ListIpRoutesTestCase(functional_base.BaseSudoTestCase):
def setUp(self):
super().setUp()
self.namespace = self.useFixture(net_helpers.NamespaceFixture()).name
self.device_names = ['test_device1', 'test_device2']
self.device_ips = ['10.0.0.1/24', '10.0.1.1/24']
self.device_cidrs = [netaddr.IPNetwork(ip_address).cidr for ip_address
in self.device_ips]
for idx, dev in enumerate(self.device_names):
ip_lib.IPWrapper(self.namespace).add_dummy(dev)
device = ip_lib.IPDevice(dev, namespace=self.namespace)
device.link.set_up()
device.addr.add(self.device_ips[idx])
def test_list_ip_routes_multipath(self):
multipath = [
{'device': self.device_names[0],
'via': str(self.device_cidrs[0].ip + 100), 'weight': 10},
{'device': self.device_names[1],
'via': str(self.device_cidrs[1].ip + 100), 'weight': 20},
{'via': str(self.device_cidrs[1].ip + 101), 'weight': 30},
{'via': str(self.device_cidrs[1].ip + 102)}]
ip_lib.add_ip_route(self.namespace, '1.2.3.0/24',
constants.IP_VERSION_4, via=multipath)
routes = ip_lib.list_ip_routes(self.namespace, constants.IP_VERSION_4)
multipath[2]['device'] = self.device_names[1]
multipath[3]['device'] = self.device_names[1]
multipath[3]['weight'] = 1
for route in (route for route in routes if
route['cidr'] == '1.2.3.0/24'):
if not isinstance(route['via'], list):
continue
self.assertEqual(len(multipath), len(route['via']))
for nexthop in multipath:
for mp in route['via']:
if nexthop != mp:
continue
break
else:
self.fail('Not matching route, routes: %s' % routes)
return
self.fail('Not matching route, routes: %s' % routes)

View File

@ -509,7 +509,7 @@ class RouteTestCase(functional_base.BaseSudoTestCase):
table = table or iproute_linux.DEFAULT_TABLE
if not scope:
scope = 'universe' if gateway else 'link'
scope = priv_ip_lib._get_scope_name(scope)
scope = priv_ip_lib.get_scope_name(scope)
for cidr in cidrs:
ip_version = common_utils.get_ip_version(cidr)
if ip_version == n_cons.IP_VERSION_6 and not metric: