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
This commit is contained in:
Rodolfo Alonso Hernandez 2020-11-18 17:07:35 +00:00
parent e17b2cdfe9
commit 32193267f5
5 changed files with 43 additions and 16 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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'