2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2020-07-18 19:01:04 +02:00
|
|
|
|
2021-02-04 18:04:13 +01:00
|
|
|
#include "src/core/nm-default-daemon.h"
|
2020-07-18 19:01:04 +02:00
|
|
|
|
|
|
|
|
#include "nm-l3cfg.h"
|
|
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
#include "libnm-std-aux/nm-linux-compat.h"
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
#include <net/if.h>
|
2022-09-20 13:29:42 +02:00
|
|
|
#include "nm-compat-headers/linux/if_addr.h"
|
2020-12-13 16:08:56 +01:00
|
|
|
#include <linux/if_ether.h>
|
2020-09-23 15:55:28 +02:00
|
|
|
#include <linux/rtnetlink.h>
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2021-03-02 21:05:11 +01:00
|
|
|
#include "libnm-glib-aux/nm-time-utils.h"
|
2021-03-04 11:29:39 +01:00
|
|
|
#include "libnm-platform/nm-platform.h"
|
|
|
|
|
#include "libnm-platform/nmp-object.h"
|
2022-07-18 10:07:21 +02:00
|
|
|
#include "libnm-platform/nmp-global-tracker.h"
|
2020-07-18 19:01:04 +02:00
|
|
|
#include "nm-netns.h"
|
2020-08-03 17:33:31 +02:00
|
|
|
#include "n-acd/src/n-acd.h"
|
2020-09-16 19:14:20 +02:00
|
|
|
#include "nm-l3-ipv4ll.h"
|
2021-08-06 15:17:05 +02:00
|
|
|
#include "nm-ip-config.h"
|
2020-07-18 19:01:04 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
#define ROUTES_TEMPORARY_NOT_AVAILABLE_MAX_AGE_MSEC ((gint64) 20000)
|
|
|
|
|
|
|
|
|
|
/* When a ObjStateData becomes a "zombie", we aim to delete it from platform
|
|
|
|
|
* on the next commit (until it disappears from platform). But we might have
|
|
|
|
|
* a bug, so that we fail to delete the platform (for example, related to
|
|
|
|
|
* IPv6 multicast routes). We thus rate limit how often we try to do this,
|
|
|
|
|
* before giving up. */
|
|
|
|
|
#define ZOMBIE_COUNT_START 5
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-10-26 18:48:47 +01:00
|
|
|
G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227);
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
#define ACD_SUPPORTED_ETH_ALEN ETH_ALEN
|
|
|
|
|
#define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u)
|
2021-05-03 21:48:58 +02:00
|
|
|
#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (1000u + ACD_ENSURE_RATELIMIT_MSEC))
|
2020-08-03 17:33:31 +02:00
|
|
|
#define ACD_WAIT_PROBING_EXTRA_TIME2_MSEC ((guint32) 1000u)
|
|
|
|
|
#define ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC ((guint32) 30000u)
|
2020-09-28 18:07:51 +02:00
|
|
|
#define ACD_WAIT_TIME_CONFLICT_RESTART_MSEC ((guint32) 120000u)
|
|
|
|
|
#define ACD_WAIT_TIME_ANNOUNCE_RESTART_MSEC ((guint32) 30000u)
|
|
|
|
|
#define ACD_DEFENDCONFLICT_INFO_RATELIMIT_MSEC ((guint32) 30000u)
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
ACD_ADDR_SKIP(in_addr_t addr)
|
|
|
|
|
{
|
|
|
|
|
return addr == 0u;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
#define ACD_TRACK_FMT \
|
|
|
|
|
"[l3cd=" NM_HASH_OBFUSCATE_PTR_FMT ",obj=" NM_HASH_OBFUSCATE_PTR_FMT \
|
|
|
|
|
",tag=" NM_HASH_OBFUSCATE_PTR_FMT "]"
|
2020-08-03 17:33:31 +02:00
|
|
|
#define ACD_TRACK_PTR2(l3cd, obj, tag) \
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(l3cd), NM_HASH_OBFUSCATE_PTR(obj), NM_HASH_OBFUSCATE_PTR(tag)
|
|
|
|
|
#define ACD_TRACK_PTR(acd_track) \
|
|
|
|
|
ACD_TRACK_PTR2((acd_track)->l3cd, (acd_track)->obj, (acd_track)->tag)
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
2020-09-28 18:07:51 +02:00
|
|
|
ACD_STATE_CHANGE_MODE_NACD_CONFLICT = N_ACD_EVENT_CONFLICT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_DEFENDED = N_ACD_EVENT_DEFENDED,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_DOWN = N_ACD_EVENT_DOWN,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_READY = N_ACD_EVENT_READY,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_USED = N_ACD_EVENT_USED,
|
|
|
|
|
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT = _N_ACD_EVENT_N,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT_REAPPLY,
|
2020-08-03 17:33:31 +02:00
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT,
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_ADDED,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_REMOVED,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_LINK_NOW_UP,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INSTANCE_RESET,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_TIMEOUT,
|
|
|
|
|
} AcdStateChangeMode;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
G_STATIC_ASSERT(G_STRUCT_OFFSET(NML3AcdAddrInfo, addr) == 0);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
typedef struct {
|
|
|
|
|
NML3AcdAddrInfo info;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
CList acd_lst;
|
|
|
|
|
CList acd_event_notify_lst;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
NAcdProbe *nacd_probe;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
GSource *acd_data_timeout_source;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
/* see probing_timeout_msec. */
|
|
|
|
|
gint64 probing_timestamp_msec;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
gint64 last_defendconflict_timestamp_msec;
|
|
|
|
|
|
|
|
|
|
guint n_track_infos_alloc;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
/* This is only relevant while in state NM_L3_ACD_ADDR_STATE_PROBING. It's the
|
|
|
|
|
* duration for how long we probe, and @probing_timestamp_msec is the
|
|
|
|
|
* timestamp when we start probing. */
|
|
|
|
|
guint32 probing_timeout_msec;
|
|
|
|
|
|
|
|
|
|
NMEtherAddr last_conflict_addr;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdDefendType acd_defend_type_desired : 3;
|
|
|
|
|
NML3AcdDefendType acd_defend_type_current : 3;
|
|
|
|
|
bool acd_defend_type_is_active : 1;
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
bool track_infos_changed : 1;
|
2020-08-03 17:33:31 +02:00
|
|
|
} AcdData;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdData, info.addr) == 0);
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
typedef struct {
|
|
|
|
|
const NMPObject *obj;
|
|
|
|
|
|
2021-09-15 23:16:25 +02:00
|
|
|
/* Whether obj is currently in the platform cache or not.
|
|
|
|
|
* Since "obj" is the NMPObject from the merged NML3ConfigData,
|
|
|
|
|
* the object in platform has the same ID (but may otherwise not
|
|
|
|
|
* be identical). If this is not NULL, then currently the object
|
|
|
|
|
* is configured in kernel. */
|
|
|
|
|
const NMPObject *os_plobj;
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
CList os_lst;
|
|
|
|
|
|
|
|
|
|
/* If we have a timeout pending, we link the instance to
|
|
|
|
|
* self->priv.p->obj_state_temporary_not_available_lst_head. */
|
|
|
|
|
CList os_temporary_not_available_lst;
|
|
|
|
|
|
|
|
|
|
/* If a NMPObject is no longer to be configured (but was configured
|
|
|
|
|
* during a previous commit), then we need to remember it so that the
|
|
|
|
|
* next commit can delete the address/route in kernel. It becomes a zombie. */
|
|
|
|
|
CList os_zombie_lst;
|
|
|
|
|
|
|
|
|
|
/* We might want to configure "obj" in platform, but it's currently not possible.
|
|
|
|
|
* For example, certain IPv6 routes can only be added after the IPv6 address
|
|
|
|
|
* becomes non-tentative (*sigh*). In such a case, we need to remember that, and
|
|
|
|
|
* retry later. If this timestamp is set to a non-zero value, then it means
|
|
|
|
|
* we tried to configure the obj (at that timestamp) and failed, but we are
|
|
|
|
|
* waiting to retry.
|
|
|
|
|
*
|
|
|
|
|
* See also self->priv.p->obj_state_temporary_not_available_lst_head
|
|
|
|
|
* and self->priv.p->obj_state_temporary_not_available_timeout_source. */
|
|
|
|
|
gint64 os_temporary_not_available_timestamp_msec;
|
|
|
|
|
|
|
|
|
|
/* When the obj is a zombie (that means, it was previously configured by NML3Cfg, but
|
|
|
|
|
* now no longer), it needs to be deleted from platform. This ratelimits the time
|
|
|
|
|
* how often we try that. When the counter reaches zero, we forget about it. */
|
|
|
|
|
guint8 os_zombie_count;
|
|
|
|
|
|
|
|
|
|
/* whether we ever saw the object in platform. */
|
|
|
|
|
bool os_was_in_platform : 1;
|
|
|
|
|
|
|
|
|
|
/* Indicates whether NetworkManager actively tried to configure the object
|
|
|
|
|
* in platform once. */
|
|
|
|
|
bool os_nm_configured : 1;
|
|
|
|
|
|
|
|
|
|
/* This flag is only used temporarily to do a bulk update and
|
|
|
|
|
* clear all the ones that are no longer in used. */
|
|
|
|
|
bool os_dirty : 1;
|
|
|
|
|
bool os_tna_dirty : 1;
|
|
|
|
|
} ObjStateData;
|
|
|
|
|
|
|
|
|
|
G_STATIC_ASSERT(G_STRUCT_OFFSET(ObjStateData, obj) == 0);
|
|
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
struct _NML3CfgCommitTypeHandle {
|
|
|
|
|
CList commit_type_lst;
|
|
|
|
|
NML3CfgCommitType commit_type;
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
typedef struct {
|
2020-08-03 17:19:27 +02:00
|
|
|
const NML3ConfigData *l3cd;
|
2021-08-31 17:12:45 +02:00
|
|
|
NML3CfgConfigFlags config_flags;
|
2020-08-03 17:19:27 +02:00
|
|
|
NML3ConfigMergeFlags merge_flags;
|
2020-09-23 15:55:28 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint32 default_route_table_6;
|
|
|
|
|
guint32 default_route_table_4;
|
|
|
|
|
};
|
|
|
|
|
guint32 default_route_table_x[2];
|
|
|
|
|
};
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint32 default_route_metric_6;
|
|
|
|
|
guint32 default_route_metric_4;
|
|
|
|
|
};
|
|
|
|
|
guint32 default_route_metric_x[2];
|
|
|
|
|
};
|
2020-08-03 17:19:27 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint32 default_route_penalty_6;
|
|
|
|
|
guint32 default_route_penalty_4;
|
|
|
|
|
};
|
|
|
|
|
guint32 default_route_penalty_x[2];
|
|
|
|
|
};
|
2021-09-15 15:38:26 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
int default_dns_priority_6;
|
|
|
|
|
int default_dns_priority_4;
|
|
|
|
|
};
|
|
|
|
|
int default_dns_priority_x[2];
|
|
|
|
|
};
|
2020-09-28 18:07:51 +02:00
|
|
|
gconstpointer tag_confdata;
|
|
|
|
|
guint64 pseudo_timestamp_confdata;
|
|
|
|
|
int priority_confdata;
|
|
|
|
|
guint32 acd_timeout_msec_confdata;
|
|
|
|
|
NML3AcdDefendType acd_defend_type_confdata : 3;
|
|
|
|
|
bool dirty_confdata : 1;
|
2021-11-11 22:16:14 +01:00
|
|
|
gboolean force_commit_once : 1;
|
2020-07-23 16:15:26 +02:00
|
|
|
} L3ConfigData;
|
|
|
|
|
|
2022-05-27 17:11:02 +02:00
|
|
|
struct _NML3CfgBlockHandle {
|
|
|
|
|
NML3Cfg *self;
|
|
|
|
|
CList lst;
|
|
|
|
|
gboolean is_ipv4;
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE(NML3Cfg, PROP_NETNS, PROP_IFINDEX, );
|
|
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
enum {
|
|
|
|
|
SIGNAL_NOTIFY,
|
|
|
|
|
LAST_SIGNAL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = {0};
|
|
|
|
|
|
2020-07-21 12:39:31 +02:00
|
|
|
typedef struct _NML3CfgPrivate {
|
2020-07-23 16:15:26 +02:00
|
|
|
GArray *l3_config_datas;
|
2020-09-16 12:44:38 +02:00
|
|
|
|
2020-10-26 21:42:04 +01:00
|
|
|
NML3IPv4LL *ipv4ll;
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
const NML3ConfigData *combined_l3cd_merged;
|
|
|
|
|
|
|
|
|
|
const NML3ConfigData *combined_l3cd_commited;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
CList commit_type_lst_head;
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
GHashTable *obj_state_hash;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
CList obj_state_lst_head;
|
|
|
|
|
CList obj_state_zombie_lst_head;
|
|
|
|
|
CList obj_state_temporary_not_available_lst_head;
|
2020-07-29 08:39:12 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
GHashTable *acd_ipv4_addresses_on_link;
|
|
|
|
|
|
|
|
|
|
GHashTable *acd_lst_hash;
|
|
|
|
|
CList acd_lst_head;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
CList acd_event_notify_lst_head;
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2021-11-09 13:28:54 +01:00
|
|
|
NAcd *nacd;
|
2020-08-03 17:33:31 +02:00
|
|
|
GSource *nacd_source;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
GSource *nacd_event_down_source;
|
|
|
|
|
gint64 nacd_event_down_ratelimited_until_msec;
|
|
|
|
|
|
2022-05-27 17:11:02 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
CList blocked_lst_head_6;
|
|
|
|
|
CList blocked_lst_head_4;
|
|
|
|
|
};
|
|
|
|
|
CList blocked_lst_head_x[2];
|
|
|
|
|
};
|
|
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
NMIPConfig *ipconfig_6;
|
|
|
|
|
NMIPConfig *ipconfig_4;
|
|
|
|
|
};
|
|
|
|
|
NMIPConfig *ipconfig_x[2];
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
/* Whether we earlier configured MPTCP endpoints for the interface. */
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
bool mptcp_set_6;
|
|
|
|
|
bool mptcp_set_4;
|
|
|
|
|
};
|
|
|
|
|
bool mptcp_set_x[2];
|
|
|
|
|
};
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
/* This is for rate-limiting the creation of nacd instance. */
|
|
|
|
|
GSource *nacd_instance_ensure_retry;
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
GSource *commit_on_idle_source;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
guint64 pseudo_timestamp_counter;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
GSource *obj_state_temporary_not_available_timeout_source;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
NML3CfgCommitType commit_on_idle_type;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
gint8 commit_reentrant_count;
|
|
|
|
|
|
2021-10-17 10:23:04 +02:00
|
|
|
/* The value that was set before we touched the sysctl (this only is
|
|
|
|
|
* meaningful if "ip6_privacy_set" is true. At the end, we want to restore
|
|
|
|
|
* this value. */
|
|
|
|
|
NMSettingIP6ConfigPrivacy ip6_privacy_initial : 4;
|
|
|
|
|
|
|
|
|
|
/* The value that we set the last time. This is cached so that we don't
|
|
|
|
|
* repeatedly try to commit the same value. */
|
|
|
|
|
NMSettingIP6ConfigPrivacy ip6_privacy_set_before : 4;
|
|
|
|
|
|
|
|
|
|
guint32 ndisc_retrans_timer_msec;
|
|
|
|
|
guint32 ndisc_reachable_time_msec;
|
|
|
|
|
int ndisc_hop_limit;
|
|
|
|
|
|
|
|
|
|
/* Whether "self" set the ip6_privacy sysctl (and whether it needs to be reset). */
|
|
|
|
|
bool ip6_privacy_set : 1;
|
|
|
|
|
bool ndisc_reachable_time_msec_set : 1;
|
|
|
|
|
bool ndisc_retrans_timer_msec_set : 1;
|
|
|
|
|
bool ndisc_hop_limit_set : 1;
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
bool commit_type_update_sticky : 1;
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
bool acd_is_pending : 1;
|
|
|
|
|
|
|
|
|
|
bool nacd_acd_not_supported : 1;
|
|
|
|
|
bool acd_ipv4_addresses_on_link_has : 1;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
bool changed_configs_configs : 1;
|
|
|
|
|
bool changed_configs_acd_state : 1;
|
2022-07-18 21:24:09 +02:00
|
|
|
|
|
|
|
|
bool rp_filter_handled : 1;
|
|
|
|
|
bool rp_filter_set : 1;
|
2020-07-21 12:39:31 +02:00
|
|
|
} NML3CfgPrivate;
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
struct _NML3CfgClass {
|
|
|
|
|
GObjectClass parent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
#define _NODEV_ROUTES_TAG(self, IS_IPv4) \
|
|
|
|
|
((gconstpointer) (&(((const char *) (self))[0 + (!(IS_IPv4))])))
|
|
|
|
|
|
|
|
|
|
#define _MPTCP_TAG(self, IS_IPv4) ((gconstpointer) (&(((const char *) (self))[2 + (!(IS_IPv4))])))
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
#define _NMLOG_DOMAIN LOGD_CORE
|
|
|
|
|
#define _NMLOG_PREFIX_NAME "l3cfg"
|
|
|
|
|
#define _NMLOG(level, ...) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
nm_log((level), \
|
|
|
|
|
(_NMLOG_DOMAIN), \
|
|
|
|
|
NULL, \
|
|
|
|
|
NULL, \
|
|
|
|
|
"l3cfg[" NM_HASH_OBFUSCATE_PTR_FMT \
|
|
|
|
|
",ifindex=%d]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(self), \
|
|
|
|
|
nm_l3cfg_get_ifindex(self) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
|
|
|
|
} \
|
|
|
|
|
G_STMT_END
|
2020-09-28 16:03:33 +02:00
|
|
|
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
#define _LOGT_acd(acd_data, ...) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
char _sbuf_acd[NM_INET_ADDRSTRLEN]; \
|
|
|
|
|
\
|
|
|
|
|
_LOGT("acd[%s, %s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
|
|
|
|
nm_inet4_ntop((acd_data)->info.addr, _sbuf_acd), \
|
|
|
|
|
_l3_acd_addr_state_to_string((acd_data)->info.state) \
|
|
|
|
|
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
|
|
|
|
} \
|
2020-08-03 17:33:31 +02:00
|
|
|
G_STMT_END
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle);
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
static void _nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self);
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static gboolean _acd_has_valid_link(const NMPObject *obj,
|
2021-11-09 13:28:54 +01:00
|
|
|
const guint8 **out_addr_bin,
|
|
|
|
|
gboolean *out_acd_not_supported);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_data_notify);
|
|
|
|
|
|
2021-11-09 13:28:54 +01:00
|
|
|
static void _l3_acd_data_state_change(NML3Cfg *self,
|
|
|
|
|
AcdData *acd_data,
|
2020-08-03 17:33:31 +02:00
|
|
|
AcdStateChangeMode mode,
|
2020-09-28 18:07:51 +02:00
|
|
|
const NMEtherAddr *sender,
|
2021-11-09 13:28:54 +01:00
|
|
|
gint64 *p_now_msec);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
static AcdData *_l3_acd_data_find(NML3Cfg *self, in_addr_t addr);
|
|
|
|
|
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
static NM_UTILS_ENUM2STR_DEFINE(_l3_cfg_commit_type_to_string,
|
|
|
|
|
NML3CfgCommitType,
|
2020-09-03 12:24:08 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CFG_COMMIT_TYPE_AUTO, "auto"),
|
|
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CFG_COMMIT_TYPE_NONE, "none"),
|
2020-07-29 08:39:12 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CFG_COMMIT_TYPE_UPDATE, "update"),
|
|
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CFG_COMMIT_TYPE_REAPPLY, "reapply"), );
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
static NM_UTILS_ENUM2STR_DEFINE(
|
|
|
|
|
_l3_config_notify_type_to_string,
|
|
|
|
|
NML3ConfigNotifyType,
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, "acd-event"),
|
2020-09-16 19:14:20 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT, "ipv4ll-event"),
|
2021-05-18 13:35:18 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED, "l3cd-changed"),
|
2020-09-23 18:55:08 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE, "platform-change"),
|
2020-09-19 12:20:45 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"),
|
2021-10-12 09:21:10 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, "pre-commit"),
|
2020-09-19 12:20:45 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"),
|
|
|
|
|
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
|
|
|
|
|
"routes-temporary-not-available-expired"),
|
|
|
|
|
NM_UTILS_ENUM2STR_IGNORE(_NM_L3_CONFIG_NOTIFY_TYPE_NUM), );
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
static NM_UTILS_ENUM2STR_DEFINE(_l3_acd_defend_type_to_string,
|
|
|
|
|
NML3AcdDefendType,
|
|
|
|
|
NM_UTILS_ENUM2STR(NM_L3_ACD_DEFEND_TYPE_ALWAYS, "always"),
|
|
|
|
|
NM_UTILS_ENUM2STR(NM_L3_ACD_DEFEND_TYPE_NEVER, "never"),
|
2021-08-30 10:31:45 +02:00
|
|
|
NM_UTILS_ENUM2STR(_NM_L3_ACD_DEFEND_TYPE_NONE, "none"),
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_UTILS_ENUM2STR(NM_L3_ACD_DEFEND_TYPE_ONCE, "once"), );
|
|
|
|
|
|
|
|
|
|
static NM_UTILS_LOOKUP_DEFINE(_l3_acd_defend_type_to_nacd,
|
|
|
|
|
NML3AcdDefendType,
|
|
|
|
|
int,
|
|
|
|
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(0),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_DEFEND_TYPE_ALWAYS,
|
|
|
|
|
N_ACD_DEFEND_ALWAYS),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_DEFEND_TYPE_ONCE, N_ACD_DEFEND_ONCE),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_DEFEND_TYPE_NEVER, N_ACD_DEFEND_NEVER),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER(), );
|
|
|
|
|
|
|
|
|
|
static NM_UTILS_LOOKUP_DEFINE(_l3_acd_addr_state_to_string,
|
|
|
|
|
NML3AcdAddrState,
|
|
|
|
|
const char *,
|
|
|
|
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(NULL),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_CONFLICT, "conflict"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_READY, "ready"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_DEFENDING, "defending"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_INIT, "init"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_PROBING, "probing"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED,
|
|
|
|
|
"external-removed"),
|
|
|
|
|
NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_USED, "used"), );
|
|
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
static gboolean
|
|
|
|
|
_obj_is_route_nodev(const NMPObject *obj)
|
|
|
|
|
{
|
|
|
|
|
gboolean has_ifindex;
|
|
|
|
|
|
|
|
|
|
nm_assert(obj);
|
|
|
|
|
|
|
|
|
|
has_ifindex = (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex > 0);
|
|
|
|
|
|
|
|
|
|
nm_assert(has_ifindex
|
|
|
|
|
== !(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj),
|
|
|
|
|
NMP_OBJECT_TYPE_IP4_ROUTE,
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ROUTE)
|
|
|
|
|
&& nm_platform_route_type_is_nodev(nm_platform_route_type_uncoerce(
|
|
|
|
|
NMP_OBJECT_CAST_IP_ROUTE(obj)->type_coerced))));
|
|
|
|
|
|
|
|
|
|
return !has_ifindex;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
NMIPConfig *
|
|
|
|
|
nm_l3cfg_ipconfig_get(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
|
|
|
|
|
nm_assert_addr_family(addr_family);
|
|
|
|
|
|
|
|
|
|
return self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_ipconfig_toggle_notify(gpointer data, GObject *object, gboolean is_last_ref)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self = NM_L3CFG(data);
|
2021-08-06 15:17:05 +02:00
|
|
|
NMIPConfig *ipconfig = NM_IP_CONFIG(object);
|
|
|
|
|
|
|
|
|
|
if (!is_last_ref) {
|
|
|
|
|
/* This happens while we take another ref below. Ignore the signal. */
|
|
|
|
|
nm_assert(!NM_IN_SET(ipconfig, self->priv.p->ipconfig_4, self->priv.p->ipconfig_6));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ipconfig == self->priv.p->ipconfig_4)
|
|
|
|
|
self->priv.p->ipconfig_4 = NULL;
|
|
|
|
|
else {
|
|
|
|
|
nm_assert(ipconfig == self->priv.p->ipconfig_6);
|
|
|
|
|
self->priv.p->ipconfig_6 = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We take a second reference to keep the instance alive, while also removing the
|
|
|
|
|
* toggle ref. This will notify the function again, but we will ignore that. */
|
|
|
|
|
g_object_ref(ipconfig);
|
|
|
|
|
|
|
|
|
|
g_object_remove_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self);
|
|
|
|
|
|
|
|
|
|
/* pass on the reference, and unexport on idle. */
|
|
|
|
|
nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&ipconfig));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMIPConfig *
|
|
|
|
|
nm_l3cfg_ipconfig_acquire(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
|
|
|
|
NMIPConfig *ipconfig;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
|
|
|
|
|
nm_assert_addr_family(addr_family);
|
|
|
|
|
|
|
|
|
|
ipconfig = self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)];
|
|
|
|
|
|
|
|
|
|
if (ipconfig)
|
|
|
|
|
return g_object_ref(ipconfig);
|
|
|
|
|
|
|
|
|
|
ipconfig = nm_ip_config_new(addr_family, self);
|
|
|
|
|
|
|
|
|
|
self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)] = ipconfig;
|
|
|
|
|
|
|
|
|
|
/* The ipconfig keeps self alive. We use a toggle reference
|
|
|
|
|
* to avoid a cycle. But we anyway wouldn't want a strong reference,
|
|
|
|
|
* because the user releases the instance by unrefing it, and we
|
|
|
|
|
* notice that via the weak reference. */
|
|
|
|
|
g_object_add_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self);
|
|
|
|
|
|
|
|
|
|
/* We keep the toggle reference, and return the other reference to the caller. */
|
|
|
|
|
return g_steal_pointer(&ipconfig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-09-27 07:48:43 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_is_vrf(const NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
const NMPlatformLink *pllink;
|
|
|
|
|
|
|
|
|
|
pllink = nm_l3cfg_get_pllink(self, TRUE);
|
|
|
|
|
return pllink && pllink->type == NM_LINK_TYPE_VRF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
static const char *
|
2020-09-28 16:19:31 +02:00
|
|
|
_l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data,
|
2021-11-09 13:28:54 +01:00
|
|
|
char *sbuf,
|
2020-09-28 16:19:31 +02:00
|
|
|
gsize sbuf_size)
|
2020-07-28 13:29:36 +02:00
|
|
|
{
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
2020-09-16 19:14:20 +02:00
|
|
|
char sbuf100[100];
|
2021-05-18 13:35:18 +02:00
|
|
|
char sbufobf[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE];
|
2021-11-09 13:28:54 +01:00
|
|
|
char *s = sbuf;
|
2020-09-16 19:14:20 +02:00
|
|
|
gsize l = sbuf_size;
|
|
|
|
|
in_addr_t addr4;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
nm_assert(sbuf);
|
|
|
|
|
nm_assert(sbuf_size > 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
_l3_config_notify_type_to_string(notify_data->notify_type, s, l);
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_seek_end(&s, &l);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
switch (notify_data->notify_type) {
|
2021-05-18 13:35:18 +02:00
|
|
|
case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED:
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_append(&s,
|
|
|
|
|
&l,
|
|
|
|
|
", l3cd-old=%s",
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_old, sbufobf));
|
|
|
|
|
nm_strbuf_append(&s,
|
|
|
|
|
&l,
|
|
|
|
|
", l3cd-new=%s",
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_new, sbufobf));
|
|
|
|
|
nm_strbuf_append(&s, &l, ", commited=%d", notify_data->l3cd_changed.commited);
|
2021-05-18 13:35:18 +02:00
|
|
|
break;
|
2020-09-28 18:07:51 +02:00
|
|
|
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT:
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_append(&s,
|
|
|
|
|
&l,
|
|
|
|
|
", addr=%s, state=%s",
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(notify_data->acd_event.info.addr, sbuf_addr),
|
2021-07-30 08:53:16 +02:00
|
|
|
_l3_acd_addr_state_to_string(notify_data->acd_event.info.state));
|
2020-09-19 12:20:45 +02:00
|
|
|
break;
|
2020-09-23 18:55:08 +02:00
|
|
|
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_append(
|
2020-09-23 18:55:08 +02:00
|
|
|
&s,
|
|
|
|
|
&l,
|
|
|
|
|
", obj-type=%s, change=%s, obj=",
|
2020-09-28 16:19:31 +02:00
|
|
|
NMP_OBJECT_GET_CLASS(notify_data->platform_change.obj)->obj_type_name,
|
|
|
|
|
nm_platform_signal_change_type_to_string(notify_data->platform_change.change_type));
|
|
|
|
|
nmp_object_to_string(notify_data->platform_change.obj, NMP_OBJECT_TO_STRING_PUBLIC, s, l);
|
2020-09-23 18:55:08 +02:00
|
|
|
break;
|
2020-09-19 12:20:45 +02:00
|
|
|
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_append(&s,
|
|
|
|
|
&l,
|
|
|
|
|
", obj-type-flags=0x%x",
|
|
|
|
|
notify_data->platform_change_on_idle.obj_type_flags);
|
2020-09-19 12:20:45 +02:00
|
|
|
break;
|
2020-09-16 19:14:20 +02:00
|
|
|
case NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT:
|
|
|
|
|
nm_assert(NM_IS_L3_IPV4LL(notify_data->ipv4ll_event.ipv4ll));
|
|
|
|
|
addr4 = nm_l3_ipv4ll_get_addr(notify_data->ipv4ll_event.ipv4ll);
|
2021-07-30 08:53:16 +02:00
|
|
|
nm_strbuf_append(
|
2020-09-16 19:14:20 +02:00
|
|
|
&s,
|
|
|
|
|
&l,
|
|
|
|
|
", ipv4ll=" NM_HASH_OBFUSCATE_PTR_FMT "%s%s, state=%s",
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(notify_data->ipv4ll_event.ipv4ll),
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
NM_PRINT_FMT_QUOTED2(addr4 != 0, ", addr=", nm_inet4_ntop(addr4, sbuf_addr), ""),
|
2020-09-16 19:14:20 +02:00
|
|
|
nm_l3_ipv4ll_state_to_string(nm_l3_ipv4ll_get_state(notify_data->ipv4ll_event.ipv4ll),
|
|
|
|
|
sbuf100,
|
|
|
|
|
sizeof(sbuf100)));
|
|
|
|
|
break;
|
2020-09-19 12:20:45 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
return sbuf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-09-28 16:19:31 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_data)
|
2020-09-19 12:20:45 +02:00
|
|
|
{
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
nm_assert(notify_data);
|
|
|
|
|
nm_assert(_NM_INT_NOT_NEGATIVE(notify_data->notify_type));
|
|
|
|
|
nm_assert(notify_data->notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
_LOGT("emit signal (%s)", _l3_config_notify_data_to_string(notify_data, sbuf, sizeof(sbuf)));
|
2020-07-28 13:29:36 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
g_signal_emit(self, signals[SIGNAL_NOTIFY], 0, notify_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_simple(NML3Cfg *self, NML3ConfigNotifyType notify_type)
|
|
|
|
|
{
|
|
|
|
|
NML3ConfigNotifyData notify_data;
|
|
|
|
|
|
|
|
|
|
notify_data.notify_type = notify_type;
|
|
|
|
|
_nm_l3cfg_emit_signal_notify(self, ¬ify_data);
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-18 13:35:18 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg *self,
|
2021-05-18 13:35:18 +02:00
|
|
|
const NML3ConfigData *l3cd_old,
|
|
|
|
|
const NML3ConfigData *l3cd_new,
|
|
|
|
|
gboolean commited)
|
|
|
|
|
{
|
|
|
|
|
NML3ConfigNotifyData notify_data;
|
|
|
|
|
|
|
|
|
|
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED;
|
|
|
|
|
notify_data.l3cd_changed = (typeof(notify_data.l3cd_changed)){
|
|
|
|
|
.l3cd_old = l3cd_old,
|
|
|
|
|
.l3cd_new = l3cd_new,
|
|
|
|
|
.commited = commited,
|
|
|
|
|
};
|
|
|
|
|
_nm_l3cfg_emit_signal_notify(self, ¬ify_data);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
static void
|
|
|
|
|
_l3_changed_configs_set_dirty(NML3Cfg *self)
|
|
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT("IP configuration changed (mark dirty)");
|
|
|
|
|
self->priv.p->changed_configs_configs = TRUE;
|
|
|
|
|
self->priv.p->changed_configs_acd_state = TRUE;
|
2020-09-16 12:44:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_ipv4_addresses_on_link_update(NML3Cfg *self,
|
2020-08-03 17:33:31 +02:00
|
|
|
in_addr_t addr,
|
|
|
|
|
gboolean add /* or else remove */)
|
|
|
|
|
{
|
|
|
|
|
AcdData *acd_data;
|
|
|
|
|
|
|
|
|
|
acd_data = _l3_acd_data_find(self, addr);
|
|
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
|
if (self->priv.p->acd_ipv4_addresses_on_link)
|
|
|
|
|
g_hash_table_add(self->priv.p->acd_ipv4_addresses_on_link, GUINT_TO_POINTER(addr));
|
|
|
|
|
else
|
|
|
|
|
self->priv.p->acd_ipv4_addresses_on_link_has = FALSE;
|
|
|
|
|
if (acd_data)
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_ADDED,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* when we remove an IPv4 address from kernel, we cannot know whether the same address is still
|
|
|
|
|
* present (with a different prefix length or peer). So we cannot be sure whether we removed
|
|
|
|
|
* the only address, or whether more are still present. All we can do is forget about the
|
|
|
|
|
* cached addresses, and fetch them new the next time we need the information. */
|
|
|
|
|
nm_clear_pointer(&self->priv.p->acd_ipv4_addresses_on_link, g_hash_table_unref);
|
|
|
|
|
self->priv.p->acd_ipv4_addresses_on_link_has = FALSE;
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data) {
|
|
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_REMOVED,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_ipv4_addresses_on_link_contains(NML3Cfg *self, in_addr_t addr)
|
|
|
|
|
{
|
|
|
|
|
if (!self->priv.p->acd_ipv4_addresses_on_link) {
|
|
|
|
|
if (self->priv.p->acd_ipv4_addresses_on_link_has)
|
|
|
|
|
return FALSE;
|
|
|
|
|
self->priv.p->acd_ipv4_addresses_on_link_has = TRUE;
|
|
|
|
|
self->priv.p->acd_ipv4_addresses_on_link =
|
|
|
|
|
nm_platform_ip4_address_addr_to_hash(self->priv.platform, self->priv.ifindex);
|
|
|
|
|
if (!self->priv.p->acd_ipv4_addresses_on_link)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return g_hash_table_contains(self->priv.p->acd_ipv4_addresses_on_link, GUINT_TO_POINTER(addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static NAcdProbe *
|
|
|
|
|
_nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
nm_auto(n_acd_probe_config_freep) NAcdProbeConfig *probe_config = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
NAcdProbe *probe;
|
2020-08-03 17:33:31 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
nm_assert(self);
|
|
|
|
|
|
|
|
|
|
if (!self->priv.p->nacd)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (addr == 0)
|
|
|
|
|
return nm_assert_unreachable_val(NULL);
|
|
|
|
|
|
|
|
|
|
r = n_acd_probe_config_new(&probe_config);
|
|
|
|
|
if (r)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
n_acd_probe_config_set_ip(probe_config, (struct in_addr){addr});
|
|
|
|
|
n_acd_probe_config_set_timeout(probe_config, timeout_msec);
|
|
|
|
|
|
|
|
|
|
r = n_acd_probe(self->priv.p->nacd, &probe, probe_config);
|
|
|
|
|
if (r)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
n_acd_probe_set_userdata(probe, user_data);
|
|
|
|
|
return probe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-09-30 09:55:56 +02:00
|
|
|
#define nm_assert_obj_state(self, obj_state) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
if (NM_MORE_ASSERTS > 0) { \
|
2021-11-09 13:28:54 +01:00
|
|
|
const NML3Cfg *_self = (self); \
|
2021-09-30 09:55:56 +02:00
|
|
|
const ObjStateData *_obj_state = (obj_state); \
|
|
|
|
|
\
|
|
|
|
|
nm_assert(_obj_state); \
|
|
|
|
|
nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj_state->obj), \
|
|
|
|
|
NMP_OBJECT_TYPE_IP4_ADDRESS, \
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ADDRESS, \
|
|
|
|
|
NMP_OBJECT_TYPE_IP4_ROUTE, \
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ROUTE)); \
|
|
|
|
|
nm_assert(!_obj_state->os_plobj || _obj_state->os_was_in_platform); \
|
|
|
|
|
nm_assert((_obj_state->os_temporary_not_available_timestamp_msec == 0) \
|
|
|
|
|
== c_list_is_empty(&_obj_state->os_temporary_not_available_lst)); \
|
|
|
|
|
if (_self) { \
|
|
|
|
|
if (c_list_is_empty(&_obj_state->os_zombie_lst)) { \
|
|
|
|
|
nm_assert(_self->priv.p->combined_l3cd_commited); \
|
|
|
|
|
\
|
|
|
|
|
if (NM_MORE_ASSERTS > 5) { \
|
|
|
|
|
nm_assert(c_list_contains(&_self->priv.p->obj_state_lst_head, \
|
|
|
|
|
&_obj_state->os_lst)); \
|
|
|
|
|
nm_assert((_obj_state->os_temporary_not_available_timestamp_msec == 0) \
|
|
|
|
|
|| c_list_contains( \
|
|
|
|
|
&_self->priv.p->obj_state_temporary_not_available_lst_head, \
|
|
|
|
|
&_obj_state->os_temporary_not_available_lst)); \
|
|
|
|
|
nm_assert(_obj_state->os_plobj \
|
|
|
|
|
== nm_platform_lookup_obj(_self->priv.platform, \
|
|
|
|
|
NMP_CACHE_ID_TYPE_OBJECT_TYPE, \
|
|
|
|
|
_obj_state->obj)); \
|
|
|
|
|
nm_assert( \
|
|
|
|
|
c_list_is_empty(&obj_state->os_zombie_lst) \
|
|
|
|
|
? (_obj_state->obj \
|
|
|
|
|
== nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj( \
|
|
|
|
|
_self->priv.p->combined_l3cd_commited, \
|
|
|
|
|
_obj_state->obj))) \
|
|
|
|
|
: (!nm_l3_config_data_lookup_obj( \
|
|
|
|
|
_self->priv.p->combined_l3cd_commited, \
|
|
|
|
|
_obj_state->obj))); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
G_STMT_END
|
|
|
|
|
|
|
|
|
|
static ObjStateData *
|
2021-09-15 23:16:25 +02:00
|
|
|
_obj_state_data_new(const NMPObject *obj, const NMPObject *plobj)
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
{
|
|
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
|
|
|
|
|
obj_state = g_slice_new(ObjStateData);
|
|
|
|
|
*obj_state = (ObjStateData){
|
|
|
|
|
.obj = nmp_object_ref(obj),
|
2021-09-15 23:16:25 +02:00
|
|
|
.os_plobj = nmp_object_ref(plobj),
|
|
|
|
|
.os_was_in_platform = !!plobj,
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
.os_nm_configured = FALSE,
|
|
|
|
|
.os_dirty = FALSE,
|
|
|
|
|
.os_temporary_not_available_lst = C_LIST_INIT(obj_state->os_temporary_not_available_lst),
|
|
|
|
|
.os_zombie_lst = C_LIST_INIT(obj_state->os_zombie_lst),
|
|
|
|
|
};
|
|
|
|
|
return obj_state;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_obj_state_data_free(gpointer data)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
ObjStateData *obj_state = data;
|
|
|
|
|
|
|
|
|
|
c_list_unlink_stale(&obj_state->os_lst);
|
2021-10-12 09:21:10 +02:00
|
|
|
c_list_unlink_stale(&obj_state->os_zombie_lst);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_unlink_stale(&obj_state->os_temporary_not_available_lst);
|
|
|
|
|
nmp_object_unref(obj_state->obj);
|
2021-09-16 09:15:04 +02:00
|
|
|
nmp_object_unref(obj_state->os_plobj);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_g_slice_free(obj_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
_obj_state_data_to_string(const ObjStateData *obj_state, char *buf, gsize buf_size)
|
|
|
|
|
{
|
|
|
|
|
const char *buf0 = buf;
|
|
|
|
|
gint64 now_msec = 0;
|
|
|
|
|
|
|
|
|
|
nm_assert(buf);
|
|
|
|
|
nm_assert(buf_size > 0);
|
|
|
|
|
nm_assert_obj_state(NULL, obj_state);
|
|
|
|
|
|
|
|
|
|
nm_strbuf_append(&buf,
|
|
|
|
|
&buf_size,
|
|
|
|
|
"[" NM_HASH_OBFUSCATE_PTR_FMT ", %s, ",
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(obj_state),
|
|
|
|
|
NMP_OBJECT_GET_CLASS(obj_state->obj)->obj_type_name);
|
|
|
|
|
|
|
|
|
|
nmp_object_to_string(obj_state->obj, NMP_OBJECT_TO_STRING_PUBLIC, buf, buf_size);
|
|
|
|
|
nm_strbuf_seek_end(&buf, &buf_size);
|
|
|
|
|
nm_strbuf_append_c(&buf, &buf_size, ']');
|
|
|
|
|
|
|
|
|
|
if (!c_list_is_empty(&obj_state->os_zombie_lst))
|
|
|
|
|
nm_strbuf_append(&buf, &buf_size, ", zombie[%u]", obj_state->os_zombie_count);
|
|
|
|
|
|
|
|
|
|
if (obj_state->os_nm_configured)
|
|
|
|
|
nm_strbuf_append_str(&buf, &buf_size, ", nm-configured");
|
|
|
|
|
|
2021-09-15 23:16:25 +02:00
|
|
|
if (obj_state->os_plobj) {
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_assert(obj_state->os_was_in_platform);
|
|
|
|
|
nm_strbuf_append_str(&buf, &buf_size, ", in-platform");
|
|
|
|
|
} else if (obj_state->os_was_in_platform)
|
|
|
|
|
nm_strbuf_append_str(&buf, &buf_size, ", was-in-platform");
|
|
|
|
|
|
|
|
|
|
if (obj_state->os_temporary_not_available_timestamp_msec > 0) {
|
|
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(&now_msec);
|
|
|
|
|
nm_strbuf_append(
|
|
|
|
|
&buf,
|
|
|
|
|
&buf_size,
|
|
|
|
|
", temporary-not-available-since=%" G_GINT64_FORMAT ".%03d",
|
|
|
|
|
(now_msec - obj_state->os_temporary_not_available_timestamp_msec) / 1000,
|
|
|
|
|
(int) ((now_msec - obj_state->os_temporary_not_available_timestamp_msec) % 1000));
|
|
|
|
|
}
|
2020-07-29 08:39:12 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
return buf0;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
static gboolean
|
|
|
|
|
_obj_state_data_update(ObjStateData *obj_state, const NMPObject *obj)
|
|
|
|
|
{
|
|
|
|
|
gboolean changed = FALSE;
|
|
|
|
|
|
|
|
|
|
nm_assert_obj_state(NULL, obj_state);
|
|
|
|
|
nm_assert(obj);
|
|
|
|
|
nm_assert(nmp_object_id_equal(obj_state->obj, obj));
|
|
|
|
|
|
|
|
|
|
obj_state->os_dirty = FALSE;
|
|
|
|
|
|
|
|
|
|
if (obj_state->obj != obj) {
|
|
|
|
|
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
|
|
|
|
|
|
|
|
|
if (!nmp_object_equal(obj_state->obj, obj))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
obj_old = g_steal_pointer(&obj_state->obj);
|
|
|
|
|
obj_state->obj = nmp_object_ref(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!c_list_is_empty(&obj_state->os_zombie_lst)) {
|
|
|
|
|
c_list_unlink(&obj_state->os_zombie_lst);
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
static void
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_obj_states_externally_removed_track(NML3Cfg *self, const NMPObject *obj, gboolean in_platform)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
ObjStateData *obj_state;
|
2020-07-29 08:39:12 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_assert_is_bool(in_platform);
|
|
|
|
|
|
|
|
|
|
nm_assert(
|
|
|
|
|
in_platform
|
2021-09-15 23:16:25 +02:00
|
|
|
? (obj
|
|
|
|
|
== nm_platform_lookup_obj(self->priv.platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj))
|
|
|
|
|
: (!nm_platform_lookup_obj(self->priv.platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj)));
|
2020-07-29 08:39:12 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
|
|
|
|
|
if (!obj_state)
|
2020-07-29 08:39:12 +02:00
|
|
|
return;
|
|
|
|
|
|
2021-09-15 23:16:25 +02:00
|
|
|
if (!in_platform)
|
|
|
|
|
obj = NULL;
|
|
|
|
|
|
|
|
|
|
if (obj_state->os_plobj == obj)
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (!in_platform && !c_list_is_empty(&obj_state->os_zombie_lst)) {
|
|
|
|
|
/* this is a zombie. We can forget about it.*/
|
2021-09-15 23:16:25 +02:00
|
|
|
nm_clear_nmp_object(&obj_state->os_plobj);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_unlink(&obj_state->os_zombie_lst);
|
|
|
|
|
_LOGD("obj-state: zombie gone (untrack): %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
g_hash_table_remove(self->priv.p->obj_state_hash, obj_state);
|
2020-07-29 08:39:12 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
l3cfg: fix assertion failure for zombie in _obj_states_externally_removed_track()
We can get a platform signal for any number of reasons. In particular,
we can get a signal that the object is present in platform, while the object
is tracked as zombie.
"Zombies" are objects that were actively configured by NetworkManager, but
now no longer and thus will need to be removed. We remember them as objects
that we need to delete.
The assertion was wrong. We don't need to handle the case "in_platform"
and linked in "os_zombie_lst" specially. If we get a signal that the
object exists while being a zombie, that is fine and not something to
handle specially.
Backtrace:
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007f6a208f1db5 in __GI_abort () at abort.c:79
#2 0x00007f6a212ed123 in g_assertion_message (domain=<optimized out>, file=<optimized out>, line=<optimized out>,
func=0x560e23ada2c0 <__func__.39909> "_obj_states_externally_removed_track", message=<optimized out>) at gtestutils.c:2533
#3 0x00007f6a2134620e in g_assertion_message_expr (domain=domain@entry=0x560e23b781a0 "nm", file=file@entry=0x560e23acec60 "src/core/nm-l3cfg.c", line=line@entry=920,
func=func@entry=0x560e23ada2c0 <__func__.39909> "_obj_states_externally_removed_track", expr=expr@entry=0x560e23ad1980 "c_list_is_empty(&obj_state->os_zombie_lst)") at gtestutils.c:2556
#4 0x0000560e23853f38 in _obj_states_externally_removed_track (self=self@entry=0x560e25f168e0, obj=<optimized out>, obj@entry=0x560e25e466a0, in_platform=in_platform@entry=1)
at src/core/nm-l3cfg.c:920
#5 0x0000560e2385b8ea in _nm_l3cfg_notify_platform_change (self=0x560e25f168e0, change_type=change_type@entry=NM_PLATFORM_SIGNAL_CHANGED, obj=0x560e25e466a0) at src/core/nm-l3cfg.c:1364
#6 0x0000560e23861251 in _platform_signal_cb (platform=<optimized out>, obj_type_i=<optimized out>, ifindex=<optimized out>, platform_object=0x560e25e466b8, change_type_i=2,
p_self=<optimized out>) at ./src/libnm-platform/nmp-object.h:443
#7 0x00007f6a1c4a914e in ffi_call_unix64 () at ../src/x86/unix64.S:76
#8 0x00007f6a1c4a8aff in ffi_call (cif=cif@entry=0x7fffac40e570, fn=fn@entry=0x560e23861100 <_platform_signal_cb>, rvalue=<optimized out>, avalue=avalue@entry=0x7fffac40e480)
at ../src/x86/ffi64.c:525
#9 0x00007f6a217fee85 in g_cclosure_marshal_generic (closure=<optimized out>, return_gvalue=<optimized out>, n_param_values=<optimized out>, param_values=<optimized out>,
invocation_hint=<optimized out>, marshal_data=<optimized out>) at gclosure.c:1490
#10 0x00007f6a217fe3bd in g_closure_invoke (closure=0x560e25df53c0, return_value=0x0, n_param_values=5, param_values=0x7fffac40e7a0, invocation_hint=0x7fffac40e720) at gclosure.c:804
#11 0x00007f6a21811945 in signal_emit_unlocked_R (node=node@entry=0x7f6a00008870, detail=detail@entry=0, instance=instance@entry=0x560e25ddd080, emission_return=emission_return@entry=0x0,
instance_and_params=instance_and_params@entry=0x7fffac40e7a0) at gsignal.c:3636
#12 0x00007f6a2181aa56 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffac40e9c0) at gsignal.c:3392
#13 0x00007f6a2181b093 in g_signal_emit (instance=instance@entry=0x560e25ddd080, signal_id=<optimized out>, detail=detail@entry=0) at gsignal.c:3448
#14 0x0000560e2392deea in nm_platform_cache_update_emit_signal (self=0x560e25ddd080, cache_op=NMP_CACHE_OPS_UPDATED, obj_old=<optimized out>, obj_new=<optimized out>)
at src/libnm-platform/nm-platform.c:8824
#15 0x0000560e238fd520 in event_handler_recvmsgs () at src/libnm-platform/nm-linux-platform.c:7183
#16 0x0000560e238fdcbf in event_handler_read_netlink () at src/libnm-platform/nm-linux-platform.c:9403
#17 0x0000560e238ffab3 in delayed_action_handle_one () at src/libnm-platform/nm-linux-platform.c:6238
#18 0x0000560e238ffcae in delayed_action_handle_all () at src/libnm-platform/nm-linux-platform.c:6256
#19 0x0000560e23901acc in do_delete_object () at src/libnm-platform/nm-linux-platform.c:7392
#20 0x0000560e2390227c in ip4_address_delete () at src/libnm-platform/nm-linux-platform.c:8782
#21 0x0000560e23922709 in nm_platform_ip4_address_delete (self=self@entry=0x560e25ddd080, ifindex=ifindex@entry=150, address=16843009, plen=<optimized out>, peer_address=16843009)
at src/libnm-platform/nm-platform.c:3574
#22 0x0000560e239275ab in nm_platform_ip_address_sync (self=0x560e25ddd080, addr_family=addr_family@entry=2, ifindex=150, known_addresses=<optimized out>, known_addresses@entry=0x0,
addresses_prune=0x560e25e81aa0) at src/libnm-platform/nm-platform.c:3984
#23 0x0000560e23855e17 in _l3_commit_one (self=0x560e25f168e0, addr_family=2, commit_type=<optimized out>, l3cd_old=<optimized out>, changed_combined_l3cd=<optimized out>)
at src/core/nm-l3cfg.c:4256
#24 0x0000560e2385fc5c in _l3_commit (self=0x560e25f168e0, commit_type=NM_L3_CFG_COMMIT_TYPE_REAPPLY, is_idle=<optimized out>) at src/core/nm-l3cfg.c:4353
#25 0x0000560e239c6a6d in nm_device_cleanup (self=0x560e25e985e0, reason=<optimized out>, cleanup_type=CLEANUP_TYPE_DECONFIGURE) at src/core/devices/nm-device.c:15082
#26 0x0000560e239c7522 in _set_state_full (self=0x560e25e985e0, state=<optimized out>, reason=<optimized out>, quitting=0) at src/core/devices/nm-device.c:15467
#27 0x0000560e239cd482 in queued_state_set (user_data=user_data@entry=0x560e25e985e0) at src/core/devices/nm-device.c:15706
#28 0x00007f6a2131b27b in g_idle_dispatch (source=0x560e25ebab60, callback=0x560e239cd3d0 <queued_state_set>, user_data=0x560e25e985e0) at gmain.c:5579
#29 0x00007f6a2131e95d in g_main_dispatch (context=0x560e25d97bc0) at gmain.c:3193
#30 g_main_context_dispatch (context=context@entry=0x560e25d97bc0) at gmain.c:3873
#31 0x00007f6a2131ed18 in g_main_context_iterate (context=0x560e25d97bc0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3946
#32 0x00007f6a2131f042 in g_main_loop_run (loop=0x560e25d730f0) at gmain.c:4142
#33 0x0000560e237c06ec in main (argc=<optimized out>, argv=<optimized out>) at src/core/main.c:509
Fixes: 929eae245d5d ('l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state')
(cherry picked from commit 849a4eee5c06e6f5eb70a4616e0060ba66a6c5e4)
2022-02-22 19:42:50 +01:00
|
|
|
/* Even if this is a zombie (os_zombie_lst), it is still in platform. We continue
|
|
|
|
|
* tracking it, until it gets deleted from platform or until the os_zombie_count
|
|
|
|
|
* drops to zero. We don't need to handle this specially here. */
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
|
|
|
|
if (in_platform) {
|
2021-09-16 09:15:04 +02:00
|
|
|
nmp_object_ref_set(&obj_state->os_plobj, obj);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state->os_was_in_platform = TRUE;
|
|
|
|
|
_LOGD("obj-state: appeared in platform: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
goto out;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
2021-09-15 23:16:25 +02:00
|
|
|
nm_clear_nmp_object(&obj_state->os_plobj);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_LOGD("obj-state: remove from platform: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
nm_assert_obj_state(self, obj_state);
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_obj_states_update_all(NML3Cfg *self)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
static const NMPObjectType obj_types[] = {
|
|
|
|
|
NMP_OBJECT_TYPE_IP4_ADDRESS,
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ADDRESS,
|
|
|
|
|
NMP_OBJECT_TYPE_IP4_ROUTE,
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ROUTE,
|
|
|
|
|
};
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
int i;
|
|
|
|
|
gboolean any_dirty = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_for_each_entry (obj_state, &self->priv.p->obj_state_lst_head, os_lst) {
|
|
|
|
|
if (!c_list_is_empty(&obj_state->os_zombie_lst)) {
|
|
|
|
|
/* we can ignore zombies. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
any_dirty = TRUE;
|
|
|
|
|
obj_state->os_dirty = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < (int) G_N_ELEMENTS(obj_types); i++) {
|
|
|
|
|
const NMPObjectType obj_type = obj_types[i];
|
|
|
|
|
NMDedupMultiIter o_iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj;
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
|
|
|
|
if (!self->priv.p->combined_l3cd_commited)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nm_l3_config_data_iter_obj_for_each (&o_iter,
|
|
|
|
|
self->priv.p->combined_l3cd_commited,
|
|
|
|
|
&obj,
|
|
|
|
|
obj_type) {
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (_obj_is_route_nodev(obj)) {
|
|
|
|
|
/* this is a nodev route. We don't track an obj-state for this. */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
|
|
|
|
|
if (!obj_state) {
|
|
|
|
|
obj_state =
|
|
|
|
|
_obj_state_data_new(obj,
|
2021-09-15 23:16:25 +02:00
|
|
|
nm_platform_lookup_obj(self->priv.platform,
|
|
|
|
|
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
|
|
|
|
obj));
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_link_tail(&self->priv.p->obj_state_lst_head, &obj_state->os_lst);
|
|
|
|
|
g_hash_table_add(self->priv.p->obj_state_hash, obj_state);
|
|
|
|
|
_LOGD("obj-state: track: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
nm_assert_obj_state(self, obj_state);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (_obj_state_data_update(obj_state, obj)) {
|
|
|
|
|
_LOGD("obj-state: update: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
|
|
|
|
nm_assert_obj_state(self, obj_state);
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (any_dirty) {
|
|
|
|
|
GHashTableIter h_iter;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash);
|
|
|
|
|
while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) {
|
|
|
|
|
if (!c_list_is_empty(&obj_state->os_zombie_lst))
|
|
|
|
|
continue;
|
|
|
|
|
if (!obj_state->os_dirty)
|
|
|
|
|
continue;
|
|
|
|
|
|
2021-09-15 23:16:25 +02:00
|
|
|
if (obj_state->os_plobj && obj_state->os_nm_configured) {
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_link_tail(&self->priv.p->obj_state_zombie_lst_head,
|
|
|
|
|
&obj_state->os_zombie_lst);
|
|
|
|
|
obj_state->os_zombie_count = ZOMBIE_COUNT_START;
|
|
|
|
|
_LOGD("obj-state: now zombie: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_LOGD("obj-state: untrack: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
g_hash_table_iter_remove(&h_iter);
|
|
|
|
|
}
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
typedef struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self;
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
NML3CfgCommitType commit_type;
|
|
|
|
|
} ObjStatesSyncFilterData;
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2022-02-07 19:33:06 +01:00
|
|
|
_obj_states_sync_filter(NML3Cfg *self, const NMPObject *obj, NML3CfgCommitType commit_type)
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
{
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
2022-02-07 19:33:06 +01:00
|
|
|
NMPObjectType obj_type;
|
|
|
|
|
ObjStateData *obj_state;
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
|
|
|
|
obj_type = NMP_OBJECT_GET_TYPE(obj);
|
|
|
|
|
|
|
|
|
|
if (obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS
|
|
|
|
|
&& NMP_OBJECT_CAST_IP4_ADDRESS(obj)->a_acd_not_ready)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2022-02-07 19:33:06 +01:00
|
|
|
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
2022-02-07 19:33:06 +01:00
|
|
|
nm_assert_obj_state(self, obj_state);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_assert(obj_state->obj == obj);
|
|
|
|
|
nm_assert(c_list_is_empty(&obj_state->os_zombie_lst));
|
|
|
|
|
|
|
|
|
|
if (!obj_state->os_nm_configured) {
|
|
|
|
|
obj_state->os_nm_configured = TRUE;
|
|
|
|
|
|
|
|
|
|
_LOGD("obj-state: configure-first-time: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
return TRUE;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (obj_state->os_temporary_not_available_timestamp_msec > 0) {
|
|
|
|
|
/* we currently try to configure this address (but failed earlier).
|
|
|
|
|
* Definitely retry. */
|
|
|
|
|
return TRUE;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
2022-02-07 19:33:06 +01:00
|
|
|
if (!obj_state->os_plobj && commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY
|
2021-11-11 22:16:14 +01:00
|
|
|
&& !nmp_object_get_force_commit(obj))
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-07 19:33:06 +01:00
|
|
|
static gboolean
|
|
|
|
|
_obj_states_sync_filter_predicate(gconstpointer o, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
const NMPObject *obj = o;
|
|
|
|
|
const ObjStatesSyncFilterData *sync_filter_data = user_data;
|
|
|
|
|
|
|
|
|
|
return _obj_states_sync_filter(sync_filter_data->self, obj, sync_filter_data->commit_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GPtrArray *
|
|
|
|
|
_commit_collect_addresses(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
const NMDedupMultiHeadEntry *head_entry;
|
|
|
|
|
const ObjStatesSyncFilterData sync_filter_data = {
|
|
|
|
|
.self = self,
|
|
|
|
|
.commit_type = commit_type,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited,
|
|
|
|
|
NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4));
|
|
|
|
|
return nm_dedup_multi_objs_to_ptr_array_head(head_entry,
|
|
|
|
|
_obj_states_sync_filter_predicate,
|
|
|
|
|
(gpointer) &sync_filter_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_commit_collect_routes(NML3Cfg *self,
|
|
|
|
|
int addr_family,
|
|
|
|
|
NML3CfgCommitType commit_type,
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
GPtrArray **routes,
|
|
|
|
|
GPtrArray **routes_nodev)
|
2022-02-07 19:33:06 +01:00
|
|
|
{
|
|
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
const NMDedupMultiHeadEntry *head_entry;
|
|
|
|
|
const NMDedupMultiEntry *entry;
|
|
|
|
|
|
|
|
|
|
nm_assert(routes && !*routes);
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
nm_assert(routes_nodev && !*routes_nodev);
|
2022-02-07 19:33:06 +01:00
|
|
|
|
|
|
|
|
head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited,
|
|
|
|
|
NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4));
|
|
|
|
|
|
|
|
|
|
if (!head_entry)
|
2022-11-23 08:29:48 +01:00
|
|
|
goto loop_done;
|
2022-02-07 19:33:06 +01:00
|
|
|
|
|
|
|
|
c_list_for_each_entry (entry, &head_entry->lst_entries_head, lst_entries) {
|
|
|
|
|
const NMPObject *obj = entry->obj;
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
GPtrArray **r;
|
2022-02-07 19:33:06 +01:00
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (_obj_is_route_nodev(obj))
|
|
|
|
|
r = routes_nodev;
|
|
|
|
|
else {
|
2022-11-23 08:29:48 +01:00
|
|
|
nm_assert(NMP_OBJECT_CAST_IP_ROUTE(obj)->ifindex == self->priv.ifindex);
|
|
|
|
|
|
|
|
|
|
if (IS_IPv4 && NMP_OBJECT_CAST_IP4_ROUTE(obj)->weight > 0) {
|
|
|
|
|
/* This route needs to be registered as ECMP route. */
|
|
|
|
|
nm_netns_ip_route_ecmp_register(self->priv.netns, self, obj);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (!_obj_states_sync_filter(self, obj, commit_type))
|
|
|
|
|
continue;
|
|
|
|
|
r = routes;
|
2022-02-07 19:33:06 +01:00
|
|
|
}
|
|
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (!*r)
|
|
|
|
|
*r = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add(*r, (gpointer) nmp_object_ref(obj));
|
2022-02-07 19:33:06 +01:00
|
|
|
}
|
2022-11-23 08:29:48 +01:00
|
|
|
|
|
|
|
|
loop_done:
|
|
|
|
|
|
|
|
|
|
if (IS_IPv4) {
|
|
|
|
|
gs_unref_ptrarray GPtrArray *singlehop_routes = NULL;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
/* NMNetns will merge the routes. The ones that found a merge partner are true multihop
|
|
|
|
|
* routes, with potentially a next hop on different interfaces. The routes
|
|
|
|
|
* that didn't find a merge partner are returned in "singlehop_routes". */
|
2023-01-31 10:30:04 +01:00
|
|
|
nm_netns_ip_route_ecmp_commit(self->priv.netns,
|
|
|
|
|
self,
|
|
|
|
|
&singlehop_routes,
|
|
|
|
|
NM_IN_SET(commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY));
|
2022-11-23 08:29:48 +01:00
|
|
|
|
|
|
|
|
if (singlehop_routes) {
|
|
|
|
|
for (i = 0; i < singlehop_routes->len; i++) {
|
|
|
|
|
const NMPObject *obj = singlehop_routes->pdata[i];
|
|
|
|
|
|
|
|
|
|
if (!_obj_states_sync_filter(self, obj, commit_type))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!*routes)
|
|
|
|
|
*routes =
|
|
|
|
|
g_ptr_array_new_with_free_func((GDestroyNotify) nm_dedup_multi_obj_unref);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add(*routes, (gpointer) nmp_object_ref(obj));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-07 19:33:06 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_obj_state_zombie_lst_get_prune_lists(NML3Cfg *self,
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
int addr_family,
|
|
|
|
|
GPtrArray **out_addresses_prune,
|
|
|
|
|
GPtrArray **out_routes_prune)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
const NMPObjectType obj_type_route = NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4);
|
|
|
|
|
const NMPObjectType obj_type_address = NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4);
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
2021-11-09 13:28:54 +01:00
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
ObjStateData *obj_state_safe;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(out_addresses_prune && !*out_addresses_prune);
|
|
|
|
|
nm_assert(out_routes_prune && !*out_routes_prune);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_for_each_entry_safe (obj_state,
|
|
|
|
|
obj_state_safe,
|
|
|
|
|
&self->priv.p->obj_state_zombie_lst_head,
|
|
|
|
|
os_zombie_lst) {
|
|
|
|
|
NMPObjectType obj_type;
|
2021-11-09 13:28:54 +01:00
|
|
|
GPtrArray **p_a;
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
|
|
|
|
nm_assert_obj_state(self, obj_state);
|
|
|
|
|
nm_assert(obj_state->os_zombie_count > 0);
|
|
|
|
|
|
|
|
|
|
obj_type = NMP_OBJECT_GET_TYPE(obj_state->obj);
|
|
|
|
|
|
|
|
|
|
if (obj_type == obj_type_route)
|
|
|
|
|
p_a = out_routes_prune;
|
|
|
|
|
else if (obj_type == obj_type_address)
|
|
|
|
|
p_a = out_addresses_prune;
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!*p_a)
|
|
|
|
|
*p_a = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add(*p_a, (gpointer) nmp_object_ref(obj_state->obj));
|
|
|
|
|
|
|
|
|
|
if (--obj_state->os_zombie_count == 0) {
|
|
|
|
|
_LOGD("obj-state: prune zombie (untrack): %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
g_hash_table_remove(self->priv.p->obj_state_hash, obj_state);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
_LOGD("obj-state: prune zombie: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
static void
|
|
|
|
|
_obj_state_zombie_lst_prune_all(NML3Cfg *self, int addr_family)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
ObjStateData *obj_state_safe;
|
2020-07-29 08:39:12 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
/* we call this during reapply. Then we delete all the routes/addresses
|
|
|
|
|
* that are configured, and not only the zombies.
|
|
|
|
|
*
|
|
|
|
|
* Still, we need to adjust the os_zombie_count and assume that we
|
|
|
|
|
* are going to drop them. */
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry_safe (obj_state,
|
|
|
|
|
obj_state_safe,
|
|
|
|
|
&self->priv.p->obj_state_zombie_lst_head,
|
|
|
|
|
os_zombie_lst) {
|
|
|
|
|
nm_assert_obj_state(self, obj_state);
|
|
|
|
|
nm_assert(obj_state->os_zombie_count > 0);
|
2020-10-09 19:04:38 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (NMP_OBJECT_GET_ADDR_FAMILY(obj_state->obj) != addr_family)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (--obj_state->os_zombie_count == 0) {
|
|
|
|
|
_LOGD("obj-state: zombie pruned during reapply (untrack): %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
g_hash_table_remove(self->priv.p->obj_state_hash, obj_state);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
_LOGD("obj-state: zombie pruned during reapply: %s",
|
|
|
|
|
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
|
|
|
|
|
}
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-21 11:57:31 +02:00
|
|
|
static void
|
|
|
|
|
_load_link(NML3Cfg *self, gboolean initial)
|
|
|
|
|
{
|
|
|
|
|
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj;
|
|
|
|
|
const char *ifname;
|
|
|
|
|
const char *ifname_old;
|
2020-08-03 17:33:31 +02:00
|
|
|
gboolean nacd_changed;
|
|
|
|
|
gboolean nacd_new_valid;
|
|
|
|
|
gboolean nacd_old_valid;
|
2021-11-09 13:28:54 +01:00
|
|
|
const guint8 *nacd_old_addr = NULL;
|
|
|
|
|
const guint8 *nacd_new_addr = NULL;
|
2020-08-03 17:33:31 +02:00
|
|
|
gboolean nacd_link_now_up;
|
2021-11-09 13:28:54 +01:00
|
|
|
AcdData *acd_data;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
if (initial) {
|
|
|
|
|
obj = nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE);
|
|
|
|
|
self->priv.plobj_next = nmp_object_ref(obj);
|
|
|
|
|
} else {
|
|
|
|
|
obj = self->priv.plobj_next;
|
|
|
|
|
nm_assert(obj == nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
if (initial && obj == self->priv.plobj)
|
2020-07-21 11:57:31 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
obj_old = g_steal_pointer(&self->priv.plobj);
|
|
|
|
|
self->priv.plobj = nmp_object_ref(obj);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (obj && NM_FLAGS_HAS(NMP_OBJECT_CAST_LINK(obj)->n_ifi_flags, IFF_UP)
|
|
|
|
|
&& (!obj_old || !NM_FLAGS_HAS(NMP_OBJECT_CAST_LINK(obj_old)->n_ifi_flags, IFF_UP)))
|
|
|
|
|
nacd_link_now_up = TRUE;
|
|
|
|
|
else
|
|
|
|
|
nacd_link_now_up = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nacd_changed = FALSE;
|
|
|
|
|
nacd_old_valid = _acd_has_valid_link(obj_old, &nacd_old_addr, NULL);
|
|
|
|
|
nacd_new_valid = _acd_has_valid_link(obj, &nacd_new_addr, NULL);
|
|
|
|
|
if (self->priv.p->nacd_instance_ensure_retry) {
|
|
|
|
|
if (nacd_new_valid
|
|
|
|
|
&& (!nacd_old_valid
|
|
|
|
|
|| memcmp(nacd_new_addr, nacd_old_addr, ACD_SUPPORTED_ETH_ALEN) == 0))
|
|
|
|
|
nacd_changed = TRUE;
|
|
|
|
|
} else if (self->priv.p->nacd) {
|
|
|
|
|
if (!nacd_new_valid)
|
|
|
|
|
nacd_changed = TRUE;
|
|
|
|
|
else if (!nacd_old_valid)
|
|
|
|
|
nacd_changed = nm_assert_unreachable_val(TRUE);
|
|
|
|
|
else if (memcmp(nacd_old_addr, nacd_new_addr, ACD_SUPPORTED_ETH_ALEN) != 0)
|
|
|
|
|
nacd_changed = TRUE;
|
|
|
|
|
} else if (nacd_new_valid)
|
|
|
|
|
nacd_changed = TRUE;
|
2020-07-21 11:57:31 +02:00
|
|
|
ifname_old = nmp_object_link_get_ifname(obj_old);
|
2020-09-25 17:05:58 +02:00
|
|
|
ifname = nmp_object_link_get_ifname(self->priv.plobj);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-21 11:57:31 +02:00
|
|
|
if (initial) {
|
|
|
|
|
_LOGT("link ifname changed: %s%s%s (initial)", NM_PRINT_FMT_QUOTE_STRING(ifname));
|
|
|
|
|
} else if (!nm_streq0(ifname, ifname_old)) {
|
|
|
|
|
_LOGT("link ifname changed: %s%s%s (was %s%s%s)",
|
|
|
|
|
NM_PRINT_FMT_QUOTE_STRING(ifname),
|
|
|
|
|
NM_PRINT_FMT_QUOTE_STRING(ifname_old));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (nacd_changed) {
|
|
|
|
|
if (!c_list_is_empty(&self->priv.p->acd_lst_head))
|
|
|
|
|
_LOGT("acd: link change causes restart of ACD");
|
|
|
|
|
_l3_acd_nacd_instance_reset(self, NM_TERNARY_FALSE, TRUE);
|
|
|
|
|
} else if (nacd_link_now_up) {
|
|
|
|
|
if (!c_list_is_empty(&self->priv.p->acd_lst_head)) {
|
2020-09-28 18:07:51 +02:00
|
|
|
gint64 now_msec = 0;
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
_LOGT("acd: link up requires are re-initialize of ACD probes");
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) {
|
|
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_LINK_NOW_UP,
|
|
|
|
|
NULL,
|
|
|
|
|
&now_msec);
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-21 11:57:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-21 11:21:44 +02:00
|
|
|
void
|
|
|
|
|
_nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags)
|
|
|
|
|
{
|
2020-09-28 16:19:31 +02:00
|
|
|
NML3ConfigNotifyData notify_data;
|
2020-09-16 16:49:46 +02:00
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
if (self->priv.plobj_next != self->priv.plobj)
|
2020-07-21 11:57:31 +02:00
|
|
|
_load_link(self, FALSE);
|
2020-09-16 16:49:46 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE;
|
|
|
|
|
notify_data.platform_change_on_idle = (typeof(notify_data.platform_change_on_idle)){
|
|
|
|
|
.obj_type_flags = obj_type_flags,
|
2020-09-16 16:49:46 +02:00
|
|
|
};
|
2020-09-28 16:19:31 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify(self, ¬ify_data);
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_all(self);
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
void
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_l3cfg_notify_platform_change(NML3Cfg *self,
|
2020-07-29 08:39:12 +02:00
|
|
|
NMPlatformSignalChangeType change_type,
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj)
|
2020-07-29 08:39:12 +02:00
|
|
|
{
|
2020-09-28 16:19:31 +02:00
|
|
|
NML3ConfigNotifyData notify_data;
|
|
|
|
|
NMPObjectType obj_type;
|
2020-09-23 18:55:08 +02:00
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
nm_assert(NMP_OBJECT_IS_VALID(obj));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-23 18:55:08 +02:00
|
|
|
obj_type = NMP_OBJECT_GET_TYPE(obj);
|
|
|
|
|
|
|
|
|
|
switch (obj_type) {
|
2020-09-25 17:05:58 +02:00
|
|
|
case NMP_OBJECT_TYPE_LINK:
|
|
|
|
|
{
|
|
|
|
|
const NMPObject *plobj;
|
|
|
|
|
|
|
|
|
|
plobj = (change_type != NM_PLATFORM_SIGNAL_REMOVED) ? obj : NULL;
|
|
|
|
|
nm_assert(plobj == nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE));
|
|
|
|
|
nmp_object_ref_set(&self->priv.plobj_next, plobj);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-07-29 08:39:12 +02:00
|
|
|
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
2020-08-03 17:33:31 +02:00
|
|
|
_l3_acd_ipv4_addresses_on_link_update(self,
|
|
|
|
|
NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address,
|
|
|
|
|
change_type != NM_PLATFORM_SIGNAL_REMOVED);
|
|
|
|
|
/* fall-through */
|
2020-07-29 08:39:12 +02:00
|
|
|
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
|
|
|
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
|
|
|
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_obj_states_externally_removed_track(self, obj, change_type != NM_PLATFORM_SIGNAL_REMOVED);
|
2020-07-29 08:39:12 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-23 18:55:08 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE;
|
|
|
|
|
notify_data.platform_change = (typeof(notify_data.platform_change)){
|
|
|
|
|
.obj = obj,
|
|
|
|
|
.change_type = change_type,
|
2020-09-23 18:55:08 +02:00
|
|
|
};
|
2020-09-28 16:19:31 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify(self, ¬ify_data);
|
2020-09-23 18:55:08 +02:00
|
|
|
|
|
|
|
|
nm_assert(NMP_OBJECT_IS_VALID(obj));
|
2020-07-29 08:39:12 +02:00
|
|
|
}
|
|
|
|
|
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_get_acd_is_pending(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), FALSE);
|
|
|
|
|
|
|
|
|
|
return self->priv.p->acd_is_pending;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-10-22 12:18:39 +02:00
|
|
|
_acd_track_data_clear(NML3AcdAddrTrackInfo *acd_track)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
|
|
|
|
nm_l3_config_data_unref(acd_track->l3cd);
|
|
|
|
|
nmp_object_unref(acd_track->obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_acd_data_free(AcdData *acd_data)
|
|
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(acd_data->info.n_track_infos == 0u);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
n_acd_probe_free(acd_data->nacd_probe);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_clear_g_source_inst(&acd_data->acd_data_timeout_source);
|
2020-08-03 17:33:31 +02:00
|
|
|
c_list_unlink_stale(&acd_data->acd_lst);
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_unlink_stale(&acd_data->acd_event_notify_lst);
|
2020-10-22 12:18:39 +02:00
|
|
|
g_free((NML3AcdAddrTrackInfo *) acd_data->info.track_infos);
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_g_slice_free(acd_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
2022-06-12 19:50:09 -04:00
|
|
|
_acd_data_collect_tracks_data(NML3Cfg *self,
|
|
|
|
|
const AcdData *acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NMTernary dirty_selector,
|
2021-11-09 13:28:54 +01:00
|
|
|
guint32 *out_best_acd_timeout_msec,
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdDefendType *out_best_acd_defend_type)
|
|
|
|
|
{
|
2021-08-30 10:31:45 +02:00
|
|
|
NML3AcdDefendType best_acd_defend_type = _NM_L3_ACD_DEFEND_TYPE_NONE;
|
2020-09-28 18:07:51 +02:00
|
|
|
guint32 best_acd_timeout_msec = G_MAXUINT32;
|
|
|
|
|
guint n = 0;
|
|
|
|
|
guint i;
|
|
|
|
|
|
2022-01-28 18:48:13 +01:00
|
|
|
/* We do a simple search over all track-infos for the best, which determines
|
|
|
|
|
* our ACD state. That is, we prefer ACD disabled, and otherwise the
|
|
|
|
|
* shortest configured timeout.
|
|
|
|
|
*
|
|
|
|
|
* This linear search is probably fast enough, because we expect that each
|
|
|
|
|
* address/acd_data has few trackers.
|
|
|
|
|
* The alternative would be caching the best result, but that is more complicated,
|
|
|
|
|
* so not done. */
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
2020-10-22 12:18:39 +02:00
|
|
|
const NML3AcdAddrTrackInfo *acd_track = &acd_data->info.track_infos[i];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (dirty_selector != NM_TERNARY_DEFAULT) {
|
2020-10-22 12:18:39 +02:00
|
|
|
if ((!!dirty_selector) != (!!acd_track->_priv.acd_dirty_track))
|
2020-08-03 17:33:31 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
n++;
|
2020-10-22 12:18:39 +02:00
|
|
|
if (best_acd_timeout_msec > acd_track->_priv.acd_timeout_msec_track)
|
|
|
|
|
best_acd_timeout_msec = acd_track->_priv.acd_timeout_msec_track;
|
|
|
|
|
if (best_acd_defend_type < acd_track->_priv.acd_defend_type_track)
|
|
|
|
|
best_acd_defend_type = acd_track->_priv.acd_defend_type_track;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-30 10:31:45 +02:00
|
|
|
nm_assert(n == 0 || best_acd_defend_type > _NM_L3_ACD_DEFEND_TYPE_NONE);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(best_acd_defend_type <= NM_L3_ACD_DEFEND_TYPE_ALWAYS);
|
|
|
|
|
|
2022-06-12 19:50:09 -04:00
|
|
|
if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
|
|
|
|
|
/* On loopback interface, ACD makes no sense. We always force the
|
|
|
|
|
* timeout to zero, which means no ACD. */
|
|
|
|
|
best_acd_timeout_msec = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
NM_SET_OUT(out_best_acd_timeout_msec, n > 0 ? best_acd_timeout_msec : 0u);
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_SET_OUT(out_best_acd_defend_type, best_acd_defend_type);
|
2020-08-03 17:33:31 +02:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 12:18:39 +02:00
|
|
|
static NML3AcdAddrTrackInfo *
|
2021-11-09 13:28:54 +01:00
|
|
|
_acd_data_find_track(const AcdData *acd_data,
|
2020-08-03 17:33:31 +02:00
|
|
|
const NML3ConfigData *l3cd,
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj,
|
2020-08-03 17:33:31 +02:00
|
|
|
gconstpointer tag)
|
|
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
2020-10-22 12:18:39 +02:00
|
|
|
const NML3AcdAddrTrackInfo *acd_track = &acd_data->info.track_infos[i];
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
if (acd_track->obj == obj && acd_track->l3cd == l3cd && acd_track->tag == tag)
|
2020-10-22 12:18:39 +02:00
|
|
|
return (NML3AcdAddrTrackInfo *) acd_track;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_acd_has_valid_link(const NMPObject *obj,
|
2021-11-09 13:28:54 +01:00
|
|
|
const guint8 **out_addr_bin,
|
|
|
|
|
gboolean *out_acd_not_supported)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
|
|
|
|
const NMPlatformLink *link;
|
2021-11-09 13:28:54 +01:00
|
|
|
const guint8 *addr_bin;
|
2020-08-03 17:33:31 +02:00
|
|
|
gsize addr_len;
|
|
|
|
|
|
|
|
|
|
if (!obj) {
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, FALSE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
link = NMP_OBJECT_CAST_LINK(obj);
|
|
|
|
|
|
|
|
|
|
addr_bin = nmp_link_address_get(&link->l_address, &addr_len);
|
2020-09-28 18:07:51 +02:00
|
|
|
if (addr_len != ACD_SUPPORTED_ETH_ALEN) {
|
2020-08-03 17:33:31 +02:00
|
|
|
NM_SET_OUT(out_acd_not_supported, TRUE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, FALSE);
|
|
|
|
|
NM_SET_OUT(out_addr_bin, addr_bin);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_nacd_event_down_timeout_cb(gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NML3Cfg *self = user_data;
|
|
|
|
|
AcdData *acd_data;
|
|
|
|
|
gint64 now_msec = 0;
|
|
|
|
|
|
|
|
|
|
_LOGT("acd: message possibly dropped due to device down (handle events)");
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_event_down_source);
|
|
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst)
|
|
|
|
|
_l3_acd_data_state_change(self, acd_data, ACD_STATE_CHANGE_MODE_NACD_DOWN, NULL, &now_msec);
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_all(self);
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data)
|
|
|
|
|
{
|
2021-08-25 11:15:39 +02:00
|
|
|
gs_unref_object NML3Cfg *self = g_object_ref(user_data);
|
|
|
|
|
gboolean success = FALSE;
|
|
|
|
|
int r;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(self->priv.p->nacd);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
r = n_acd_dispatch(self->priv.p->nacd);
|
|
|
|
|
if (!NM_IN_SET(r, 0, N_ACD_E_PREEMPTED)) {
|
|
|
|
|
_LOGT("acd: dispatch failed with error %d", r);
|
2020-09-19 12:20:45 +02:00
|
|
|
goto out;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
while (TRUE) {
|
2020-09-28 18:07:51 +02:00
|
|
|
NMEtherAddr sender_addr_data;
|
|
|
|
|
const NMEtherAddr *sender_addr;
|
2021-11-09 13:28:54 +01:00
|
|
|
AcdData *acd_data;
|
|
|
|
|
NAcdEvent *event;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-25 11:15:39 +02:00
|
|
|
if (!self->priv.p->nacd) {
|
|
|
|
|
/* In the loop we emit signals, where *anything* might happen.
|
|
|
|
|
* Check that we still have the nacd instance. */
|
|
|
|
|
success = TRUE;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
r = n_acd_pop_event(self->priv.p->nacd, &event);
|
|
|
|
|
if (r) {
|
|
|
|
|
_LOGT("acd: pop-event failed with error %d", r);
|
2020-09-19 12:20:45 +02:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
if (!event) {
|
|
|
|
|
success = TRUE;
|
|
|
|
|
goto out;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (event->event) {
|
|
|
|
|
case N_ACD_EVENT_READY:
|
2020-09-28 18:07:51 +02:00
|
|
|
n_acd_probe_get_userdata(event->ready.probe, (void **) &acd_data);
|
|
|
|
|
_l3_acd_data_state_change(self, acd_data, ACD_STATE_CHANGE_MODE_NACD_READY, NULL, NULL);
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
case N_ACD_EVENT_USED:
|
|
|
|
|
case N_ACD_EVENT_DEFENDED:
|
|
|
|
|
case N_ACD_EVENT_CONFLICT:
|
|
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
#define _acd_event_payload_with_sender(event) \
|
|
|
|
|
({ \
|
|
|
|
|
NAcdEvent *_event = (event); \
|
|
|
|
|
\
|
|
|
|
|
nm_assert(event); \
|
|
|
|
|
nm_assert(NM_IN_SET(event->event, \
|
|
|
|
|
N_ACD_EVENT_USED, \
|
|
|
|
|
N_ACD_EVENT_DEFENDED, \
|
|
|
|
|
N_ACD_EVENT_CONFLICT)); \
|
|
|
|
|
nm_assert(&_event->used == &_event->defended); \
|
|
|
|
|
nm_assert(&_event->used == &_event->conflict); \
|
|
|
|
|
&_event->used; \
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
n_acd_probe_get_userdata(_acd_event_payload_with_sender(event)->probe,
|
|
|
|
|
(void **) &acd_data);
|
|
|
|
|
|
|
|
|
|
if (_acd_event_payload_with_sender(event)->n_sender == ETH_ALEN) {
|
|
|
|
|
G_STATIC_ASSERT_EXPR(_nm_alignof(NMEtherAddr) == 1);
|
|
|
|
|
nm_assert(_acd_event_payload_with_sender(event)->sender);
|
|
|
|
|
memcpy(&sender_addr_data, _acd_event_payload_with_sender(event)->sender, ETH_ALEN);
|
|
|
|
|
sender_addr = &sender_addr_data;
|
|
|
|
|
} else {
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
sender_addr = &nm_ether_addr_zero;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
(AcdStateChangeMode) event->event,
|
|
|
|
|
sender_addr,
|
|
|
|
|
NULL);
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case N_ACD_EVENT_DOWN:
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!self->priv.p->nacd_event_down_source) {
|
|
|
|
|
gint64 now_msec;
|
|
|
|
|
guint32 timeout_msec;
|
|
|
|
|
|
|
|
|
|
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
|
|
|
|
if (self->priv.p->nacd_event_down_ratelimited_until_msec > 0
|
|
|
|
|
&& now_msec < self->priv.p->nacd_event_down_ratelimited_until_msec)
|
|
|
|
|
timeout_msec = self->priv.p->nacd_event_down_ratelimited_until_msec - now_msec;
|
|
|
|
|
else {
|
|
|
|
|
timeout_msec = 0;
|
|
|
|
|
self->priv.p->nacd_event_down_ratelimited_until_msec = now_msec + 2000;
|
|
|
|
|
}
|
|
|
|
|
_LOGT("acd: message possibly dropped due to device down (schedule handling event "
|
|
|
|
|
"in %u msec)",
|
|
|
|
|
timeout_msec);
|
|
|
|
|
self->priv.p->nacd_event_down_source =
|
2022-01-28 16:38:23 +01:00
|
|
|
nm_g_timeout_add_source(timeout_msec, _l3_acd_nacd_event_down_timeout_cb, self);
|
2020-09-28 18:07:51 +02:00
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGE("acd: unexpected event %u. Ignore", event->event);
|
|
|
|
|
nm_assert_not_reached();
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
/* We are on an idle handler, and the n-acd events are expected to be independent. So, after
|
|
|
|
|
* each event emit all queued AcdEvent signals. */
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_all(self);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
out:
|
|
|
|
|
if (!success) {
|
|
|
|
|
/* Something is seriously wrong with our nacd instance. We handle that by resetting the
|
|
|
|
|
* ACD instance. */
|
|
|
|
|
_l3_acd_nacd_instance_reset(self, NM_TERNARY_TRUE, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_nacd_instance_ensure_retry_cb(gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NML3Cfg *self = user_data;
|
|
|
|
|
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry);
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
_l3_changed_configs_set_dirty(self);
|
2020-09-25 15:46:06 +02:00
|
|
|
nm_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
2020-08-03 17:33:31 +02:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_data_notify)
|
|
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (self->priv.p->nacd) {
|
|
|
|
|
_LOGT("acd: clear nacd instance");
|
|
|
|
|
self->priv.p->nacd = n_acd_unref(self->priv.p->nacd);
|
|
|
|
|
}
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_source);
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry);
|
2021-10-27 10:19:47 +02:00
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_event_down_source);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (c_list_is_empty(&self->priv.p->acd_lst_head))
|
|
|
|
|
start_timer = NM_TERNARY_DEFAULT;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
switch (start_timer) {
|
|
|
|
|
case NM_TERNARY_FALSE:
|
2020-09-25 15:46:06 +02:00
|
|
|
_l3_changed_configs_set_dirty(self);
|
2021-09-24 19:32:03 +02:00
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
case NM_TERNARY_TRUE:
|
|
|
|
|
self->priv.p->nacd_instance_ensure_retry =
|
2022-01-28 16:38:23 +01:00
|
|
|
nm_g_timeout_add_seconds_source(ACD_ENSURE_RATELIMIT_MSEC / 1000u,
|
2020-08-03 17:33:31 +02:00
|
|
|
_l3_acd_nacd_instance_ensure_retry_cb,
|
2022-01-28 16:38:23 +01:00
|
|
|
self);
|
2020-08-03 17:33:31 +02:00
|
|
|
break;
|
|
|
|
|
case NM_TERNARY_DEFAULT:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (acd_data_notify) {
|
|
|
|
|
AcdData *acd_data;
|
2020-09-28 18:07:51 +02:00
|
|
|
gint64 now_msec = 0;
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) {
|
|
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INSTANCE_RESET,
|
|
|
|
|
NULL,
|
|
|
|
|
&now_msec);
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NAcd *
|
|
|
|
|
_l3_acd_nacd_instance_ensure(NML3Cfg *self, gboolean *out_acd_not_supported)
|
|
|
|
|
{
|
|
|
|
|
nm_auto(n_acd_config_freep) NAcdConfig *config = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_auto(n_acd_unrefp) NAcd *nacd = NULL;
|
|
|
|
|
const guint8 *addr_bin;
|
2020-08-03 17:33:31 +02:00
|
|
|
gboolean acd_not_supported;
|
|
|
|
|
gboolean valid;
|
|
|
|
|
int fd;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(self->priv.ifindex > 0);
|
|
|
|
|
|
|
|
|
|
again:
|
|
|
|
|
if (G_LIKELY(self->priv.p->nacd)) {
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, FALSE);
|
|
|
|
|
return self->priv.p->nacd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->nacd_instance_ensure_retry) {
|
|
|
|
|
/* we just tried to create an instance and failed. We are rate-limited,
|
|
|
|
|
* don't yet try again. */
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, self->priv.p->nacd_acd_not_supported);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
valid = _acd_has_valid_link(self->priv.plobj, &addr_bin, &acd_not_supported);
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!valid)
|
|
|
|
|
goto failed_create_acd;
|
|
|
|
|
|
|
|
|
|
nm_assert(!acd_not_supported);
|
|
|
|
|
|
|
|
|
|
r = n_acd_config_new(&config);
|
|
|
|
|
if (r)
|
|
|
|
|
goto failed_create_acd;
|
|
|
|
|
|
|
|
|
|
n_acd_config_set_ifindex(config, self->priv.ifindex);
|
|
|
|
|
n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET);
|
|
|
|
|
n_acd_config_set_mac(config, addr_bin, ACD_SUPPORTED_ETH_ALEN);
|
|
|
|
|
|
|
|
|
|
r = n_acd_new(&nacd, config);
|
|
|
|
|
if (r)
|
|
|
|
|
goto failed_create_acd;
|
|
|
|
|
|
|
|
|
|
self->priv.p->nacd = g_steal_pointer(&nacd);
|
|
|
|
|
|
|
|
|
|
n_acd_get_fd(self->priv.p->nacd, &fd);
|
|
|
|
|
|
2022-03-08 14:31:53 +01:00
|
|
|
self->priv.p->nacd_source = nm_g_unix_fd_add_source(fd, G_IO_IN, _l3_acd_nacd_event, self);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, FALSE);
|
|
|
|
|
return self->priv.p->nacd;
|
|
|
|
|
|
|
|
|
|
failed_create_acd:
|
|
|
|
|
/* is-internal-error means that we failed to create the NAcd instance. Most likely due
|
|
|
|
|
* to being unable to create a file descriptor. Anyway, something is seriously wrong here.
|
|
|
|
|
*
|
|
|
|
|
* Otherwise, the MAC address might just not be suitable (ETH_ALEN) or we might have
|
|
|
|
|
* not NMPlatformLink. In that case, it means the interface is currently not ready to
|
|
|
|
|
* do acd. */
|
|
|
|
|
self->priv.p->nacd_acd_not_supported = acd_not_supported;
|
|
|
|
|
_l3_acd_nacd_instance_reset(self, NM_TERNARY_TRUE, FALSE);
|
|
|
|
|
goto again;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NAcdProbe *
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_nacd_instance_create_probe(NML3Cfg *self,
|
2020-08-03 17:33:31 +02:00
|
|
|
in_addr_t addr,
|
|
|
|
|
guint32 timeout_msec,
|
|
|
|
|
gpointer user_data,
|
2021-11-09 13:28:54 +01:00
|
|
|
gboolean *out_acd_not_supported,
|
2020-08-03 17:33:31 +02:00
|
|
|
const char **out_failure_reason)
|
|
|
|
|
{
|
|
|
|
|
gboolean acd_not_supported;
|
|
|
|
|
NAcdProbe *probe;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!_l3_acd_nacd_instance_ensure(self, &acd_not_supported)) {
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, acd_not_supported);
|
|
|
|
|
if (acd_not_supported)
|
|
|
|
|
NM_SET_OUT(out_failure_reason, "interface not suitable for ACD");
|
|
|
|
|
else
|
|
|
|
|
NM_SET_OUT(out_failure_reason, "failure to create nacd instance");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(!acd_not_supported);
|
|
|
|
|
NM_SET_OUT(out_acd_not_supported, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
probe = _nm_n_acd_data_probe_new(self, addr, timeout_msec, user_data);
|
|
|
|
|
if (!probe) {
|
|
|
|
|
NM_SET_OUT(out_failure_reason, "failure to create nacd probe");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
NM_SET_OUT(out_failure_reason, NULL);
|
|
|
|
|
return probe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_prune_one(NML3Cfg *self, AcdData *acd_data, gboolean all /* or only dirty */)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
2020-10-22 12:18:39 +02:00
|
|
|
NML3AcdAddrTrackInfo *acd_tracks;
|
|
|
|
|
guint i;
|
|
|
|
|
guint j;
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2020-10-22 12:18:39 +02:00
|
|
|
acd_tracks = (NML3AcdAddrTrackInfo *) acd_data->info.track_infos;
|
2020-09-28 18:07:51 +02:00
|
|
|
j = 0;
|
|
|
|
|
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
2020-10-22 12:18:39 +02:00
|
|
|
NML3AcdAddrTrackInfo *acd_track = &acd_tracks[i];
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
/* If not "all" is requested, we only delete the dirty ones
|
|
|
|
|
* (and mark the survivors as dirty right away). */
|
2020-10-22 12:18:39 +02:00
|
|
|
if (!all && !acd_track->_priv.acd_dirty_track) {
|
|
|
|
|
acd_track->_priv.acd_dirty_track = TRUE;
|
2020-09-28 18:07:51 +02:00
|
|
|
if (j != i)
|
|
|
|
|
acd_tracks[j] = *acd_track;
|
|
|
|
|
j++;
|
2020-08-03 17:33:31 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_LOGT_acd(acd_data, "untrack " ACD_TRACK_FMT "", ACD_TRACK_PTR(acd_track));
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_acd_track_data_clear(acd_track);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->info.n_track_infos = j;
|
|
|
|
|
if (j > 0)
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data, "removed");
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!g_hash_table_remove(self->priv.p->acd_lst_hash, acd_data))
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
_acd_data_free(acd_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_acd_data_prune(NML3Cfg *self, gboolean all /* or only dirty */)
|
|
|
|
|
{
|
|
|
|
|
AcdData *acd_data_safe;
|
|
|
|
|
AcdData *acd_data;
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry_safe (acd_data, acd_data_safe, &self->priv.p->acd_lst_head, acd_lst)
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_prune_one(self, acd_data, all);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static AcdData *
|
|
|
|
|
_l3_acd_data_find(NML3Cfg *self, in_addr_t addr)
|
|
|
|
|
{
|
|
|
|
|
return nm_g_hash_table_lookup(self->priv.p->acd_lst_hash, &addr);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_data_defendconflict_warning_ratelimited(AcdData *acd_data, gint64 *p_now_msec)
|
|
|
|
|
{
|
|
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
|
|
|
|
|
|
|
|
|
if (acd_data->last_defendconflict_timestamp_msec == 0
|
|
|
|
|
|| acd_data->last_defendconflict_timestamp_msec
|
|
|
|
|
> *p_now_msec - ACD_DEFENDCONFLICT_INFO_RATELIMIT_MSEC) {
|
|
|
|
|
acd_data->last_defendconflict_timestamp_msec = *p_now_msec;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_data_add(NML3Cfg *self,
|
2020-08-03 17:33:31 +02:00
|
|
|
const NML3ConfigData *l3cd,
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj,
|
2020-08-03 17:33:31 +02:00
|
|
|
gconstpointer tag,
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdDefendType acd_defend_type,
|
2020-08-03 17:33:31 +02:00
|
|
|
guint32 acd_timeout_msec)
|
|
|
|
|
{
|
2020-10-22 12:18:39 +02:00
|
|
|
in_addr_t addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address;
|
|
|
|
|
NML3AcdAddrTrackInfo *acd_track;
|
2021-11-09 13:28:54 +01:00
|
|
|
AcdData *acd_data;
|
|
|
|
|
const char *track_mode;
|
2020-10-22 12:18:39 +02:00
|
|
|
char sbuf100[100];
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
if (ACD_ADDR_SKIP(addr))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
acd_data = _l3_acd_data_find(self, addr);
|
|
|
|
|
|
2022-05-19 09:23:29 +02:00
|
|
|
if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC) {
|
2020-08-03 17:33:31 +02:00
|
|
|
/* we limit the maximum timeout. Otherwise we have to handle integer overflow
|
|
|
|
|
* when adding timeouts. */
|
2022-05-19 09:23:29 +02:00
|
|
|
acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!acd_data) {
|
|
|
|
|
if (G_UNLIKELY(!self->priv.p->acd_lst_hash)) {
|
2020-09-28 18:07:51 +02:00
|
|
|
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(AcdData, info.addr) == 0);
|
2021-05-20 20:39:38 +02:00
|
|
|
self->priv.p->acd_lst_hash = g_hash_table_new(nm_puint32_hash, nm_puint32_equal);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
acd_data = g_slice_new(AcdData);
|
|
|
|
|
*acd_data = (AcdData){
|
2020-09-28 18:07:51 +02:00
|
|
|
.info =
|
|
|
|
|
{
|
|
|
|
|
.l3cfg = self,
|
|
|
|
|
.addr = addr,
|
|
|
|
|
.state = NM_L3_ACD_ADDR_STATE_INIT,
|
|
|
|
|
.n_track_infos = 0,
|
|
|
|
|
.track_infos = NULL,
|
|
|
|
|
},
|
|
|
|
|
.n_track_infos_alloc = 0,
|
|
|
|
|
.acd_event_notify_lst = C_LIST_INIT(acd_data->acd_event_notify_lst),
|
|
|
|
|
.probing_timestamp_msec = 0,
|
2021-08-30 10:31:45 +02:00
|
|
|
.acd_defend_type_desired = _NM_L3_ACD_DEFEND_TYPE_NONE,
|
|
|
|
|
.acd_defend_type_current = _NM_L3_ACD_DEFEND_TYPE_NONE,
|
2020-09-28 18:07:51 +02:00
|
|
|
.acd_defend_type_is_active = FALSE,
|
2020-08-03 17:33:31 +02:00
|
|
|
};
|
|
|
|
|
c_list_link_tail(&self->priv.p->acd_lst_head, &acd_data->acd_lst);
|
|
|
|
|
if (!g_hash_table_add(self->priv.p->acd_lst_hash, acd_data))
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
acd_track = NULL;
|
2020-09-28 18:07:51 +02:00
|
|
|
} else
|
2020-08-03 17:33:31 +02:00
|
|
|
acd_track = _acd_data_find_track(acd_data, l3cd, obj, tag);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!acd_track) {
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data->info.n_track_infos >= acd_data->n_track_infos_alloc) {
|
|
|
|
|
acd_data->n_track_infos_alloc = NM_MAX(2u, acd_data->n_track_infos_alloc * 2u);
|
|
|
|
|
acd_data->info.track_infos =
|
|
|
|
|
g_realloc((gpointer) acd_data->info.track_infos,
|
|
|
|
|
acd_data->n_track_infos_alloc * sizeof(acd_data->info.track_infos[0]));
|
|
|
|
|
}
|
2020-10-22 12:18:39 +02:00
|
|
|
acd_track =
|
|
|
|
|
(NML3AcdAddrTrackInfo *) &acd_data->info.track_infos[acd_data->info.n_track_infos++];
|
|
|
|
|
*acd_track = (NML3AcdAddrTrackInfo){
|
|
|
|
|
.l3cd = nm_l3_config_data_ref(l3cd),
|
|
|
|
|
.obj = nmp_object_ref(obj),
|
|
|
|
|
.tag = tag,
|
|
|
|
|
._priv.acd_dirty_track = FALSE,
|
|
|
|
|
._priv.acd_defend_type_track = acd_defend_type,
|
|
|
|
|
._priv.acd_timeout_msec_track = acd_timeout_msec,
|
2020-08-03 17:33:31 +02:00
|
|
|
};
|
|
|
|
|
track_mode = "new";
|
|
|
|
|
} else {
|
2020-10-22 12:18:39 +02:00
|
|
|
nm_assert(acd_track->_priv.acd_dirty_track);
|
|
|
|
|
acd_track->_priv.acd_dirty_track = FALSE;
|
|
|
|
|
if (acd_track->_priv.acd_timeout_msec_track != acd_timeout_msec
|
|
|
|
|
|| acd_track->_priv.acd_defend_type_track != acd_defend_type) {
|
|
|
|
|
acd_track->_priv.acd_defend_type_track = acd_defend_type;
|
|
|
|
|
acd_track->_priv.acd_timeout_msec_track = acd_timeout_msec;
|
|
|
|
|
track_mode = "update";
|
2020-08-03 17:33:31 +02:00
|
|
|
} else
|
2020-09-28 18:07:51 +02:00
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->track_infos_changed = TRUE;
|
2020-10-22 12:18:39 +02:00
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"track " ACD_TRACK_FMT " with timeout %u msec, defend=%s (%s)",
|
|
|
|
|
ACD_TRACK_PTR(acd_track),
|
|
|
|
|
acd_timeout_msec,
|
|
|
|
|
_l3_acd_defend_type_to_string(acd_track->_priv.acd_defend_type_track,
|
|
|
|
|
sbuf100,
|
|
|
|
|
sizeof(sbuf100)),
|
|
|
|
|
track_mode);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_data_add_all(NML3Cfg *self,
|
2020-09-28 18:07:51 +02:00
|
|
|
const L3ConfigData *const *infos,
|
|
|
|
|
guint infos_len,
|
|
|
|
|
gboolean reapply)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
|
|
|
|
AcdData *acd_data;
|
|
|
|
|
guint i_info;
|
2020-09-28 18:07:51 +02:00
|
|
|
gint64 now_msec = 0;
|
|
|
|
|
guint i;
|
|
|
|
|
|
2020-12-03 14:53:54 +01:00
|
|
|
if (NM_MORE_ASSERTS > 5) {
|
|
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) {
|
|
|
|
|
nm_assert(acd_data->info.n_track_infos > 0u);
|
|
|
|
|
for (i = 0; i < acd_data->info.n_track_infos; i++)
|
|
|
|
|
nm_assert(acd_data->info.track_infos[i]._priv.acd_dirty_track);
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
/* First we add/track all the relevant addresses for ACD. */
|
|
|
|
|
for (i_info = 0; i_info < infos_len; i_info++) {
|
|
|
|
|
const L3ConfigData *info = infos[i_info];
|
|
|
|
|
NMDedupMultiIter iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *obj;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_l3_config_data_iter_obj_for_each (&iter, info->l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) {
|
|
|
|
|
_l3_acd_data_add(self,
|
|
|
|
|
info->l3cd,
|
|
|
|
|
obj,
|
|
|
|
|
info->tag_confdata,
|
|
|
|
|
info->acd_defend_type_confdata,
|
|
|
|
|
info->acd_timeout_msec_confdata);
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Then we do a pre-flight check, whether some of the acd_data entries can already
|
|
|
|
|
* move forward to automatically pass ACD. That is the case if acd_timeout_msec
|
|
|
|
|
* is zero (to disable ACD) or if the address is already configured on the
|
|
|
|
|
* interface. */
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) {
|
|
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
reapply ? ACD_STATE_CHANGE_MODE_INIT_REAPPLY
|
|
|
|
|
: ACD_STATE_CHANGE_MODE_INIT,
|
|
|
|
|
NULL,
|
|
|
|
|
&now_msec);
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_l3_acd_data_timeout_cb(gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
AcdData *acd_data = user_data;
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3Cfg *self = acd_data->info.l3cfg;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_clear_g_source_inst(&acd_data->acd_data_timeout_source);
|
|
|
|
|
_l3_acd_data_state_change(self, acd_data, ACD_STATE_CHANGE_MODE_TIMEOUT, NULL, NULL);
|
2020-08-03 17:33:31 +02:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_timeout_schedule(AcdData *acd_data, gint64 timeout_msec)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
2022-01-28 16:59:45 +01:00
|
|
|
/* in _l3_acd_data_state_set_full() we clear the timer. At the same time,
|
|
|
|
|
* in _l3_acd_data_state_change(ACD_STATE_CHANGE_MODE_TIMEOUT) we only
|
|
|
|
|
* expect timeouts in certain states.
|
|
|
|
|
*
|
|
|
|
|
* That means, scheduling a timeout is only correct if we are in a certain
|
|
|
|
|
* state, which allows to handle timeouts. This assert checks for that to
|
|
|
|
|
* ensure we don't call a timeout in an unexpected state. */
|
|
|
|
|
nm_assert(NM_IN_SET(acd_data->info.state,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_PROBING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_USED,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_DEFENDING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_CONFLICT));
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_clear_g_source_inst(&acd_data->acd_data_timeout_source);
|
|
|
|
|
acd_data->acd_data_timeout_source =
|
2022-01-28 16:38:23 +01:00
|
|
|
nm_g_timeout_add_source(NM_CLAMP((gint64) 0, timeout_msec, (gint64) G_MAXUINT),
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_timeout_cb,
|
2022-01-28 16:38:23 +01:00
|
|
|
acd_data);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_acd_data_timeout_schedule_probing_restart(AcdData *acd_data, gint64 now_msec)
|
|
|
|
|
{
|
|
|
|
|
gint64 expiry_msec;
|
|
|
|
|
gint64 timeout_msec;
|
|
|
|
|
|
|
|
|
|
nm_assert(acd_data);
|
|
|
|
|
nm_assert(now_msec > 0);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING);
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(!acd_data->nacd_probe);
|
|
|
|
|
nm_assert(acd_data->probing_timeout_msec > 0);
|
|
|
|
|
nm_assert(acd_data->probing_timestamp_msec > 0);
|
|
|
|
|
|
|
|
|
|
expiry_msec = acd_data->probing_timestamp_msec + ACD_WAIT_PROBING_EXTRA_TIME_MSEC;
|
|
|
|
|
|
|
|
|
|
timeout_msec = NM_MAX(0, expiry_msec - now_msec);
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (timeout_msec > 1500) {
|
|
|
|
|
/* we poll at least every 1.5 seconds to re-check the state. */
|
|
|
|
|
timeout_msec = 1500;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_timeout_schedule(acd_data, timeout_msec);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-09-28 18:07:51 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event(NML3Cfg *self, AcdData *acd_data)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
gs_free NML3AcdAddrTrackInfo *track_infos_clone = NULL;
|
|
|
|
|
NML3ConfigNotifyData notify_data;
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3AcdAddrInfo *info;
|
2020-09-28 18:07:51 +02:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(acd_data);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(acd_data->info.state > NM_L3_ACD_ADDR_STATE_INIT);
|
|
|
|
|
nm_assert(acd_data->info.n_track_infos > 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT;
|
|
|
|
|
notify_data.acd_event = (typeof(notify_data.acd_event)){
|
2021-11-09 13:28:54 +01:00
|
|
|
.info = acd_data->info,
|
2020-09-28 18:07:51 +02:00
|
|
|
};
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
/* we need to clone the track-data, because the callee is allowed to add/remove
|
|
|
|
|
* configs. This means, the event data is stale. If you need the current
|
|
|
|
|
* value, look it up with nm_l3cfg_get_acd_addr_info(). */
|
|
|
|
|
info = ¬ify_data.acd_event.info;
|
|
|
|
|
info->track_infos = nm_memdup_maybe_a(300,
|
|
|
|
|
info->track_infos,
|
|
|
|
|
info->n_track_infos * sizeof(info->track_infos[0]),
|
|
|
|
|
&track_infos_clone);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
for (i = 0; i < info->n_track_infos; i++) {
|
|
|
|
|
NML3AcdAddrTrackInfo *ti = (NML3AcdAddrTrackInfo *) &info->track_infos[i];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nmp_object_ref(ti->obj);
|
|
|
|
|
nm_l3_config_data_ref(ti->l3cd);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify(self, ¬ify_data);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
for (i = 0; i < info->n_track_infos; i++) {
|
|
|
|
|
NML3AcdAddrTrackInfo *ti = (NML3AcdAddrTrackInfo *) &info->track_infos[i];
|
|
|
|
|
|
|
|
|
|
nmp_object_unref(ti->obj);
|
|
|
|
|
nm_l3_config_data_unref(ti->l3cd);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
static void
|
2020-09-28 18:07:51 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_queue(NML3Cfg *self, AcdData *acd_data)
|
2020-09-19 12:20:45 +02:00
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!c_list_is_empty(&acd_data->acd_event_notify_lst)) {
|
|
|
|
|
nm_assert(c_list_contains(&self->priv.p->acd_event_notify_lst_head,
|
|
|
|
|
&acd_data->acd_event_notify_lst));
|
2020-09-19 12:20:45 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_link_tail(&self->priv.p->acd_event_notify_lst_head, &acd_data->acd_event_notify_lst);
|
2020-09-19 12:20:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-09-28 18:07:51 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self)
|
2020-09-19 12:20:45 +02:00
|
|
|
{
|
|
|
|
|
gs_unref_object NML3Cfg *self_keep_alive = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
AcdData *acd_data;
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
while ((acd_data = c_list_first_entry(&self->priv.p->acd_event_notify_lst_head,
|
2020-09-19 12:20:45 +02:00
|
|
|
AcdData,
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_event_notify_lst))) {
|
2020-09-19 12:20:45 +02:00
|
|
|
if (!self_keep_alive)
|
|
|
|
|
self_keep_alive = g_object_ref(self);
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_unlink(&acd_data->acd_event_notify_lst);
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event(self, acd_data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg *self,
|
|
|
|
|
AcdData *acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdAddrState state,
|
|
|
|
|
gboolean allow_commit,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *format,
|
2020-09-28 18:07:51 +02:00
|
|
|
...)
|
|
|
|
|
{
|
|
|
|
|
NML3AcdAddrState old_state;
|
|
|
|
|
gboolean changed;
|
|
|
|
|
|
|
|
|
|
if (acd_data->info.state == state)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* in every state we only have one timer possibly running. Resetting
|
|
|
|
|
* the states makes the previous timeout obsolete. */
|
|
|
|
|
nm_clear_g_source_inst(&acd_data->acd_data_timeout_source);
|
|
|
|
|
|
|
|
|
|
old_state = acd_data->info.state;
|
|
|
|
|
acd_data->info.state = state;
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_queue(self, acd_data);
|
|
|
|
|
|
|
|
|
|
if (state == NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED)
|
|
|
|
|
changed = FALSE;
|
|
|
|
|
else if (NM_IN_SET(old_state, NM_L3_ACD_ADDR_STATE_READY, NM_L3_ACD_ADDR_STATE_DEFENDING)
|
|
|
|
|
!= NM_IN_SET(state, NM_L3_ACD_ADDR_STATE_READY, NM_L3_ACD_ADDR_STATE_DEFENDING))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
else
|
|
|
|
|
changed = FALSE;
|
|
|
|
|
|
2022-01-28 16:22:32 +01:00
|
|
|
if (_LOGT_ENABLED()) {
|
|
|
|
|
if (format) {
|
|
|
|
|
gs_free char *msg = NULL;
|
|
|
|
|
va_list args;
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2022-01-28 16:22:32 +01:00
|
|
|
va_start(args, format);
|
|
|
|
|
msg = g_strdup_vprintf(format, args);
|
|
|
|
|
va_end(args);
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2022-01-28 16:22:32 +01:00
|
|
|
_LOGT_acd(acd_data, "set state to %s (%s)", _l3_acd_addr_state_to_string(state), msg);
|
|
|
|
|
} else
|
|
|
|
|
_LOGT_acd(acd_data, "set state to %s", _l3_acd_addr_state_to_string(state));
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
if (changed && allow_commit) {
|
|
|
|
|
/* The availability of an address just changed (and we are instructed to
|
|
|
|
|
* trigger a new commit). Do it. */
|
|
|
|
|
_l3_changed_configs_set_dirty(self);
|
2021-09-24 19:32:03 +02:00
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
2020-09-19 12:20:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_data_state_set(NML3Cfg *self,
|
|
|
|
|
AcdData *acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdAddrState state,
|
|
|
|
|
gboolean allow_commit)
|
|
|
|
|
{
|
|
|
|
|
_l3_acd_data_state_set_full(self, acd_data, state, allow_commit, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_acd_data_state_change(NML3Cfg *self,
|
|
|
|
|
AcdData *acd_data,
|
2020-08-03 17:33:31 +02:00
|
|
|
AcdStateChangeMode state_change_mode,
|
2020-09-28 18:07:51 +02:00
|
|
|
const NMEtherAddr *sender_addr,
|
2021-11-09 13:28:54 +01:00
|
|
|
gint64 *p_now_msec)
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
guint32 acd_timeout_msec;
|
|
|
|
|
NML3AcdDefendType acd_defend_type;
|
|
|
|
|
gint64 now_msec;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *log_reason;
|
2020-09-28 18:07:51 +02:00
|
|
|
char sbuf256[256];
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
if (!p_now_msec) {
|
|
|
|
|
now_msec = 0;
|
|
|
|
|
p_now_msec = &now_msec;
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
/* Keeping track of ACD inevitably requires keeping (and mutating) state. Then a multitude of
|
|
|
|
|
* things can happen, and depending on the state, we need to do something.
|
|
|
|
|
*
|
|
|
|
|
* Here, all the state for one address that we probe/announce is tracked in AcdData/acd_data.
|
|
|
|
|
*
|
2020-10-22 12:18:39 +02:00
|
|
|
* The acd_data has a list of NML3AcdAddrTrackInfo/acd_track_lst_head, which are configuration items
|
2020-08-03 17:33:31 +02:00
|
|
|
* that are interested in configuring this address. The "owners" of the ACD check for a certain
|
|
|
|
|
* address.
|
|
|
|
|
*
|
|
|
|
|
* We try to do all the state changes in this _l3_acd_data_state_change() function, where --
|
|
|
|
|
* depending on the @state_change_mode -- we progress the state.
|
|
|
|
|
*
|
|
|
|
|
* It is complicated, but I think this is not really avoidable if you want to handle all
|
|
|
|
|
* the special things (state-changes) that can happen.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(acd_data);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(acd_data->info.n_track_infos);
|
|
|
|
|
nm_assert(NM_IN_SET(acd_data->info.state,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_CONFLICT,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_READY,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_DEFENDING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_INIT,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_PROBING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_USED));
|
|
|
|
|
nm_assert(!acd_data->track_infos_changed
|
|
|
|
|
|| NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT_REAPPLY,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_ADDED,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_REMOVED));
|
|
|
|
|
nm_assert((!!sender_addr)
|
|
|
|
|
== NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_USED,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_CONFLICT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_NACD_DEFENDED));
|
|
|
|
|
|
|
|
|
|
if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED) {
|
|
|
|
|
/* once remove, the state can only change by external added or during
|
|
|
|
|
* the POST-COMMIT check. */
|
|
|
|
|
if (!NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_EXTERNAL_ADDED))
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
switch (state_change_mode) {
|
|
|
|
|
case ACD_STATE_CHANGE_MODE_INIT:
|
2020-09-28 18:07:51 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_INIT_REAPPLY:
|
|
|
|
|
|
|
|
|
|
/* We are called right before commit. We check whether we have a acd_data
|
|
|
|
|
* in INIT or PROBING state. In that case, maybe the new configuration
|
|
|
|
|
* disables ACD, or we have the address already configured (which also let's
|
|
|
|
|
* us skip/cancel the probing). The point is that if the address would be ready
|
|
|
|
|
* already, we want to commit it right away. */
|
|
|
|
|
|
|
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
goto handle_init;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
if (state_change_mode != ACD_STATE_CHANGE_MODE_INIT_REAPPLY)
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
2020-09-28 18:07:51 +02:00
|
|
|
goto handle_init;
|
|
|
|
|
}
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
handle_init:
|
2022-06-12 19:50:09 -04:00
|
|
|
if (_acd_data_collect_tracks_data(self,
|
|
|
|
|
acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_TERNARY_FALSE,
|
|
|
|
|
&acd_timeout_msec,
|
|
|
|
|
&acd_defend_type)
|
|
|
|
|
<= 0u) {
|
|
|
|
|
/* the acd_data has no active trackers. It will soon be pruned. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (acd_timeout_msec == 0u)
|
|
|
|
|
log_reason = "acd disabled by configuration";
|
|
|
|
|
else if (_l3_acd_ipv4_addresses_on_link_contains(self, acd_data->info.addr))
|
|
|
|
|
log_reason = "address already configured";
|
|
|
|
|
else {
|
|
|
|
|
if (state_change_mode == ACD_STATE_CHANGE_MODE_INIT_REAPPLY) {
|
|
|
|
|
/* during a reapply, we forget all the state and start from scratch. */
|
|
|
|
|
_LOGT_acd(acd_data, "reset state for reapply");
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
_l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_INIT, FALSE);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"%s probing (%s, during pre-check)",
|
|
|
|
|
acd_data->info.state == NM_L3_ACD_ADDR_STATE_INIT ? "skip" : "cancel",
|
|
|
|
|
log_reason);
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
acd_data->acd_defend_type_desired = acd_defend_type;
|
|
|
|
|
_l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_READY, FALSE);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case ACD_STATE_CHANGE_MODE_POST_COMMIT:
|
|
|
|
|
|
|
|
|
|
if (acd_data->track_infos_changed) {
|
|
|
|
|
acd_data->track_infos_changed = FALSE;
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_queue(self, acd_data);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (_l3_acd_ipv4_addresses_on_link_contains(self, acd_data->info.addr)) {
|
|
|
|
|
log_reason = "address already configured";
|
|
|
|
|
goto handle_probing_done;
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED)
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
/* we just did a commit of the IP configuration and now visit all ACD states
|
|
|
|
|
* and kick off the necessary actions... */
|
2022-06-12 19:50:09 -04:00
|
|
|
if (_acd_data_collect_tracks_data(self,
|
|
|
|
|
acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_TERNARY_TRUE,
|
|
|
|
|
&acd_timeout_msec,
|
|
|
|
|
&acd_defend_type)
|
|
|
|
|
<= 0)
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
|
|
|
|
|
acd_data->acd_defend_type_desired = acd_defend_type;
|
|
|
|
|
|
|
|
|
|
if (acd_timeout_msec <= 0) {
|
|
|
|
|
log_reason = "acd disabled by configuration";
|
|
|
|
|
goto handle_probing_done;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
nm_assert(!acd_data->nacd_probe);
|
|
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
|
|
|
|
acd_data->probing_timestamp_msec = (*p_now_msec);
|
|
|
|
|
acd_data->probing_timeout_msec = acd_timeout_msec;
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_queue(self, acd_data);
|
|
|
|
|
log_reason = "initial post-commit";
|
|
|
|
|
goto handle_start_probing;
|
|
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
{
|
|
|
|
|
gint64 old_expiry_msec;
|
|
|
|
|
gint64 new_expiry_msec;
|
|
|
|
|
|
|
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
|
|
|
|
|
|
|
|
|
new_expiry_msec = (*p_now_msec) + acd_timeout_msec;
|
|
|
|
|
old_expiry_msec = acd_data->probing_timestamp_msec + acd_data->probing_timeout_msec;
|
|
|
|
|
|
|
|
|
|
if (!acd_data->nacd_probe) {
|
|
|
|
|
/* we are currently waiting for restarting a probe. At this point, at most we have
|
|
|
|
|
* to adjust the timeout/timestamp and let the regular timeouts handle this. */
|
|
|
|
|
|
|
|
|
|
if (new_expiry_msec >= old_expiry_msec) {
|
|
|
|
|
/* the running timeout expires before the new timeout. We don't update the timestamp/timeout,
|
|
|
|
|
* because we don't want to prolong the overall probing time. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* update the timers after out timeout got reduced. Also, reschedule the timeout
|
|
|
|
|
* so that it expires immediately. */
|
|
|
|
|
acd_data->probing_timestamp_msec = (*p_now_msec);
|
|
|
|
|
acd_data->probing_timeout_msec = acd_timeout_msec;
|
|
|
|
|
_l3_acd_data_timeout_schedule(acd_data, 0);
|
|
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
if (new_expiry_msec >= old_expiry_msec) {
|
|
|
|
|
/* we already have ACD running with a timeout that expires before the requested one. There
|
|
|
|
|
* is nothing to do at this time. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* the timeout got reduced. We try to restart the probe. */
|
|
|
|
|
acd_data->probing_timestamp_msec = (*p_now_msec);
|
|
|
|
|
acd_data->probing_timeout_msec = acd_timeout_msec;
|
|
|
|
|
log_reason = "post-commit timeout update";
|
|
|
|
|
goto handle_start_probing;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
/* we are done for now. We however scheduled a timeout to restart. This
|
|
|
|
|
* will be handled with the ACD_STATE_CHANGE_MODE_TIMEOUT event. */
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
goto handle_start_defending;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_TIMEOUT:
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
if (acd_data->nacd_probe) {
|
|
|
|
|
/* we are already probing. There is nothing to do for this timeout. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
/* fall-through */
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
|
|
|
|
|
nm_assert(!acd_data->nacd_probe);
|
|
|
|
|
|
|
|
|
|
/* after a timeout, re-probe the address. This only happens if the caller
|
|
|
|
|
* does not deconfigure the address after USED/CONFLICT. But in that case,
|
|
|
|
|
* we eventually want to retry. */
|
2022-06-12 19:50:09 -04:00
|
|
|
if (_acd_data_collect_tracks_data(self,
|
|
|
|
|
acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_TERNARY_TRUE,
|
|
|
|
|
&acd_timeout_msec,
|
|
|
|
|
&acd_defend_type)
|
|
|
|
|
<= 0)
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
|
|
|
|
|
acd_data->acd_defend_type_desired = acd_defend_type;
|
|
|
|
|
|
|
|
|
|
if (acd_timeout_msec <= 0) {
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING)
|
|
|
|
|
log_reason = "acd disabled by configuration (timeout during probing)";
|
|
|
|
|
else
|
|
|
|
|
log_reason = "acd disabled by configuration (restart after previous conflict)";
|
2020-09-28 18:07:51 +02:00
|
|
|
goto handle_probing_done;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (_l3_acd_ipv4_addresses_on_link_contains(self, acd_data->info.addr)) {
|
|
|
|
|
log_reason = "address already configured (restart after previous conflict)";
|
|
|
|
|
goto handle_probing_done;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
|
|
|
|
|
if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) {
|
2022-02-10 09:53:20 +01:00
|
|
|
if ((*p_now_msec) > acd_data->probing_timestamp_msec
|
|
|
|
|
+ ACD_WAIT_PROBING_EXTRA_TIME_MSEC
|
|
|
|
|
+ ACD_WAIT_PROBING_EXTRA_TIME2_MSEC) {
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
/* hm. We failed to create a new probe too long. Something is really wrong
|
|
|
|
|
* internally, but let's ignore the issue and assume the address is good. What
|
|
|
|
|
* else would we do? Assume the address is USED? */
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"probe-good (waiting for creating probe timed out. Assume good)");
|
|
|
|
|
goto handle_start_defending;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_reason = "retry probing on timeout";
|
|
|
|
|
goto handle_start_probing;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->probing_timestamp_msec = (*p_now_msec);
|
|
|
|
|
acd_data->probing_timeout_msec = acd_timeout_msec;
|
|
|
|
|
if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_USED)
|
|
|
|
|
log_reason = "restart probing after previously used address";
|
|
|
|
|
else
|
|
|
|
|
log_reason = "restart probing after previous conflict";
|
|
|
|
|
goto handle_start_probing;
|
|
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
nm_assert_not_reached();
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(!acd_data->nacd_probe);
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data, "retry announcing address");
|
|
|
|
|
goto handle_start_defending;
|
|
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case ACD_STATE_CHANGE_MODE_NACD_USED:
|
|
|
|
|
nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING);
|
|
|
|
|
nm_assert(acd_data->nacd_probe);
|
|
|
|
|
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
acd_data->last_conflict_addr = *sender_addr;
|
|
|
|
|
_l3_acd_data_state_set_full(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_USED,
|
|
|
|
|
TRUE,
|
|
|
|
|
"acd completed with address already in use by %s",
|
|
|
|
|
nm_ether_addr_to_string_a(sender_addr));
|
|
|
|
|
|
|
|
|
|
if (!acd_data->acd_data_timeout_source)
|
|
|
|
|
_l3_acd_data_timeout_schedule(acd_data, ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC);
|
|
|
|
|
|
|
|
|
|
if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) {
|
|
|
|
|
_LOGI("IPv4 address %s is used on network connected to interface %d%s%s%s from "
|
|
|
|
|
"host %s",
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(acd_data->info.addr, sbuf_addr),
|
2020-09-28 18:07:51 +02:00
|
|
|
self->priv.ifindex,
|
|
|
|
|
NM_PRINT_FMT_QUOTED(self->priv.plobj_next,
|
|
|
|
|
" (",
|
|
|
|
|
NMP_OBJECT_CAST_LINK(self->priv.plobj_next)->name,
|
|
|
|
|
")",
|
|
|
|
|
""),
|
|
|
|
|
nm_ether_addr_to_string_a(sender_addr));
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_NACD_DEFENDED:
|
|
|
|
|
nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_DEFENDING);
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"address %s defended from %s",
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(acd_data->info.addr, sbuf_addr),
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_ether_addr_to_string_a(sender_addr));
|
|
|
|
|
/* we just log an info message. Nothing else to do. */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case ACD_STATE_CHANGE_MODE_NACD_CONFLICT:
|
|
|
|
|
nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_DEFENDING);
|
|
|
|
|
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"address conflict for %s detected with %s",
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(acd_data->info.addr, sbuf_addr),
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_ether_addr_to_string_a(sender_addr));
|
|
|
|
|
|
|
|
|
|
if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) {
|
|
|
|
|
_LOGW("IPv4 address collision detection sees conflict on interface %d%s%s%s for "
|
|
|
|
|
"address %s from host %s",
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
NM_PRINT_FMT_QUOTED(self->priv.plobj_next,
|
|
|
|
|
" (",
|
|
|
|
|
NMP_OBJECT_CAST_LINK(self->priv.plobj_next)->name,
|
|
|
|
|
")",
|
|
|
|
|
""),
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
nm_inet4_ntop(acd_data->info.addr, sbuf_addr),
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_ether_addr_to_string_a(sender_addr));
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
acd_data->last_conflict_addr = *sender_addr;
|
|
|
|
|
_l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_CONFLICT, TRUE);
|
|
|
|
|
if (!acd_data->acd_data_timeout_source)
|
|
|
|
|
_l3_acd_data_timeout_schedule(acd_data, ACD_WAIT_TIME_CONFLICT_RESTART_MSEC);
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_NACD_READY:
|
2020-09-28 18:07:51 +02:00
|
|
|
|
|
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
nm_assert(acd_data->nacd_probe);
|
|
|
|
|
/* we theoretically could re-use this probe for defending. But as we
|
|
|
|
|
* may not start defending right away, it makes it more complicated. */
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
log_reason = "acd indicates ready";
|
|
|
|
|
goto handle_probing_done;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
nm_assert(!acd_data->acd_defend_type_is_active);
|
|
|
|
|
acd_data->acd_defend_type_is_active = TRUE;
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"start announcing (defend=%s) (after new probe ready)",
|
|
|
|
|
_l3_acd_defend_type_to_string(acd_data->acd_defend_type_current,
|
|
|
|
|
sbuf256,
|
|
|
|
|
sizeof(sbuf256)));
|
|
|
|
|
if (n_acd_probe_announce(acd_data->nacd_probe,
|
|
|
|
|
_l3_acd_defend_type_to_nacd(acd_data->acd_defend_type_current))
|
|
|
|
|
!= 0)
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-09-28 18:07:51 +02:00
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_EXTERNAL_ADDED:
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (self->priv.p->commit_reentrant_count > 0)
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data, "address was externally added");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
goto handle_start_defending;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
log_reason = "address configured on link";
|
|
|
|
|
goto handle_probing_done;
|
|
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_EXTERNAL_REMOVED:
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (self->priv.p->commit_reentrant_count > 0)
|
|
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (_l3_acd_ipv4_addresses_on_link_contains(self, acd_data->info.addr)) {
|
|
|
|
|
/* this can happen, because there might still be the same address with different
|
|
|
|
|
* plen or peer_address. */
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data, "address was externally removed");
|
|
|
|
|
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
_l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED, FALSE);
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_NACD_DOWN:
|
2020-08-03 17:33:31 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_LINK_NOW_UP:
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
if (!acd_data->nacd_probe) {
|
2020-09-28 18:07:51 +02:00
|
|
|
/* we failed starting to probe before and have a timer running to
|
|
|
|
|
* restart. We don't do anything now, but let the timer handle it.
|
|
|
|
|
* This also implements some rate limiting for us. */
|
2020-08-03 17:33:31 +02:00
|
|
|
_LOGT_acd(acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
"ignore link %s event while we are waiting to start probing",
|
|
|
|
|
state_change_mode == ACD_STATE_CHANGE_MODE_NACD_DOWN ? "down" : "up");
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data->probing_timestamp_msec + acd_data->probing_timeout_msec
|
|
|
|
|
+ ACD_WAIT_PROBING_EXTRA_TIME_MSEC + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC
|
|
|
|
|
>= (*p_now_msec)) {
|
|
|
|
|
/* The probing already started quite a while ago. We ignore the link event
|
|
|
|
|
* and let the probe come to it's natural end. */
|
|
|
|
|
_LOGT_acd(acd_data, "ignore link up event for a probe started long ago");
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
if (state_change_mode == ACD_STATE_CHANGE_MODE_NACD_DOWN)
|
|
|
|
|
log_reason = "restart probing after down event";
|
|
|
|
|
else
|
|
|
|
|
log_reason = "restart probing after link up";
|
|
|
|
|
goto handle_start_probing;
|
|
|
|
|
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
|
|
|
/* if the link was down/came up, it's no clear what we should do about these
|
|
|
|
|
* cases. Ignore the event. */
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert_not_reached();
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
case ACD_STATE_CHANGE_MODE_INSTANCE_RESET:
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
nm_assert(NM_IN_SET(acd_data->info.state,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_PROBING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_DEFENDING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_READY,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_USED,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_CONFLICT,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED));
|
2020-09-28 18:07:51 +02:00
|
|
|
|
l3cfg: fix handling "instance-reset" ACD event
The ACD state handling is unfortunately very complicated. That is, because
we obviously need to track state about how ACD is going (the acd_data, and
in particular NML3AcdAddrState). Then there are various things that can
happen, which are the AcdStateChangeMode enums. All these state-changes
come together in one function: _l3_acd_data_state_change(), which is
therefore complicated (I don't think that it would become simpler by
spreading this code out to different functions, on the contrary).
Anyway.
So, what happens when we need to reset the n-acd instance? For example,
because the MAC address of the link changed or some error. I guess, we
need to restart probing.
Previously, I think this was not handled properly. We already tried to
fix this several times, the last was commit b3316063862b ('l3cfg: on
n-acd instance-reset clear also ready ACD state'). There is still an
issue ([1]).
The bug [1] is, that we are in state NM_L3_ACD_ADDR_STATE_READY, during
ACD_STATE_CHANGE_MODE_TIMEOUT event. That leads to an assertion
failure.
#5 0x00007f23be74698f in g_assertion_message_expr (domain=0x5629aca70359 "nm", file=0x5629aca62aab "src/core/nm-l3cfg.c", line=2395, func=0x5629acb26b30 <__func__.72.lto_priv.4> "_l3_acd_data_state_change", expr=<optimized out>) at ../glib/gtestutils.c:3091
#6 0x00005629ac937e46 in _l3_acd_data_state_change (self=0x5629add69790, acd_data=0x5629add8d520, state_change_mode=ACD_STATE_CHANGE_MODE_TIMEOUT, sender_addr=0x0, p_now_msec=0x7ffded506460) at src/core/nm-l3cfg.c:2395
#7 0x00005629ac939f4d in _l3_acd_data_timeout_cb (user_data=user_data@entry=0x5629add8d520) at src/core/nm-l3cfg.c:1933
#8 0x00007f23be71c5a1 in g_timeout_dispatch (source=0x5629addd7a80, callback=0x5629ac939ee0 <_l3_acd_data_timeout_cb>, user_data=0x5629add8d520) at ../glib/gmain.c:4889
#9 0x00007f23be71bd4f in g_main_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:3337
#10 g_main_context_dispatch (context=0x5629adc6da00) at ../glib/gmain.c:4055
That can only happen, (I think) when we scheduled the timeout
during an earlier ACD_STATE_CHANGE_MODE_INSTANCE_RESET event. Meaning,
we need to handle instance-reset better.
Instead, during instance-reset, switch always back to state PROBING, and
let the timeout figure it out.
[1] https://bugzilla.redhat.com/show_bug.cgi?id=2047788
2022-01-28 17:52:34 +01:00
|
|
|
/* an instance-reset is a dramatic event. We start over with probing. */
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"n-acd instance reset. Reset to probing while in state %s",
|
|
|
|
|
_l3_acd_addr_state_to_string(acd_data->info.state));
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
|
|
|
|
acd_data->last_defendconflict_timestamp_msec = 0;
|
|
|
|
|
acd_data->probing_timestamp_msec = nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec);
|
|
|
|
|
_l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_PROBING, FALSE);
|
|
|
|
|
_l3_acd_data_timeout_schedule(acd_data, 0);
|
2020-09-19 12:20:45 +02:00
|
|
|
return;
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
handle_start_probing:
|
|
|
|
|
if (TRUE) {
|
|
|
|
|
const NML3AcdAddrState orig_state = acd_data->info.state;
|
|
|
|
|
nm_auto(n_acd_probe_freep) NAcdProbe *probe = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *failure_reason;
|
2020-08-03 17:33:31 +02:00
|
|
|
gboolean acd_not_supported;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(NM_IN_SET(acd_data->info.state,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_INIT,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_PROBING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_USED,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_CONFLICT));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
/* note that we reach this line also during a ACD_STATE_CHANGE_MODE_TIMEOUT, when
|
|
|
|
|
* or when we restart the probing (with a new timeout). In all cases, we still
|
|
|
|
|
* give the original timeout (acd_data->probing_timeout_msec), and not the remaining
|
|
|
|
|
* time. That means, the probing step might take longer then originally planned
|
|
|
|
|
* (e.g. if we initially cannot start probing right away). */
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
probe = _l3_acd_nacd_instance_create_probe(self,
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->info.addr,
|
|
|
|
|
acd_data->probing_timeout_msec,
|
2020-08-03 17:33:31 +02:00
|
|
|
acd_data,
|
|
|
|
|
&acd_not_supported,
|
|
|
|
|
&failure_reason);
|
|
|
|
|
NM_SWAP(&probe, &acd_data->nacd_probe);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (acd_not_supported) {
|
|
|
|
|
nm_assert(!acd_data->nacd_probe);
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"probe-good (interface does not support acd%s, %s)",
|
|
|
|
|
orig_state == NM_L3_ACD_ADDR_STATE_INIT ? ""
|
|
|
|
|
: (state_change_mode != ACD_STATE_CHANGE_MODE_TIMEOUT)
|
|
|
|
|
? " anymore"
|
|
|
|
|
: " anymore after timeout",
|
|
|
|
|
log_reason);
|
|
|
|
|
goto handle_start_defending;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_state_set(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_PROBING,
|
|
|
|
|
!NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT_REAPPLY,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT));
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!acd_data->nacd_probe) {
|
|
|
|
|
_LOGT_acd(acd_data,
|
2020-09-28 18:07:51 +02:00
|
|
|
"probing currently %snot possible (timeout %u msec; %s, %s)",
|
|
|
|
|
orig_state == NM_L3_ACD_ADDR_STATE_INIT ? "" : " still",
|
|
|
|
|
acd_data->probing_timeout_msec,
|
|
|
|
|
failure_reason,
|
|
|
|
|
log_reason);
|
|
|
|
|
_l3_acd_data_timeout_schedule_probing_restart(acd_data, (*p_now_msec));
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"%sstart probing (timeout %u msec, %s)",
|
|
|
|
|
orig_state == NM_L3_ACD_ADDR_STATE_INIT ? "" : "re",
|
|
|
|
|
acd_data->probing_timeout_msec,
|
|
|
|
|
log_reason);
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
handle_probing_done:
|
|
|
|
|
switch (acd_data->info.state) {
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
|
|
|
_LOGT_acd(acd_data, "probe-done good (%s, initializing)", log_reason);
|
|
|
|
|
goto handle_start_defending;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
|
|
|
_LOGT_acd(acd_data, "probe-done good (%s, probing done)", log_reason);
|
2020-08-03 17:33:31 +02:00
|
|
|
if (state_change_mode != ACD_STATE_CHANGE_MODE_NACD_READY)
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
2020-09-28 18:07:51 +02:00
|
|
|
goto handle_start_defending;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_USED:
|
|
|
|
|
_LOGT_acd(acd_data, "probe-done good (%s, after probe failed)", log_reason);
|
|
|
|
|
goto handle_start_defending;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_READY:
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
2021-11-10 16:45:40 +01:00
|
|
|
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
2020-09-28 18:07:51 +02:00
|
|
|
goto handle_start_defending;
|
|
|
|
|
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
return;
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert_not_reached();
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
handle_start_defending:
|
|
|
|
|
if (!_l3_acd_ipv4_addresses_on_link_contains(self, acd_data->info.addr)) {
|
|
|
|
|
if (acd_data->info.state != NM_L3_ACD_ADDR_STATE_READY) {
|
|
|
|
|
_l3_acd_data_state_set_full(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_READY,
|
|
|
|
|
!NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT_REAPPLY,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT),
|
|
|
|
|
"probe is ready, waiting for address to be configured");
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_state_set(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_DEFENDING,
|
|
|
|
|
!NM_IN_SET(state_change_mode,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_INIT_REAPPLY,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT));
|
|
|
|
|
|
2021-08-30 10:31:45 +02:00
|
|
|
nm_assert(acd_data->acd_defend_type_desired > _NM_L3_ACD_DEFEND_TYPE_NONE);
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(acd_data->acd_defend_type_desired <= NM_L3_ACD_DEFEND_TYPE_ALWAYS);
|
|
|
|
|
|
|
|
|
|
if (acd_data->acd_defend_type_desired != acd_data->acd_defend_type_current) {
|
|
|
|
|
acd_data->acd_defend_type_current = acd_data->acd_defend_type_desired;
|
|
|
|
|
acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe);
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (!acd_data->nacd_probe) {
|
|
|
|
|
const char *failure_reason;
|
2021-11-09 13:28:54 +01:00
|
|
|
NAcdProbe *probe;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data->acd_data_timeout_source) {
|
2020-08-03 17:33:31 +02:00
|
|
|
/* we already failed to create a probe. We are ratelimited to retry, but
|
|
|
|
|
* we have a timer pending... */
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
probe = _l3_acd_nacd_instance_create_probe(self,
|
2020-09-28 18:07:51 +02:00
|
|
|
acd_data->info.addr,
|
2020-08-03 17:33:31 +02:00
|
|
|
0,
|
|
|
|
|
acd_data,
|
|
|
|
|
NULL,
|
|
|
|
|
&failure_reason);
|
|
|
|
|
if (!probe) {
|
2020-09-28 18:07:51 +02:00
|
|
|
/* we failed to create a probe for announcing the address. We log a
|
|
|
|
|
* warning and start a timer to retry. This way (of having a timer pending)
|
|
|
|
|
* we also back off and are rate limited from retrying too frequently. */
|
|
|
|
|
_LOGT_acd(acd_data, "start announcing failed to create probe (%s)", failure_reason);
|
|
|
|
|
_l3_acd_data_timeout_schedule(acd_data, ACD_WAIT_TIME_ANNOUNCE_RESTART_MSEC);
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"start announcing (defend=%s) (probe created)",
|
|
|
|
|
_l3_acd_defend_type_to_string(acd_data->acd_defend_type_current,
|
|
|
|
|
sbuf256,
|
|
|
|
|
sizeof(sbuf256)));
|
|
|
|
|
acd_data->acd_defend_type_is_active = FALSE;
|
|
|
|
|
acd_data->nacd_probe = probe;
|
2020-08-03 17:33:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!acd_data->acd_defend_type_is_active) {
|
|
|
|
|
acd_data->acd_defend_type_is_active = TRUE;
|
|
|
|
|
_LOGT_acd(acd_data,
|
|
|
|
|
"start announcing (defend=%s) (with existing probe)",
|
|
|
|
|
_l3_acd_defend_type_to_string(acd_data->acd_defend_type_current,
|
|
|
|
|
sbuf256,
|
|
|
|
|
sizeof(sbuf256)));
|
|
|
|
|
if (n_acd_probe_announce(acd_data->nacd_probe,
|
|
|
|
|
_l3_acd_defend_type_to_nacd(acd_data->acd_defend_type_current))
|
|
|
|
|
!= 0)
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_not_reached();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_acd_data_process_changes(NML3Cfg *self)
|
|
|
|
|
{
|
2020-09-28 18:07:51 +02:00
|
|
|
gboolean acd_is_pending = FALSE;
|
|
|
|
|
gboolean acd_busy = FALSE;
|
2020-08-03 17:33:31 +02:00
|
|
|
AcdData *acd_data;
|
2020-09-28 18:07:51 +02:00
|
|
|
gint64 now_msec = 0;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
_l3_acd_data_prune(self, FALSE);
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) {
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_acd_data_state_change(self,
|
|
|
|
|
acd_data,
|
|
|
|
|
ACD_STATE_CHANGE_MODE_POST_COMMIT,
|
|
|
|
|
NULL,
|
|
|
|
|
&now_msec);
|
|
|
|
|
if (acd_data->info.state <= NM_L3_ACD_ADDR_STATE_PROBING)
|
2020-08-03 17:33:31 +02:00
|
|
|
acd_is_pending = TRUE;
|
2020-09-28 18:07:51 +02:00
|
|
|
if (acd_data->nacd_probe)
|
|
|
|
|
acd_busy = TRUE;
|
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.
2020-07-21 12:52:42 +02:00
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
self->priv.p->acd_is_pending = acd_is_pending;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!acd_busy)
|
2020-08-03 17:33:31 +02:00
|
|
|
_l3_acd_nacd_instance_reset(self, NM_TERNARY_DEFAULT, FALSE);
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_acd_event_all(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
const NML3AcdAddrInfo *
|
|
|
|
|
nm_l3cfg_get_acd_addr_info(NML3Cfg *self, in_addr_t addr)
|
|
|
|
|
{
|
|
|
|
|
AcdData *acd_data;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
acd_data = _l3_acd_data_find(self, addr);
|
|
|
|
|
if (!acd_data)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return &acd_data->info;
|
2020-07-21 11:21:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2022-02-14 09:47:20 +01:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_has_temp_not_available_obj(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
|
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert_addr_family(addr_family);
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (obj_state,
|
|
|
|
|
&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
os_temporary_not_available_lst) {
|
|
|
|
|
if (NMP_OBJECT_GET_ADDR_FAMILY(obj_state->obj) == addr_family)
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 21:17:43 +02:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_l3cfg_check_ready(NML3Cfg *self,
|
|
|
|
|
const NML3ConfigData *l3cd,
|
2021-10-17 10:20:25 +02:00
|
|
|
int addr_family,
|
|
|
|
|
NML3CfgCheckReadyFlags flags,
|
2022-09-08 15:34:19 +02:00
|
|
|
GArray **conflicts)
|
2021-09-23 21:17:43 +02:00
|
|
|
{
|
|
|
|
|
NMDedupMultiIter iter;
|
|
|
|
|
const NMPObject *obj;
|
2022-09-08 15:19:16 +02:00
|
|
|
gboolean ready = TRUE;
|
2021-09-23 21:17:43 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2022-09-08 15:19:16 +02:00
|
|
|
nm_assert_addr_family(addr_family);
|
2022-09-08 15:34:19 +02:00
|
|
|
nm_assert(!conflicts || !*conflicts);
|
2021-09-23 21:17:43 +02:00
|
|
|
|
|
|
|
|
if (!l3cd)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2022-09-08 15:19:16 +02:00
|
|
|
if (addr_family == AF_INET) {
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY)) {
|
|
|
|
|
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) {
|
|
|
|
|
const NML3AcdAddrInfo *addr_info;
|
|
|
|
|
|
|
|
|
|
addr_info =
|
|
|
|
|
nm_l3cfg_get_acd_addr_info(self, NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address);
|
|
|
|
|
if (!addr_info) {
|
|
|
|
|
/* We don't track the this address? That's odd. Not ready. */
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) {
|
|
|
|
|
/* Still probing. Not ready. */
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
} else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) {
|
2022-09-08 15:34:19 +02:00
|
|
|
if (conflicts) {
|
|
|
|
|
if (!*conflicts)
|
|
|
|
|
*conflicts = g_array_new(FALSE,
|
|
|
|
|
FALSE,
|
|
|
|
|
nm_utils_addr_family_to_size(addr_family));
|
|
|
|
|
g_array_append_val(*conflicts, addr_info->addr);
|
|
|
|
|
}
|
2022-09-08 15:19:16 +02:00
|
|
|
}
|
2021-10-17 10:20:25 +02:00
|
|
|
}
|
2022-09-08 15:19:16 +02:00
|
|
|
/* we only care that we don't have ACD still pending. Otherwise we are ready,
|
|
|
|
|
* including if we have no addr_info about this address or the address is in use. */
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-08 15:19:16 +02:00
|
|
|
return ready;
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-08 15:19:16 +02:00
|
|
|
/* AF_INET6 */
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) {
|
2021-09-23 21:17:43 +02:00
|
|
|
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
|
|
|
|
ObjStateData *obj_state;
|
2022-09-08 15:34:19 +02:00
|
|
|
gboolean dadfailed = FALSE;
|
2021-09-23 21:17:43 +02:00
|
|
|
|
|
|
|
|
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
|
|
|
|
|
|
|
|
|
|
if (!obj_state) {
|
|
|
|
|
/* Hm, we don't track this object? That is odd. Not ready. */
|
2022-09-08 15:19:16 +02:00
|
|
|
ready = FALSE;
|
|
|
|
|
continue;
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!obj_state->os_nm_configured && !obj_state->os_plobj) {
|
|
|
|
|
/* We didn't (yet) configure this address and it also is not in platform.
|
|
|
|
|
* Not ready. */
|
2022-09-08 15:19:16 +02:00
|
|
|
ready = FALSE;
|
|
|
|
|
continue;
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-08 15:34:19 +02:00
|
|
|
if (obj_state->os_plobj
|
|
|
|
|
&& NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags,
|
|
|
|
|
IFA_F_DADFAILED)) {
|
|
|
|
|
/* The address is still present with DADFAILED flag. */
|
|
|
|
|
dadfailed = TRUE;
|
|
|
|
|
} else if (obj_state->os_nm_configured && !obj_state->os_plobj
|
|
|
|
|
&& nm_platform_ip6_dadfailed_check(
|
|
|
|
|
self->priv.platform,
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
&NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address)) {
|
|
|
|
|
/* We configured the address and kernel removed it with DADFAILED flag. */
|
|
|
|
|
dadfailed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dadfailed) {
|
|
|
|
|
if (conflicts) {
|
|
|
|
|
if (!*conflicts) {
|
|
|
|
|
*conflicts =
|
|
|
|
|
g_array_new(FALSE, FALSE, nm_utils_addr_family_to_size(addr_family));
|
|
|
|
|
}
|
|
|
|
|
g_array_append_val(*conflicts,
|
|
|
|
|
NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 21:17:43 +02:00
|
|
|
if (obj_state->os_plobj
|
|
|
|
|
&& NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags,
|
|
|
|
|
IFA_F_TENTATIVE)) {
|
|
|
|
|
/* The address is configured in kernel, but still tentative. Not ready. */
|
2022-09-08 15:19:16 +02:00
|
|
|
ready = FALSE;
|
|
|
|
|
continue;
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This address is ready. Even if it is not (not anymore) configured in kernel (as
|
|
|
|
|
* indicated by obj_state->os_plobj). We apparently did configure it once, and
|
|
|
|
|
* it's no longer tentative. This address are good. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-08 15:19:16 +02:00
|
|
|
return ready;
|
2021-09-23 21:17:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
static gboolean
|
|
|
|
|
_l3_commit_on_idle_cb(gpointer user_data)
|
|
|
|
|
{
|
2021-10-11 13:32:26 +02:00
|
|
|
_nm_unused gs_unref_object NML3Cfg *self_keep_alive = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self = user_data;
|
2021-10-11 13:32:26 +02:00
|
|
|
NML3CfgCommitType commit_type;
|
2020-09-25 15:46:06 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
commit_type = self->priv.p->commit_on_idle_type;
|
|
|
|
|
|
2021-10-11 13:32:26 +02:00
|
|
|
if (nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source))
|
|
|
|
|
self_keep_alive = self;
|
|
|
|
|
else
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
self->priv.p->commit_on_idle_type = NM_L3_CFG_COMMIT_TYPE_AUTO;
|
2020-09-25 15:46:06 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
_l3_commit(self, commit_type, TRUE);
|
2020-09-25 15:46:06 +02:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-29 09:24:52 +02:00
|
|
|
/* DOC(l3cfg:commit-type):
|
|
|
|
|
*
|
|
|
|
|
* Usually we don't want to call the synchronous nm_l3cfg_commit(), because
|
|
|
|
|
* that has side effects and might not be safe to do (depending on the current
|
|
|
|
|
* circumstances in which commit is called). The usually proper thing to do
|
|
|
|
|
* is schedule a commit on an idle handler. Use this function.
|
|
|
|
|
*
|
|
|
|
|
* During commit, the actually used commit-type (that is, the level of "how much"
|
|
|
|
|
* will be synced) is determined by users who register their desired commit
|
|
|
|
|
* type via nm_l3cfg_commit_type_register(), where always the "maxium" is used.
|
|
|
|
|
*
|
|
|
|
|
* nm_l3cfg_commit() and nm_l3cfg_commit_on_idle_schedule() also accept an additional
|
|
|
|
|
* commit_type argument. This acts like a one-shot registration.
|
|
|
|
|
*/
|
2021-05-21 21:24:32 +02:00
|
|
|
gboolean
|
2021-09-24 19:32:03 +02:00
|
|
|
nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self, NML3CfgCommitType commit_type)
|
2020-09-25 15:46:06 +02:00
|
|
|
{
|
2021-09-24 19:32:03 +02:00
|
|
|
char sbuf_commit_type[50];
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2021-09-24 19:32:03 +02:00
|
|
|
nm_assert(NM_IN_SET(commit_type,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_AUTO,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_UPDATE,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_REAPPLY));
|
2020-09-25 15:46:06 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
if (self->priv.p->commit_on_idle_source) {
|
|
|
|
|
if (self->priv.p->commit_on_idle_type < commit_type) {
|
2021-09-29 09:24:52 +02:00
|
|
|
/* For multiple calls, we collect the maximum "commit-type". */
|
2021-09-24 19:32:03 +02:00
|
|
|
_LOGT("commit on idle (scheduled) (update to %s)",
|
|
|
|
|
_l3_cfg_commit_type_to_string(commit_type,
|
|
|
|
|
sbuf_commit_type,
|
|
|
|
|
sizeof(sbuf_commit_type)));
|
|
|
|
|
self->priv.p->commit_on_idle_type = commit_type;
|
|
|
|
|
}
|
2021-05-21 21:24:32 +02:00
|
|
|
return FALSE;
|
2021-09-24 19:32:03 +02:00
|
|
|
}
|
2020-09-25 15:46:06 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
_LOGT("commit on idle (scheduled) (%s)",
|
|
|
|
|
_l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type)));
|
|
|
|
|
self->priv.p->commit_on_idle_source = nm_g_idle_add_source(_l3_commit_on_idle_cb, self);
|
|
|
|
|
self->priv.p->commit_on_idle_type = commit_type;
|
2021-10-11 13:32:26 +02:00
|
|
|
|
|
|
|
|
/* While we have an idle update scheduled, we need to keep the instance alive. */
|
|
|
|
|
g_object_ref(self);
|
|
|
|
|
|
2021-05-21 21:24:32 +02:00
|
|
|
return TRUE;
|
2020-09-25 15:46:06 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-25 11:15:39 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_commit_on_idle_is_scheduled(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
return !!(self->priv.p->commit_on_idle_source);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
#define _l3_config_datas_at(l3_config_datas, idx) \
|
2022-09-08 12:05:56 +02:00
|
|
|
(&nm_g_array_index((l3_config_datas), L3ConfigData, (idx)))
|
2020-07-23 16:15:26 +02:00
|
|
|
|
|
|
|
|
static gssize
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_config_datas_find_next(GArray *l3_config_datas,
|
2020-07-23 16:15:26 +02:00
|
|
|
guint start_idx,
|
|
|
|
|
gconstpointer needle_tag,
|
2020-07-31 12:39:58 +02:00
|
|
|
const NML3ConfigData *needle_l3cd)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
nm_assert(l3_config_datas);
|
|
|
|
|
nm_assert(start_idx <= l3_config_datas->len);
|
|
|
|
|
|
|
|
|
|
for (i = start_idx; i < l3_config_datas->len; i++) {
|
|
|
|
|
const L3ConfigData *l3_config_data = _l3_config_datas_at(l3_config_datas, i);
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (NM_IN_SET(needle_tag, NULL, l3_config_data->tag_confdata)
|
2020-08-03 17:19:27 +02:00
|
|
|
&& NM_IN_SET(needle_l3cd, NULL, l3_config_data->l3cd))
|
2020-07-23 16:15:26 +02:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static int
|
|
|
|
|
_l3_config_datas_get_sorted_cmp(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
const L3ConfigData *a = *((L3ConfigData **) p_a);
|
|
|
|
|
const L3ConfigData *b = *((L3ConfigData **) p_b);
|
|
|
|
|
|
|
|
|
|
nm_assert(a);
|
|
|
|
|
nm_assert(b);
|
|
|
|
|
nm_assert(nm_l3_config_data_get_ifindex(a->l3cd) == nm_l3_config_data_get_ifindex(b->l3cd));
|
|
|
|
|
|
2022-01-28 13:32:32 +01:00
|
|
|
/* we sort the entries with higher priority (higher numerical value, more important)
|
2020-08-03 17:33:31 +02:00
|
|
|
* first. */
|
2022-01-28 13:32:32 +01:00
|
|
|
NM_CMP_FIELD(b, a, priority_confdata);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
/* if the priority is not unique, we sort them in the order they were added,
|
|
|
|
|
* with the oldest first (lower numerical value). */
|
2020-09-28 18:07:51 +02:00
|
|
|
NM_CMP_FIELD(a, b, pseudo_timestamp_confdata);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
return nm_assert_unreachable_val(0);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
static void
|
|
|
|
|
_l3_config_datas_remove_index_fast(GArray *arr, guint idx)
|
|
|
|
|
{
|
|
|
|
|
L3ConfigData *l3_config_data;
|
|
|
|
|
|
|
|
|
|
nm_assert(arr);
|
|
|
|
|
nm_assert(idx < arr->len);
|
|
|
|
|
|
|
|
|
|
l3_config_data = _l3_config_datas_at(arr, idx);
|
|
|
|
|
|
2020-08-03 17:19:27 +02:00
|
|
|
nm_l3_config_data_unref(l3_config_data->l3cd);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
|
|
|
|
g_array_remove_index_fast(arr, idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_l3cfg_mark_config_dirty(NML3Cfg *self, gconstpointer tag, gboolean dirty)
|
|
|
|
|
{
|
|
|
|
|
gssize idx;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(tag);
|
|
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
if (!self->priv.p->l3_config_datas)
|
2020-07-23 16:15:26 +02:00
|
|
|
return;
|
|
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
nm_assert(self->priv.p->l3_config_datas->len > 0);
|
|
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
idx = 0;
|
|
|
|
|
while (TRUE) {
|
2020-09-22 18:25:25 +02:00
|
|
|
idx = _l3_config_datas_find_next(self->priv.p->l3_config_datas, idx, tag, NULL);
|
2020-07-23 16:15:26 +02:00
|
|
|
if (idx < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_config_datas_at(self->priv.p->l3_config_datas, idx)->dirty_confdata = dirty;
|
2020-07-23 16:15:26 +02:00
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-28 13:32:32 +01:00
|
|
|
/*
|
|
|
|
|
* nm_l3cfg_add_config:
|
|
|
|
|
* @priority: all l3cd get merged/combined. This merging requires that some
|
|
|
|
|
* l3cd are more important than others. For example, coming from static IP
|
|
|
|
|
* configuration needs to take precedence over DHCP. The @priority determines
|
|
|
|
|
* the order in which l3cds get merged (and thus the outcome). Higher numbers
|
|
|
|
|
* mean more important!!
|
|
|
|
|
*/
|
2020-08-28 17:20:53 +02:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_l3cfg_add_config(NML3Cfg *self,
|
2020-07-23 16:15:26 +02:00
|
|
|
gconstpointer tag,
|
|
|
|
|
gboolean replace_same_tag,
|
2020-07-31 12:39:58 +02:00
|
|
|
const NML3ConfigData *l3cd,
|
2020-07-23 16:15:26 +02:00
|
|
|
int priority,
|
2020-09-23 15:55:28 +02:00
|
|
|
guint32 default_route_table_4,
|
|
|
|
|
guint32 default_route_table_6,
|
|
|
|
|
guint32 default_route_metric_4,
|
|
|
|
|
guint32 default_route_metric_6,
|
2020-07-23 16:15:26 +02:00
|
|
|
guint32 default_route_penalty_4,
|
|
|
|
|
guint32 default_route_penalty_6,
|
2021-09-15 15:38:26 +02:00
|
|
|
int default_dns_priority_4,
|
|
|
|
|
int default_dns_priority_6,
|
2020-09-28 18:07:51 +02:00
|
|
|
NML3AcdDefendType acd_defend_type,
|
2020-08-03 17:33:31 +02:00
|
|
|
guint32 acd_timeout_msec,
|
2021-08-31 17:12:45 +02:00
|
|
|
NML3CfgConfigFlags config_flags,
|
2020-07-23 16:15:26 +02:00
|
|
|
NML3ConfigMergeFlags merge_flags)
|
|
|
|
|
{
|
|
|
|
|
L3ConfigData *l3_config_data;
|
|
|
|
|
gssize idx;
|
|
|
|
|
gboolean changed = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(tag);
|
2020-07-31 12:39:58 +02:00
|
|
|
nm_assert(l3cd);
|
|
|
|
|
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
|
2020-09-16 19:14:20 +02:00
|
|
|
|
2022-05-19 09:23:29 +02:00
|
|
|
if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC)
|
|
|
|
|
acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC;
|
2020-09-16 19:14:20 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(NM_IN_SET(acd_defend_type,
|
|
|
|
|
NM_L3_ACD_DEFEND_TYPE_NEVER,
|
|
|
|
|
NM_L3_ACD_DEFEND_TYPE_ONCE,
|
|
|
|
|
NM_L3_ACD_DEFEND_TYPE_ALWAYS));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-23 15:55:28 +02:00
|
|
|
nm_assert(default_route_metric_6 != 0u); /* IPv6 default route metric cannot be zero. */
|
|
|
|
|
|
|
|
|
|
if (default_route_table_4 == 0u)
|
|
|
|
|
default_route_table_4 = RT_TABLE_MAIN;
|
|
|
|
|
if (default_route_table_6 == 0u)
|
|
|
|
|
default_route_table_6 = RT_TABLE_MAIN;
|
|
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
if (!self->priv.p->l3_config_datas) {
|
|
|
|
|
self->priv.p->l3_config_datas = g_array_new(FALSE, FALSE, sizeof(L3ConfigData));
|
|
|
|
|
g_object_ref(self);
|
|
|
|
|
} else
|
|
|
|
|
nm_assert(self->priv.p->l3_config_datas->len > 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
idx = _l3_config_datas_find_next(self->priv.p->l3_config_datas,
|
2020-07-23 16:15:26 +02:00
|
|
|
0,
|
|
|
|
|
tag,
|
2020-07-31 12:39:58 +02:00
|
|
|
replace_same_tag ? NULL : l3cd);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
if (replace_same_tag && idx >= 0) {
|
2020-07-23 16:15:26 +02:00
|
|
|
gssize idx2;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
idx2 = idx;
|
|
|
|
|
idx = -1;
|
|
|
|
|
while (TRUE) {
|
2020-09-22 18:25:25 +02:00
|
|
|
l3_config_data = _l3_config_datas_at(self->priv.p->l3_config_datas, idx2);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:19:27 +02:00
|
|
|
if (l3_config_data->l3cd == l3cd) {
|
2020-07-23 16:15:26 +02:00
|
|
|
nm_assert(idx == -1);
|
|
|
|
|
idx = idx2;
|
2020-10-21 12:13:14 +02:00
|
|
|
idx2++;
|
|
|
|
|
} else {
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
_l3_config_datas_remove_index_fast(self->priv.p->l3_config_datas, idx2);
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
2020-09-22 18:25:25 +02:00
|
|
|
idx2 = _l3_config_datas_find_next(self->priv.p->l3_config_datas, idx2, tag, NULL);
|
2020-07-23 16:15:26 +02:00
|
|
|
if (idx2 < 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
if (idx < 0) {
|
2020-09-22 18:25:25 +02:00
|
|
|
l3_config_data = nm_g_array_append_new(self->priv.p->l3_config_datas, L3ConfigData);
|
2020-07-23 16:15:26 +02:00
|
|
|
*l3_config_data = (L3ConfigData){
|
2020-09-28 18:07:51 +02:00
|
|
|
.tag_confdata = tag,
|
|
|
|
|
.l3cd = nm_l3_config_data_ref_and_seal(l3cd),
|
2021-08-31 17:12:45 +02:00
|
|
|
.config_flags = config_flags,
|
2020-09-28 18:07:51 +02:00
|
|
|
.merge_flags = merge_flags,
|
|
|
|
|
.default_route_table_4 = default_route_table_4,
|
|
|
|
|
.default_route_table_6 = default_route_table_6,
|
|
|
|
|
.default_route_metric_4 = default_route_metric_4,
|
|
|
|
|
.default_route_metric_6 = default_route_metric_6,
|
|
|
|
|
.default_route_penalty_4 = default_route_penalty_4,
|
|
|
|
|
.default_route_penalty_6 = default_route_penalty_6,
|
2021-09-15 15:38:26 +02:00
|
|
|
.default_dns_priority_4 = default_dns_priority_4,
|
|
|
|
|
.default_dns_priority_6 = default_dns_priority_6,
|
2020-09-28 18:07:51 +02:00
|
|
|
.acd_defend_type_confdata = acd_defend_type,
|
|
|
|
|
.acd_timeout_msec_confdata = acd_timeout_msec,
|
|
|
|
|
.priority_confdata = priority,
|
|
|
|
|
.pseudo_timestamp_confdata = ++self->priv.p->pseudo_timestamp_counter,
|
2021-11-11 22:16:14 +01:00
|
|
|
.force_commit_once = NM_FLAGS_HAS(config_flags, NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE),
|
|
|
|
|
.dirty_confdata = FALSE,
|
2020-07-23 16:15:26 +02:00
|
|
|
};
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
} else {
|
2020-09-28 18:07:51 +02:00
|
|
|
l3_config_data = _l3_config_datas_at(self->priv.p->l3_config_datas, idx);
|
|
|
|
|
l3_config_data->dirty_confdata = FALSE;
|
|
|
|
|
nm_assert(l3_config_data->tag_confdata == tag);
|
2020-08-03 17:19:27 +02:00
|
|
|
nm_assert(l3_config_data->l3cd == l3cd);
|
2020-09-28 18:07:51 +02:00
|
|
|
if (l3_config_data->priority_confdata != priority) {
|
|
|
|
|
l3_config_data->priority_confdata = priority;
|
|
|
|
|
changed = TRUE;
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
2021-08-31 17:12:45 +02:00
|
|
|
if (l3_config_data->config_flags != config_flags) {
|
|
|
|
|
l3_config_data->config_flags = config_flags;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-08-03 17:19:27 +02:00
|
|
|
if (l3_config_data->merge_flags != merge_flags) {
|
|
|
|
|
l3_config_data->merge_flags = merge_flags;
|
2020-07-23 16:15:26 +02:00
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-09-23 15:55:28 +02:00
|
|
|
if (l3_config_data->default_route_table_4 != default_route_table_4) {
|
|
|
|
|
l3_config_data->default_route_table_4 = default_route_table_4;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (l3_config_data->default_route_table_6 != default_route_table_6) {
|
|
|
|
|
l3_config_data->default_route_table_6 = default_route_table_6;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (l3_config_data->default_route_metric_4 != default_route_metric_4) {
|
|
|
|
|
l3_config_data->default_route_metric_4 = default_route_metric_4;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (l3_config_data->default_route_metric_6 != default_route_metric_6) {
|
|
|
|
|
l3_config_data->default_route_metric_6 = default_route_metric_6;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-08-03 17:19:27 +02:00
|
|
|
if (l3_config_data->default_route_penalty_4 != default_route_penalty_4) {
|
|
|
|
|
l3_config_data->default_route_penalty_4 = default_route_penalty_4;
|
2020-07-23 16:15:26 +02:00
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-08-03 17:19:27 +02:00
|
|
|
if (l3_config_data->default_route_penalty_6 != default_route_penalty_6) {
|
|
|
|
|
l3_config_data->default_route_penalty_6 = default_route_penalty_6;
|
2020-07-23 16:15:26 +02:00
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2021-09-15 15:38:26 +02:00
|
|
|
if (l3_config_data->default_dns_priority_4 != default_dns_priority_4) {
|
|
|
|
|
l3_config_data->default_dns_priority_4 = default_dns_priority_4;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (l3_config_data->default_dns_priority_6 != default_dns_priority_6) {
|
|
|
|
|
l3_config_data->default_dns_priority_6 = default_dns_priority_6;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
if (l3_config_data->acd_defend_type_confdata != acd_defend_type) {
|
|
|
|
|
l3_config_data->acd_defend_type_confdata = acd_defend_type;
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (l3_config_data->acd_timeout_msec_confdata != acd_timeout_msec) {
|
|
|
|
|
l3_config_data->acd_timeout_msec_confdata = acd_timeout_msec;
|
|
|
|
|
changed = TRUE;
|
2020-08-03 17:33:31 +02:00
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(l3_config_data->acd_defend_type_confdata == acd_defend_type);
|
|
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
if (changed) {
|
2020-09-16 12:44:38 +02:00
|
|
|
_l3_changed_configs_set_dirty(self);
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-28 17:20:53 +02:00
|
|
|
return changed;
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-28 17:20:53 +02:00
|
|
|
static gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3cfg_remove_config(NML3Cfg *self,
|
2020-07-23 16:15:26 +02:00
|
|
|
gconstpointer tag,
|
|
|
|
|
gboolean only_dirty,
|
2020-07-31 12:39:58 +02:00
|
|
|
const NML3ConfigData *l3cd)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
2020-08-28 17:20:53 +02:00
|
|
|
gboolean changed;
|
2020-07-23 16:15:26 +02:00
|
|
|
gssize idx;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(tag);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
if (!self->priv.p->l3_config_datas)
|
2020-08-28 17:20:53 +02:00
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
nm_assert(self->priv.p->l3_config_datas->len > 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-23 16:15:26 +02:00
|
|
|
idx = 0;
|
2020-08-28 17:20:53 +02:00
|
|
|
changed = FALSE;
|
2020-07-23 16:15:26 +02:00
|
|
|
while (TRUE) {
|
2020-09-22 18:25:25 +02:00
|
|
|
idx = _l3_config_datas_find_next(self->priv.p->l3_config_datas, idx, tag, l3cd);
|
2020-07-23 16:15:26 +02:00
|
|
|
if (idx < 0)
|
2020-09-22 18:25:25 +02:00
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (only_dirty
|
|
|
|
|
&& !_l3_config_datas_at(self->priv.p->l3_config_datas, idx)->dirty_confdata) {
|
2020-07-23 16:15:26 +02:00
|
|
|
idx++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
_l3_changed_configs_set_dirty(self);
|
2020-09-22 18:25:25 +02:00
|
|
|
_l3_config_datas_remove_index_fast(self->priv.p->l3_config_datas, idx);
|
|
|
|
|
changed = TRUE;
|
2020-08-28 17:20:53 +02:00
|
|
|
if (l3cd) {
|
|
|
|
|
/* only one was requested to be removed. We are done. */
|
2020-09-22 18:25:25 +02:00
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2020-08-28 17:20:53 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
if (changed)
|
|
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
|
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
if (self->priv.p->l3_config_datas->len == 0) {
|
|
|
|
|
nm_assert(changed);
|
|
|
|
|
nm_clear_pointer(&self->priv.p->l3_config_datas, g_array_unref);
|
|
|
|
|
g_object_unref(self);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
return changed;
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-28 17:20:53 +02:00
|
|
|
gboolean
|
2021-09-21 09:12:23 +02:00
|
|
|
nm_l3cfg_remove_config(NML3Cfg *self, gconstpointer tag, const NML3ConfigData *l3cd)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
2021-09-21 09:12:23 +02:00
|
|
|
nm_assert(l3cd);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2021-09-21 09:12:23 +02:00
|
|
|
return _l3cfg_remove_config(self, tag, FALSE, l3cd);
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-28 17:20:53 +02:00
|
|
|
gboolean
|
2021-08-05 11:42:29 +02:00
|
|
|
nm_l3cfg_remove_config_all(NML3Cfg *self, gconstpointer tag)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
2021-08-05 11:42:29 +02:00
|
|
|
return _l3cfg_remove_config(self, tag, FALSE, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag)
|
|
|
|
|
{
|
|
|
|
|
return _l3cfg_remove_config(self, tag, TRUE, NULL);
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
static gboolean
|
|
|
|
|
_nodev_routes_untrack(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
return nmp_global_tracker_untrack_all(self->priv.global_tracker,
|
|
|
|
|
_NODEV_ROUTES_TAG(self, NM_IS_IPv4(addr_family)),
|
|
|
|
|
FALSE,
|
|
|
|
|
TRUE);
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_nodev_routes_sync(NML3Cfg *self,
|
|
|
|
|
int addr_family,
|
|
|
|
|
NML3CfgCommitType commit_type,
|
|
|
|
|
GPtrArray *routes_nodev)
|
|
|
|
|
{
|
|
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
const NMPObjectType obj_type = NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4);
|
|
|
|
|
guint i;
|
|
|
|
|
gboolean changed = FALSE;
|
|
|
|
|
|
|
|
|
|
if (!routes_nodev)
|
|
|
|
|
goto out_clear;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < routes_nodev->len; i++) {
|
|
|
|
|
const NMPObject *obj = routes_nodev->pdata[i];
|
|
|
|
|
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
if (nmp_global_tracker_track(self->priv.global_tracker,
|
|
|
|
|
obj_type,
|
|
|
|
|
NMP_OBJECT_CAST_IP_ROUTE(obj),
|
|
|
|
|
1,
|
|
|
|
|
_NODEV_ROUTES_TAG(self, IS_IPv4),
|
|
|
|
|
NULL))
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_clear:
|
|
|
|
|
if (_nodev_routes_untrack(self, addr_family))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
if (changed || commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
nmp_global_tracker_sync(self->priv.global_tracker,
|
|
|
|
|
NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4),
|
|
|
|
|
FALSE);
|
2022-07-18 21:24:09 +02:00
|
|
|
}
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
typedef struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self;
|
2020-08-03 17:33:31 +02:00
|
|
|
gconstpointer tag;
|
2021-09-25 00:07:21 +02:00
|
|
|
bool to_commit;
|
2021-11-11 22:16:14 +01:00
|
|
|
bool force_commit_once;
|
2020-08-03 17:33:31 +02:00
|
|
|
} L3ConfigMergeHookAddObjData;
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_hook_add_obj_cb(const NML3ConfigData *l3cd,
|
|
|
|
|
const NMPObject *obj,
|
2021-09-06 09:08:22 +02:00
|
|
|
NML3ConfigMergeHookResult *hook_result,
|
|
|
|
|
gpointer user_data)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
2020-08-03 17:33:31 +02:00
|
|
|
const L3ConfigMergeHookAddObjData *hook_data = user_data;
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self = hook_data->self;
|
|
|
|
|
AcdData *acd_data;
|
2020-08-03 17:33:31 +02:00
|
|
|
in_addr_t addr;
|
2020-09-28 18:07:51 +02:00
|
|
|
gboolean acd_bad = FALSE;
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
nm_assert(obj);
|
2021-09-06 09:08:22 +02:00
|
|
|
nm_assert(hook_result);
|
|
|
|
|
nm_assert(hook_result->ip4acd_not_ready == NM_OPTION_BOOL_DEFAULT);
|
2021-11-11 22:16:14 +01:00
|
|
|
nm_assert(hook_result->force_commit == NM_OPTION_BOOL_DEFAULT);
|
2021-09-06 14:10:39 +02:00
|
|
|
|
2022-04-19 18:39:37 +02:00
|
|
|
hook_result->force_commit = hook_data->force_commit_once;
|
2020-10-09 19:04:38 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
switch (NMP_OBJECT_GET_TYPE(obj)) {
|
|
|
|
|
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address;
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
if (ACD_ADDR_SKIP(addr))
|
|
|
|
|
goto out_ip4_address;
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
acd_data = _l3_acd_data_find(self, addr);
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2021-09-25 00:07:21 +02:00
|
|
|
if (!hook_data->to_commit) {
|
2021-09-06 09:33:31 +02:00
|
|
|
nm_assert(self->priv.p->changed_configs_acd_state);
|
2021-09-25 00:07:21 +02:00
|
|
|
/* We don't do an actual commit in _l3cfg_update_combined_config(). That means our acd-data
|
|
|
|
|
* is not up to date. Check whether we have no acd_data ready, and if not, consider the address
|
|
|
|
|
* as not ready. It cannot be ready until the next commit starts ACD. */
|
|
|
|
|
if (!acd_data) {
|
|
|
|
|
acd_bad = TRUE;
|
|
|
|
|
goto out_ip4_address;
|
|
|
|
|
}
|
|
|
|
|
nm_assert(({
|
|
|
|
|
NML3AcdAddrTrackInfo *_ti =
|
|
|
|
|
_acd_data_find_track(acd_data, l3cd, obj, hook_data->tag);
|
|
|
|
|
|
|
|
|
|
!_ti || _ti->_priv.acd_dirty_track;
|
|
|
|
|
}));
|
|
|
|
|
} else {
|
|
|
|
|
/* If we commit, we called _l3_acd_data_add_all(), thus our acd_data must be present
|
|
|
|
|
* and not dirty. */
|
|
|
|
|
nm_assert(({
|
|
|
|
|
NML3AcdAddrTrackInfo *_ti =
|
|
|
|
|
_acd_data_find_track(acd_data, l3cd, obj, hook_data->tag);
|
|
|
|
|
|
|
|
|
|
_ti && !_ti->_priv.acd_dirty_track;
|
|
|
|
|
}));
|
2021-09-06 09:33:31 +02:00
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
if (!NM_IN_SET(acd_data->info.state,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_READY,
|
2021-11-10 17:08:59 +01:00
|
|
|
NM_L3_ACD_ADDR_STATE_DEFENDING,
|
|
|
|
|
NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED)) {
|
2021-09-06 09:33:31 +02:00
|
|
|
acd_bad = TRUE;
|
2021-09-25 00:07:21 +02:00
|
|
|
goto out_ip4_address;
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2021-09-06 09:33:31 +02:00
|
|
|
out_ip4_address:
|
|
|
|
|
hook_result->ip4acd_not_ready = acd_bad ? NM_OPTION_BOOL_TRUE : NM_OPTION_BOOL_FALSE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
/* fall-through */
|
|
|
|
|
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
|
|
|
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
|
|
|
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static void
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3cfg_update_combined_config(NML3Cfg *self,
|
2020-09-16 12:44:38 +02:00
|
|
|
gboolean to_commit,
|
2020-09-28 18:07:51 +02:00
|
|
|
gboolean reapply,
|
2020-08-03 17:33:31 +02:00
|
|
|
const NML3ConfigData **out_old /* transfer reference */,
|
2021-11-09 13:28:54 +01:00
|
|
|
gboolean *out_changed_combined_l3cd)
|
2020-07-23 16:15:26 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_auto_unref_l3cd const NML3ConfigData *l3cd_commited_old = NULL;
|
|
|
|
|
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
|
|
|
|
|
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
|
|
|
|
gs_free const L3ConfigData **l3_config_datas_free = NULL;
|
|
|
|
|
const L3ConfigData **l3_config_datas_arr;
|
|
|
|
|
guint l3_config_datas_len;
|
|
|
|
|
guint i;
|
|
|
|
|
gboolean merged_changed = FALSE;
|
|
|
|
|
gboolean commited_changed = FALSE;
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2020-08-03 17:19:27 +02:00
|
|
|
nm_assert(!out_old || !*out_old);
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
NM_SET_OUT(out_changed_combined_l3cd, FALSE);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!self->priv.p->changed_configs_configs) {
|
|
|
|
|
if (!self->priv.p->changed_configs_acd_state)
|
|
|
|
|
goto out;
|
|
|
|
|
if (!to_commit) {
|
|
|
|
|
/* since we are not going to commit, we don't care about the
|
|
|
|
|
* ACD state. */
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->priv.p->changed_configs_configs = FALSE;
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
l3_config_datas_len = nm_g_array_len(self->priv.p->l3_config_datas);
|
|
|
|
|
l3_config_datas_arr = nm_malloc_maybe_a(300,
|
|
|
|
|
l3_config_datas_len * sizeof(l3_config_datas_arr[0]),
|
|
|
|
|
&l3_config_datas_free);
|
|
|
|
|
for (i = 0; i < l3_config_datas_len; i++)
|
|
|
|
|
l3_config_datas_arr[i] = _l3_config_datas_at(self->priv.p->l3_config_datas, i);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (l3_config_datas_len > 1) {
|
2022-01-28 13:32:32 +01:00
|
|
|
/* We are about to merge the l3cds. The order in which we do that matters.
|
|
|
|
|
*
|
|
|
|
|
* Below, we iterate over the l3cds and merge them into a new one. nm_l3_config_data_merge()
|
|
|
|
|
* uses "NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE" flag, which means to keep the first entry.
|
|
|
|
|
*
|
|
|
|
|
* Consider for example addresses/routes, which have a set of ID attributes (based on
|
|
|
|
|
* which no duplicates can be accepted) and additional attributes. For example, trying
|
|
|
|
|
* to add the same address twice ("same" according to their ID), only one can be added.
|
|
|
|
|
* If they differ in their lifetimes, we need to make a choice.
|
|
|
|
|
* We could merge the attributes in a sensible way. Instead, NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE
|
|
|
|
|
* takes care to only take the first one.
|
|
|
|
|
*
|
|
|
|
|
* So we want to sort the more important entries *first*, and this is based on
|
|
|
|
|
* the priority_confdata. */
|
2020-09-28 18:07:51 +02:00
|
|
|
g_qsort_with_data(l3_config_datas_arr,
|
|
|
|
|
l3_config_datas_len,
|
|
|
|
|
sizeof(l3_config_datas_arr[0]),
|
|
|
|
|
_l3_config_datas_get_sorted_cmp,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
if (!to_commit) {
|
|
|
|
|
/* we are not going to commit these changes. Hence, we don't update the
|
|
|
|
|
* ACD states, but we need to remember that we have to on the next commit. */
|
|
|
|
|
self->priv.p->changed_configs_acd_state = TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
_l3_acd_data_add_all(self, l3_config_datas_arr, l3_config_datas_len, reapply);
|
|
|
|
|
self->priv.p->changed_configs_acd_state = FALSE;
|
|
|
|
|
}
|
2020-08-03 17:19:27 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
if (l3_config_datas_len > 0) {
|
|
|
|
|
L3ConfigMergeHookAddObjData hook_data = {
|
2021-09-25 00:07:21 +02:00
|
|
|
.self = self,
|
|
|
|
|
.to_commit = to_commit,
|
2020-08-03 17:33:31 +02:00
|
|
|
};
|
2020-08-03 17:19:27 +02:00
|
|
|
|
|
|
|
|
l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(self->priv.platform),
|
2021-08-03 18:53:25 +02:00
|
|
|
self->priv.ifindex,
|
|
|
|
|
NM_IP_CONFIG_SOURCE_UNKNOWN);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-08-03 17:19:27 +02:00
|
|
|
for (i = 0; i < l3_config_datas_len; i++) {
|
2020-09-28 18:07:51 +02:00
|
|
|
const L3ConfigData *l3cd_data = l3_config_datas_arr[i];
|
2020-09-23 16:38:46 +02:00
|
|
|
|
2022-01-28 13:32:32 +01:00
|
|
|
/* more important entries must be sorted *first*. */
|
|
|
|
|
nm_assert(
|
|
|
|
|
i == 0
|
|
|
|
|
|| (l3_config_datas_arr[i - 1]->priority_confdata > l3cd_data->priority_confdata)
|
|
|
|
|
|| (l3_config_datas_arr[i - 1]->priority_confdata == l3cd_data->priority_confdata
|
|
|
|
|
&& l3_config_datas_arr[i - 1]->pseudo_timestamp_confdata
|
|
|
|
|
< l3cd_data->pseudo_timestamp_confdata));
|
|
|
|
|
|
2021-09-02 16:51:36 +02:00
|
|
|
if (NM_FLAGS_HAS(l3cd_data->config_flags, NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD))
|
2020-09-23 16:38:46 +02:00
|
|
|
continue;
|
|
|
|
|
|
2022-04-19 18:39:37 +02:00
|
|
|
hook_data.tag = l3cd_data->tag_confdata;
|
2021-11-11 22:16:14 +01:00
|
|
|
hook_data.force_commit_once = l3cd_data->force_commit_once;
|
2021-09-06 14:10:39 +02:00
|
|
|
|
2020-08-03 17:19:27 +02:00
|
|
|
nm_l3_config_data_merge(l3cd,
|
2020-09-23 16:38:46 +02:00
|
|
|
l3cd_data->l3cd,
|
|
|
|
|
l3cd_data->merge_flags,
|
|
|
|
|
l3cd_data->default_route_table_x,
|
|
|
|
|
l3cd_data->default_route_metric_x,
|
|
|
|
|
l3cd_data->default_route_penalty_x,
|
2021-09-15 15:38:26 +02:00
|
|
|
l3cd_data->default_dns_priority_x,
|
2021-09-06 09:08:22 +02:00
|
|
|
_l3_hook_add_obj_cb,
|
2020-08-03 17:19:27 +02:00
|
|
|
&hook_data);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2022-06-12 19:50:09 -04:00
|
|
|
if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
|
|
|
|
|
NMPlatformIPXAddress ax;
|
|
|
|
|
NMPlatformIPXRoute rx;
|
|
|
|
|
|
|
|
|
|
if (!nm_l3_config_data_lookup_address_4(l3cd,
|
|
|
|
|
NM_IPV4LO_ADDR1,
|
|
|
|
|
NM_IPV4LO_PREFIXLEN,
|
|
|
|
|
NM_IPV4LO_ADDR1)) {
|
|
|
|
|
nm_l3_config_data_add_address_4(
|
|
|
|
|
l3cd,
|
|
|
|
|
nm_platform_ip4_address_init_loopback_addr1(&ax.a4));
|
|
|
|
|
}
|
|
|
|
|
if (!nm_l3_config_data_lookup_address_6(l3cd, &in6addr_loopback)) {
|
|
|
|
|
nm_l3_config_data_add_address_6(l3cd,
|
|
|
|
|
nm_platform_ip6_address_init_loopback(&ax.a6));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rx.r4 = (NMPlatformIP4Route){
|
|
|
|
|
.ifindex = NM_LOOPBACK_IFINDEX,
|
|
|
|
|
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
|
|
|
|
|
.network = NM_IPV4LO_ADDR1,
|
|
|
|
|
.plen = NM_IPV4LO_PREFIXLEN,
|
|
|
|
|
.table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL),
|
|
|
|
|
.scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST),
|
|
|
|
|
.type_coerced = nm_platform_route_type_coerce(RTN_LOCAL),
|
|
|
|
|
.pref_src = NM_IPV4LO_ADDR1,
|
|
|
|
|
};
|
|
|
|
|
nm_platform_ip_route_normalize(AF_INET, &rx.rx);
|
|
|
|
|
if (!nm_l3_config_data_lookup_route(l3cd, AF_INET, &rx.rx)) {
|
|
|
|
|
nm_l3_config_data_add_route_4(l3cd, &rx.r4);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-27 07:48:43 +02:00
|
|
|
for (i = 0; i < l3_config_datas_len; i++) {
|
|
|
|
|
const L3ConfigData *l3cd_data = l3_config_datas_arr[i];
|
|
|
|
|
int IS_IPv4;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(l3cd_data->config_flags, NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
|
|
|
|
|
nm_l3_config_data_add_dependent_device_routes(
|
|
|
|
|
l3cd,
|
|
|
|
|
IS_IPv4 ? AF_INET : AF_INET6,
|
|
|
|
|
l3cd_data->default_route_table_x[IS_IPv4],
|
|
|
|
|
l3cd_data->default_route_metric_x[IS_IPv4],
|
2021-12-15 17:23:23 +01:00
|
|
|
l3cd_data->force_commit_once,
|
2021-09-27 07:48:43 +02:00
|
|
|
l3cd_data->l3cd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_l3_config_data_add_dependent_onlink_routes(l3cd, AF_UNSPEC);
|
|
|
|
|
|
2020-08-03 17:19:27 +02:00
|
|
|
nm_assert(l3cd);
|
|
|
|
|
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
nm_l3_config_data_seal(l3cd);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
if (nm_l3_config_data_equal(l3cd, self->priv.p->combined_l3cd_merged))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
l3cd_old = g_steal_pointer(&self->priv.p->combined_l3cd_merged);
|
|
|
|
|
self->priv.p->combined_l3cd_merged = nm_l3_config_data_seal(g_steal_pointer(&l3cd));
|
2020-09-28 18:07:51 +02:00
|
|
|
merged_changed = TRUE;
|
2021-05-18 13:35:18 +02:00
|
|
|
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_l3cd_changed(self,
|
|
|
|
|
l3cd_old,
|
|
|
|
|
self->priv.p->combined_l3cd_merged,
|
|
|
|
|
FALSE);
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
if (!to_commit) {
|
|
|
|
|
NM_SET_OUT(out_old, g_steal_pointer(&l3cd_old));
|
|
|
|
|
NM_SET_OUT(out_changed_combined_l3cd, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (to_commit && self->priv.p->combined_l3cd_commited != self->priv.p->combined_l3cd_merged) {
|
|
|
|
|
l3cd_commited_old = g_steal_pointer(&self->priv.p->combined_l3cd_commited);
|
|
|
|
|
self->priv.p->combined_l3cd_commited =
|
|
|
|
|
nm_l3_config_data_ref(self->priv.p->combined_l3cd_merged);
|
2020-09-28 18:07:51 +02:00
|
|
|
commited_changed = TRUE;
|
2021-05-18 13:35:18 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
_obj_states_update_all(self);
|
|
|
|
|
|
2021-05-18 13:35:18 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_l3cd_changed(self,
|
|
|
|
|
l3cd_commited_old,
|
|
|
|
|
self->priv.p->combined_l3cd_commited,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
NM_SET_OUT(out_old, g_steal_pointer(&l3cd_commited_old));
|
|
|
|
|
NM_SET_OUT(out_changed_combined_l3cd, TRUE);
|
2020-09-28 18:07:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((merged_changed || commited_changed) && _LOGT_ENABLED()) {
|
|
|
|
|
char sbuf256[256];
|
|
|
|
|
char sbuf30[30];
|
|
|
|
|
|
|
|
|
|
_LOGT("IP configuration changed (merged=%c%s, commited=%c%s)",
|
|
|
|
|
merged_changed ? '>' : '=',
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR_STR(self->priv.p->combined_l3cd_merged, sbuf256),
|
|
|
|
|
commited_changed ? '>' : '=',
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR_STR(self->priv.p->combined_l3cd_commited, sbuf30));
|
|
|
|
|
|
|
|
|
|
if (merged_changed) {
|
|
|
|
|
nm_l3_config_data_log(self->priv.p->combined_l3cd_merged,
|
|
|
|
|
NULL,
|
|
|
|
|
nm_sprintf_buf(sbuf256,
|
|
|
|
|
"l3cfg[" NM_HASH_OBFUSCATE_PTR_FMT
|
|
|
|
|
",ifindex=%d]: ",
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(self),
|
|
|
|
|
nm_l3cfg_get_ifindex(self)),
|
|
|
|
|
LOGL_TRACE,
|
|
|
|
|
_NMLOG_DOMAIN);
|
|
|
|
|
}
|
2020-09-16 12:44:38 +02:00
|
|
|
}
|
2020-07-23 16:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
static gboolean
|
|
|
|
|
_routes_temporary_not_available_timeout(gpointer user_data)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NML3Cfg *self = NM_L3CFG(user_data);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
gint64 now_msec;
|
|
|
|
|
gint64 expiry_msec;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_clear_g_source_inst(&self->priv.p->obj_state_temporary_not_available_timeout_source);
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state = c_list_first_entry(&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
ObjStateData,
|
|
|
|
|
os_temporary_not_available_lst);
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (!obj_state)
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
|
|
|
|
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
|
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
expiry_msec = obj_state->os_temporary_not_available_timestamp_msec
|
|
|
|
|
+ ROUTES_TEMPORARY_NOT_AVAILABLE_MAX_AGE_MSEC;
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (now_msec < expiry_msec) {
|
|
|
|
|
/* the timeout is not yet reached. Restart the timer... */
|
|
|
|
|
self->priv.p->obj_state_temporary_not_available_timeout_source =
|
|
|
|
|
nm_g_timeout_add_source(expiry_msec - now_msec,
|
|
|
|
|
_routes_temporary_not_available_timeout,
|
|
|
|
|
self);
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
/* One (or several) routes expired. We emit a signal, but we don't schedule it again.
|
|
|
|
|
* We expect the callers to commit again, which will one last time try to configure
|
|
|
|
|
* the route. If that again fails, we detect the timeout, log a warning and don't
|
|
|
|
|
* track the object as not temporary-not-available anymore. */
|
|
|
|
|
_nm_l3cfg_emit_signal_notify_simple(
|
|
|
|
|
self,
|
|
|
|
|
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED);
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_routes_temporary_not_available_update(NML3Cfg *self,
|
2020-07-28 13:29:36 +02:00
|
|
|
int addr_family,
|
|
|
|
|
GPtrArray *routes_temporary_not_available_arr)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
ObjStateData *obj_state;
|
|
|
|
|
ObjStateData *obj_state_safe;
|
2021-10-12 09:21:10 +02:00
|
|
|
gint64 now_msec;
|
|
|
|
|
gboolean prune_all = FALSE;
|
|
|
|
|
gboolean success = TRUE;
|
|
|
|
|
guint i;
|
|
|
|
|
const NMPClass *klass;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-10-12 09:21:10 +02:00
|
|
|
klass = nmp_class_from_type(NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)));
|
2020-07-28 13:29:36 +02:00
|
|
|
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
if (nm_g_ptr_array_len(routes_temporary_not_available_arr) <= 0) {
|
|
|
|
|
prune_all = TRUE;
|
|
|
|
|
goto out_prune;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_for_each_entry (obj_state,
|
|
|
|
|
&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
os_temporary_not_available_lst) {
|
2021-10-12 09:21:10 +02:00
|
|
|
if (NMP_OBJECT_GET_CLASS(obj_state->obj) == klass) {
|
|
|
|
|
nm_assert(obj_state->os_temporary_not_available_timestamp_msec > 0);
|
|
|
|
|
obj_state->os_tna_dirty = TRUE;
|
|
|
|
|
}
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
for (i = 0; i < routes_temporary_not_available_arr->len; i++) {
|
|
|
|
|
const NMPObject *o = routes_temporary_not_available_arr->pdata[i];
|
2022-03-30 09:23:54 +02:00
|
|
|
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &o);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (!obj_state) {
|
|
|
|
|
/* Hm? We don't track this object? Very odd, a bug? */
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj_state->os_temporary_not_available_timestamp_msec > 0) {
|
|
|
|
|
nm_assert(obj_state->os_temporary_not_available_timestamp_msec > 0
|
|
|
|
|
&& obj_state->os_temporary_not_available_timestamp_msec <= now_msec);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (!obj_state->os_tna_dirty) {
|
|
|
|
|
/* Odd, this only can happen if routes_temporary_not_available_arr contains duplicates.
|
|
|
|
|
* It should not. */
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
if (now_msec > obj_state->os_temporary_not_available_timestamp_msec
|
|
|
|
|
+ ROUTES_TEMPORARY_NOT_AVAILABLE_MAX_AGE_MSEC) {
|
|
|
|
|
/* Timeout. Could not add this address.
|
|
|
|
|
*
|
|
|
|
|
* For now, keep it obj_state->os_tna_dirty and prune it below. */
|
2020-07-28 13:29:36 +02:00
|
|
|
_LOGW("failure to add IPv%c route: %s",
|
|
|
|
|
nm_utils_addr_family_to_char(addr_family),
|
|
|
|
|
nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
|
|
|
|
success = FALSE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state->os_tna_dirty = FALSE;
|
2020-07-28 13:29:36 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
_LOGT("(temporarily) unable to add IPv%c route: %s",
|
|
|
|
|
nm_utils_addr_family_to_char(addr_family),
|
|
|
|
|
nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
obj_state->os_tna_dirty = FALSE;
|
|
|
|
|
obj_state->os_temporary_not_available_timestamp_msec = now_msec;
|
|
|
|
|
c_list_link_tail(&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
&obj_state->os_temporary_not_available_lst);
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_prune:
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_for_each_entry_safe (obj_state,
|
|
|
|
|
obj_state_safe,
|
|
|
|
|
&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
os_temporary_not_available_lst) {
|
|
|
|
|
if (prune_all || obj_state->os_tna_dirty) {
|
2021-10-12 09:21:10 +02:00
|
|
|
if (NMP_OBJECT_GET_CLASS(obj_state->obj) == klass) {
|
|
|
|
|
obj_state->os_temporary_not_available_timestamp_msec = 0;
|
|
|
|
|
c_list_unlink(&obj_state->os_temporary_not_available_lst);
|
|
|
|
|
}
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_clear_g_source_inst(&self->priv.p->obj_state_temporary_not_available_timeout_source);
|
|
|
|
|
|
|
|
|
|
obj_state = c_list_first_entry(&self->priv.p->obj_state_temporary_not_available_lst_head,
|
|
|
|
|
ObjStateData,
|
|
|
|
|
os_temporary_not_available_lst);
|
|
|
|
|
if (obj_state) {
|
|
|
|
|
self->priv.p->obj_state_temporary_not_available_timeout_source =
|
|
|
|
|
nm_g_timeout_add_source((obj_state->os_temporary_not_available_timestamp_msec
|
|
|
|
|
+ ROUTES_TEMPORARY_NOT_AVAILABLE_MAX_AGE_MSEC - now_msec),
|
|
|
|
|
_routes_temporary_not_available_timeout,
|
|
|
|
|
self);
|
2020-07-28 13:29:36 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2022-02-07 19:33:06 +01:00
|
|
|
|
2021-10-17 10:23:04 +02:00
|
|
|
static const char *
|
|
|
|
|
ip6_privacy_to_str(NMSettingIP6ConfigPrivacy ip6_privacy)
|
|
|
|
|
{
|
|
|
|
|
switch (ip6_privacy) {
|
|
|
|
|
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
|
|
|
|
|
return "0";
|
|
|
|
|
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
|
|
|
|
|
return "1";
|
|
|
|
|
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
|
|
|
|
|
return "2";
|
|
|
|
|
case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return nm_assert_unreachable_val("0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_commit_ndisc_params(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
const NML3ConfigData *l3cd;
|
|
|
|
|
gboolean retrans_set = FALSE;
|
|
|
|
|
gboolean reachable_set = FALSE;
|
|
|
|
|
gboolean hop_limit_set = FALSE;
|
2021-10-17 14:59:31 +02:00
|
|
|
guint32 reachable = 0;
|
|
|
|
|
guint32 retrans = 0;
|
|
|
|
|
int hop_limit = 0;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *ifname;
|
2021-10-17 10:23:04 +02:00
|
|
|
|
|
|
|
|
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) {
|
|
|
|
|
self->priv.p->ndisc_reachable_time_msec_set = FALSE;
|
|
|
|
|
self->priv.p->ndisc_retrans_timer_msec_set = FALSE;
|
|
|
|
|
self->priv.p->ndisc_hop_limit_set = FALSE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l3cd = self->priv.p->combined_l3cd_commited;
|
|
|
|
|
if (l3cd) {
|
|
|
|
|
reachable_set = nm_l3_config_data_get_ndisc_reachable_time_msec(l3cd, &reachable);
|
|
|
|
|
retrans_set = nm_l3_config_data_get_ndisc_retrans_timer_msec(l3cd, &retrans);
|
|
|
|
|
hop_limit = nm_l3_config_data_get_ndisc_hop_limit(l3cd, &hop_limit);
|
|
|
|
|
}
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
|
|
|
|
|
if (reachable_set
|
|
|
|
|
&& (!self->priv.p->ndisc_reachable_time_msec_set
|
|
|
|
|
|| self->priv.p->ndisc_reachable_time_msec != reachable)) {
|
|
|
|
|
self->priv.p->ndisc_reachable_time_msec = reachable;
|
|
|
|
|
self->priv.p->ndisc_reachable_time_msec_set = TRUE;
|
|
|
|
|
if (ifname) {
|
|
|
|
|
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(self->priv.platform,
|
|
|
|
|
ifname,
|
|
|
|
|
reachable);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (retrans_set
|
|
|
|
|
&& (!self->priv.p->ndisc_retrans_timer_msec_set
|
2022-10-20 14:51:47 +02:00
|
|
|
|| self->priv.p->ndisc_retrans_timer_msec != retrans)) {
|
2021-10-17 10:23:04 +02:00
|
|
|
self->priv.p->ndisc_retrans_timer_msec = retrans;
|
|
|
|
|
self->priv.p->ndisc_retrans_timer_msec_set = TRUE;
|
|
|
|
|
if (ifname) {
|
|
|
|
|
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(self->priv.platform, ifname, retrans);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hop_limit_set
|
|
|
|
|
&& (!self->priv.p->ndisc_hop_limit_set || self->priv.p->ndisc_hop_limit != hop_limit)) {
|
|
|
|
|
self->priv.p->ndisc_hop_limit = hop_limit;
|
|
|
|
|
self->priv.p->ndisc_hop_limit_set = TRUE;
|
|
|
|
|
if (ifname) {
|
|
|
|
|
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(self->priv.platform,
|
|
|
|
|
ifname,
|
|
|
|
|
hop_limit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: restore values if necessary
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_commit_ip6_privacy(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
NMSettingIP6ConfigPrivacy ip6_privacy;
|
|
|
|
|
NMSettingIP6ConfigPrivacy ip6_privacy_set_before;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *ifname;
|
2021-10-17 10:23:04 +02:00
|
|
|
|
|
|
|
|
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE)
|
|
|
|
|
ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
|
|
|
|
|
else
|
|
|
|
|
ip6_privacy = nm_l3_config_data_get_ip6_privacy(self->priv.p->combined_l3cd_commited);
|
|
|
|
|
|
|
|
|
|
if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) {
|
|
|
|
|
if (!self->priv.p->ip6_privacy_set) {
|
|
|
|
|
/* Nothing to set. But do we need to reset a previous value? */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
self->priv.p->ip6_privacy_set = FALSE;
|
|
|
|
|
ip6_privacy = self->priv.p->ip6_privacy_initial;
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
_LOGT("commit-ip6-privacy: reset initial value %d (was %d)%s%s",
|
|
|
|
|
(int) ip6_privacy,
|
|
|
|
|
(int) self->priv.p->ip6_privacy_set_before,
|
|
|
|
|
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
|
|
|
|
|
if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
|
|
|
|
|
return;
|
|
|
|
|
if (!ifname)
|
|
|
|
|
return;
|
|
|
|
|
goto set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IN_SET(ip6_privacy,
|
|
|
|
|
NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED,
|
|
|
|
|
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR,
|
|
|
|
|
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR));
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->ip6_privacy_set && self->priv.p->ip6_privacy_set_before == ip6_privacy
|
|
|
|
|
&& commit_type < NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
|
|
|
|
|
/* Already set. We leave this alone except during reapply. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ip6_privacy_set_before = self->priv.p->ip6_privacy_set_before;
|
|
|
|
|
self->priv.p->ip6_privacy_set_before = ip6_privacy;
|
|
|
|
|
|
|
|
|
|
if (!self->priv.p->ip6_privacy_set) {
|
|
|
|
|
gint64 s = G_MININT64;
|
|
|
|
|
|
|
|
|
|
self->priv.p->ip6_privacy_set = TRUE;
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
if (ifname) {
|
|
|
|
|
s = nm_platform_sysctl_ip_conf_get_int_checked(self->priv.platform,
|
|
|
|
|
AF_INET6,
|
|
|
|
|
ifname,
|
|
|
|
|
"use_tempaddr",
|
|
|
|
|
10,
|
|
|
|
|
G_MININT32,
|
|
|
|
|
G_MAXINT32,
|
|
|
|
|
G_MININT64);
|
|
|
|
|
if (s != G_MININT64)
|
|
|
|
|
s = NM_CLAMP(s, 0, 2);
|
|
|
|
|
}
|
|
|
|
|
switch (s) {
|
|
|
|
|
case 0:
|
|
|
|
|
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
/* fall-through */
|
|
|
|
|
case G_MININT64:
|
|
|
|
|
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
_LOGT("commit-ip6-privacy: set value %d (initial value was %d)%s%s",
|
|
|
|
|
(int) ip6_privacy,
|
|
|
|
|
(int) self->priv.p->ip6_privacy_initial,
|
|
|
|
|
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
|
|
|
|
|
if (!ifname)
|
|
|
|
|
return;
|
|
|
|
|
/* The first time, we always set the value, and don't skip it based on what we
|
|
|
|
|
* read. */
|
|
|
|
|
goto set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
_LOGT("commit-ip6-privacy: set value %d (after %d, initial value was %d)%s%s",
|
|
|
|
|
(int) ip6_privacy,
|
|
|
|
|
(int) ip6_privacy_set_before,
|
|
|
|
|
(int) self->priv.p->ip6_privacy_initial,
|
|
|
|
|
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
|
|
|
|
|
if (!ifname)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
set:
|
|
|
|
|
nm_assert(ifname);
|
|
|
|
|
self->priv.p->ip6_privacy_set_before = ip6_privacy;
|
|
|
|
|
nm_platform_sysctl_ip_conf_set(self->priv.platform,
|
|
|
|
|
AF_INET6,
|
|
|
|
|
ifname,
|
|
|
|
|
"use_tempaddr",
|
|
|
|
|
ip6_privacy_to_str(ip6_privacy));
|
|
|
|
|
}
|
2020-07-28 13:29:36 +02:00
|
|
|
|
2021-10-31 15:10:53 +01:00
|
|
|
static void
|
|
|
|
|
_l3_commit_ip6_token(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
NMUtilsIPv6IfaceId token;
|
|
|
|
|
const NMPlatformLink *pllink;
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE || !self->priv.p->combined_l3cd_commited)
|
|
|
|
|
token.id = 0;
|
|
|
|
|
else
|
|
|
|
|
token = nm_l3_config_data_get_ip6_token(self->priv.p->combined_l3cd_commited);
|
|
|
|
|
|
|
|
|
|
pllink = nm_l3cfg_get_pllink(self, TRUE);
|
|
|
|
|
if (!pllink || pllink->inet6_token.id == token.id)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (_LOGT_ENABLED()) {
|
|
|
|
|
struct in6_addr addr = {};
|
|
|
|
|
struct in6_addr addr_old = {};
|
|
|
|
|
char addr_str[INET6_ADDRSTRLEN];
|
|
|
|
|
char addr_str_old[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
|
|
nm_utils_ipv6_addr_set_interface_identifier(&addr, &token);
|
|
|
|
|
nm_utils_ipv6_addr_set_interface_identifier(&addr_old, &pllink->inet6_token);
|
|
|
|
|
|
|
|
|
|
_LOGT("commit-ip6-token: set value %s (was %s)",
|
|
|
|
|
inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN),
|
|
|
|
|
inet_ntop(AF_INET6, &addr_old, addr_str_old, INET6_ADDRSTRLEN));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The kernel allows setting a token only when 'accept_ra'
|
|
|
|
|
* is 1: temporarily flip it if necessary; unfortunately
|
|
|
|
|
* this will also generate an additional Router Solicitation
|
|
|
|
|
* from kernel. */
|
|
|
|
|
val = nm_platform_sysctl_ip_conf_get_int_checked(self->priv.platform,
|
|
|
|
|
AF_INET6,
|
|
|
|
|
pllink->name,
|
|
|
|
|
"accept_ra",
|
|
|
|
|
10,
|
|
|
|
|
G_MININT32,
|
|
|
|
|
G_MAXINT32,
|
|
|
|
|
1);
|
|
|
|
|
|
|
|
|
|
if (val != 1) {
|
|
|
|
|
nm_platform_sysctl_ip_conf_set(self->priv.platform,
|
|
|
|
|
AF_INET6,
|
|
|
|
|
pllink->name,
|
|
|
|
|
"accept_ra",
|
|
|
|
|
"1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_platform_link_set_ipv6_token(self->priv.platform, self->priv.ifindex, &token);
|
|
|
|
|
|
|
|
|
|
if (val != 1) {
|
|
|
|
|
nm_platform_sysctl_ip_conf_set_int64(self->priv.platform,
|
|
|
|
|
AF_INET6,
|
|
|
|
|
pllink->name,
|
|
|
|
|
"accept_ra",
|
|
|
|
|
val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_rp_filter_update(NML3Cfg *self, gboolean reapply)
|
|
|
|
|
{
|
|
|
|
|
gboolean rp_filter_relax = FALSE;
|
|
|
|
|
const char *ifname;
|
|
|
|
|
int rf_val;
|
|
|
|
|
|
|
|
|
|
/* The rp_filter sysctl is only an IPv4 thing. We only enable the rp-filter
|
|
|
|
|
* handling, if we did anything to MPTCP about IPv4 addresses.
|
|
|
|
|
*
|
|
|
|
|
* While we only have one "connection.mptcp-flags=enabled" property, whether
|
|
|
|
|
* we handle MPTCP is still tracked per AF. In particular, with "enabled-on-global-iface"
|
|
|
|
|
* flag, which honors the AF-specific default route. */
|
2022-08-05 15:30:38 +02:00
|
|
|
if (self->priv.p->mptcp_set_4)
|
2022-07-18 21:24:09 +02:00
|
|
|
rp_filter_relax = TRUE;
|
|
|
|
|
|
|
|
|
|
if (!rp_filter_relax) {
|
|
|
|
|
if (self->priv.p->rp_filter_handled) {
|
|
|
|
|
self->priv.p->rp_filter_handled = FALSE;
|
|
|
|
|
if (self->priv.p->rp_filter_set) {
|
|
|
|
|
self->priv.p->rp_filter_set = FALSE;
|
|
|
|
|
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
rf_val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(self->priv.platform,
|
|
|
|
|
ifname,
|
|
|
|
|
FALSE,
|
|
|
|
|
NULL);
|
|
|
|
|
if (rf_val == 2) {
|
|
|
|
|
/* We only relaxed from 1 to 2. Only if that is still the case, reset. */
|
|
|
|
|
nm_platform_sysctl_ip_conf_set(self->priv.platform,
|
|
|
|
|
AF_INET,
|
|
|
|
|
ifname,
|
|
|
|
|
"rp_filter",
|
|
|
|
|
"1");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->rp_filter_handled && !reapply) {
|
|
|
|
|
/* We only set rp_filter once (except reapply). */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No matter whether we actually reset the value below, we set the "handled" flag
|
|
|
|
|
* so that we only do this once (except during reapply). */
|
|
|
|
|
self->priv.p->rp_filter_handled = TRUE;
|
|
|
|
|
|
|
|
|
|
ifname = nm_l3cfg_get_ifname(self, TRUE);
|
|
|
|
|
|
|
|
|
|
rf_val =
|
|
|
|
|
nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(self->priv.platform, ifname, FALSE, NULL);
|
|
|
|
|
|
|
|
|
|
if (rf_val != 1) {
|
|
|
|
|
/* We only relax from strict (1) to loose (2). No other transition. Nothing to do. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We actually loosen the flag. We need to remember to reset it. */
|
|
|
|
|
self->priv.p->rp_filter_set = TRUE;
|
|
|
|
|
nm_platform_sysctl_ip_conf_set(self->priv.platform, AF_INET, ifname, "rp_filter", "2");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_global_tracker_mptcp_untrack(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
|
|
|
|
return nmp_global_tracker_untrack_all(self->priv.global_tracker,
|
|
|
|
|
_MPTCP_TAG(self, NM_IS_IPv4(addr_family)),
|
|
|
|
|
FALSE,
|
|
|
|
|
TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_l3_commit_mptcp_af(NML3Cfg *self,
|
|
|
|
|
NML3CfgCommitType commit_type,
|
|
|
|
|
int addr_family,
|
|
|
|
|
gboolean *out_reapply)
|
|
|
|
|
{
|
|
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
NMMptcpFlags mptcp_flags;
|
|
|
|
|
gboolean reapply = FALSE;
|
|
|
|
|
gboolean changed = FALSE;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(NM_IN_SET(commit_type,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_NONE,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_UPDATE));
|
|
|
|
|
|
|
|
|
|
if (commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY)
|
|
|
|
|
reapply = TRUE;
|
|
|
|
|
|
|
|
|
|
if (commit_type != NM_L3_CFG_COMMIT_TYPE_NONE && self->priv.p->combined_l3cd_commited)
|
|
|
|
|
mptcp_flags = nm_l3_config_data_get_mptcp_flags(self->priv.p->combined_l3cd_commited);
|
|
|
|
|
else
|
|
|
|
|
mptcp_flags = NM_MPTCP_FLAGS_DISABLED;
|
|
|
|
|
|
|
|
|
|
if (mptcp_flags == NM_MPTCP_FLAGS_NONE || NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_DISABLED))
|
|
|
|
|
mptcp_flags = NM_MPTCP_FLAGS_DISABLED;
|
mptcp: rework "connection.mptcp-flags" for enabling MPTCP
1) The "enabled-on-global-iface" flag was odd. Instead, have only
and "enabled" flag and skip (by default) endpoints on interface
that have no default route. With the new flag "also-without-default-route",
this can be overruled. So previous "enabled-on-global-default" now is
the same as "enabled", and "enabled" from before behaves now like
"enabled,also-without-default-route".
2) What was also odd, as that the fallback default value for the flags
depends on "/proc/sys/net/mptcp/enabled". There was not one fixed
fallback default, instead the used fallback value was either
"enabled-on-global-iface,subflow" or "disabled".
Usually that is not a problem (e.g. the default value for
"ipv6.ip6-privacy" also depends on use_tempaddr sysctl). In this case
it is a problem, because the mptcp-flags (for better or worse) encode
different things at the same time.
Consider that the mptcp-flags can also have their default configured in
"NetworkManager.conf", a user who wants to switch the address flags
could previously do:
[connection.mptcp]
connection.mptcp-flags=0x32 # enabled-on-global-iface,signal,subflow
but then the global toggle "/proc/sys/net/mptcp/enabled" was no longer
honored. That means, MPTCP handling was always on, even if the sysctl was
disabled. Now, "enabled" means that it's only enabled if the sysctl
is enabled too. Now the user could write to "NetworkManager.conf"
[connection.mptcp]
connection.mptcp-flags=0x32 # enabled,signal,subflow
and MPTCP handling would still be disabled unless the sysctl
is enabled.
There is now also a new flag "also-without-sysctl", so if you want
to really enable MPTCP handling regardless of the sysctl, you can.
The point of that might be, that we still can configure endpoints,
even if kernel won't do anything with them. Then you could just flip
the sysctl, and it would start working (as NetworkManager configured
the endpoints already).
Fixes: eb083eece5a2 ('all: add NMMptcpFlags and connection.mptcp-flags property')
2022-08-25 09:40:46 +02:00
|
|
|
else if (!NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE)) {
|
|
|
|
|
/* Whether MPTCP is enabled/disabled (per address family), depends on whether we have a unicast
|
|
|
|
|
* default route (in the main routing table). */
|
2022-07-18 21:24:09 +02:00
|
|
|
if (self->priv.p->combined_l3cd_commited
|
|
|
|
|
&& nm_l3_config_data_get_best_default_route(self->priv.p->combined_l3cd_commited,
|
|
|
|
|
addr_family))
|
mptcp: rework "connection.mptcp-flags" for enabling MPTCP
1) The "enabled-on-global-iface" flag was odd. Instead, have only
and "enabled" flag and skip (by default) endpoints on interface
that have no default route. With the new flag "also-without-default-route",
this can be overruled. So previous "enabled-on-global-default" now is
the same as "enabled", and "enabled" from before behaves now like
"enabled,also-without-default-route".
2) What was also odd, as that the fallback default value for the flags
depends on "/proc/sys/net/mptcp/enabled". There was not one fixed
fallback default, instead the used fallback value was either
"enabled-on-global-iface,subflow" or "disabled".
Usually that is not a problem (e.g. the default value for
"ipv6.ip6-privacy" also depends on use_tempaddr sysctl). In this case
it is a problem, because the mptcp-flags (for better or worse) encode
different things at the same time.
Consider that the mptcp-flags can also have their default configured in
"NetworkManager.conf", a user who wants to switch the address flags
could previously do:
[connection.mptcp]
connection.mptcp-flags=0x32 # enabled-on-global-iface,signal,subflow
but then the global toggle "/proc/sys/net/mptcp/enabled" was no longer
honored. That means, MPTCP handling was always on, even if the sysctl was
disabled. Now, "enabled" means that it's only enabled if the sysctl
is enabled too. Now the user could write to "NetworkManager.conf"
[connection.mptcp]
connection.mptcp-flags=0x32 # enabled,signal,subflow
and MPTCP handling would still be disabled unless the sysctl
is enabled.
There is now also a new flag "also-without-sysctl", so if you want
to really enable MPTCP handling regardless of the sysctl, you can.
The point of that might be, that we still can configure endpoints,
even if kernel won't do anything with them. Then you could just flip
the sysctl, and it would start working (as NetworkManager configured
the endpoints already).
Fixes: eb083eece5a2 ('all: add NMMptcpFlags and connection.mptcp-flags property')
2022-08-25 09:40:46 +02:00
|
|
|
mptcp_flags = NM_FLAGS_UNSET(mptcp_flags, NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE)
|
2022-07-18 21:24:09 +02:00
|
|
|
| NM_MPTCP_FLAGS_ENABLED;
|
|
|
|
|
else
|
|
|
|
|
mptcp_flags = NM_MPTCP_FLAGS_DISABLED;
|
|
|
|
|
} else
|
|
|
|
|
mptcp_flags |= NM_MPTCP_FLAGS_ENABLED;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_DISABLED)) {
|
|
|
|
|
if (!self->priv.p->mptcp_set_x[IS_IPv4] && !reapply) {
|
|
|
|
|
/* Nothing to configure, and we did not earlier configure MPTCP. Nothing to do. */
|
|
|
|
|
NM_SET_OUT(out_reapply, FALSE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->priv.p->mptcp_set_x[IS_IPv4] = FALSE;
|
|
|
|
|
reapply = TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
const NMPlatformIPXAddress *addr;
|
|
|
|
|
NMDedupMultiIter iter;
|
|
|
|
|
const guint32 FLAGS =
|
|
|
|
|
(NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SIGNAL) ? MPTCP_PM_ADDR_FLAG_SIGNAL : 0)
|
|
|
|
|
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SUBFLOW) ? MPTCP_PM_ADDR_FLAG_SUBFLOW : 0)
|
|
|
|
|
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_BACKUP) ? MPTCP_PM_ADDR_FLAG_BACKUP : 0)
|
|
|
|
|
| (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH
|
|
|
|
|
: 0);
|
|
|
|
|
NMPlatformMptcpAddr a = {
|
|
|
|
|
.ifindex = self->priv.ifindex,
|
|
|
|
|
.id = 0,
|
|
|
|
|
.flags = FLAGS,
|
|
|
|
|
.addr_family = addr_family,
|
|
|
|
|
.port = 0,
|
|
|
|
|
};
|
|
|
|
|
gboolean any_tracked = FALSE;
|
|
|
|
|
|
|
|
|
|
self->priv.p->mptcp_set_x[IS_IPv4] = TRUE;
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->combined_l3cd_commited) {
|
|
|
|
|
gint32 addr_prio;
|
|
|
|
|
|
|
|
|
|
addr_prio = 100;
|
|
|
|
|
|
|
|
|
|
nm_l3_config_data_iter_ip_address_for_each (&iter,
|
|
|
|
|
self->priv.p->combined_l3cd_commited,
|
|
|
|
|
addr_family,
|
|
|
|
|
(const NMPlatformIPAddress **) &addr) {
|
|
|
|
|
/* We want to evaluate the with-{loopback,link_local}-{4,6} flags based on the actual
|
|
|
|
|
* ifa_scope that the address will have once we configure it.
|
|
|
|
|
* "addr" is an address we want to configure, we expect that it will
|
|
|
|
|
* later have the scope nm_platform_ip_address_get_scope() based on
|
|
|
|
|
* the address. */
|
|
|
|
|
switch (nm_platform_ip_address_get_scope(addr_family, addr->ax.address_ptr)) {
|
|
|
|
|
case RT_SCOPE_HOST:
|
2022-08-05 15:30:38 +02:00
|
|
|
goto skip_addr;
|
2022-07-18 21:24:09 +02:00
|
|
|
case RT_SCOPE_LINK:
|
2022-08-05 15:30:38 +02:00
|
|
|
goto skip_addr;
|
2022-07-18 21:24:09 +02:00
|
|
|
default:
|
|
|
|
|
if (IS_IPv4) {
|
2022-08-05 15:30:38 +02:00
|
|
|
/* We take all addresses, including rfc1918 private addresses
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
* (nm_ip_addr_is_site_local()). */
|
2022-07-18 21:24:09 +02:00
|
|
|
} else {
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
if (nm_ip6_addr_is_ula(&addr->a6.address)) {
|
2022-08-05 15:30:38 +02:00
|
|
|
/* Exclude unique local IPv6 addresses fc00::/7. */
|
|
|
|
|
goto skip_addr;
|
2022-07-18 21:24:09 +02:00
|
|
|
} else {
|
|
|
|
|
/* We take all other addresses, including deprecated IN6_IS_ADDR_SITELOCAL()
|
|
|
|
|
* (fec0::/10). */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.addr = nm_ip_addr_init(addr_family, addr->ax.address_ptr);
|
|
|
|
|
|
|
|
|
|
/* We track the address with different priorities, that depends
|
|
|
|
|
* on the order in which they are listed here. NMPGlobalTracker
|
|
|
|
|
* will sort all tracked addresses by priority. That means, if we
|
|
|
|
|
* have multiple interfaces then we will prefer the first address
|
|
|
|
|
* of those interfaces, then the second, etc.
|
|
|
|
|
*
|
|
|
|
|
* That is relevant, because the overall number of addresses we
|
|
|
|
|
* can configure in kernel is strongly limited (MPTCP_PM_ADDR_MAX). */
|
|
|
|
|
if (addr_prio > 10)
|
|
|
|
|
addr_prio--;
|
|
|
|
|
|
|
|
|
|
if (nmp_global_tracker_track(self->priv.global_tracker,
|
|
|
|
|
NMP_OBJECT_TYPE_MPTCP_ADDR,
|
|
|
|
|
&a,
|
|
|
|
|
addr_prio,
|
|
|
|
|
_MPTCP_TAG(self, IS_IPv4),
|
|
|
|
|
NULL))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
|
|
|
|
|
any_tracked = TRUE;
|
|
|
|
|
|
|
|
|
|
skip_addr:
|
|
|
|
|
(void) 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!any_tracked) {
|
|
|
|
|
/* We need to make it known that this ifindex is used. Track a dummy object. */
|
|
|
|
|
if (nmp_global_tracker_track(
|
|
|
|
|
self->priv.global_tracker,
|
|
|
|
|
NMP_OBJECT_TYPE_MPTCP_ADDR,
|
|
|
|
|
nmp_global_tracker_mptcp_addr_init_for_ifindex(&a, self->priv.ifindex),
|
|
|
|
|
1,
|
|
|
|
|
_MPTCP_TAG(self, IS_IPv4),
|
|
|
|
|
NULL))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_global_tracker_mptcp_untrack(self, addr_family))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
|
|
|
|
|
NM_SET_OUT(out_reapply, reapply);
|
|
|
|
|
return changed || reapply;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_l3_commit_mptcp(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
gboolean changed = FALSE;
|
|
|
|
|
gboolean reapply = FALSE;
|
|
|
|
|
gboolean i_reapply = FALSE;
|
|
|
|
|
|
|
|
|
|
if (_l3_commit_mptcp_af(self, commit_type, AF_INET, &i_reapply))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
reapply |= i_reapply;
|
|
|
|
|
if (_l3_commit_mptcp_af(self, commit_type, AF_INET6, &i_reapply))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
reapply |= i_reapply;
|
|
|
|
|
|
|
|
|
|
nm_assert(commit_type < NM_L3_CFG_COMMIT_TYPE_REAPPLY || reapply);
|
|
|
|
|
|
|
|
|
|
if (changed)
|
2022-08-10 11:25:20 +02:00
|
|
|
nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, reapply);
|
2022-07-18 21:24:09 +02:00
|
|
|
else
|
|
|
|
|
nm_assert(!reapply);
|
|
|
|
|
|
|
|
|
|
_rp_filter_update(self, reapply);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
static gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
_l3_commit_one(NML3Cfg *self,
|
2020-09-28 18:07:51 +02:00
|
|
|
int addr_family,
|
|
|
|
|
NML3CfgCommitType commit_type,
|
|
|
|
|
gboolean changed_combined_l3cd,
|
|
|
|
|
const NML3ConfigData *l3cd_old)
|
2020-07-28 10:43:33 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
2020-07-28 10:43:33 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *addresses = NULL;
|
|
|
|
|
gs_unref_ptrarray GPtrArray *routes = NULL;
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
gs_unref_ptrarray GPtrArray *routes_nodev = NULL;
|
2020-07-29 08:39:12 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *addresses_prune = NULL;
|
2020-07-28 10:43:33 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
|
2020-07-28 13:29:36 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *routes_temporary_not_available_arr = NULL;
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
NMIPRouteTableSyncMode route_table_sync;
|
2020-07-28 13:29:36 +02:00
|
|
|
gboolean final_failure_for_temporary_not_available = FALSE;
|
2020-07-29 08:39:12 +02:00
|
|
|
char sbuf_commit_type[50];
|
2020-07-28 10:43:33 +02:00
|
|
|
gboolean success = TRUE;
|
l3cfg: fix clearing IPv6 temporary addresses to avoid stale addresses
IPv6 temporary addresses are configured by kernel, with the
"ipv6.ip6-privacy" setting ("use_tempaddr" sysctl) and the
IFA_F_MANAGETEMPADDR flag.
As such, the idea was that during reapply we would not remove them.
However, that is wrong.
The only case when we want to keep those addresses, is if during reapply
we are going to configure the same primary address (with mngtmpaddr
flag) again. Otherwise, theses addresses must always go away.
This is quite serious. This not only affects Reapply. Also during disconnect
we clear IP configuration via l3cfg.
Have an ethernet profile active with "ipv6.ip6-privacy". Unplug
the cable, the device disconnects but the temporary IPv6 address is not
cleared. As such, nm_device_generate_connection() will now generate
an external profile (with "ipv6.method=disabled" and no manual IP addresses).
The result is, that the device cannot properly autoconnect again,
once you replug the cable.
This is serious for disconnect. But I could not actually reproduce the
problem using reapply. That is, because during reapply we usually
toggle ipv6_disable sysctl, which drops all IPv6 addresses. I still
went through the effort of trying to preserve addresses that we still
want to have, because I am not sure whether there are cases where we
don't toggle ipv6_disable. Also, doing ipv6_disable during reapply is
bad anyway, and we might want to avoid that in the future.
Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration')
(cherry picked from commit 518f6124c6476e5f91b30b7d5583f494e84fd936)
2022-05-05 10:22:20 +02:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2020-09-03 12:24:08 +02:00
|
|
|
nm_assert(NM_IN_SET(commit_type,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_NONE,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
2022-04-19 18:39:37 +02:00
|
|
|
NM_L3_CFG_COMMIT_TYPE_UPDATE));
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert_addr_family(addr_family);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
_LOGT("committing IPv%c configuration (%s)",
|
|
|
|
|
nm_utils_addr_family_to_char(addr_family),
|
|
|
|
|
_l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type)));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
addresses = _commit_collect_addresses(self, addr_family, commit_type);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
_commit_collect_routes(self, addr_family, commit_type, &routes, &routes_nodev);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
route_table_sync =
|
|
|
|
|
self->priv.p->combined_l3cd_commited
|
|
|
|
|
? nm_l3_config_data_get_route_table_sync(self->priv.p->combined_l3cd_commited,
|
|
|
|
|
addr_family)
|
|
|
|
|
: NM_IP_ROUTE_TABLE_SYNC_MODE_NONE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-10-17 10:23:04 +02:00
|
|
|
if (!IS_IPv4) {
|
|
|
|
|
_l3_commit_ip6_privacy(self, commit_type);
|
|
|
|
|
_l3_commit_ndisc_params(self, commit_type);
|
2021-10-31 15:10:53 +01:00
|
|
|
_l3_commit_ip6_token(self, commit_type);
|
2021-10-17 10:23:04 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-28 10:43:33 +02:00
|
|
|
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE)
|
2021-10-18 18:07:30 +02:00
|
|
|
route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
|
l3cfg: fix clearing IPv6 temporary addresses to avoid stale addresses
IPv6 temporary addresses are configured by kernel, with the
"ipv6.ip6-privacy" setting ("use_tempaddr" sysctl) and the
IFA_F_MANAGETEMPADDR flag.
As such, the idea was that during reapply we would not remove them.
However, that is wrong.
The only case when we want to keep those addresses, is if during reapply
we are going to configure the same primary address (with mngtmpaddr
flag) again. Otherwise, theses addresses must always go away.
This is quite serious. This not only affects Reapply. Also during disconnect
we clear IP configuration via l3cfg.
Have an ethernet profile active with "ipv6.ip6-privacy". Unplug
the cable, the device disconnects but the temporary IPv6 address is not
cleared. As such, nm_device_generate_connection() will now generate
an external profile (with "ipv6.method=disabled" and no manual IP addresses).
The result is, that the device cannot properly autoconnect again,
once you replug the cable.
This is serious for disconnect. But I could not actually reproduce the
problem using reapply. That is, because during reapply we usually
toggle ipv6_disable sysctl, which drops all IPv6 addresses. I still
went through the effort of trying to preserve addresses that we still
want to have, because I am not sure whether there are cases where we
don't toggle ipv6_disable. Also, doing ipv6_disable during reapply is
bad anyway, and we might want to avoid that in the future.
Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration')
(cherry picked from commit 518f6124c6476e5f91b30b7d5583f494e84fd936)
2022-05-05 10:22:20 +02:00
|
|
|
gs_unref_array GArray *ipv6_temp_addrs_keep = NULL;
|
|
|
|
|
|
2022-05-05 17:24:48 +02:00
|
|
|
nm_platform_process_events(self->priv.platform);
|
|
|
|
|
|
l3cfg: fix clearing IPv6 temporary addresses to avoid stale addresses
IPv6 temporary addresses are configured by kernel, with the
"ipv6.ip6-privacy" setting ("use_tempaddr" sysctl) and the
IFA_F_MANAGETEMPADDR flag.
As such, the idea was that during reapply we would not remove them.
However, that is wrong.
The only case when we want to keep those addresses, is if during reapply
we are going to configure the same primary address (with mngtmpaddr
flag) again. Otherwise, theses addresses must always go away.
This is quite serious. This not only affects Reapply. Also during disconnect
we clear IP configuration via l3cfg.
Have an ethernet profile active with "ipv6.ip6-privacy". Unplug
the cable, the device disconnects but the temporary IPv6 address is not
cleared. As such, nm_device_generate_connection() will now generate
an external profile (with "ipv6.method=disabled" and no manual IP addresses).
The result is, that the device cannot properly autoconnect again,
once you replug the cable.
This is serious for disconnect. But I could not actually reproduce the
problem using reapply. That is, because during reapply we usually
toggle ipv6_disable sysctl, which drops all IPv6 addresses. I still
went through the effort of trying to preserve addresses that we still
want to have, because I am not sure whether there are cases where we
don't toggle ipv6_disable. Also, doing ipv6_disable during reapply is
bad anyway, and we might want to avoid that in the future.
Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration')
(cherry picked from commit 518f6124c6476e5f91b30b7d5583f494e84fd936)
2022-05-05 10:22:20 +02:00
|
|
|
if (!IS_IPv4 && addresses) {
|
|
|
|
|
for (i = 0; i < addresses->len; i++) {
|
|
|
|
|
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(addresses->pdata[i]);
|
|
|
|
|
|
|
|
|
|
if (!NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_MANAGETEMPADDR))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nm_assert(addr->plen == 64);
|
|
|
|
|
|
|
|
|
|
/* Construct a list of all IPv6 prefixes for which we (still) set
|
|
|
|
|
* IFA_F_MANAGETEMPADDR (that is, for which we will have temporary addresses).
|
|
|
|
|
* Those should not be pruned during reapply. */
|
|
|
|
|
if (!ipv6_temp_addrs_keep)
|
|
|
|
|
ipv6_temp_addrs_keep = g_array_new(FALSE, FALSE, sizeof(struct in6_addr));
|
|
|
|
|
g_array_append_val(ipv6_temp_addrs_keep, addr->address);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-27 17:11:02 +02:00
|
|
|
|
|
|
|
|
if (c_list_is_empty(&self->priv.p->blocked_lst_head_x[IS_IPv4])) {
|
|
|
|
|
addresses_prune =
|
|
|
|
|
nm_platform_ip_address_get_prune_list(self->priv.platform,
|
|
|
|
|
addr_family,
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
nm_g_array_data(ipv6_temp_addrs_keep),
|
|
|
|
|
nm_g_array_len(ipv6_temp_addrs_keep));
|
|
|
|
|
|
|
|
|
|
routes_prune = nm_platform_ip_route_get_prune_list(self->priv.platform,
|
|
|
|
|
addr_family,
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
route_table_sync);
|
|
|
|
|
_obj_state_zombie_lst_prune_all(self, addr_family);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (c_list_is_empty(&self->priv.p->blocked_lst_head_x[IS_IPv4])) {
|
|
|
|
|
_obj_state_zombie_lst_get_prune_lists(self,
|
l3cfg: fix clearing IPv6 temporary addresses to avoid stale addresses
IPv6 temporary addresses are configured by kernel, with the
"ipv6.ip6-privacy" setting ("use_tempaddr" sysctl) and the
IFA_F_MANAGETEMPADDR flag.
As such, the idea was that during reapply we would not remove them.
However, that is wrong.
The only case when we want to keep those addresses, is if during reapply
we are going to configure the same primary address (with mngtmpaddr
flag) again. Otherwise, theses addresses must always go away.
This is quite serious. This not only affects Reapply. Also during disconnect
we clear IP configuration via l3cfg.
Have an ethernet profile active with "ipv6.ip6-privacy". Unplug
the cable, the device disconnects but the temporary IPv6 address is not
cleared. As such, nm_device_generate_connection() will now generate
an external profile (with "ipv6.method=disabled" and no manual IP addresses).
The result is, that the device cannot properly autoconnect again,
once you replug the cable.
This is serious for disconnect. But I could not actually reproduce the
problem using reapply. That is, because during reapply we usually
toggle ipv6_disable sysctl, which drops all IPv6 addresses. I still
went through the effort of trying to preserve addresses that we still
want to have, because I am not sure whether there are cases where we
don't toggle ipv6_disable. Also, doing ipv6_disable during reapply is
bad anyway, and we might want to avoid that in the future.
Fixes: 58287cbcc0c8 ('core: rework IP configuration in NetworkManager using layer 3 configuration')
(cherry picked from commit 518f6124c6476e5f91b30b7d5583f494e84fd936)
2022-05-05 10:22:20 +02:00
|
|
|
addr_family,
|
2022-05-27 17:11:02 +02:00
|
|
|
&addresses_prune,
|
|
|
|
|
&routes_prune);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 18:07:51 +02:00
|
|
|
|
2022-06-12 19:50:09 -04:00
|
|
|
if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
|
|
|
|
|
if (!addresses) {
|
|
|
|
|
NMPlatformIPXAddress ax;
|
|
|
|
|
|
|
|
|
|
addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
|
|
|
|
|
if (IS_IPv4) {
|
|
|
|
|
g_ptr_array_add(
|
|
|
|
|
addresses,
|
|
|
|
|
nmp_object_new(NMP_OBJECT_TYPE_IP4_ADDRESS,
|
|
|
|
|
nm_platform_ip4_address_init_loopback_addr1(&ax.a4)));
|
|
|
|
|
} else {
|
|
|
|
|
g_ptr_array_add(addresses,
|
|
|
|
|
nmp_object_new(NMP_OBJECT_TYPE_IP6_ADDRESS,
|
|
|
|
|
nm_platform_ip6_address_init_loopback(&ax.a6)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-15 17:37:53 +02:00
|
|
|
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ndisc_*(). */
|
2020-09-15 18:05:18 +02:00
|
|
|
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_mtu(). */
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-29 08:39:12 +02:00
|
|
|
nm_platform_ip_address_sync(self->priv.platform,
|
|
|
|
|
addr_family,
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
addresses,
|
2022-09-08 09:28:28 +02:00
|
|
|
addresses_prune,
|
2022-06-12 19:50:09 -04:00
|
|
|
self->priv.ifindex == NM_LOOPBACK_IFINDEX
|
|
|
|
|
? NMP_IP_ADDRESS_SYNC_FLAGS_NONE
|
|
|
|
|
: NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
_nodev_routes_sync(self, addr_family, commit_type, routes_nodev);
|
|
|
|
|
|
2020-07-28 10:43:33 +02:00
|
|
|
if (!nm_platform_ip_route_sync(self->priv.platform,
|
|
|
|
|
addr_family,
|
|
|
|
|
self->priv.ifindex,
|
|
|
|
|
routes,
|
|
|
|
|
routes_prune,
|
2020-07-28 13:29:36 +02:00
|
|
|
&routes_temporary_not_available_arr))
|
2020-07-28 10:43:33 +02:00
|
|
|
success = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
final_failure_for_temporary_not_available = FALSE;
|
|
|
|
|
if (!_routes_temporary_not_available_update(self,
|
|
|
|
|
addr_family,
|
|
|
|
|
routes_temporary_not_available_arr))
|
|
|
|
|
final_failure_for_temporary_not_available = TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
/* FIXME(l3cfg) */
|
|
|
|
|
(void) final_failure_for_temporary_not_available;
|
|
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
static void
|
|
|
|
|
_l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
|
2020-08-03 17:33:31 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
_nm_unused gs_unref_object NML3Cfg *self_keep_alive = NULL;
|
|
|
|
|
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
|
2021-09-24 19:32:03 +02:00
|
|
|
NML3CfgCommitType commit_type_auto;
|
|
|
|
|
gboolean commit_type_from_auto = FALSE;
|
|
|
|
|
gboolean is_sticky_update = FALSE;
|
2020-09-28 18:07:51 +02:00
|
|
|
char sbuf_ct[30];
|
|
|
|
|
gboolean changed_combined_l3cd;
|
2021-11-11 22:16:14 +01:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-25 15:46:06 +02:00
|
|
|
g_return_if_fail(NM_IS_L3CFG(self));
|
2020-09-19 12:20:45 +02:00
|
|
|
nm_assert(NM_IN_SET(commit_type,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_NONE,
|
|
|
|
|
NM_L3_CFG_COMMIT_TYPE_AUTO,
|
2020-08-03 17:33:31 +02:00
|
|
|
NM_L3_CFG_COMMIT_TYPE_UPDATE,
|
2020-09-19 12:20:45 +02:00
|
|
|
NM_L3_CFG_COMMIT_TYPE_REAPPLY));
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(self->priv.p->commit_reentrant_count == 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
/* The actual commit type is always the maximum of what is requested
|
2021-09-29 09:24:52 +02:00
|
|
|
* and what is registered via nm_l3cfg_commit_type_register(), combined
|
|
|
|
|
* with the ad-hoc requested @commit_type argument. */
|
2021-09-24 19:32:03 +02:00
|
|
|
commit_type_auto = nm_l3cfg_commit_type_get(self);
|
|
|
|
|
if (commit_type == NM_L3_CFG_COMMIT_TYPE_AUTO || commit_type_auto > commit_type) {
|
|
|
|
|
commit_type_from_auto = TRUE;
|
|
|
|
|
commit_type = commit_type_auto;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-29 09:24:52 +02:00
|
|
|
/* Levels UPDATE and higher are sticky. That means, when do perform such a commit
|
2021-09-24 19:32:03 +02:00
|
|
|
* type, then the next one will at least be of level "UPDATE". The idea is
|
|
|
|
|
* that if the current commit adds an address, then the following needs
|
|
|
|
|
* to do at least "UPDATE" level to remove it again. Even if in the meantime
|
|
|
|
|
* the "UPDATE" is unregistered (nm_l3cfg_commit_type_unregister()). */
|
|
|
|
|
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) {
|
|
|
|
|
if (self->priv.p->commit_type_update_sticky) {
|
2020-09-19 12:20:45 +02:00
|
|
|
self->priv.p->commit_type_update_sticky = FALSE;
|
|
|
|
|
commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE;
|
2021-09-24 19:32:03 +02:00
|
|
|
is_sticky_update = TRUE;
|
2020-09-19 12:20:45 +02:00
|
|
|
}
|
2021-09-24 19:32:03 +02:00
|
|
|
} else
|
|
|
|
|
self->priv.p->commit_type_update_sticky = TRUE;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
_LOGT("commit %s%s%s%s",
|
2020-09-19 12:20:45 +02:00
|
|
|
_l3_cfg_commit_type_to_string(commit_type, sbuf_ct, sizeof(sbuf_ct)),
|
2021-09-24 19:32:03 +02:00
|
|
|
commit_type_from_auto ? " (auto)" : "",
|
|
|
|
|
is_sticky_update ? " (sticky-update)" : "",
|
2020-09-25 15:46:06 +02:00
|
|
|
is_idle ? " (idle handler)" : "");
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2021-09-24 19:32:03 +02:00
|
|
|
nm_assert(commit_type > NM_L3_CFG_COMMIT_TYPE_AUTO);
|
|
|
|
|
|
2021-10-11 13:32:26 +02:00
|
|
|
if (nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source))
|
|
|
|
|
self_keep_alive = self;
|
2021-09-24 19:32:03 +02:00
|
|
|
self->priv.p->commit_on_idle_type = NM_L3_CFG_COMMIT_TYPE_AUTO;
|
|
|
|
|
|
|
|
|
|
if (commit_type <= NM_L3_CFG_COMMIT_TYPE_NONE)
|
2020-09-25 15:46:06 +02:00
|
|
|
return;
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
self->priv.p->commit_reentrant_count++;
|
|
|
|
|
|
|
|
|
|
_l3cfg_update_combined_config(self,
|
|
|
|
|
TRUE,
|
|
|
|
|
commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
|
|
|
|
&l3cd_old,
|
|
|
|
|
&changed_combined_l3cd);
|
|
|
|
|
|
2021-10-12 09:21:10 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT);
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3_commit_one(self, AF_INET, commit_type, changed_combined_l3cd, l3cd_old);
|
|
|
|
|
_l3_commit_one(self, AF_INET6, commit_type, changed_combined_l3cd, l3cd_old);
|
2020-09-19 12:20:45 +02:00
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
_l3_commit_mptcp(self, commit_type);
|
|
|
|
|
|
2020-09-19 12:20:45 +02:00
|
|
|
_l3_acd_data_process_changes(self);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2021-11-11 22:16:14 +01:00
|
|
|
if (self->priv.p->l3_config_datas) {
|
|
|
|
|
for (i = 0; i < self->priv.p->l3_config_datas->len; i++) {
|
|
|
|
|
L3ConfigData *l3_config_data = _l3_config_datas_at(self->priv.p->l3_config_datas, i);
|
|
|
|
|
|
|
|
|
|
if (l3_config_data->force_commit_once)
|
|
|
|
|
l3_config_data->force_commit_once = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(self->priv.p->commit_reentrant_count == 1);
|
|
|
|
|
self->priv.p->commit_reentrant_count--;
|
|
|
|
|
|
2020-09-28 16:19:31 +02:00
|
|
|
_nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT);
|
2020-09-25 15:46:06 +02:00
|
|
|
}
|
2020-08-03 17:33:31 +02:00
|
|
|
|
2022-05-27 17:11:02 +02:00
|
|
|
NML3CfgBlockHandle *
|
|
|
|
|
nm_l3cfg_block_obj_pruning(NML3Cfg *self, int addr_family)
|
|
|
|
|
{
|
|
|
|
|
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
|
|
|
|
NML3CfgBlockHandle *handle;
|
|
|
|
|
|
|
|
|
|
if (!self)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
handle = g_slice_new(NML3CfgBlockHandle);
|
|
|
|
|
handle->self = g_object_ref(self);
|
|
|
|
|
handle->is_ipv4 = IS_IPv4;
|
|
|
|
|
c_list_link_tail(&self->priv.p->blocked_lst_head_x[IS_IPv4], &handle->lst);
|
|
|
|
|
|
|
|
|
|
_LOGT("obj-pruning for IPv%c: blocked (%zu)",
|
|
|
|
|
nm_utils_addr_family_to_char(addr_family),
|
|
|
|
|
c_list_length(&self->priv.p->blocked_lst_head_x[IS_IPv4]));
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_l3cfg_unblock_obj_pruning(NML3CfgBlockHandle *handle)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_object NML3Cfg *self = handle->self;
|
|
|
|
|
const int IS_IPv4 = handle->is_ipv4;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
nm_assert(c_list_is_linked(&handle->lst));
|
|
|
|
|
nm_assert(c_list_contains(&self->priv.p->blocked_lst_head_x[IS_IPv4], &handle->lst));
|
|
|
|
|
|
|
|
|
|
c_list_unlink_stale(&handle->lst);
|
|
|
|
|
|
|
|
|
|
_LOGT("obj-pruning for IPv%c: unblocked (%zu)",
|
|
|
|
|
IS_IPv4 ? '4' : '6',
|
|
|
|
|
c_list_length(&self->priv.p->blocked_lst_head_x[IS_IPv4]));
|
|
|
|
|
|
|
|
|
|
nm_g_slice_free(handle);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-29 09:24:52 +02:00
|
|
|
/* See DOC(l3cfg:commit-type) */
|
2020-09-25 15:46:06 +02:00
|
|
|
void
|
|
|
|
|
nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|
|
|
|
{
|
|
|
|
|
_l3_commit(self, commit_type, FALSE);
|
2020-07-28 10:43:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
NML3CfgCommitType
|
|
|
|
|
nm_l3cfg_commit_type_get(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
NML3CfgCommitTypeHandle *handle;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
handle = c_list_first_entry(&self->priv.p->commit_type_lst_head,
|
|
|
|
|
NML3CfgCommitTypeHandle,
|
|
|
|
|
commit_type_lst);
|
|
|
|
|
return handle ? handle->commit_type : NM_L3_CFG_COMMIT_TYPE_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_l3cfg_commit_type_register:
|
|
|
|
|
* @self: the #NML3Cfg
|
|
|
|
|
* @commit_type: the commit type to register
|
|
|
|
|
* @existing_handle: instead of being a new registration, update an existing handle.
|
|
|
|
|
* This may be %NULL, which is like having no previous registration.
|
2021-09-28 22:15:24 +02:00
|
|
|
* @source: the source of the commit type, for logging.
|
2020-09-03 12:24:08 +02:00
|
|
|
*
|
|
|
|
|
* NML3Cfg needs to know whether it is in charge of an interface (and how "much").
|
|
|
|
|
* By default, it is not in charge, but various users can register themself with
|
|
|
|
|
* a certain @commit_type. The "higher" commit type is the used one when calling
|
2020-09-25 15:46:06 +02:00
|
|
|
* nm_l3cfg_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
|
2020-09-03 12:24:08 +02:00
|
|
|
*
|
2021-08-25 11:30:35 +02:00
|
|
|
* Returns: a handle tracking the registration, or %NULL if @commit_type
|
2020-09-03 12:24:08 +02:00
|
|
|
* is %NM_L3_CFG_COMMIT_TYPE_NONE.
|
|
|
|
|
*/
|
|
|
|
|
NML3CfgCommitTypeHandle *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_l3cfg_commit_type_register(NML3Cfg *self,
|
2020-09-03 12:24:08 +02:00
|
|
|
NML3CfgCommitType commit_type,
|
2021-09-28 22:15:24 +02:00
|
|
|
NML3CfgCommitTypeHandle *existing_handle,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *source)
|
2020-09-03 12:24:08 +02:00
|
|
|
{
|
|
|
|
|
NML3CfgCommitTypeHandle *handle;
|
|
|
|
|
NML3CfgCommitTypeHandle *h;
|
|
|
|
|
gboolean linked;
|
2021-09-28 22:15:24 +02:00
|
|
|
NML3CfgCommitTypeHandle *ret = NULL;
|
|
|
|
|
char buf[64];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
2022-04-19 18:39:37 +02:00
|
|
|
nm_assert(NM_IN_SET(commit_type, NM_L3_CFG_COMMIT_TYPE_NONE, NM_L3_CFG_COMMIT_TYPE_UPDATE));
|
2021-10-11 14:56:38 +02:00
|
|
|
|
|
|
|
|
/* It would be easy (and maybe convenient) to allow that @existing_handle
|
|
|
|
|
* can currently be registered on another NML3Cfg instance. But then we couldn't
|
|
|
|
|
* do this assertion, and it seems error prone to allow arbitrary handles where
|
|
|
|
|
* we cannot check whether it is valid. So if @existing_handle is given, it
|
|
|
|
|
* must be tracked by @self (and only by @self). */
|
2020-09-03 12:24:08 +02:00
|
|
|
nm_assert(
|
|
|
|
|
!existing_handle
|
|
|
|
|
|| c_list_contains(&self->priv.p->commit_type_lst_head, &existing_handle->commit_type_lst));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
if (existing_handle) {
|
|
|
|
|
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE) {
|
|
|
|
|
nm_l3cfg_commit_type_unregister(self, existing_handle);
|
2021-09-28 22:15:24 +02:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
if (existing_handle->commit_type == commit_type) {
|
|
|
|
|
ret = existing_handle;
|
|
|
|
|
goto out;
|
2020-09-03 12:24:08 +02:00
|
|
|
}
|
|
|
|
|
c_list_unlink_stale(&existing_handle->commit_type_lst);
|
|
|
|
|
handle = existing_handle;
|
|
|
|
|
} else {
|
|
|
|
|
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
|
2021-09-28 22:15:24 +02:00
|
|
|
goto out;
|
|
|
|
|
handle = g_slice_new(NML3CfgCommitTypeHandle);
|
2020-09-03 12:24:08 +02:00
|
|
|
if (c_list_is_empty(&self->priv.p->commit_type_lst_head))
|
|
|
|
|
g_object_ref(self);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-09-28 22:15:24 +02:00
|
|
|
handle->commit_type = commit_type;
|
|
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
linked = FALSE;
|
|
|
|
|
c_list_for_each_entry (h, &self->priv.p->commit_type_lst_head, commit_type_lst) {
|
|
|
|
|
if (handle->commit_type >= h->commit_type) {
|
2020-10-21 12:13:14 +02:00
|
|
|
c_list_link_before(&h->commit_type_lst, &handle->commit_type_lst);
|
2020-09-03 12:24:08 +02:00
|
|
|
linked = TRUE;
|
2020-09-19 12:20:45 +02:00
|
|
|
break;
|
2020-09-03 12:24:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!linked)
|
|
|
|
|
c_list_link_tail(&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-09-28 22:15:24 +02:00
|
|
|
ret = handle;
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
|
|
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
|
|
|
|
|
2021-09-28 22:15:24 +02:00
|
|
|
out:
|
|
|
|
|
_LOGT("commit type register (type \"%s\", source \"%s\", existing " NM_HASH_OBFUSCATE_PTR_FMT
|
|
|
|
|
") -> " NM_HASH_OBFUSCATE_PTR_FMT "",
|
|
|
|
|
_l3_cfg_commit_type_to_string(commit_type, buf, sizeof(buf)),
|
|
|
|
|
source,
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(existing_handle),
|
|
|
|
|
NM_HASH_OBFUSCATE_PTR(ret));
|
|
|
|
|
return ret;
|
2020-09-03 12:24:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_l3cfg_commit_type_unregister(NML3Cfg *self, NML3CfgCommitTypeHandle *handle)
|
|
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
if (!handle)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
nm_assert(c_list_contains(&self->priv.p->commit_type_lst_head, &handle->commit_type_lst));
|
|
|
|
|
|
2021-09-28 22:15:24 +02:00
|
|
|
_LOGT("commit type unregister " NM_HASH_OBFUSCATE_PTR_FMT "", NM_HASH_OBFUSCATE_PTR(handle));
|
|
|
|
|
|
l3cfg: schedule an update after every commit-type/config-data register/unregister
When we register/unregister a commit-type or when we add/remove a
config-data to NML3Cfg, that act only does the registration/addition.
Only on the next commit, are the changes actually done. The purpose
of that is to add/register multiple configurations and commit them later
when ready.
However, it would be wrong to not do the commit a short time after. The
configuration state is dirty with need to be committed, and that should
happen soon.
Worse, when a interface disappears, NMDevice will clear the ifindex and
the NML3Cfg instance, thereby unregistering all config data and commit
type. If we previously commited something, we need to do another follow-up
commit to cleanup that state.
That is for example important with ECMP routes, which are registered in
NMNetns. When NML3Cfg goes down, it always must unregister to properly
cleanup. Failure to do so, causes an assertion failure and crash. This
change fixes that.
Fix that by automatically schedule and idle commit on
register/unregister/add/remove of commit-type/config-data.
It should *always* be permissible to call a AUTO commit from
an idle handler, because various parties cannot use NML3Cfg
independently, and they cannot know when somebody else does a
commit.
Note that NML3Cfg remembers if it presiouvly did a commit
("commit_type_update_sticky"), so even if the last commit-type gets
unregistered, the next commit will still do a sticky update (one more
time).
The only remaining question is what happens during quitting. When
quitting, NetworkManager we may want to leave some interfaces up and
configured. If we were to properly cleanup the NML3Cfg we might need a
mechanism to handle that. However, currently we just leak everything
during quit, so that is not a concern now. It is something that needs
to be addressed in the future.
https://bugzilla.redhat.com/show_bug.cgi?id=2158394
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1505
2023-01-17 17:41:38 +01:00
|
|
|
nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
|
|
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
c_list_unlink_stale(&handle->commit_type_lst);
|
|
|
|
|
if (c_list_is_empty(&self->priv.p->commit_type_lst_head))
|
|
|
|
|
g_object_unref(self);
|
|
|
|
|
nm_g_slice_free(handle);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-07 17:06:03 -05:00
|
|
|
void
|
|
|
|
|
nm_l3cfg_commit_type_reset_update(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
NML3CfgCommitTypeHandle *h;
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (h, &self->priv.p->commit_type_lst_head, commit_type_lst) {
|
|
|
|
|
if (h->commit_type >= NM_L3_CFG_COMMIT_TYPE_UPDATE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->priv.p->commit_type_update_sticky = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-08 18:25:41 +02:00
|
|
|
const NML3ConfigData *
|
2020-09-16 12:44:38 +02:00
|
|
|
nm_l3cfg_get_combined_l3cd(NML3Cfg *self, gboolean get_commited)
|
2020-09-08 18:25:41 +02:00
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
if (get_commited)
|
|
|
|
|
return self->priv.p->combined_l3cd_commited;
|
|
|
|
|
|
2020-09-28 18:07:51 +02:00
|
|
|
_l3cfg_update_combined_config(self, FALSE, FALSE, NULL, NULL);
|
2020-09-16 12:44:38 +02:00
|
|
|
return self->priv.p->combined_l3cd_merged;
|
2020-09-08 18:25:41 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-08 17:05:34 +02:00
|
|
|
const NMPObject *
|
|
|
|
|
nm_l3cfg_get_best_default_route(NML3Cfg *self, int addr_family, gboolean get_commited)
|
|
|
|
|
{
|
2020-09-16 12:44:38 +02:00
|
|
|
const NML3ConfigData *l3cd;
|
2020-09-08 17:05:34 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
l3cd = nm_l3cfg_get_combined_l3cd(self, get_commited);
|
|
|
|
|
if (!l3cd)
|
2020-09-08 17:05:34 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
return nm_l3_config_data_get_best_default_route(l3cd, addr_family);
|
2020-09-08 17:05:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-09-16 13:18:54 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
const NML3ConfigData *l3cd;
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMPObject *plat_obj;
|
2020-09-16 13:18:54 +02:00
|
|
|
NMPLookup plat_lookup;
|
|
|
|
|
NMDedupMultiIter iter;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
|
|
|
|
l3cd = nm_l3cfg_get_combined_l3cd(self, TRUE);
|
|
|
|
|
if (!l3cd)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* we iterate over all addresses in platform, and check whether the tentative
|
|
|
|
|
* addresses are tracked by our l3cd. Not the other way around, because we assume
|
|
|
|
|
* that there are few addresses in platform that are still tentative, so
|
|
|
|
|
* we only need to lookup few platform addresses in l3cd.
|
|
|
|
|
*
|
|
|
|
|
* Of course, all lookups are O(1) anyway, so in any case the operation is
|
|
|
|
|
* O(n) (once "n" being the addresses in platform, and once in l3cd). */
|
|
|
|
|
|
2022-06-24 23:32:13 +02:00
|
|
|
nmp_lookup_init_object_by_ifindex(&plat_lookup,
|
|
|
|
|
NMP_OBJECT_TYPE_IP6_ADDRESS,
|
|
|
|
|
self->priv.ifindex);
|
2020-09-16 13:18:54 +02:00
|
|
|
|
2020-10-13 12:48:09 +02:00
|
|
|
nm_platform_iter_obj_for_each (&iter, self->priv.platform, &plat_lookup, &plat_obj) {
|
2020-09-16 13:18:54 +02:00
|
|
|
const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj);
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMDedupMultiEntry *l3cd_entry;
|
2020-09-16 13:18:54 +02:00
|
|
|
|
|
|
|
|
if (!NM_FLAGS_HAS(plat_addr->n_ifa_flags, IFA_F_TENTATIVE)
|
|
|
|
|
|| NM_FLAGS_ANY(plat_addr->n_ifa_flags, IFA_F_DADFAILED | IFA_F_OPTIMISTIC))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
l3cd_entry = nm_l3_config_data_lookup_obj(l3cd, plat_obj);
|
|
|
|
|
|
|
|
|
|
nm_assert(NMP_OBJECT_CAST_IP6_ADDRESS(nm_dedup_multi_entry_get_obj(l3cd_entry))
|
|
|
|
|
== nm_l3_config_data_lookup_address_6(l3cd, &plat_addr->address));
|
|
|
|
|
|
|
|
|
|
if (l3cd_entry)
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-10-26 21:42:04 +01:00
|
|
|
NML3IPv4LL *
|
|
|
|
|
nm_l3cfg_get_ipv4ll(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
|
|
|
|
|
|
|
|
|
|
return self->priv.p->ipv4ll;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NML3IPv4LL *
|
|
|
|
|
nm_l3cfg_access_ipv4ll(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), NULL);
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->ipv4ll)
|
|
|
|
|
return nm_l3_ipv4ll_ref(self->priv.p->ipv4ll);
|
|
|
|
|
|
|
|
|
|
/* We return the reference. But the NML3IPv4LL instance
|
|
|
|
|
* will call _nm_l3cfg_unregister_ipv4ll() when it gets
|
|
|
|
|
* destroyed.
|
|
|
|
|
*
|
|
|
|
|
* We don't have weak references, but NML3Cfg and NML3IPv4LL
|
|
|
|
|
* cooperate to handle this reference. */
|
|
|
|
|
self->priv.p->ipv4ll = nm_l3_ipv4ll_new(self);
|
|
|
|
|
return self->priv.p->ipv4ll;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_nm_l3cfg_unregister_ipv4ll(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_L3CFG(self));
|
|
|
|
|
|
2021-10-11 14:56:38 +02:00
|
|
|
/* we don't own the reference to "self->priv.p->ipv4ll", but
|
2020-10-26 21:42:04 +01:00
|
|
|
* when that instance gets destroyed, we get called back to
|
|
|
|
|
* forget about it. Basically, it's like a weak pointer. */
|
|
|
|
|
|
|
|
|
|
nm_assert(self->priv.p->ipv4ll);
|
|
|
|
|
self->priv.p->ipv4ll = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-05-21 21:24:32 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_l3cfg_is_ready(NML3Cfg *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_L3CFG(self), FALSE);
|
|
|
|
|
|
|
|
|
|
if (self->priv.p->changed_configs_configs)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (self->priv.p->changed_configs_acd_state)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (self->priv.p->commit_on_idle_source)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
static void
|
|
|
|
|
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NML3Cfg *self = NM_L3CFG(object);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
switch (prop_id) {
|
|
|
|
|
case PROP_NETNS:
|
|
|
|
|
/* construct-only */
|
|
|
|
|
self->priv.netns = g_object_ref(g_value_get_pointer(value));
|
|
|
|
|
nm_assert(NM_IS_NETNS(self->priv.netns));
|
|
|
|
|
break;
|
|
|
|
|
case PROP_IFINDEX:
|
|
|
|
|
/* construct-only */
|
|
|
|
|
self->priv.ifindex = g_value_get_int(value);
|
|
|
|
|
nm_assert(self->priv.ifindex > 0);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_l3cfg_init(NML3Cfg *self)
|
|
|
|
|
{
|
2020-08-03 17:33:31 +02:00
|
|
|
self->priv.p = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_L3CFG, NML3CfgPrivate);
|
2020-07-21 12:39:31 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
c_list_init(&self->priv.p->acd_lst_head);
|
2020-09-28 18:07:51 +02:00
|
|
|
c_list_init(&self->priv.p->acd_event_notify_lst_head);
|
2020-09-03 12:24:08 +02:00
|
|
|
c_list_init(&self->priv.p->commit_type_lst_head);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
c_list_init(&self->priv.p->obj_state_lst_head);
|
|
|
|
|
c_list_init(&self->priv.p->obj_state_temporary_not_available_lst_head);
|
|
|
|
|
c_list_init(&self->priv.p->obj_state_zombie_lst_head);
|
2022-05-27 17:11:02 +02:00
|
|
|
c_list_init(&self->priv.p->blocked_lst_head_4);
|
|
|
|
|
c_list_init(&self->priv.p->blocked_lst_head_6);
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
|
l3cfg: closer integrate NML3Cfg and NMNetns
NML3Cfg and NMNetns are already strongly related and cooperate.
An NML3Cfg instance is created via NMNetns, which is necessary
because NMNetns ensures that there is only one NML3Cfg instance per
ifindex and it won't ever make sense to have multiple NML3Cfg instances
per namespace.
Note that NMNetns tracks additional information for each NML3Cfg.
Previously, in a pointless attempt to separate code, it did so
by putting that information in another struct (L3CfgData).
But as the classes are strongly related, there really is no
reason why we cannot just attach this information to NML3Cfg
directly. Sure, we want that code has low coupling, high cohesion
but that doesn't mean we gain anything by putting data that is
strongly related to the NML3Cfg to another struct L3CfgData.
The advantage is we save some redundant data and an additional
L3CfgData. But the bigger reason is that with this change, it
will be possible to access the NMNetns specific data directly from
an NML3Cfg instance, without another dictionary lookup. Currently
such a lookup is never used, but it will be.
Basically, NML3Cfg and NMNetns shares some state. It is now in the
"internal_netns" field of the NML3Cfg instead of L3CfgData.
2022-12-09 18:13:20 +01:00
|
|
|
c_list_init(&self->internal_netns.signal_pending_lst);
|
2022-11-23 08:29:48 +01:00
|
|
|
c_list_init(&self->internal_netns.ecmp_track_ifindex_lst_head);
|
l3cfg: closer integrate NML3Cfg and NMNetns
NML3Cfg and NMNetns are already strongly related and cooperate.
An NML3Cfg instance is created via NMNetns, which is necessary
because NMNetns ensures that there is only one NML3Cfg instance per
ifindex and it won't ever make sense to have multiple NML3Cfg instances
per namespace.
Note that NMNetns tracks additional information for each NML3Cfg.
Previously, in a pointless attempt to separate code, it did so
by putting that information in another struct (L3CfgData).
But as the classes are strongly related, there really is no
reason why we cannot just attach this information to NML3Cfg
directly. Sure, we want that code has low coupling, high cohesion
but that doesn't mean we gain anything by putting data that is
strongly related to the NML3Cfg to another struct L3CfgData.
The advantage is we save some redundant data and an additional
L3CfgData. But the bigger reason is that with this change, it
will be possible to access the NMNetns specific data directly from
an NML3Cfg instance, without another dictionary lookup. Currently
such a lookup is never used, but it will be.
Basically, NML3Cfg and NMNetns shares some state. It is now in the
"internal_netns" field of the NML3Cfg instead of L3CfgData.
2022-12-09 18:13:20 +01:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
self->priv.p->obj_state_hash = g_hash_table_new_full(nmp_object_indirect_id_hash,
|
|
|
|
|
nmp_object_indirect_id_equal,
|
|
|
|
|
_obj_state_data_free,
|
|
|
|
|
NULL);
|
2020-07-18 19:01:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
constructed(GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NML3Cfg *self = NM_L3CFG(object);
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_NETNS(self->priv.netns));
|
|
|
|
|
nm_assert(self->priv.ifindex > 0);
|
|
|
|
|
|
|
|
|
|
self->priv.platform = g_object_ref(nm_netns_get_platform(self->priv.netns));
|
|
|
|
|
nm_assert(NM_IS_PLATFORM(self->priv.platform));
|
|
|
|
|
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
self->priv.global_tracker =
|
|
|
|
|
nmp_global_tracker_ref(nm_netns_get_global_tracker(self->priv.netns));
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
_LOGT("created (netns=" NM_HASH_OBFUSCATE_PTR_FMT ")", NM_HASH_OBFUSCATE_PTR(self->priv.netns));
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_l3cfg_parent_class)->constructed(object);
|
2020-07-21 11:57:31 +02:00
|
|
|
|
|
|
|
|
_load_link(self, TRUE);
|
2020-07-18 19:01:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NML3Cfg *
|
|
|
|
|
nm_l3cfg_new(NMNetns *netns, int ifindex)
|
|
|
|
|
{
|
|
|
|
|
nm_assert(NM_IS_NETNS(netns));
|
|
|
|
|
nm_assert(ifindex > 0);
|
|
|
|
|
|
|
|
|
|
return g_object_new(NM_TYPE_L3CFG, NM_L3CFG_NETNS, netns, NM_L3CFG_IFINDEX, ifindex, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
finalize(GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NML3Cfg *self = NM_L3CFG(object);
|
2022-07-18 21:24:09 +02:00
|
|
|
gboolean changed;
|
2020-07-18 19:01:04 +02:00
|
|
|
|
l3cfg: closer integrate NML3Cfg and NMNetns
NML3Cfg and NMNetns are already strongly related and cooperate.
An NML3Cfg instance is created via NMNetns, which is necessary
because NMNetns ensures that there is only one NML3Cfg instance per
ifindex and it won't ever make sense to have multiple NML3Cfg instances
per namespace.
Note that NMNetns tracks additional information for each NML3Cfg.
Previously, in a pointless attempt to separate code, it did so
by putting that information in another struct (L3CfgData).
But as the classes are strongly related, there really is no
reason why we cannot just attach this information to NML3Cfg
directly. Sure, we want that code has low coupling, high cohesion
but that doesn't mean we gain anything by putting data that is
strongly related to the NML3Cfg to another struct L3CfgData.
The advantage is we save some redundant data and an additional
L3CfgData. But the bigger reason is that with this change, it
will be possible to access the NMNetns specific data directly from
an NML3Cfg instance, without another dictionary lookup. Currently
such a lookup is never used, but it will be.
Basically, NML3Cfg and NMNetns shares some state. It is now in the
"internal_netns" field of the NML3Cfg instead of L3CfgData.
2022-12-09 18:13:20 +01:00
|
|
|
nm_assert(c_list_is_empty(&self->internal_netns.signal_pending_lst));
|
2022-11-23 08:29:48 +01:00
|
|
|
nm_assert(c_list_is_empty(&self->internal_netns.ecmp_track_ifindex_lst_head));
|
l3cfg: closer integrate NML3Cfg and NMNetns
NML3Cfg and NMNetns are already strongly related and cooperate.
An NML3Cfg instance is created via NMNetns, which is necessary
because NMNetns ensures that there is only one NML3Cfg instance per
ifindex and it won't ever make sense to have multiple NML3Cfg instances
per namespace.
Note that NMNetns tracks additional information for each NML3Cfg.
Previously, in a pointless attempt to separate code, it did so
by putting that information in another struct (L3CfgData).
But as the classes are strongly related, there really is no
reason why we cannot just attach this information to NML3Cfg
directly. Sure, we want that code has low coupling, high cohesion
but that doesn't mean we gain anything by putting data that is
strongly related to the NML3Cfg to another struct L3CfgData.
The advantage is we save some redundant data and an additional
L3CfgData. But the bigger reason is that with this change, it
will be possible to access the NMNetns specific data directly from
an NML3Cfg instance, without another dictionary lookup. Currently
such a lookup is never used, but it will be.
Basically, NML3Cfg and NMNetns shares some state. It is now in the
"internal_netns" field of the NML3Cfg instead of L3CfgData.
2022-12-09 18:13:20 +01:00
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
nm_assert(!self->priv.p->ipconfig_4);
|
|
|
|
|
nm_assert(!self->priv.p->ipconfig_6);
|
|
|
|
|
|
2020-09-22 18:25:25 +02:00
|
|
|
nm_assert(!self->priv.p->l3_config_datas);
|
2020-10-26 21:42:04 +01:00
|
|
|
nm_assert(!self->priv.p->ipv4ll);
|
2020-09-22 18:25:25 +02:00
|
|
|
|
2020-09-03 12:24:08 +02:00
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->commit_type_lst_head));
|
2022-05-27 17:11:02 +02:00
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->blocked_lst_head_4));
|
|
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->blocked_lst_head_6));
|
2020-09-03 12:24:08 +02:00
|
|
|
|
2021-10-11 13:32:26 +02:00
|
|
|
nm_assert(!self->priv.p->commit_on_idle_source);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
|
|
|
|
_l3_acd_data_prune(self, TRUE);
|
|
|
|
|
|
|
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->acd_lst_head));
|
2020-09-28 18:07:51 +02:00
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->acd_event_notify_lst_head));
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_assert(nm_g_hash_table_size(self->priv.p->acd_lst_hash) == 0);
|
|
|
|
|
|
|
|
|
|
nm_clear_pointer(&self->priv.p->acd_lst_hash, g_hash_table_unref);
|
|
|
|
|
nm_clear_pointer(&self->priv.p->nacd, n_acd_unref);
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_source);
|
|
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry);
|
2021-10-27 10:19:47 +02:00
|
|
|
nm_clear_g_source_inst(&self->priv.p->nacd_event_down_source);
|
2020-08-03 17:33:31 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_clear_g_source_inst(&self->priv.p->obj_state_temporary_not_available_timeout_source);
|
2020-07-28 13:29:36 +02:00
|
|
|
|
l3cfg: implement NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE and rework object state
NML3Cfg tracks state about all addresses/routes. It needs that (at
least) for the following reaons:
1) if a address/route gets added by NetworkManager and then gets
externally removed then it is presumed that the user did this. In this
case, we remember that ("externally-removed") to not re-add the
address/route, until we do a full reapply. This was previously
tracked as "externally_removed_objs_hash".
2) when NML3Cfg configures a address/route in kernel, and later the
address/route is no longer to be configured, then NML3Cfg needs to
delete it again. It thus needs to remember which addresses/routes
it configured earlier to remove them. This was previously tracked via
"last_addresses_x" and "last_routes_x".
3) kernel rejects configuring certain routes while a related IPv6
address is still tentative. That means, NML3Cfg needs to detect that,
remember it, and retry later. That is previously tracked as
"routes_temporary_not_available_hash".
4) during NM_L3_CFG_COMMIT_TYPE_ASSUME, we don't remove extraneous
and don't add missing addresses/routes. This commit mode is done
while assuming a device, that is, gracefully taking over after
a restart. However, sometimes while assuming a device we forcefully
want to configure an address/route. That happens for example if we
do IPv6 link local addressing. Then we really want to add that
address/route, even in assume mode. That is what the
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE flag does, and to implement
that we need to track whether we already tried to add the
address/route previously. This is something new.
Consolidate these various states in a new "obj_state_hash" and
"ObjStateData" structure. This solves above points the following way:
1) to track externally removed objects, we have a flag in ObjStateData
that indicates whether the object was every configured and whether
it currently is configured. Based on that we make decisions to
configure (or not) an address. See "_obj_states_sync_filter()".
2) we now mark objects that NML3Cfg configured, which are still in platform
and which are no longer to be configured as "zombies".
3) this is now tracked via ObjStateData's "os_temporary_not_available_lst".
4) with the available ObjStateData we can make appropriate decisions
in "_obj_states_sync_filter()".
2021-09-06 15:06:15 +02:00
|
|
|
nm_clear_pointer(&self->priv.p->obj_state_hash, g_hash_table_destroy);
|
|
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->obj_state_lst_head));
|
|
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->obj_state_temporary_not_available_lst_head));
|
|
|
|
|
nm_assert(c_list_is_empty(&self->priv.p->obj_state_zombie_lst_head));
|
2020-07-29 08:39:12 +02:00
|
|
|
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (_nodev_routes_untrack(self, AF_INET))
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
nmp_global_tracker_sync(self->priv.global_tracker, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE);
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
if (_nodev_routes_untrack(self, AF_INET6))
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
nmp_global_tracker_sync(self->priv.global_tracker, NMP_OBJECT_TYPE_IP6_ROUTE, FALSE);
|
core/l3cfg: let NML3Cfg handle nodev (blackhole) routes
Certain route types (blackhole, unreachable, prohibit) are not tied to
an interface. They are thus global and we need to track them system wide
(or better: per network namespace). That is done by NMPRouteManager.
For the routing rules, it's NMDevice itself to track/untrack the rules.
That is done for historical reasons, at the time, NML3Cfg did not exit.
Now with NML3Cfg, it seems that also NML3Cfg should be the part that
handles nodev routes. One reason is that we want to move IP
functionality out of NMDevice. So callers (NMDevice) would just add
blackhole routes to the NML3ConfigData and let NML3Cfg handle them.
Still, to handle these routes is rather different from regular routes.
Normally, NML3Cfg tracks an object state (ObjStateData) for each address/route,
and it hooks into platform signals to update the os_plobj field. Those signals
are dispatched by NMNetns and are only per-ifindex. Hence, NML3Cfg
wouldn't be notified about those nodev routes. Consequently, there
os_plobj could not be (efficiently) maintained and there is no
ObjStateData for such routes.
Instead, all that NML3Cfg does is have the routes in the NML3ConfigData and
tell NMPRouteManager about them. Seems simple enough. The only question
is when should NMPRouteManager sync? For now, we sync when the
track/untracking brings any changes and during reapply. Which is
probably fine.
(cherry picked from commit 9ab53e561a636a48e772d48c96d6bd2e0be13329)
2022-02-07 20:52:49 +01:00
|
|
|
|
2022-07-18 21:24:09 +02:00
|
|
|
changed = FALSE;
|
|
|
|
|
if (_global_tracker_mptcp_untrack(self, AF_INET))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
if (_global_tracker_mptcp_untrack(self, AF_INET6))
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
if (changed)
|
2022-08-10 11:25:20 +02:00
|
|
|
nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, FALSE);
|
2022-07-18 21:24:09 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
g_clear_object(&self->priv.netns);
|
|
|
|
|
g_clear_object(&self->priv.platform);
|
platform: rename NMPRouteManager to NMPGlobalTracker
NetworkManager primarily manages interfaces in an independent fashion.
That means, whenever possible, we want to have a interface specific
view. In many cases, the underlying kernel API also supports that view.
For example, when configuring IP addresses or unicast routes, we do so
per interfaces and don't need a holistic view.
However, that is not always sufficient. For routing rules and certain
route types (blackhole, unreachable, etc), we need a system wide view
of all the objects in the network namespace.
Originally, NMPRulesManager was added to track routing rules. Then, it
was extended to also track certain route types, and the API was renamed to
NMPRouteManager.
This will also be used to track MPTCP addresses.
So rename again, to give it a general name that is suitable for what it
does. Still, the name is not great (suggestion welcome), but it should
cover the purpose of the API well enough. And it's the best I came
up with.
Rename.
2022-07-18 09:12:09 +02:00
|
|
|
nm_clear_pointer(&self->priv.global_tracker, nmp_global_tracker_unref);
|
2020-07-18 19:01:04 +02:00
|
|
|
|
2020-09-16 12:44:38 +02:00
|
|
|
nm_clear_l3cd(&self->priv.p->combined_l3cd_merged);
|
|
|
|
|
nm_clear_l3cd(&self->priv.p->combined_l3cd_commited);
|
2020-07-23 16:15:26 +02:00
|
|
|
|
2020-09-25 17:05:58 +02:00
|
|
|
nm_clear_pointer(&self->priv.plobj, nmp_object_unref);
|
|
|
|
|
nm_clear_pointer(&self->priv.plobj_next, nmp_object_unref);
|
2020-07-21 11:57:31 +02:00
|
|
|
|
2020-08-03 17:33:31 +02:00
|
|
|
nm_clear_pointer(&self->priv.p->acd_ipv4_addresses_on_link, g_hash_table_unref);
|
|
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
_LOGT("finalized");
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_l3cfg_parent_class)->finalize(object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_l3cfg_class_init(NML3CfgClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-21 12:39:31 +02:00
|
|
|
g_type_class_add_private(klass, sizeof(NML3CfgPrivate));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
object_class->set_property = set_property;
|
|
|
|
|
object_class->constructed = constructed;
|
|
|
|
|
object_class->finalize = finalize;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
obj_properties[PROP_NETNS] =
|
|
|
|
|
g_param_spec_pointer(NM_L3CFG_NETNS,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
obj_properties[PROP_IFINDEX] =
|
|
|
|
|
g_param_spec_int(NM_L3CFG_IFINDEX,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
G_MAXINT,
|
|
|
|
|
0,
|
|
|
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-18 19:01:04 +02:00
|
|
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-07-28 13:29:36 +02:00
|
|
|
signals[SIGNAL_NOTIFY] = g_signal_new(NM_L3CFG_SIGNAL_NOTIFY,
|
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
2020-08-03 17:33:31 +02:00
|
|
|
G_SIGNAL_RUN_FIRST,
|
2020-07-28 13:29:36 +02:00
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
2020-09-28 16:19:31 +02:00
|
|
|
g_cclosure_marshal_VOID__POINTER,
|
2020-07-28 13:29:36 +02:00
|
|
|
G_TYPE_NONE,
|
2020-09-28 16:19:31 +02:00
|
|
|
1,
|
|
|
|
|
G_TYPE_POINTER /* (const NML3ConfigNotifyData *) */);
|
2020-07-18 19:01:04 +02:00
|
|
|
}
|