From 32193267f5bf5434ec628f3b2ce410492b5b86f1 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Wed, 18 Nov 2020 17:07:35 +0000 Subject: [PATCH] Replace "ip route" command in "dvr_local_router" This is a leftover of the "ip route" command migration to Pyroute2. A new paremeter, "proto", is added to the IP route add and list commands. The default protocol used is "static". Story: #2007686 Task: #41284 Related-Bug: #1492714 Change-Id: I319fd0611d3e8a3a09d6d4e077a17a622f74f51c --- neutron/agent/l3/dvr_local_router.py | 16 +++++++------ neutron/agent/linux/ip_lib.py | 12 ++++++++-- neutron/privileged/agent/linux/ip_lib.py | 5 ++-- .../functional/agent/linux/test_ip_lib.py | 3 ++- .../privileged/agent/linux/test_ip_lib.py | 23 +++++++++++++++---- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/neutron/agent/l3/dvr_local_router.py b/neutron/agent/l3/dvr_local_router.py index 39eb5db4675..e581c01ccee 100644 --- a/neutron/agent/l3/dvr_local_router.py +++ b/neutron/agent/l3/dvr_local_router.py @@ -19,6 +19,7 @@ import netaddr from neutron_lib import constants as lib_constants from oslo_log import log as logging from oslo_utils import excutils +from pyroute2.netlink import exceptions as pyroute2_exc from neutron.agent.l3 import dvr_fip_ns from neutron.agent.l3 import dvr_router_base @@ -800,16 +801,17 @@ class DvrLocalRouter(dvr_router_base.DvrRouterBase): def _update_fip_route_table_with_next_hop_routes(self, operation, route, fip_ns_name, tbl_index): - cmd = ['ip', 'route', operation, 'to', route['destination'], - 'via', route['nexthop'], 'table', tbl_index] - ip_wrapper = ip_lib.IPWrapper(namespace=fip_ns_name) - if ip_wrapper.netns.exists(fip_ns_name): - ip_wrapper.netns.execute(cmd, check_exit_code=False, - privsep_exec=True) - else: + cmd = (ip_lib.add_ip_route if operation == 'replace' else + ip_lib.delete_ip_route) + try: + cmd(fip_ns_name, route['destination'], via=route['nexthop'], + table=tbl_index, proto='boot') + except priv_ip_lib.NetworkNamespaceNotFound: LOG.debug("The FIP namespace %(ns)s does not exist for " "router %(id)s", {'ns': fip_ns_name, 'id': self.router_id}) + except (OSError, pyroute2_exc.NetlinkError): + pass def _check_if_route_applicable_to_fip_namespace(self, route, agent_gateway_port): diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index 50309166b35..3df7ec92216 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -1500,14 +1500,14 @@ def ip_monitor(namespace, queue, event_stop, event_started): def add_ip_route(namespace, cidr, device=None, via=None, table=None, - metric=None, scope=None, **kwargs): + metric=None, scope=None, proto='static', **kwargs): """Add an IP route""" if table: table = IP_RULE_TABLES.get(table, table) ip_version = common_utils.get_ip_version(cidr or via) privileged.add_ip_route(namespace, cidr, ip_version, device=device, via=via, table=table, - metric=metric, scope=scope, **kwargs) + metric=metric, scope=scope, proto=proto, **kwargs) def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, @@ -1517,6 +1517,12 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, for device in (d for d in devices if d['index'] == index): return get_attr(device, 'IFLA_IFNAME') + def get_proto(proto_number): + if proto_number in rtnl.rt_proto: + return rtnl.rt_proto[proto_number] + elif str(proto_number) in constants.IP_PROTOCOL_NUM_TO_NAME_MAP: + return constants.IP_PROTOCOL_NUM_TO_NAME_MAP[str(proto_number)] + table = table if table else 'main' table = IP_RULE_TABLES.get(table, table) routes = privileged.list_ip_routes(namespace, ip_version, device=device, @@ -1532,6 +1538,7 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, table = int(get_attr(route, 'RTA_TABLE')) metric = (get_attr(route, 'RTA_PRIORITY') or IP_ROUTE_METRIC_DEFAULT[ip_version]) + proto = get_proto(route['proto']) value = { 'table': IP_RULE_TABLES_NAMES.get(table, table), 'source_prefix': get_attr(route, 'RTA_PREFSRC'), @@ -1540,6 +1547,7 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, 'device': get_device(int(get_attr(route, 'RTA_OIF')), devices), 'via': get_attr(route, 'RTA_GATEWAY'), 'metric': metric, + 'proto': proto, } ret.append(value) diff --git a/neutron/privileged/agent/linux/ip_lib.py b/neutron/privileged/agent/linux/ip_lib.py index c4af147a57a..5e14bbcb3b6 100644 --- a/neutron/privileged/agent/linux/ip_lib.py +++ b/neutron/privileged/agent/linux/ip_lib.py @@ -720,11 +720,12 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table, @privileged.default.entrypoint def add_ip_route(namespace, cidr, ip_version, device=None, via=None, - table=None, metric=None, scope=None, **kwargs): + table=None, metric=None, scope=None, proto='static', + **kwargs): """Add an IP route""" kwargs.update(_make_pyroute2_route_args( namespace, ip_version, cidr, device, via, table, metric, scope, - 'static')) + proto)) try: with get_iproute(namespace) as ip: ip.route('replace', **kwargs) diff --git a/neutron/tests/functional/agent/linux/test_ip_lib.py b/neutron/tests/functional/agent/linux/test_ip_lib.py index 6bf4d3dea8d..494f7e014d5 100644 --- a/neutron/tests/functional/agent/linux/test_ip_lib.py +++ b/neutron/tests/functional/agent/linux/test_ip_lib.py @@ -919,7 +919,8 @@ class IpRouteCommandTestCase(functional_base.BaseSudoTestCase): 'scope': scope, 'device': 'test_device', 'via': via, - 'metric': metric} + 'metric': metric, + 'proto': 'static'} try: utils.wait_until_true(fn, timeout=5) except utils.WaitTimeout: diff --git a/neutron/tests/functional/privileged/agent/linux/test_ip_lib.py b/neutron/tests/functional/privileged/agent/linux/test_ip_lib.py index 1f5b16af0eb..81d08ca4f93 100644 --- a/neutron/tests/functional/privileged/agent/linux/test_ip_lib.py +++ b/neutron/tests/functional/privileged/agent/linux/test_ip_lib.py @@ -22,6 +22,7 @@ from neutron_lib import constants as n_cons from oslo_utils import uuidutils from pyroute2.ipdb import routes as ipdb_routes from pyroute2.iproute import linux as iproute_linux +from pyroute2.netlink import rtnl import testtools from neutron.agent.linux import ip_lib @@ -476,7 +477,7 @@ class RouteTestCase(functional_base.BaseSudoTestCase): self.device.link.set_up() def _check_routes(self, cidrs, table=None, gateway=None, metric=None, - scope=None): + scope=None, proto='static'): table = table or iproute_linux.DEFAULT_TABLE if not scope: scope = 'universe' if gateway else 'link' @@ -503,6 +504,7 @@ class RouteTestCase(functional_base.BaseSudoTestCase): self.assertEqual(metric, ip_lib.get_attr(route, 'RTA_PRIORITY')) self.assertEqual(scope, route['scope']) + self.assertEqual(rtnl.rt_proto[proto], route['proto']) break else: self.fail('CIDR %s not found in the list of routes' % cidr) @@ -533,16 +535,17 @@ class RouteTestCase(functional_base.BaseSudoTestCase): % gateway) def _add_route_device_and_check(self, table=None, metric=None, - scope='link'): + scope='link', proto='static'): cidrs = ['192.168.0.0/24', '172.90.0.0/16', '10.0.0.0/8', '2001:db8::/64'] for cidr in cidrs: ip_version = common_utils.get_ip_version(cidr) priv_ip_lib.add_ip_route(self.namespace, cidr, ip_version, device=self.device_name, table=table, - metric=metric, scope=scope) + metric=metric, scope=scope, proto=proto) - self._check_routes(cidrs, table=table, metric=metric, scope=scope) + self._check_routes(cidrs, table=table, metric=metric, scope=scope, + proto=proto) def test_add_route_device(self): self._add_route_device_and_check(table=None) @@ -565,6 +568,18 @@ class RouteTestCase(functional_base.BaseSudoTestCase): def test_add_route_device_scope_host(self): self._add_route_device_and_check(scope='host') + def test_add_route_device_proto_static(self): + self._add_route_device_and_check(proto='static') # default + + def test_add_route_device_proto_redirect(self): + self._add_route_device_and_check(proto='redirect') + + def test_add_route_device_proto_kernel(self): + self._add_route_device_and_check(proto='kernel') + + def test_add_route_device_proto_boot(self): + self._add_route_device_and_check(proto='boot') + def test_add_route_via_ipv4(self): cidrs = ['192.168.0.0/24', '172.90.0.0/16', '10.0.0.0/8'] int_cidr = '192.168.20.1/24'