summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-02-07 20:52:49 +0100
committerThomas Haller <thaller@redhat.com>2022-02-09 19:13:05 +0100
commit9ab53e561a636a48e772d48c96d6bd2e0be13329 (patch)
tree239cc1f17b0e01c5b3e114255d961674278419b3
parent6255e0dcac06111a121541f982d11eefbae20cb1 (diff)
downloadNetworkManager-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.c107
-rw-r--r--src/core/nm-l3cfg.h14
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;
};