diff options
author | Thomas Haller <thaller@redhat.com> | 2020-07-21 12:52:42 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-07-23 15:29:25 +0200 |
commit | 6e8a98776340fd0005021655f07d15135b62695c (patch) | |
tree | a5efae306c2faebf8484e9e66f239e4a2905bb0a | |
parent | 2eb5639a30de575a3ad13e8f554ac98496f1416c (diff) | |
download | NetworkManager-6e8a98776340fd0005021655f07d15135b62695c.tar.gz |
l3cfg: add nm_l3cfg_property_emit_register() API
The NML3Cfg instance tracks and prepares the IP configuration.
However, that is also partly exposed on other objects, like
NMIP4Config's "route-data" property.
Add an API, so that NMIP4Config can register itself to be notified
when something relevant changes.
This is an alternative to standard GObject properties and signals. They
often seem more effort than worth. That is, because in this case,
NMIP4Config.route-data has no other task then to re-emit the signal.
So, to implement that with GObject properties/signals, we would have to
add a property/signal to NML3Cfg, subscribe to it from NMIP4Config,
and remit the signal. An alternative is to bind properties, but that
would still be quite some extra code, and unclear that it would be
simpler. Not to mention the overhead, as bindings are themself full
GObject instances, that register to and emit signals by name.
-rw-r--r-- | src/nm-l3cfg.c | 149 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 17 | ||||
-rw-r--r-- | src/nm-netns.c | 2 |
3 files changed, 167 insertions, 1 deletions
diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index f415a2fc44..aefaef1cd8 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -16,7 +16,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, ); typedef struct _NML3CfgPrivate { - int dummy; + GArray *property_emit_list; } NML3CfgPrivate; struct _NML3CfgClass { @@ -40,6 +40,10 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +static void _property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type); + +/*****************************************************************************/ + static void _load_link (NML3Cfg *self, gboolean initial) { @@ -77,6 +81,147 @@ _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags) { if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_LINK))) _load_link (self, FALSE); + if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP4_ROUTE))) + _property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE); + if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP6_ROUTE))) + _property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE); +} + +/*****************************************************************************/ + +typedef struct { + GObject *target_obj; + const GParamSpec *target_property; + NML3CfgPropertyEmitType emit_type; +} PropertyEmitData; + +static void +_property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type) +{ + gs_free PropertyEmitData *collected_heap = NULL; + PropertyEmitData *collected = NULL; + PropertyEmitData *emit_data; + guint num; + guint i; + guint j; + + if (!self->priv.p->property_emit_list) + return; + + num = 0; + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if (emit_data->emit_type == emit_type) { + collected = emit_data; + num++; + } + } + + if (num == 0) + return; + + if (num == 1) { + g_object_notify_by_pspec (collected->target_obj, (GParamSpec *) collected->target_property); + return; + } + + if (num < 300u / sizeof (*collected)) + collected = g_alloca (sizeof (PropertyEmitData) * num); + else { + collected_heap = g_new (PropertyEmitData, num); + collected = collected_heap; + } + + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0, j = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if (emit_data->emit_type == emit_type) { + collected[j++] = *emit_data; + g_object_ref (collected->target_obj); + } + } + + nm_assert (j == num); + + for (i = 0; i < num; i++) { + g_object_notify_by_pspec (collected[i].target_obj, (GParamSpec *) collected[i].target_property); + if (i > 0) + g_object_unref (collected[i].target_obj); + } +} + +void +nm_l3cfg_property_emit_register (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property, + NML3CfgPropertyEmitType emit_type) +{ + PropertyEmitData *emit_data; + guint i; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (G_IS_OBJECT (target_obj)); + nm_assert (target_property); + nm_assert (NM_IN_SET (emit_type, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE)); + nm_assert (target_property == nm_g_object_class_find_property_from_gtype (G_OBJECT_TYPE (target_obj), + target_property->name)); + + if (!self->priv.p->property_emit_list) + self->priv.p->property_emit_list = g_array_new (FALSE, FALSE, sizeof (PropertyEmitData)); + else { + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, 0); + for (i = 0; i < self->priv.p->property_emit_list->len; i++, emit_data++) { + if ( emit_data->target_obj != target_obj + || emit_data->target_property != target_property) + continue; + nm_assert (emit_data->emit_type == emit_type); + emit_data->emit_type = emit_type; + return; + } + } + + emit_data = nm_g_array_append_new (self->priv.p->property_emit_list, PropertyEmitData); + *emit_data = (PropertyEmitData) { + .target_obj = target_obj, + .target_property = target_property, + .emit_type = emit_type, + }; +} + +void +nm_l3cfg_property_emit_unregister (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property) +{ + PropertyEmitData *emit_data; + guint i; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (G_IS_OBJECT (target_obj)); + nm_assert ( !target_property + || target_property == nm_g_object_class_find_property_from_gtype (G_OBJECT_TYPE (target_obj), + target_property->name)); + + if (!self->priv.p->property_emit_list) + return; + + for (i = self->priv.p->property_emit_list->len; i > 0; i--) { + emit_data = &g_array_index (self->priv.p->property_emit_list, PropertyEmitData, i); + + if (emit_data->target_obj != target_obj) + continue; + if ( target_property + && emit_data->target_property != target_property) + continue; + + g_array_remove_index_fast (self->priv.p->property_emit_list, i); + + if (target_property) { + /* if a target-property is given, we don't have another entry in + * the list. */ + return; + } + } } /*****************************************************************************/ @@ -154,6 +299,8 @@ finalize (GObject *object) { NML3Cfg *self = NM_L3CFG (object); + nm_assert (nm_g_array_len (self->priv.p->property_emit_list) == 0u); + g_clear_object (&self->priv.netns); g_clear_object (&self->priv.platform); diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index c7e3062269..7fc4b4b7d2 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -72,4 +72,21 @@ nm_l3cfg_get_platform (const NML3Cfg *self) return self->priv.platform; } +/*****************************************************************************/ + +typedef enum { + NM_L3CFG_PROPERTY_EMIT_TYPE_ANY, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE, + NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE, +} NML3CfgPropertyEmitType; + +void nm_l3cfg_property_emit_register (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property, + NML3CfgPropertyEmitType emit_type); + +void nm_l3cfg_property_emit_unregister (NML3Cfg *self, + GObject *target_obj, + const GParamSpec *target_property); + #endif /* __NM_L3CFG_H__ */ diff --git a/src/nm-netns.c b/src/nm-netns.c index ebefeea649..5b170c036b 100644 --- a/src/nm-netns.c +++ b/src/nm-netns.c @@ -286,6 +286,8 @@ constructed (GObject *object) 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); + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); + g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data); } NMNetns * |