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.
This commit is contained in:
Thomas Haller 2020-09-16 16:49:46 +02:00
parent 000ad171e3
commit 7ff1beabdb
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 40 additions and 2 deletions

View file

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

View file

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

View file

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

View file

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