diff options
author | Thomas Haller <thaller@redhat.com> | 2023-11-29 12:01:08 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2023-11-29 12:18:59 +0100 |
commit | 0e30415575ccd611602c9d2858cf25125740c357 (patch) | |
tree | 4ec5d413a49bfea7f860527850333e57cc93e034 | |
parent | ca7cbf6feabd475d5f4b8032f4650a47ef9174ce (diff) |
core: assert that tracked objects in NML3Cfg don't have metric_anyth/tmp8
It wouldn't work otherwise. The object state is used to track routes
and compare them to what we find in platform.
A "metric_any" is useful at higher layers, to track a route where the
metric is decided by somebody else. But at the point when we add such an
object to the object-state, a fixed metric must be chosen.
Assert for that.
Also add some code comment to nm_platofmr_ip_route_normalize() related
to this.
-rw-r--r-- | src/core/nm-l3cfg.c | 8 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 27 |
2 files changed, 35 insertions, 0 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 1c4a7774d0..0b4ad62b84 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -811,6 +811,14 @@ _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gp nm_assert(_self->priv.p->combined_l3cd_commited); \ \ if (NM_MORE_ASSERTS > 5) { \ + /* metric-any must be resolved before adding the object. Otherwise, + * their real metric is not known, and they cannot be compared to objects + * from NMPlatform cache. */ \ + nm_assert(!NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj_state->obj), \ + NMP_OBJECT_TYPE_IP4_ROUTE, \ + NMP_OBJECT_TYPE_IP6_ROUTE) \ + || !NMP_OBJECT_CAST_IP_ROUTE(_obj_state->obj)->metric_any); \ + \ nm_assert(c_list_contains(&_self->priv.p->obj_state_lst_head, \ &_obj_state->os_lst)); \ nm_assert(_obj_state->os_plobj \ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 5fa191b958..a797cb034c 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -5336,6 +5336,33 @@ nm_platform_ip_route_normalize(int addr_family, route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source); + /* For the most part, nm_platform_ip_route_normalize() tries to normalize some fields + * as it happens when they go through kernel. + * + * In most cases, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID comparison performs the same + * relaxed comparison. For example, normalize() will normalize "scope_inv", and also + * the NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID comparison will do that on-the-fly. Optimally, + * looking into a hash table gives you the same result, whether you normalize the + * needle first (or whether the entries in the hash table are normalized). + * + * Unfortunately, that's not always the case. Examples: + * + * - "metric": we have a "metric_any" field. This is used by higher layers + * to indicate that the metric is dynamically chosen (e.g. by the default + * metric of the default route). As such, as far as NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID + * is concerned, the "metric_any" and "metric" values are treated as distinguishing + * properties. But when we add a route in kernel, "metric_any" no longer exist. + * It becomes a fixed metric. Normalize will fix the metric. + * - "weight": for IPv4 single-hop routes, the weight does not exist in kernel. We however + * use the field to track ECMP information in higher layers. Consequently, + * NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID treats the weight as-is, while normalization + * (and adding it to kernel) will mangle it. + * + * You thus must be careful when you track NMPlatformIP4Route that make use of such + * higher-level features, which cannot be represented in kernel or the NMPlatform + * cache. + */ + switch (addr_family) { case AF_INET: r4 = (NMPlatformIP4Route *) route; |