diff options
author | Thomas Haller <thaller@redhat.com> | 2023-11-28 15:20:33 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2023-11-29 11:24:53 +0100 |
commit | ca7cbf6feabd475d5f4b8032f4650a47ef9174ce (patch) | |
tree | 3c3f8cd568483894d8df68858d9d70b1649377ae | |
parent | 389ac096e3810d56b744065af26ffdb854b72792 (diff) |
core: fix nm_netns_ip_route_ecmp_commit() to return regular single-hop routeth/tmp7
nm_netns_ip_route_ecmp_commit() returns the ECMP routes that didn't find
a merge-partner. It expects NML3Cfg to configure such routes in
platform.
Note that these routes have a positive "weight", which was used for
tracking the ECMP information in NML3Cfg and NMNetns.
But in kernel, single-hop routes don't have a weight. All routes in
NMPlatform will have a zero weight. While it somewhat works to call
nm_platform_ip_route_add() with a single-hop route of non-zero weight,
the result will be a different(!) route. This means for example that
nm_platform_ip_route_sync() will search the NMPlatform cache for whether
the routes exist, but in the cache single-hop routes with positive weight
never exist.
The proper solution is that nm_netns_ip_route_ecmp_commit() does not
tell NML3Cfg to add a route, that cannot be added. Instead, it must
first normalize the weight to zero, to have a "regular" single-hop
route.
Fixes: 5b5ce4268211 ('nm-netns: track ECMP routes')
-rw-r--r-- | src/core/nm-netns.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index 7c279cafc3..e0bd19bbe0 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -916,6 +916,8 @@ nm_netns_ip_route_ecmp_commit(NMNetns *self, } if (route->n_nexthops <= 1) { + NMPObject *route_clone; + /* This is a single hop route. Return it to the caller. */ if (!*out_singlehop_routes) { /* Note that the returned array does not own a reference. This @@ -924,7 +926,30 @@ nm_netns_ip_route_ecmp_commit(NMNetns *self, *out_singlehop_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); } - g_ptr_array_add(*out_singlehop_routes, (gpointer) nmp_object_ref(route_obj)); + + /* We have here a IPv4 single-hop route. For internal tracking purposes, + * this route has a positive "weight" (which was used to mark it as a candidate + * for ECMP merging). Now we want to return this route to NML3Cfg and add it + * as regular single-hop routes. + * + * A single-hop route in kernel always has a "weight" of zero. This route + * cannot be added as-is. Well, if we would, then the result would be + * a different(!) route (with a zero "weight"). + * + * Anticipate that and normalize the route now to be a regular single-hop + * route (with weight zero). nm_platform_ip_route_normalize() does that. + * We really want to return a regular route here, not the route with a positive + * weight that exists for internal tracking purposes. + */ + nm_assert(route_obj->ip4_route.weight > 0u); + nm_assert(NMP_OBJECT_GET_TYPE(route_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); + + route_clone = nmp_object_clone(route_obj, FALSE); + nm_platform_ip_route_normalize(AF_INET, + NMP_OBJECT_CAST_IP_ROUTE(route_clone), + NMP_IP_ROUTE_NORMALIZE_FLAGS_NONE); + g_ptr_array_add(*out_singlehop_routes, route_clone); + if (changed) { _LOGT("ecmp-route: single-hop %s", nmp_object_to_string(route_obj, |