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