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.
This commit is contained in:
Thomas Haller 2020-07-21 11:21:44 +02:00
parent ea1f0fc0a6
commit b5c563329a
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 92 additions and 2 deletions

View file

@ -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,

View file

@ -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)
{

View file

@ -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);

View file

@ -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