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
This commit is contained in:
Rodolfo Alonso Hernandez 2020-02-17 10:28:12 +00:00
parent 6a8277d70e
commit 7593f95a74
4 changed files with 16 additions and 5 deletions

View File

@ -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 "<if>@<endpoint>" 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)

View File

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

View File

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

View File

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