From b5c563329ac3edc8334bd05ad8f8e8d7fd9c8a8d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jul 2020 11:21:44 +0200 Subject: l3cfg: notify NML3Cfg about NMPlatform changes in an idle handler We need to react to platform changes. Also, we usually want to delay the reaction to an idle handler. Instead of subscribing each NML3Cfg instance itself to platform changes, let only NMNetns do that. The goal is of course that each platform event only needs to notify the NML3Cfg instance, which collects the events and schedules them on the idle handler. --- src/nm-l3cfg.c | 7 ++++++ src/nm-l3cfg.h | 6 +++++ src/nm-netns.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/nm-types.h | 11 +++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index aaaad02b6e..6d2f26b8d8 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -35,6 +35,13 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +void +_nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags) +{ +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 4f035e231a..731b2b46fe 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -28,6 +28,12 @@ GType nm_l3cfg_get_type (void); NML3Cfg *nm_l3cfg_new (NMNetns *netns, int ifindex); +/*****************************************************************************/ + +void _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags); + +/*****************************************************************************/ + static inline int nm_l3cfg_get_ifindex (const NML3Cfg *self) { diff --git a/src/nm-netns.c b/src/nm-netns.c index cafb73164c..ebefeea649 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -23,10 +23,13 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( ); typedef struct { + NMNetns *_self_signal_user_data; NMPlatform *platform; NMPNetns *platform_netns; NMPRulesManager *rules_manager; GHashTable *l3cfgs; + CList l3cfg_signal_pending_lst_head; + guint signal_pending_idle_id; } NMNetnsPrivate; struct _NMNetns { @@ -88,7 +91,9 @@ nm_netns_get_multi_idx (NMNetns *self) typedef struct { int ifindex; + guint32 signal_pending_flag; NML3Cfg *l3cfg; + CList signal_pending_lst; } L3CfgData; static void @@ -96,6 +101,8 @@ _l3cfg_data_free (gpointer ptr) { L3CfgData *l3cfg_data = ptr; + c_list_unlink_stale (&l3cfg_data->signal_pending_lst); + nm_g_slice_free (l3cfg_data); } @@ -140,8 +147,9 @@ nm_netns_access_l3cfg (NMNetns *self, l3cfg_data = g_slice_new (L3CfgData); *l3cfg_data = (L3CfgData) { - .ifindex = ifindex, - .l3cfg = nm_l3cfg_new (self, ifindex), + .ifindex = ifindex, + .l3cfg = nm_l3cfg_new (self, ifindex), + .signal_pending_lst = C_LIST_INIT (l3cfg_data->signal_pending_lst), }; if (!g_hash_table_add (priv->l3cfgs, l3cfg_data)) @@ -160,6 +168,52 @@ nm_netns_access_l3cfg (NMNetns *self, /*****************************************************************************/ +static gboolean +_platform_signal_on_idle_cb (gpointer user_data) +{ + gs_unref_object NMNetns *self = g_object_ref (NM_NETNS (user_data)); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + L3CfgData *l3cfg_data; + + while ((l3cfg_data = c_list_first_entry (&priv->l3cfg_signal_pending_lst_head, L3CfgData, signal_pending_lst))) { + c_list_unlink (&l3cfg_data->signal_pending_lst); + _nm_l3cfg_notify_platform_change_on_idle (l3cfg_data->l3cfg, + nm_steal_int (&l3cfg_data->signal_pending_flag)); + } + + priv->signal_pending_idle_id = 0; + return G_SOURCE_REMOVE; +} + +static void +_platform_signal_cb (NMPlatform *platform, + int obj_type_i, + int ifindex, + gconstpointer platform_object, + int change_type_i, + NMNetns **p_self) +{ + NMNetns *self = NM_NETNS (*p_self); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + const NMPObjectType obj_type = obj_type_i; + L3CfgData *l3cfg_data; + + l3cfg_data = g_hash_table_lookup (priv->l3cfgs, &ifindex); + if (!l3cfg_data) + return; + + l3cfg_data->signal_pending_flag |= nmp_object_type_to_flags (obj_type); + + if (!c_list_is_empty (&l3cfg_data->signal_pending_lst)) + return; + + c_list_link_tail (&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst); + if (priv->signal_pending_idle_id == 0) + priv->signal_pending_idle_id = g_idle_add (_platform_signal_on_idle_cb, self); +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -186,6 +240,10 @@ set_property (GObject *object, guint prop_id, static void nm_netns_init (NMNetns *self) { + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); + + priv->_self_signal_user_data = self; + c_list_init (&priv->l3cfg_signal_pending_lst_head); } static void @@ -226,6 +284,8 @@ constructed (GObject *object) NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object); + + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); } NMNetns * @@ -243,6 +303,12 @@ dispose (GObject *object) NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self); nm_assert (nm_g_hash_table_size (priv->l3cfgs) == 0); + nm_assert (c_list_is_empty (&priv->l3cfg_signal_pending_lst_head)); + + nm_clear_g_source (&priv->signal_pending_idle_id); + + if (priv->platform) + g_signal_handlers_disconnect_by_data (priv->platform, &priv->_self_signal_user_data); g_clear_object (&priv->platform); g_clear_pointer (&priv->l3cfgs, g_hash_table_unref); diff --git a/src/nm-types.h b/src/nm-types.h index 5835c64188..6277e4d811 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -236,6 +236,17 @@ typedef enum { NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, } NMPObjectType; +static inline guint32 +nmp_object_type_to_flags (NMPObjectType obj_type) +{ + G_STATIC_ASSERT_EXPR (NMP_OBJECT_TYPE_MAX < 32); + + nm_assert (_NM_INT_NOT_NEGATIVE (obj_type)); + nm_assert (obj_type < NMP_OBJECT_TYPE_MAX); + + return ((guint32) 1u) << obj_type; +} + /** * NMIPConfigMergeFlags: * @NM_IP_CONFIG_MERGE_DEFAULT: no flags set -- cgit v1.2.1