platform: add flags to NMPlatformIP[46]Route to allow overriding the route table and metric

When we (for example) receive a DHCP lease, we track the routes that
should be configured via NMPlatformIP[46]Route instances. Thus, this
structure does not only track the routes that are configured (and
cached in NMPlatform), but it is also used to track the routes that
we want to configure.

This is also the case with the "rt_source" field, which represents the
NMIPConfigSource enum for routes that we want to configure, but
for routes in the cache it corresponds to rtm_protocol.

Note that NMDhcpClient creates NMIP4Config instances, which tracks the
routes as NMPlatformIP4Route instances. Previously, NMDhcpClient didn't
have any way to leave the table/metric undecided, but this information
isn't part of the DHCP lease tself. Instead, NMDevice knows the table/metric
to use. This has various problems:

  - NMDhcpClient needs to know the table/metric, for no other purpose
    than to set the value when creating the NMIP4Config instance for the
    lease. We first pass the information down, only so that it can be
    returned with the lease information.

  - during reapply or when connectivity check changes, the effectively
    used table/metric can change. Previously, we would have to
    re-generate the NMIP4Config instances.

Improve that by allowing to leave the table/metric undecided. Higher
layers can decide the effective metric to use.
This commit is contained in:
Thomas Haller 2020-09-23 13:38:39 +02:00
parent 1558e9a323
commit 02ad6416fd
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 379 additions and 289 deletions

View file

@ -4704,7 +4704,10 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
NLA_PUT(msg, RTA_SRC, addr_len, &obj->ip6_route.src);
}
NLA_PUT_U32(msg, RTA_PRIORITY, obj->ip_route.metric);
NLA_PUT_U32(msg,
RTA_PRIORITY,
is_v4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route)
: nm_platform_ip6_route_get_effective_metric(&obj->ip6_route));
if (table > 0xFF)
NLA_PUT_U32(msg, RTA_TABLE, table);

View file

