diff options
author | Thomas Haller <thaller@redhat.com> | 2022-02-07 20:52:49 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-02-09 19:13:05 +0100 |
commit | 9ab53e561a636a48e772d48c96d6bd2e0be13329 (patch) | |
tree | 239cc1f17b0e01c5b3e114255d961674278419b3 | |
parent | 6255e0dcac06111a121541f982d11eefbae20cb1 (diff) | |
download | NetworkManager-9ab53e561a636a48e772d48c96d6bd2e0be13329.tar.gz |
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
-rw-r--r-- | src/core/nm-l3cfg.c | 107 | ||||
-rw-r--r-- | src/core/nm-l3cfg.h | 14 |
2 files changed, 106 insertions, 15 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index dfb80c7cb9..e7aee79a04 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -12,6 +12,7 @@ #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-route-manager.h" #include "nm-netns.h" #include "n-acd/src/n-acd.h" #include "nm-l3-ipv4ll.h" @@ -410,6 +411,25 @@ static NM_UTILS_LOOKUP_DEFINE(_l3_acd_addr_state_to_string, "external-removed"), NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_USED, "used"), ); +static gboolean +_obj_is_route_nodev(const NMPObject *obj) +{ + gboolean has_ifindex; + + nm_assert(obj); + + has_ifindex = (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex > 0); + + nm_assert(has_ifindex + == !(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE) + && nm_platform_route_type_is_nodev(nm_platform_route_type_uncoerce( + NMP_OBJECT_CAST_IP_ROUTE(obj)->type_coerced)))); + + return !has_ifindex; +} + /*****************************************************************************/ NMIPConfig * @@ -952,6 +972,11 @@ _obj_states_update_all(NML3Cfg *self) self->priv.p->combined_l3cd_commited, &obj, obj_type) { + if (_obj_is_route_nodev(obj)) { + /* this is a nodev route. We don't track an obj-state for this. */ + continue; + } + obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); if (!obj_state) { obj_state = @@ -1081,13 +1106,15 @@ static void _commit_collect_routes(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type, - GPtrArray **routes) + GPtrArray **routes, + GPtrArray **routes_nodev) { const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMDedupMultiHeadEntry *head_entry; const NMDedupMultiEntry *entry; nm_assert(routes && !*routes); + nm_assert(routes_nodev && !*routes_nodev); head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)); @@ -1097,16 +1124,20 @@ _commit_collect_routes(NML3Cfg *self, c_list_for_each_entry (entry, &head_entry->lst_entries_head, lst_entries) { const NMPObject *obj = entry->obj; + GPtrArray **r; - if (!_obj_states_sync_filter(self, obj, commit_type)) - continue; - - if (!*routes) { - *routes = - g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); + if (_obj_is_route_nodev(obj)) + r = routes_nodev; + else { + if (!_obj_states_sync_filter(self, obj, commit_type)) + continue; + r = routes; } - g_ptr_array_add(*routes, (gpointer) nmp_object_ref(obj)); + if (!*r) + *r = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); + + g_ptr_array_add(*r, (gpointer) nmp_object_ref(obj)); } } @@ -3403,6 +3434,53 @@ nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag) /*****************************************************************************/ +#define _NODEV_ROUTES_TAG(self, IS_IPv4) ((gconstpointer) (&(&(self)->priv.route_manager)[IS_IPv4])) + +static gboolean +_nodev_routes_untrack(NML3Cfg *self, int addr_family) +{ + return nmp_route_manager_untrack_all(self->priv.route_manager, + _NODEV_ROUTES_TAG(self, NM_IS_IPv4(addr_family)), + FALSE, + TRUE); +} + +static void +_nodev_routes_sync(NML3Cfg *self, + int addr_family, + NML3CfgCommitType commit_type, + GPtrArray *routes_nodev) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMPObjectType obj_type = NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4); + guint i; + gboolean changed = FALSE; + + if (!routes_nodev) + goto out_clear; + + for (i = 0; i < routes_nodev->len; i++) { + const NMPObject *obj = routes_nodev->pdata[i]; + + if (nmp_route_manager_track(self->priv.route_manager, + obj_type, + NMP_OBJECT_CAST_IP_ROUTE(obj), + 1, + _NODEV_ROUTES_TAG(self, IS_IPv4), + NULL)) + changed = TRUE; + } + +out_clear: + if (_nodev_routes_untrack(self, addr_family)) + changed = TRUE; + + if (changed || commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), FALSE); +} + +/*****************************************************************************/ + typedef struct { NML3Cfg *self; gconstpointer tag; @@ -4102,6 +4180,7 @@ _l3_commit_one(NML3Cfg *self, const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *addresses = NULL; gs_unref_ptrarray GPtrArray *routes = NULL; + gs_unref_ptrarray GPtrArray *routes_nodev = NULL; gs_unref_ptrarray GPtrArray *addresses_prune = NULL; gs_unref_ptrarray GPtrArray *routes_prune = NULL; gs_unref_ptrarray GPtrArray *routes_temporary_not_available_arr = NULL; @@ -4125,7 +4204,7 @@ _l3_commit_one(NML3Cfg *self, if (self->priv.p->combined_l3cd_commited) { addresses = _commit_collect_addresses(self, addr_family, commit_type); - _commit_collect_routes(self, addr_family, commit_type, &routes); + _commit_collect_routes(self, addr_family, commit_type, &routes, &routes_nodev); route_table_sync = nm_l3_config_data_get_route_table_sync(self->priv.p->combined_l3cd_commited, @@ -4163,6 +4242,8 @@ _l3_commit_one(NML3Cfg *self, addresses, addresses_prune); + _nodev_routes_sync(self, addr_family, commit_type, routes_nodev); + if (!nm_platform_ip_route_sync(self->priv.platform, addr_family, self->priv.ifindex, @@ -4597,6 +4678,8 @@ constructed(GObject *object) self->priv.platform = g_object_ref(nm_netns_get_platform(self->priv.netns)); nm_assert(NM_IS_PLATFORM(self->priv.platform)); + self->priv.route_manager = nmp_route_manager_ref(nm_netns_get_route_manager(self->priv.netns)); + _LOGT("created (netns=" NM_HASH_OBFUSCATE_PTR_FMT ")", NM_HASH_OBFUSCATE_PTR(self->priv.netns)); G_OBJECT_CLASS(nm_l3cfg_parent_class)->constructed(object); @@ -4647,8 +4730,14 @@ finalize(GObject *object) nm_assert(c_list_is_empty(&self->priv.p->obj_state_temporary_not_available_lst_head)); nm_assert(c_list_is_empty(&self->priv.p->obj_state_zombie_lst_head)); + if (_nodev_routes_untrack(self, AF_INET)) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE); + if (_nodev_routes_untrack(self, AF_INET6)) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP6_ROUTE, FALSE); + g_clear_object(&self->priv.netns); g_clear_object(&self->priv.platform); + nm_clear_pointer(&self->priv.route_manager, nmp_route_manager_unref); nm_clear_l3cd(&self->priv.p->combined_l3cd_merged); nm_clear_l3cd(&self->priv.p->combined_l3cd_commited); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 6fd8f9de80..7dc9faccfe 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -195,16 +195,18 @@ typedef struct { } NML3ConfigNotifyData; struct _NML3CfgPrivate; +struct _NMPRouteManager; struct _NML3Cfg { GObject parent; struct { - struct _NML3CfgPrivate *p; - NMNetns *netns; - NMPlatform *platform; - const NMPObject *plobj; - const NMPObject *plobj_next; - int ifindex; + struct _NML3CfgPrivate *p; + NMNetns *netns; + NMPlatform *platform; + struct _NMPRouteManager *route_manager; + const NMPObject *plobj; + const NMPObject *plobj_next; + int ifindex; } priv; }; |