diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-16 16:49:46 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-09-24 09:43:55 +0200 |
commit | 7ff1beabdb28472db417f31633b7c2f75d3e8428 (patch) | |
tree | ee034787144865c9d4e40c5da5b78b1e3478d4fa | |
parent | 000ad171e32877e558ade79c8bb478c4225cd67d (diff) | |
download | NetworkManager-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.c | 1 | ||||
-rw-r--r-- | src/nm-l3cfg.c | 12 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 11 | ||||
-rw-r--r-- | src/nm-netns.c | 18 |
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; } |