diff options
author | Thomas Haller <thaller@redhat.com> | 2020-10-22 10:29:03 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-10-23 17:11:55 +0200 |
commit | 60da4cb494ea68007ab7b31e2aaed012d85dd084 (patch) | |
tree | 94b082edafb153283cd0420b2609c0df999d2c09 | |
parent | f6a8aca1b41e31eb71709ef8b3500a0e7229e246 (diff) | |
download | NetworkManager-60da4cb494ea68007ab7b31e2aaed012d85dd084.tar.gz |
platform: interpret metric_any for routes to accept offset for default metric
The DHCP client likes to order multiple default routes by adding
them with different, increasing metric.
To support that, let "metric_any" not completely disable the "metric"
field, but instead interpret it as an offset that should be added to
the default metric.
-rw-r--r-- | src/nm-l3-config-data.c | 2 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 36 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 125 |
3 files changed, 85 insertions, 78 deletions
diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index ef8d67a8f9..9b1e017b14 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -2600,7 +2600,7 @@ nm_l3_config_data_merge(NML3ConfigData * self, if (r_src->metric_any) { _ensure_r(); r.rx.metric_any = FALSE; - r.rx.metric = default_route_metric_x[IS_IPv4]; + r.rx.metric = nm_add_u32_clamped(r.rx.metric, default_route_metric_x[IS_IPv4]); } if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) { diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index eca201b087..ca5080b009 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -6515,7 +6515,9 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz route->plen, s_gateway, str_dev, - route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric), + route->metric_any + ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") + : nm_sprintf_buf(str_metric, "%u", route->metric), route->mss, nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags), @@ -6639,7 +6641,9 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz route->plen, s_gateway, str_dev, - route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric), + route->metric_any + ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") + : nm_sprintf_buf(str_metric, "%u", route->metric), route->mss, nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src) @@ -7927,7 +7931,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), obj->plen, - nm_platform_ip4_route_get_effective_metric(obj), + obj->metric, obj->tos, NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any)); break; @@ -7938,7 +7942,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), obj->plen, - nm_platform_ip4_route_get_effective_metric(obj), + obj->metric, obj->tos, /* on top of WEAK_ID: */ obj->ifindex, @@ -7970,7 +7974,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->ifindex, nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), obj->plen, - nm_platform_ip4_route_get_effective_metric(obj), + obj->metric, obj->gateway, nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source), _ip_route_scope_inv_get_normalized(obj), @@ -7999,7 +8003,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->ifindex, obj->network, obj->plen, - nm_platform_ip4_route_get_effective_metric(obj), + obj->metric, obj->gateway, obj->rt_source, obj->scope_inv, @@ -8039,8 +8043,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen)); NM_CMP_FIELD(a, b, plen); NM_CMP_FIELD_UNSAFE(a, b, metric_any); - if (!a->metric_any) - NM_CMP_FIELD(a, b, metric); + NM_CMP_FIELD(a, b, metric); NM_CMP_FIELD(a, b, tos); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { NM_CMP_FIELD(a, b, ifindex); @@ -8081,8 +8084,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_FIELD(a, b, network); NM_CMP_FIELD(a, b, plen); NM_CMP_FIELD_UNSAFE(a, b, metric_any); - if (!a->metric_any) - NM_CMP_FIELD(a, b, metric); + NM_CMP_FIELD(a, b, metric); NM_CMP_FIELD(a, b, gateway); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source), @@ -8130,7 +8132,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), obj->plen, - nm_platform_ip6_route_get_effective_metric(obj), + obj->metric, *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), obj->src_plen, NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any)); @@ -8142,7 +8144,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), obj->plen, - nm_platform_ip6_route_get_effective_metric(obj), + obj->metric, *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), obj->src_plen, NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any), @@ -8158,7 +8160,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, obj->ifindex, *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), obj->plen, - nm_platform_ip6_route_get_effective_metric(obj), + obj->metric, obj->gateway, obj->pref_src, *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), @@ -8187,7 +8189,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, obj->table_coerced, obj->ifindex, obj->network, - nm_platform_ip6_route_get_effective_metric(obj), + obj->metric, obj->gateway, obj->pref_src, obj->src, @@ -8228,8 +8230,7 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen)); NM_CMP_FIELD(a, b, plen); NM_CMP_FIELD_UNSAFE(a, b, metric_any); - if (!a->metric_any) - NM_CMP_FIELD(a, b, metric); + NM_CMP_FIELD(a, b, metric); NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen)); NM_CMP_FIELD(a, b, src_plen); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { @@ -8254,8 +8255,7 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, NM_CMP_FIELD_IN6ADDR(a, b, network); NM_CMP_FIELD(a, b, plen); NM_CMP_FIELD_UNSAFE(a, b, metric_any); - if (!a->metric_any) - NM_CMP_FIELD(a, b, metric); + NM_CMP_FIELD(a, b, metric); NM_CMP_FIELD_IN6ADDR(a, b, gateway); NM_CMP_FIELD_IN6ADDR(a, b, pref_src); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 17f3a2fd5a..df637fe03e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -415,9 +415,9 @@ typedef union { * configures addresses. */ #define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE ((guint32) 0u) -#define __NMPlatformIPRoute_COMMON \ - __NMPlatformObjWithIfindex_COMMON; \ - \ +#define __NMPlatformIPRoute_COMMON \ + __NMPlatformObjWithIfindex_COMMON; \ + \ /* The NMIPConfigSource. For routes that we receive from cache this corresponds * to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values). * When adding a route, the source will be coerced to the protocol using @@ -429,11 +429,11 @@ typedef union { * * When deleting an IPv4/IPv6 route, the rtm_protocol field must match (even * if it is not part of the primary key for IPv6) -- unless rtm_protocol is set - * to zero, in which case the first matching route (with proto ignored) is deleted. */ \ - NMIPConfigSource rt_source; \ - \ - guint8 plen; \ - \ + * to zero, in which case the first matching route (with proto ignored) is deleted. */ \ + NMIPConfigSource rt_source; \ + \ + guint8 plen; \ + \ /* RTA_METRICS: * * For IPv4 routes, these properties are part of their @@ -444,24 +444,29 @@ typedef union { * * When deleting a route, kernel seems to ignore the RTA_METRICS properties. * That is a problem/bug for IPv4 because you cannot explicitly select which - * route to delete. Kernel just picks the first. See rh#1475642. */ \ - \ - /* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \ - bool lock_window : 1; \ - bool lock_cwnd : 1; \ - bool lock_initcwnd : 1; \ - bool lock_initrwnd : 1; \ - bool lock_mtu : 1; \ - \ - /* if TRUE, the "metric" field gets ignored and can be overridden with settings from - * the device. This is to track routes that should be configured (e.g. from a DHCP - * lease), but where the actual metric is determined by NMDevice. */ \ - bool metric_any : 1; \ - \ + * route to delete. Kernel just picks the first. See rh#1475642. */ \ + \ + /* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \ + bool lock_window : 1; \ + bool lock_cwnd : 1; \ + bool lock_initcwnd : 1; \ + bool lock_initrwnd : 1; \ + bool lock_mtu : 1; \ + \ + /* if TRUE, the "metric" field is interpreted as an offset that is added to a default + * metric. For example, form a DHCP lease we don't know the actually used metric, because + * that is determined by upper layers (the configuration). However, we have a default + * metric that should be used. So we set "metric_any" to %TRUE, which means to use + * the default metric. However, we still treat the "metric" field as an offset that + * will be added to the default metric. In most case, you want that "metric" is zero + * when setting "metric_any". */ \ + bool metric_any : 1; \ + \ /* like "metric_any", the table is determined by other layers of the code. - * This field overrides "table_coerced" field. */ \ - bool table_any : 1; \ - \ + * This field overrides "table_coerced" field. If "table_any" is true, then + * the "table_coerced" field is ignored (unlike for the metric). */ \ + bool table_any : 1; \ + \ /* rtnh_flags * * Routes with rtm_flags RTM_F_CLONED are hidden by platform and @@ -471,44 +476,46 @@ typedef union { * NOTE: currently we ignore all flags except RTM_F_CLONED * and RTNH_F_ONLINK. * We also may not properly consider the flags as part of the ID - * in route-cmp. */ \ - unsigned r_rtm_flags; \ - \ - /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ - guint32 mss; \ - \ - /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \ - guint32 window; \ - \ - /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \ - guint32 cwnd; \ - \ - /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \ - guint32 initcwnd; \ - \ - /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ - guint32 initrwnd; \ - \ - /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ - guint32 mtu; \ - \ - /* RTA_PRIORITY (iproute2: metric) */ \ - guint32 metric; \ - \ + * in route-cmp. */ \ + unsigned r_rtm_flags; \ + \ + /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ + guint32 mss; \ + \ + /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \ + guint32 window; \ + \ + /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \ + guint32 cwnd; \ + \ + /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \ + guint32 initcwnd; \ + \ + /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ + guint32 initrwnd; \ + \ + /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ + guint32 mtu; \ + \ + /* RTA_PRIORITY (iproute2: metric) + * If "metric_any" is %TRUE, then this is interpreted as an offset that will be + * added to a default base metric. In such cases, the offset is usually zero. */ \ + guint32 metric; \ + \ /* rtm_table, RTA_TABLE. * * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main - * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ - guint32 table_coerced; \ - \ + * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ + guint32 table_coerced; \ + \ /* rtm_type. * * This is not the original type, if type_coerced is 0 then * it means RTN_UNSPEC otherwise the type value is preserved. - * */ \ - guint8 type_coerced; \ - \ + * */ \ + guint8 type_coerced; \ + \ /*end*/ typedef struct { @@ -2078,18 +2085,18 @@ static inline guint32 nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r) { nm_assert(r); - nm_assert(!r->metric_any || r->metric == 0); - return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 : r->metric; + return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, r->metric) + : r->metric; } static inline guint32 nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r) { nm_assert(r); - nm_assert(!r->metric_any || r->metric == 0); - return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 : r->metric; + return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, r->metric) + : r->metric; } static inline guint32 |