NetworkManager/src/core/nm-ip-config.h
Thomas Haller 623012c14a
core: rate-limit updates to IP addresses/routes on D-Bus API
It doesn't scale. If you add 100k routes one-by-one, then upon each
change from platform, we will send the growing list of the routes on
D-Bus.

That is too expensive. Especially, if you imagine that the receiving end
is a NMClient instance. There is a D-Bus worker thread that queues the
received GVariant messages, while the main thread may not be able to
process them fast enough. In that case, the memory keeps growing very
fast and due to fragmentation it is not freed.

Instead, rate limit updates to 3 per second.

Note that the receive buffer of the netlink socket can fill up and we
loose messages. Therefore, already on the lowest level, we may miss
addresses/routes. Next, on top of NMPlatform, NMIPConfig listens to
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE events. Thereby it
further will miss intermediate state (e.g. a route that exists only for
a short moment).

Now adding another delay and rate limiting on top of that, does not make
that fundamentally different, we anyway didn't get all intermediate states
from netlink. We may miss addresses/routes that only exist for a short
amount of time. This makes "the problem" worse, but not fundamentally
new.

We can only get a (correct) settled state, after all events are
processed. And we never know, whether there isn't the next event
just waiting to be received.

Rate limiting is important to not overwhelm D-Bus clients. In reality,
none of the users really need this information, because it's also
incomplete. Users who really need to know addresses/routes should use
netlink or find another way (a way that scales and where they explicitly
request this information).
2023-11-30 15:41:43 +01:00

87 lines
2.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2008 - 2013 Red Hat, Inc.
*/
#ifndef __NM_IP_CONFIG_H__
#define __NM_IP_CONFIG_H__
#include "nm-dbus-object.h"
#include "nm-l3cfg.h"
/*****************************************************************************/
#define NM_TYPE_IP_CONFIG (nm_ip_config_get_type())
#define NM_IP_CONFIG(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_CONFIG, NMIPConfig))
#define NM_IP_CONFIG_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IP_CONFIG, NMIPConfigClass))
#define NM_IS_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IP_CONFIG))
#define NM_IS_IP_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_IP_CONFIG))
#define NM_IP_CONFIG_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IP_CONFIG, NMIPConfigClass))
#define NM_IP_CONFIG_L3CFG "l3cfg"
struct _NMIPConfigPrivate {
NML3Cfg *l3cfg;
const NML3ConfigData *l3cd;
GVariant *v_address_data;
GVariant *v_addresses;
GVariant *v_route_data;
GVariant *v_routes;
struct {
const NMPObject *best_default_route;
} v_gateway;
GSource *notify_platform_timeout_source;
gint64 notify_platform_rlimited_until_msec;
gulong l3cfg_notify_id;
guint32 notify_platform_obj_type_flags;
};
struct _NMIPConfig {
NMDBusObject parent;
struct _NMIPConfigPrivate _priv;
};
typedef struct {
NMDBusObjectClass parent;
int addr_family;
} NMIPConfigClass;
GType nm_ip_config_get_type(void);
NMIPConfig *nm_ip_config_new(int addr_family, NML3Cfg *l3cfg);
void nm_ip_config_take_and_unexport_on_idle(NMIPConfig *self_take);
/*****************************************************************************/
static inline NML3Cfg *
nm_ip_config_get_l3cfg(NMIPConfig *self)
{
g_return_val_if_fail(NM_IS_IP_CONFIG(self), NULL);
return self->_priv.l3cfg;
}
static inline struct _NMDedupMultiIndex *
nm_ip_config_get_multi_index(NMIPConfig *self)
{
return nm_l3cfg_get_multi_idx(nm_ip_config_get_l3cfg(self));
}
static inline int
nm_ip_config_get_ifindex(NMIPConfig *self)
{
return nm_l3cfg_get_ifindex(nm_ip_config_get_l3cfg(self));
}
static inline int
nm_ip_config_get_addr_family(NMIPConfig *self)
{
g_return_val_if_fail(NM_IS_IP_CONFIG(self), AF_UNSPEC);
return NM_IP_CONFIG_GET_CLASS(self)->addr_family;
}
#endif /* __NM_IP_CONFIG_H__ */