summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-16 16:49:46 +0200
committerThomas Haller <thaller@redhat.com>2020-09-24 09:43:55 +0200
commit7ff1beabdb28472db417f31633b7c2f75d3e8428 (patch)
treeee034787144865c9d4e40c5da5b78b1e3478d4fa
parent000ad171e32877e558ade79c8bb478c4225cd67d (diff)
downloadNetworkManager-7ff1beabdb28472db417f31633b7c2f75d3e8428.tar.gz
l3cfg: let l3cfg emit signal on idle handler for platform changes
Currently all NMDevice instance register to the platform change signals, then if a signal for their IP ifindex appears, they schedule a task on an idle handler. That is wasteful. NML3Cfg already gets a notification on an idle handler and can just re-emit it to the respective listeners. With this, there is only one subscriber to the platform signals (NMNetns) which then multiplexes the signals to the right NML3Cfg instances, and further.
-rw-r--r--src/devices/nm-device.c1
-rw-r--r--src/nm-l3cfg.c12
-rw-r--r--src/nm-l3cfg.h11
-rw-r--r--src/nm-netns.c18
4 files changed, 40 insertions, 2 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 254ef965ef..4d9f1c0ef4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -3014,6 +3014,7 @@ _dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
_dev_l3_cfg_acd_maybe_comlete (self);
return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE:
case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED:
/* FIXME(l3cfg) */
return;
diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c
index 9b71713d82..272b79e3d6 100644
--- a/src/nm-l3cfg.c
+++ b/src/nm-l3cfg.c
@@ -620,8 +620,20 @@ _load_link (NML3Cfg *self, gboolean initial)
void
_nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags)
{
+ NML3ConfigNotifyPayload payload;
+
if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_LINK)))
_load_link (self, FALSE);
+
+ payload = (NML3ConfigNotifyPayload) {
+ .platform_change_on_idle = {
+ .obj_type_flags = obj_type_flags,
+ },
+ };
+ _l3cfg_emit_signal_notify (self,
+ NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
+ &payload);
+
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)))
diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h
index 4da85babde..1a598d1af4 100644
--- a/src/nm-l3cfg.h
+++ b/src/nm-l3cfg.h
@@ -22,6 +22,13 @@ typedef enum {
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
+
+ /* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
+ * It re-emits the signal on an idle handler. The purpose is for something
+ * like NMDevice which is already subscribed to these signals, it can get the
+ * notifications without also subscribing directly to the platform. */
+ NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
+
_NM_L3_CONFIG_NOTIFY_TYPE_NUM,
} NML3ConfigNotifyType;
@@ -38,6 +45,10 @@ typedef struct {
guint sources_len;
const NML3ConfigNotifyPayloadAcdFailedSource *sources;
} acd_failed;
+
+ struct {
+ guint32 obj_type_flags;
+ } platform_change_on_idle;
};
} NML3ConfigNotifyPayload;
diff --git a/src/nm-netns.c b/src/nm-netns.c
index a9596eaf00..53414af6a8 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -8,6 +8,7 @@
#include "nm-netns.h"
#include "nm-glib-aux/nm-dedup-multi.h"
+#include "nm-glib-aux/nm-c-list.h"
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
@@ -175,14 +176,27 @@ _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;
+ CList work_list;
- while ((l3cfg_data = c_list_first_entry (&priv->l3cfg_signal_pending_lst_head, L3CfgData, signal_pending_lst))) {
+ priv->signal_pending_idle_id = 0;
+
+ /* we emit all queued signals together. However, we don't want to hook the
+ * main loop for longer than the currently queued elements.
+ *
+ * If we catch more change events, they will be queued and processed by a future
+ * idle handler.
+ *
+ * Hence, move the list to a temporary list. Isn't CList great? */
+
+ c_list_init (&work_list);
+ c_list_splice (&work_list, &priv->l3cfg_signal_pending_lst_head);
+
+ while ((l3cfg_data = c_list_first_entry (&work_list, 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;
}