From 7593f95a741aec62d9956175ce6d3ce1b1abb9a0 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Mon, 17 Feb 2020 10:28:12 +0000 Subject: [PATCH] Set a default IP route metric in ip_lib.list_ip_routes By default, if no metric is defined, the kernel interprets the highest value (0). The current implementation, using pyroute2, is a translation from the CLI command "ip route". This command uses the netlink API to communicate with the kernel. In IPv6, when the metric value is not set is translated as 1024 as default [1]. [1]https://access.redhat.com/solutions/3659171 Change-Id: I0c5f9e320bbbf314a2d6a22c515bf903de84cdaf Related-Bug: #1855759 --- neutron/agent/linux/ip_lib.py | 11 ++++++++++- .../linuxbridge/agent/linuxbridge_neutron_agent.py | 3 ++- neutron/tests/functional/agent/linux/test_ip_lib.py | 4 ++-- .../agent/test_linuxbridge_neutron_agent.py | 3 ++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index 7e04a3f8643..7ae353c9e92 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -76,6 +76,13 @@ DEFAULT_GW_PATTERN = re.compile(r"via (\S+)") METRIC_PATTERN = re.compile(r"metric (\S+)") DEVICE_NAME_PATTERN = re.compile(r"(\d+?): (\S+?):.*") +# NOTE: no metric is interpreted by the kernel as having the highest priority +# (value 0). "ip route" uses the netlink API to communicate with the kernel. In +# IPv6, when the metric value is not set is translated as 1024 as default: +# https://access.redhat.com/solutions/3659171 +IP_ROUTE_METRIC_DEFAULT = {constants.IP_VERSION_4: 0, + constants.IP_VERSION_6: 1024} + def remove_interface_suffix(interface): """Remove a possible "@" suffix from an interface' name. @@ -1501,6 +1508,8 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, else: cidr = constants.IP_ANY[ip_version] table = int(get_attr(route, 'RTA_TABLE')) + metric = (get_attr(route, 'RTA_PRIORITY') or + IP_ROUTE_METRIC_DEFAULT[ip_version]) value = { 'table': IP_RULE_TABLES_NAMES.get(table, table), 'source_prefix': get_attr(route, 'RTA_PREFSRC'), @@ -1508,7 +1517,7 @@ def list_ip_routes(namespace, ip_version, scope=None, via=None, table=None, 'scope': IP_ADDRESS_SCOPE[int(route['scope'])], 'device': get_device(int(get_attr(route, 'RTA_OIF')), devices), 'via': get_attr(route, 'RTA_GATEWAY'), - 'metric': get_attr(route, 'RTA_PRIORITY'), + 'metric': metric, } ret.append(value) diff --git a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py index 2f515ba23ba..08f7bfc6dd5 100644 --- a/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/linuxbridge/agent/linuxbridge_neutron_agent.py @@ -397,7 +397,8 @@ class LinuxBridgeManager(amb.CommonAgentManagerBase): if gateway: # Ensure that the gateway can be updated by changing the metric metric = 100 - if 'metric' in gateway: + ip_version = utils.get_ip_version(gateway['cidr']) + if gateway['metric'] != ip_lib.IP_ROUTE_METRIC_DEFAULT[ip_version]: metric = gateway['metric'] - 1 dst_device.route.add_gateway(gateway=gateway['via'], metric=metric) diff --git a/neutron/tests/functional/agent/linux/test_ip_lib.py b/neutron/tests/functional/agent/linux/test_ip_lib.py index cef8f88089a..2bab8a5de2f 100644 --- a/neutron/tests/functional/agent/linux/test_ip_lib.py +++ b/neutron/tests/functional/agent/linux/test_ip_lib.py @@ -866,8 +866,8 @@ class IpRouteCommandTestCase(functional_base.BaseSudoTestCase): scope = ip_lib.IP_ADDRESS_SCOPE[0] elif not scope: scope = 'global' if via else 'link' - if ip_version == constants.IP_VERSION_6 and not metric: - metric = 1024 + if not metric: + metric = ip_lib.IP_ROUTE_METRIC_DEFAULT[ip_version] table = table or iproute_linux.DEFAULT_TABLE table = ip_lib.IP_RULE_TABLES_NAMES.get(table, table) cmp = {'table': table, diff --git a/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py index 06fe069a369..37954dff11d 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/linuxbridge/agent/test_linuxbridge_neutron_agent.py @@ -471,7 +471,8 @@ class TestLinuxBridgeManager(base.BaseTestCase): dv6_fn.assert_not_called() def test__update_interface_ip_details(self): - gwdict = dict(via='1.1.1.1', + gwdict = dict(cidr='1.1.1.1/24', + via='1.1.1.1', metric=50) ipdict = dict(cidr='1.1.1.1/24', broadcast='1.1.1.255',