summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-07-21 12:52:42 +0200
committerThomas Haller <thaller@redhat.com>2020-07-23 15:29:25 +0200
commit6e8a98776340fd0005021655f07d15135b62695c (patch)
treea5efae306c2faebf8484e9e66f239e4a2905bb0a
parent2eb5639a30de575a3ad13e8f554ac98496f1416c (diff)
downloadNetworkManager-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.c149
-rw-r--r--src/nm-l3cfg.h17
-rw-r--r--src/nm-netns.c2
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 *