@ -3437,7 +3437,8 @@ nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_dat
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(obj->ip_route.table_coerced);
return nm_platform_route_table_is_main(
nm_platform_ip_route_get_effective_table(&obj->ip_route));
}
gboolean
@ -3446,7 +3447,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(obj->ip_route.table_coerced)
return nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&obj->ip_route))
&& obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
}
@ -4395,11 +4396,12 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
if (nm_platform_route_table_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced, TRUE)
if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
== RT_TABLE_LOCAL)
continue;
} else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) {
if (!nm_platform_route_table_is_main(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced))
if (!nm_platform_route_table_is_main(
nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))))
continue;
} else
nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
@ -4488,7 +4490,9 @@ nm_platform_ip_route_sync(NMPlatform *self,
continue;
}
if (!IS_IPv4 && NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->metric == 0) {
if (!IS_IPv4
&& nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
== 0) {
/* User space cannot add routes with metric 0. However, kernel can, and we might track such
* routes in @route as they are present external. Skip them silently. */
continue;
@ -4582,29 +4586,33 @@ sync_route_add:
if (vt->is_ip4) {
const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o);
nmp_object_stackinit(&oo,
NMP_OBJECT_TYPE_IP4_ROUTE,
&((NMPlatformIP4Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 32,
.metric = rt->metric,
.rt_source = rt->rt_source,
.table_coerced = rt->table_coerced,
}));
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP4_ROUTE,
&((NMPlatformIP4Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 32,
.metric = nm_platform_ip4_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
} else {
const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o);
nmp_object_stackinit(&oo,
NMP_OBJECT_TYPE_IP6_ROUTE,
&((NMPlatformIP6Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 128,
.metric = rt->metric,
.rt_source = rt->rt_source,
.table_coerced = rt->table_coerced,
}));
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP6_ROUTE,
&((NMPlatformIP6Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 128,
.metric = nm_platform_ip6_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
}
_LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct "
@ -4760,21 +4768,25 @@ nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route)
NMPlatformIP4Route *r4;
NMPlatformIP6Route *r6;
route->table_coerced =
nm_platform_route_table_coerce(nm_platform_ip_route_get_effective_table(route));
route->table_any = FALSE;
route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source);
switch (addr_family) {
case AF_INET:
r4 = (NMPlatformIP4Route *) route;
r4->table_coerced = nm_platform_route_table_coerce(
nm_platform_route_table_uncoerce(r4->table_coerced, TRUE));
r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r4->rt_source);
r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
route->metric = nm_platform_ip4_route_get_effective_metric(r4);
route->metric_any = FALSE;
r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
break;
case AF_INET6:
r6 = (NMPlatformIP6Route *) route;
r6->table_coerced = nm_platform_route_table_coerce(
nm_platform_route_table_uncoerce(r6->table_coerced, TRUE));
route->metric = nm_platform_ip6_route_get_effective_metric(r6);
route->metric_any = FALSE;
nm_utils_ip6_address_clear_host_address(&r6->network, &r6->network, r6->plen);
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r6->rt_source),
nm_utils_ip6_address_clear_host_address(&r6->src, &r6->src, r6->src_plen);
break;
default:
@ -6453,6 +6465,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_type[30];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@ -6470,30 +6483,33 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
"%s/%d"
" via %s"
"%s"
" metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* rtm_flags */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
" metric %s"
" mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* rtm_flags */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: "",
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: ""),
s_network,
route->plen,
s_gateway,
str_dev,
route->metric,
route->metric_any ? "??" : 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),
@ -6568,6 +6584,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
char str_initrwnd[32];
char str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@ -6582,81 +6599,84 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
_to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
g_snprintf(buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
" via %s"
"%s"
" metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* source */
"%s" /* rtm_flags */
"%s%s" /* pref-src */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* pref */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_coerced
g_snprintf(
buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
" via %s"
"%s"
" metric %s"
" mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* source */
"%s" /* rtm_flags */
"%s%s" /* pref-src */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* pref */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: "",
s_network,
route->plen,
s_gateway,
str_dev,
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)
? nm_sprintf_buf(s_src_all,
" src %s/%u",
_nm_utils_inet6_ntop(&route->src, s_src),
(unsigned) route->src_plen)
: "",
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->window || route->lock_window
? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->rt_pref ? nm_sprintf_buf(
str_pref,
" pref %s",
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
: "");
: ""),
s_network,
route->plen,
s_gateway,
str_dev,
route->metric_any ? "??" : 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)
? nm_sprintf_buf(s_src_all,
" src %s/%u",
_nm_utils_inet6_ntop(&route->src, s_src),
(unsigned) route->src_plen)
: "",
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->window || route->lock_window ? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->rt_pref ? nm_sprintf_buf(
str_pref,
" pref %s",
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
: "");
return buf;
}
@ -7891,67 +7911,75 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
{
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(h,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos);
nm_hash_update_vals(
h,
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->tos,
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos,
/* on top of WEAK_ID: */
obj->ifindex,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->gateway,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & RTNH_F_ONLINK,
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
nm_hash_update_vals(
h,
obj->type_coerced,
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->tos,
/* on top of WEAK_ID: */
obj->ifindex,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->gateway,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & RTNH_F_ONLINK,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
obj->ifindex,
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(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->gateway,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@ -7960,7 +7988,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->ifindex,
obj->network,
obj->plen,
obj->metric,
nm_platform_ip4_route_get_effective_metric(obj),
obj->gateway,
obj->rt_source,
obj->scope_inv,
@ -7974,6 +8002,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->mtu,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@ -7992,11 +8022,14 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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);
@ -8024,9 +8057,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@ -8035,7 +8069,9 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
else
NM_CMP_FIELD(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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),
@ -8078,54 +8114,61 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(h,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen);
nm_hash_update_vals(
h,
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),
*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));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
/* on top of WEAK_ID: */
obj->ifindex,
obj->gateway);
nm_hash_update_vals(
h,
obj->type_coerced,
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),
*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),
/* on top of WEAK_ID: */
obj->ifindex,
obj->gateway);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
obj->ifindex,
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
obj->pref_src,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
obj->mss,
obj->r_rtm_flags & RTM_F_CLONED,
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
_route_pref_normalize(obj->rt_pref));
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(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->gateway,
obj->pref_src,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
obj->mss,
obj->r_rtm_flags & RTM_F_CLONED,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
_route_pref_normalize(obj->rt_pref));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@ -8133,8 +8176,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->table_coerced,
obj->ifindex,
obj->network,
obj->plen,
obj->metric,
nm_platform_ip6_route_get_effective_metric(obj),
obj->gateway,
obj->pref_src,
obj->src,
@ -8143,6 +8185,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->mss,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@ -8167,11 +8211,14 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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) {
@ -8183,9 +8230,10 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@ -8194,7 +8242,9 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
else
NM_CMP_FIELD_IN6ADDR(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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) {

View file

@ -397,22 +397,22 @@ typedef union {
* Note that contrary to IPv6, you can add routes with metric 0 and it is even
* the default.
*/
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 ((guint32) 0u)
/* Default value for adding an IPv6 route. This is also what iproute2 does.
* Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024).
*
* Note that kernel doesn't allow adding IPv6 routes with metric zero via netlink.
* It however can itself add routes with metric zero. */
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 ((guint32) 1024u)
/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user
* configures addresses. */
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
#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
@ -424,11 +424,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
@ -439,15 +439,24 @@ 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; \
\
* 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; \
\
/* like "metric_any", the table is determined by other layers of the code.
* This field overrides "table_coerced" field. */ \
bool table_any : 1; \
\
/* rtnh_flags
*
* Routes with rtm_flags RTM_F_CLONED are hidden by platform and
@ -457,44 +466,44 @@ 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) */ \
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 {
@ -1318,7 +1327,7 @@ nm_platform_route_table_coerce(guint32 table)
/**
* nm_platform_route_table_uncoerce:
* @table: the route table, in its coerced value
* @table_coerced: the route table, in its coerced value
* @normalize: whether to normalize RT_TABLE_UNSPEC to
* RT_TABLE_MAIN. For kernel, routes with a table id
* RT_TABLE_UNSPEC do not exist and are treated like
@ -2060,6 +2069,34 @@ nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddre
void nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route);
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;
}
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;
}
static inline guint32
nm_platform_ip_route_get_effective_table(const NMPlatformIPRoute *r)
{
nm_assert(r);
nm_assert(!r->table_any || r->table_coerced == 0);
return r->table_any ? 254u /* RT_TABLE_MAIN */
: nm_platform_route_table_uncoerce(r->table_coerced, TRUE);
}
static inline gconstpointer
nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route)
{