mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-10 04:40:20 +01:00
l3cfg: merge branch 'th/l3cfg-13'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/657
This commit is contained in:
commit
b4ced8b911
17 changed files with 1874 additions and 192 deletions
|
|
@ -2124,6 +2124,8 @@ src_libNetworkManagerBase_la_SOURCES = \
|
|||
src/nm-netns.h \
|
||||
src/nm-l3-config-data.c \
|
||||
src/nm-l3-config-data.h \
|
||||
src/nm-l3-ipv4ll.c \
|
||||
src/nm-l3-ipv4ll.h \
|
||||
src/nm-l3cfg.c \
|
||||
src/nm-l3cfg.h \
|
||||
src/nm-ip-config.c \
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ g_hash_table_steal_extended(GHashTable * hash_table,
|
|||
gpointer *_stolen_value = (stolen_value); \
|
||||
\
|
||||
/* we cannot allow NULL arguments, because then we would leak the values in
|
||||
* the compat implementation. */ \
|
||||
* the compat implementation. */ \
|
||||
g_assert(_stolen_key); \
|
||||
g_assert(_stolen_value); \
|
||||
\
|
||||
|
|
|
|||
|
|
@ -189,6 +189,19 @@ typedef uint64_t _nm_bitwise nm_be64_t;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline uint32_t
|
||||
nm_add_u32_clamped(uint32_t a, uint32_t b)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
/* returns the sum of a+b, or UINT32_MAX if the result would overflow. */
|
||||
|
||||
c = a + b;
|
||||
if (c < a)
|
||||
return UINT32_MAX;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate
|
||||
* the argument possibly twice.
|
||||
*
|
||||
|
|
@ -767,6 +780,21 @@ nm_steal_fd(int *p_fd)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline uintptr_t
|
||||
nm_ptr_to_uintptr(const void *p)
|
||||
{
|
||||
/* in C, pointers can only be compared (with less-than or greater-than) under certain
|
||||
* circumstances. Since uintptr_t is supposed to be able to represent the pointer
|
||||
* as a plain integer and also support to convert the integer back to the pointer,
|
||||
* it should be safer to compare the pointers directly.
|
||||
*
|
||||
* Of course, this function isn't very useful beyond that its use makes it clear
|
||||
* that we want to compare pointers by value, which otherwise may not be valid. */
|
||||
return (uintptr_t) p;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define NM_CMP_RETURN(c) \
|
||||
do { \
|
||||
const int _cc = (c); \
|
||||
|
|
@ -813,7 +841,7 @@ nm_steal_fd(int *p_fd)
|
|||
* Avoid that by casting pointers to void* and then to uintptr_t. This comparison
|
||||
* is not really meaningful, except that it provides some kind of stable sort order
|
||||
* between pointers (that can otherwise not be compared). */
|
||||
#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT((uintptr_t)((void *) (a)), (uintptr_t)((void *) (b)))
|
||||
#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT(nm_ptr_to_uintptr(a), nm_ptr_to_uintptr(b))
|
||||
|
||||
#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
|
||||
|
||||
|
|
|
|||
|
|
@ -900,14 +900,16 @@ nmtst_get_rand_uint64(void)
|
|||
static inline guint
|
||||
nmtst_get_rand_uint(void)
|
||||
{
|
||||
G_STATIC_ASSERT_EXPR(sizeof(guint32) == sizeof(guint));
|
||||
return nmtst_get_rand_uint32();
|
||||
G_STATIC_ASSERT_EXPR((sizeof(guint) == sizeof(guint32) || (sizeof(guint) == sizeof(guint64))));
|
||||
if (sizeof(guint32) == sizeof(guint))
|
||||
return nmtst_get_rand_uint32();
|
||||
return nmtst_get_rand_uint64();
|
||||
}
|
||||
|
||||
static inline gsize
|
||||
nmtst_get_rand_size(void)
|
||||
{
|
||||
G_STATIC_ASSERT_EXPR(sizeof(gsize) == sizeof(guint32) || sizeof(gsize) == sizeof(guint64));
|
||||
G_STATIC_ASSERT_EXPR((sizeof(gsize) == sizeof(guint32) || (sizeof(gsize) == sizeof(guint64))));
|
||||
if (sizeof(gsize) == sizeof(guint32))
|
||||
return nmtst_get_rand_uint32();
|
||||
return nmtst_get_rand_uint64();
|
||||
|
|
@ -919,6 +921,17 @@ nmtst_get_rand_bool(void)
|
|||
return nmtst_get_rand_uint32() % 2;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
nmtst_get_rand_one_case_in(guint32 num)
|
||||
{
|
||||
/* num=1 doesn't make much sense, because it will always return %TRUE.
|
||||
* Still accept it, it might be that @num is calculated, so 1 might be
|
||||
* a valid edge case. */
|
||||
g_assert(num > 0);
|
||||
|
||||
return (nmtst_get_rand_uint32() % num) == 0;
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
nmtst_rand_buf(GRand *rand, gpointer buffer, gsize buffer_length)
|
||||
{
|
||||
|
|
@ -1191,8 +1204,12 @@ _nmtst_main_loop_quit_on_notify(GObject *object, GParamSpec *pspec, gpointer use
|
|||
nm_auto_destroy_and_unref_gsource GSource *_source = NULL; \
|
||||
GMainContext * _context = (context); \
|
||||
gboolean _had_timeout = FALSE; \
|
||||
typeof(timeout_msec) _timeout_msec0 = (timeout_msec); \
|
||||
gint64 _timeout_msec = _timeout_msec0; \
|
||||
\
|
||||
_source = g_timeout_source_new(timeout_msec); \
|
||||
g_assert_cmpint(_timeout_msec0, ==, _timeout_msec); \
|
||||
\
|
||||
_source = g_timeout_source_new(NM_CLAMP(_timeout_msec, 0, (gint64) G_MAXUINT)); \
|
||||
g_source_set_callback(_source, nmtst_g_source_set_boolean_true, &_had_timeout, NULL); \
|
||||
g_source_attach(_source, _context); \
|
||||
\
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ sources = files(
|
|||
'nm-dbus-utils.c',
|
||||
'nm-netns.c',
|
||||
'nm-l3-config-data.c',
|
||||
'nm-l3-ipv4ll.c',
|
||||
'nm-l3cfg.c',
|
||||
'nm-ip-config.c',
|
||||
'nm-ip4-config.c',
|
||||
|
|
|
|||
|
|
@ -2600,7 +2600,7 @@ nm_l3_config_data_merge(NML3ConfigData * self,
|
|||
if (r_src->metric_any) {
|
||||
_ensure_r();
|
||||
r.rx.metric_any = FALSE;
|
||||
r.rx.metric_any = default_route_metric_x[IS_IPv4];
|
||||
r.rx.metric = nm_add_u32_clamped(r.rx.metric, default_route_metric_x[IS_IPv4]);
|
||||
}
|
||||
|
||||
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
|
||||
|
|
|
|||
1001
src/nm-l3-ipv4ll.c
Normal file
1001
src/nm-l3-ipv4ll.c
Normal file
File diff suppressed because it is too large
Load diff
103
src/nm-l3-ipv4ll.h
Normal file
103
src/nm-l3-ipv4ll.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#ifndef __NM_L3_IPV4LL_H__
|
||||
#define __NM_L3_IPV4LL_H__
|
||||
|
||||
#include "nm-l3cfg.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum _nm_packed {
|
||||
NM_L3_IPV4LL_STATE_UNKNOWN,
|
||||
NM_L3_IPV4LL_STATE_DISABLED,
|
||||
NM_L3_IPV4LL_STATE_WAIT_FOR_LINK,
|
||||
NM_L3_IPV4LL_STATE_EXTERNAL,
|
||||
NM_L3_IPV4LL_STATE_PROBING,
|
||||
NM_L3_IPV4LL_STATE_READY,
|
||||
NM_L3_IPV4LL_STATE_DEFENDING,
|
||||
} NML3IPv4LLState;
|
||||
|
||||
const char *nm_l3_ipv4ll_state_to_string(NML3IPv4LLState val, char *buf, gsize len);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _NML3IPv4LL NML3IPv4LL;
|
||||
|
||||
static inline gboolean
|
||||
NM_IS_L3_IPV4LL(const NML3IPv4LL *self)
|
||||
{
|
||||
nm_assert(!self
|
||||
|| (NM_IS_L3CFG(*((NML3Cfg **) self))
|
||||
&& (*((int *) (((char *) self) + sizeof(gpointer)))) > 0));
|
||||
return !!self;
|
||||
}
|
||||
|
||||
NML3IPv4LL *nm_l3_ipv4ll_new(NML3Cfg *self);
|
||||
|
||||
NML3IPv4LL *nm_l3_ipv4ll_ref(NML3IPv4LL *self);
|
||||
void nm_l3_ipv4ll_unref(NML3IPv4LL *self);
|
||||
|
||||
NM_AUTO_DEFINE_FCN0(NML3IPv4LL *, _nm_auto_unref_l3ipv4ll, nm_l3_ipv4ll_unref);
|
||||
#define nm_auto_unref_l3ipv4ll nm_auto(_nm_auto_unref_l3ipv4ll)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NML3Cfg *nm_l3_ipv4ll_get_l3cfg(NML3IPv4LL *self);
|
||||
|
||||
int nm_l3_ipv4ll_get_ifindex(NML3IPv4LL *self);
|
||||
|
||||
NMPlatform *nm_l3_ipv4ll_get_platform(NML3IPv4LL *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* By default, NML3IPv4LL is disabled. You also need to register (enable) it.
|
||||
* The intent of this API is that multiple users can enable/register their own
|
||||
* settings, and NML3IPv4LL will mediate the different requests.
|
||||
*
|
||||
* Also, by setting timeout_msec to zero, NML3IPv4LL is disabled again (zero
|
||||
* wins over all timeouts). This is useful if you do DHCP and IPv4LL on the
|
||||
* same interface. You possibly want to disable IPv4LL if you have a valid
|
||||
* DHCP lease. By registering a timeout_msec to zero, you can disable IPv4LL.
|
||||
*
|
||||
* Also, a registration keeps the NML3IPv4LL instance alive (it also takes
|
||||
* a reference). */
|
||||
|
||||
typedef struct _NML3IPv4LLRegistration NML3IPv4LLRegistration;
|
||||
|
||||
NML3IPv4LLRegistration *nm_l3_ipv4ll_register_new(NML3IPv4LL *self, guint timeout_msec);
|
||||
|
||||
NML3IPv4LLRegistration *nm_l3_ipv4ll_register_update(NML3IPv4LLRegistration *reg,
|
||||
guint timeout_msec);
|
||||
|
||||
NML3IPv4LLRegistration *nm_l3_ipv4ll_register_remove(NML3IPv4LLRegistration *reg);
|
||||
|
||||
NM_AUTO_DEFINE_FCN0(NML3IPv4LLRegistration *,
|
||||
_nm_auto_remove_l3ipv4ll_registration,
|
||||
nm_l3_ipv4ll_register_remove);
|
||||
#define nm_auto_remove_l3ipv4ll_registration nm_auto(_nm_auto_remove_l3ipv4ll_registration)
|
||||
|
||||
static inline NML3IPv4LL *
|
||||
nm_l3_ipv4ll_register_get_instance(NML3IPv4LLRegistration *reg)
|
||||
{
|
||||
NML3IPv4LL *ipv4ll;
|
||||
|
||||
if (!reg)
|
||||
return NULL;
|
||||
ipv4ll = *((NML3IPv4LL **) reg);
|
||||
nm_assert(NM_IS_L3_IPV4LL(ipv4ll));
|
||||
return ipv4ll;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NML3IPv4LLState nm_l3_ipv4ll_get_state(NML3IPv4LL *self);
|
||||
|
||||
in_addr_t nm_l3_ipv4ll_get_addr(NML3IPv4LL *self);
|
||||
|
||||
const NML3ConfigData *nm_l3_ipv4ll_get_l3cd(NML3IPv4LL *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void nm_l3_ipv4ll_restart(NML3IPv4LL *self);
|
||||
|
||||
#endif /* __NM_L3_IPV4LL_H__ */
|
||||
184
src/nm-l3cfg.c
184
src/nm-l3cfg.c
|
|
@ -12,6 +12,7 @@
|
|||
#include "platform/nmp-object.h"
|
||||
#include "nm-netns.h"
|
||||
#include "n-acd/src/n-acd.h"
|
||||
#include "nm-l3-ipv4ll.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -57,32 +58,6 @@ typedef enum {
|
|||
ACD_STATE_CHANGE_MODE_TIMEOUT,
|
||||
} AcdStateChangeMode;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
NML3AcdAddrTrackInfo track_info;
|
||||
struct {
|
||||
const NMPObject * obj;
|
||||
const NML3ConfigData *l3cd;
|
||||
gconstpointer tag;
|
||||
|
||||
guint32 acd_timeout_msec_track;
|
||||
NML3AcdDefendType acd_defend_type_track;
|
||||
bool acd_dirty_track : 1;
|
||||
bool acd_failed_notified_track : 1;
|
||||
};
|
||||
};
|
||||
} AcdTrackData;
|
||||
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdTrackData, track_info) == 0);
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdTrackData, obj) == G_STRUCT_OFFSET(NML3AcdAddrTrackInfo, obj));
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdTrackData, l3cd) == G_STRUCT_OFFSET(NML3AcdAddrTrackInfo, l3cd));
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdTrackData, tag) == G_STRUCT_OFFSET(NML3AcdAddrTrackInfo, tag));
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(AcdTrackData, acd_timeout_msec_track)
|
||||
>= G_STRUCT_OFFSET(NML3AcdAddrTrackInfo, _padding));
|
||||
G_STATIC_ASSERT(sizeof(AcdTrackData) == sizeof(NML3AcdAddrTrackInfo));
|
||||
|
||||
#define ACD_TRACK_DATA(arg) NM_CONSTCAST(AcdTrackData, arg, NML3AcdAddrTrackInfo)
|
||||
|
||||
G_STATIC_ASSERT(G_STRUCT_OFFSET(NML3AcdAddrInfo, addr) == 0);
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -320,6 +295,7 @@ static NM_UTILS_ENUM2STR_DEFINE(
|
|||
_l3_config_notify_type_to_string,
|
||||
NML3ConfigNotifyType,
|
||||
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, "acd-event"),
|
||||
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT, "ipv4ll-event"),
|
||||
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE, "platform-change"),
|
||||
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"),
|
||||
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"),
|
||||
|
|
@ -364,9 +340,11 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data,
|
|||
char * sbuf,
|
||||
gsize sbuf_size)
|
||||
{
|
||||
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
char *s = sbuf;
|
||||
gsize l = sbuf_size;
|
||||
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
char sbuf100[100];
|
||||
char * s = sbuf;
|
||||
gsize l = sbuf_size;
|
||||
in_addr_t addr4;
|
||||
|
||||
nm_assert(sbuf);
|
||||
nm_assert(sbuf_size > 0);
|
||||
|
|
@ -397,6 +375,19 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data,
|
|||
", obj-type-flags=0x%x",
|
||||
notify_data->platform_change_on_idle.obj_type_flags);
|
||||
break;
|
||||
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);
|
||||
nm_utils_strbuf_append(
|
||||
&s,
|
||||
&l,
|
||||
", ipv4ll=" NM_HASH_OBFUSCATE_PTR_FMT "%s%s, state=%s",
|
||||
NM_HASH_OBFUSCATE_PTR(notify_data->ipv4ll_event.ipv4ll),
|
||||
NM_PRINT_FMT_QUOTED2(addr4 != 0, ", addr=", _nm_utils_inet4_ntop(addr4, sbuf_addr), ""),
|
||||
nm_l3_ipv4ll_state_to_string(nm_l3_ipv4ll_get_state(notify_data->ipv4ll_event.ipv4ll),
|
||||
sbuf100,
|
||||
sizeof(sbuf100)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -576,15 +567,15 @@ _l3cfg_externally_removed_objs_drop_unused(NML3Cfg *self)
|
|||
|
||||
g_hash_table_iter_init(&h_iter, self->priv.p->externally_removed_objs_hash);
|
||||
while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj, NULL)) {
|
||||
if (!nm_l3_config_data_lookup_route_obj(self->priv.p->combined_l3cd_commited, obj)) {
|
||||
if (!nm_l3_config_data_lookup_obj(self->priv.p->combined_l3cd_commited, obj)) {
|
||||
/* The object is no longer tracked in the configuration.
|
||||
* The externally_removed_objs_hash is to prevent adding entires that were
|
||||
* removed externally, so if we don't plan to add the entry, we no longer need to track
|
||||
* it. */
|
||||
(*(_l3cfg_externally_removed_objs_counter(self, NMP_OBJECT_GET_TYPE(obj))))--;
|
||||
g_hash_table_iter_remove(&h_iter);
|
||||
_LOGD("externally-removed: untrack %s",
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
(*(_l3cfg_externally_removed_objs_counter(self, NMP_OBJECT_GET_TYPE(obj))))--;
|
||||
g_hash_table_iter_remove(&h_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -602,10 +593,17 @@ _l3cfg_externally_removed_objs_track(NML3Cfg *self, const NMPObject *obj, gboole
|
|||
if (!is_removed) {
|
||||
/* the object is still (or again) present. It no longer gets hidden. */
|
||||
if (self->priv.p->externally_removed_objs_hash) {
|
||||
if (g_hash_table_remove(self->priv.p->externally_removed_objs_hash, obj)) {
|
||||
(*(_l3cfg_externally_removed_objs_counter(self, NMP_OBJECT_GET_TYPE(obj))))--;
|
||||
const NMPObject *obj2;
|
||||
gpointer x_val;
|
||||
|
||||
if (g_hash_table_steal_extended(self->priv.p->externally_removed_objs_hash,
|
||||
obj,
|
||||
(gpointer *) &obj2,
|
||||
&x_val)) {
|
||||
(*(_l3cfg_externally_removed_objs_counter(self, NMP_OBJECT_GET_TYPE(obj2))))--;
|
||||
_LOGD("externally-removed: untrack %s",
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
nmp_object_to_string(obj2, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
nmp_object_unref(obj2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -977,13 +975,13 @@ nm_l3cfg_get_acd_is_pending(NML3Cfg *self)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
_acd_track_data_is_not_dirty(const AcdTrackData *acd_track)
|
||||
_acd_track_data_is_not_dirty(const NML3AcdAddrTrackInfo *acd_track)
|
||||
{
|
||||
return acd_track && !acd_track->acd_dirty_track;
|
||||
return acd_track && !acd_track->_priv.acd_dirty_track;
|
||||
}
|
||||
|
||||
static void
|
||||
_acd_track_data_clear(AcdTrackData *acd_track)
|
||||
_acd_track_data_clear(NML3AcdAddrTrackInfo *acd_track)
|
||||
{
|
||||
nm_l3_config_data_unref(acd_track->l3cd);
|
||||
nmp_object_unref(acd_track->obj);
|
||||
|
|
@ -998,7 +996,7 @@ _acd_data_free(AcdData *acd_data)
|
|||
nm_clear_g_source_inst(&acd_data->acd_data_timeout_source);
|
||||
c_list_unlink_stale(&acd_data->acd_lst);
|
||||
c_list_unlink_stale(&acd_data->acd_event_notify_lst);
|
||||
g_free((AcdTrackData *) acd_data->info.track_infos);
|
||||
g_free((NML3AcdAddrTrackInfo *) acd_data->info.track_infos);
|
||||
nm_g_slice_free(acd_data);
|
||||
}
|
||||
|
||||
|
|
@ -1014,17 +1012,17 @@ _acd_data_collect_tracks_data(const AcdData * acd_data,
|
|||
guint i;
|
||||
|
||||
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
||||
const AcdTrackData *acd_track = ACD_TRACK_DATA(&acd_data->info.track_infos[i]);
|
||||
const NML3AcdAddrTrackInfo *acd_track = &acd_data->info.track_infos[i];
|
||||
|
||||
if (dirty_selector != NM_TERNARY_DEFAULT) {
|
||||
if ((!!dirty_selector) != (!!acd_track->acd_dirty_track))
|
||||
if ((!!dirty_selector) != (!!acd_track->_priv.acd_dirty_track))
|
||||
continue;
|
||||
}
|
||||
n++;
|
||||
if (best_acd_timeout_msec > acd_track->acd_timeout_msec_track)
|
||||
best_acd_timeout_msec = acd_track->acd_timeout_msec_track;
|
||||
if (best_acd_defend_type < acd_track->acd_defend_type_track)
|
||||
best_acd_defend_type = acd_track->acd_defend_type_track;
|
||||
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;
|
||||
}
|
||||
|
||||
nm_assert(n == 0 || best_acd_defend_type > NM_L3_ACD_DEFEND_TYPE_NONE);
|
||||
|
|
@ -1035,7 +1033,7 @@ _acd_data_collect_tracks_data(const AcdData * acd_data,
|
|||
return n;
|
||||
}
|
||||
|
||||
static AcdTrackData *
|
||||
static NML3AcdAddrTrackInfo *
|
||||
_acd_data_find_track(const AcdData * acd_data,
|
||||
const NML3ConfigData *l3cd,
|
||||
const NMPObject * obj,
|
||||
|
|
@ -1044,10 +1042,10 @@ _acd_data_find_track(const AcdData * acd_data,
|
|||
guint i;
|
||||
|
||||
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
||||
const AcdTrackData *acd_track = ACD_TRACK_DATA(&acd_data->info.track_infos[i]);
|
||||
const NML3AcdAddrTrackInfo *acd_track = &acd_data->info.track_infos[i];
|
||||
|
||||
if (acd_track->obj == obj && acd_track->l3cd == l3cd && acd_track->tag == tag)
|
||||
return (AcdTrackData *) acd_track;
|
||||
return (NML3AcdAddrTrackInfo *) acd_track;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -1383,19 +1381,19 @@ _l3_acd_nacd_instance_create_probe(NML3Cfg * self,
|
|||
static void
|
||||
_l3_acd_data_prune_one(NML3Cfg *self, AcdData *acd_data, gboolean all /* or only dirty */)
|
||||
{
|
||||
AcdTrackData *acd_tracks;
|
||||
guint i;
|
||||
guint j;
|
||||
NML3AcdAddrTrackInfo *acd_tracks;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
acd_tracks = (AcdTrackData *) acd_data->info.track_infos;
|
||||
acd_tracks = (NML3AcdAddrTrackInfo *) acd_data->info.track_infos;
|
||||
j = 0;
|
||||
for (i = 0; i < acd_data->info.n_track_infos; i++) {
|
||||
AcdTrackData *acd_track = &acd_tracks[i];
|
||||
NML3AcdAddrTrackInfo *acd_track = &acd_tracks[i];
|
||||
|
||||
/* If not "all" is requested, we only delete the dirty ones
|
||||
* (and mark the survivors as dirty right away). */
|
||||
if (!all && !acd_track->acd_dirty_track) {
|
||||
acd_track->acd_dirty_track = TRUE;
|
||||
if (!all && !acd_track->_priv.acd_dirty_track) {
|
||||
acd_track->_priv.acd_dirty_track = TRUE;
|
||||
if (j != i)
|
||||
acd_tracks[j] = *acd_track;
|
||||
j++;
|
||||
|
|
@ -1455,11 +1453,11 @@ _l3_acd_data_add(NML3Cfg * self,
|
|||
NML3AcdDefendType acd_defend_type,
|
||||
guint32 acd_timeout_msec)
|
||||
{
|
||||
in_addr_t addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address;
|
||||
AcdTrackData *acd_track;
|
||||
AcdData * acd_data;
|
||||
const char * track_mode;
|
||||
char sbuf100[100];
|
||||
in_addr_t addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address;
|
||||
NML3AcdAddrTrackInfo *acd_track;
|
||||
AcdData * acd_data;
|
||||
const char * track_mode;
|
||||
char sbuf100[100];
|
||||
|
||||
if (ACD_ADDR_SKIP(addr))
|
||||
return;
|
||||
|
|
@ -1509,36 +1507,38 @@ _l3_acd_data_add(NML3Cfg * self,
|
|||
g_realloc((gpointer) acd_data->info.track_infos,
|
||||
acd_data->n_track_infos_alloc * sizeof(acd_data->info.track_infos[0]));
|
||||
}
|
||||
acd_track = (AcdTrackData *) &acd_data->info.track_infos[acd_data->info.n_track_infos++];
|
||||
*acd_track = (AcdTrackData){
|
||||
.l3cd = nm_l3_config_data_ref(l3cd),
|
||||
.obj = nmp_object_ref(obj),
|
||||
.tag = tag,
|
||||
.acd_dirty_track = FALSE,
|
||||
.acd_defend_type_track = acd_defend_type,
|
||||
.acd_timeout_msec_track = acd_timeout_msec,
|
||||
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,
|
||||
};
|
||||
track_mode = "new";
|
||||
} else {
|
||||
nm_assert(acd_track->acd_dirty_track);
|
||||
acd_track->acd_dirty_track = FALSE;
|
||||
if (acd_track->acd_timeout_msec_track != acd_timeout_msec
|
||||
|| acd_track->acd_defend_type_track != acd_defend_type) {
|
||||
acd_track->acd_defend_type_track = acd_defend_type;
|
||||
acd_track->acd_timeout_msec_track = acd_timeout_msec;
|
||||
track_mode = "update";
|
||||
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";
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
acd_data->track_infos_changed = TRUE;
|
||||
_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->acd_defend_type_track, sbuf100, sizeof(sbuf100)),
|
||||
track_mode);
|
||||
_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);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1556,7 +1556,7 @@ _l3_acd_data_add_all(NML3Cfg * self,
|
|||
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(((const AcdTrackData *) &acd_data->info.track_infos[i])->acd_dirty_track);
|
||||
nm_assert(acd_data->info.track_infos[i]._priv.acd_dirty_track);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1794,7 +1794,7 @@ _l3_acd_data_state_change(NML3Cfg * self,
|
|||
*
|
||||
* Here, all the state for one address that we probe/announce is tracked in AcdData/acd_data.
|
||||
*
|
||||
* The acd_data has a list of AcdTrackData/acd_track_lst_head, which are configuration items
|
||||
* The acd_data has a list of NML3AcdAddrTrackInfo/acd_track_lst_head, which are configuration items
|
||||
* that are interested in configuring this address. The "owners" of the ACD check for a certain
|
||||
* address.
|
||||
*
|
||||
|
|
@ -2668,7 +2668,10 @@ nm_l3cfg_add_config(NML3Cfg * self,
|
|||
nm_assert(tag);
|
||||
nm_assert(l3cd);
|
||||
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
|
||||
nm_assert(acd_timeout_msec < ACD_MAX_TIMEOUT_MSEC);
|
||||
|
||||
if (acd_timeout_msec > ACD_MAX_TIMEOUT_MSEC)
|
||||
acd_timeout_msec = ACD_MAX_TIMEOUT_MSEC;
|
||||
|
||||
nm_assert(NM_IN_SET(acd_defend_type,
|
||||
NM_L3_ACD_DEFEND_TYPE_NEVER,
|
||||
NM_L3_ACD_DEFEND_TYPE_ONCE,
|
||||
|
|
@ -2703,12 +2706,11 @@ nm_l3cfg_add_config(NML3Cfg * self,
|
|||
if (l3_config_data->l3cd == l3cd) {
|
||||
nm_assert(idx == -1);
|
||||
idx = idx2;
|
||||
continue;
|
||||
idx2++;
|
||||
} else {
|
||||
changed = TRUE;
|
||||
_l3_config_datas_remove_index_fast(self->priv.p->l3_config_datas, idx2);
|
||||
}
|
||||
|
||||
changed = TRUE;
|
||||
_l3_config_datas_remove_index_fast(self->priv.p->l3_config_datas, idx2);
|
||||
|
||||
idx2 = _l3_config_datas_find_next(self->priv.p->l3_config_datas, idx2, tag, NULL);
|
||||
if (idx2 < 0)
|
||||
break;
|
||||
|
|
@ -3503,7 +3505,7 @@ nm_l3cfg_commit_type_register(NML3Cfg * self,
|
|||
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) {
|
||||
c_list_link_before(&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
|
||||
c_list_link_before(&h->commit_type_lst, &handle->commit_type_lst);
|
||||
linked = TRUE;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "platform/nmp-object.h"
|
||||
#include "nm-l3-config-data.h"
|
||||
|
||||
#define NM_L3CFG_CONFIG_PRIORITY_IPV4LL 0
|
||||
|
||||
#define NM_TYPE_L3CFG (nm_l3cfg_get_type())
|
||||
#define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg))
|
||||
#define NM_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_L3CFG, NML3CfgClass))
|
||||
|
|
@ -40,11 +42,13 @@ typedef struct {
|
|||
const NML3ConfigData *l3cd;
|
||||
gconstpointer tag;
|
||||
|
||||
char _padding[sizeof(struct {
|
||||
guint32 a;
|
||||
NML3AcdDefendType b;
|
||||
guint8 c;
|
||||
})];
|
||||
struct {
|
||||
guint32 acd_timeout_msec_track;
|
||||
NML3AcdDefendType acd_defend_type_track;
|
||||
bool acd_dirty_track : 1;
|
||||
bool acd_failed_notified_track : 1;
|
||||
} _priv;
|
||||
|
||||
} NML3AcdAddrTrackInfo;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -55,6 +59,33 @@ typedef struct {
|
|||
const NML3AcdAddrTrackInfo *track_infos;
|
||||
} NML3AcdAddrInfo;
|
||||
|
||||
static inline const NML3AcdAddrTrackInfo *
|
||||
nm_l3_acd_addr_info_find_track_info(const NML3AcdAddrInfo *addr_info,
|
||||
gconstpointer tag,
|
||||
const NML3ConfigData * l3cd,
|
||||
const NMPObject * obj)
|
||||
{
|
||||
guint i;
|
||||
const NML3AcdAddrTrackInfo *ti;
|
||||
|
||||
nm_assert(addr_info);
|
||||
|
||||
/* we always expect that the number n_track_infos is reasonably small. Hence,
|
||||
* a naive linear search is simplest and fastest (e.g. we don't have a hash table). */
|
||||
|
||||
for (i = 0, ti = addr_info->track_infos; i < addr_info->n_track_infos; i++, ti++) {
|
||||
if (l3cd && ti->l3cd != l3cd)
|
||||
continue;
|
||||
if (tag && ti->tag != tag)
|
||||
continue;
|
||||
if (obj && ti->obj != obj)
|
||||
continue;
|
||||
return ti;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
|
||||
|
||||
|
|
@ -75,9 +106,13 @@ typedef enum {
|
|||
* notifications without also subscribing directly to the platform. */
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
|
||||
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT,
|
||||
|
||||
_NM_L3_CONFIG_NOTIFY_TYPE_NUM,
|
||||
} NML3ConfigNotifyType;
|
||||
|
||||
struct _NML3IPv4LL;
|
||||
|
||||
typedef struct {
|
||||
NML3ConfigNotifyType notify_type;
|
||||
union {
|
||||
|
|
@ -93,6 +128,10 @@ typedef struct {
|
|||
struct {
|
||||
guint32 obj_type_flags;
|
||||
} platform_change_on_idle;
|
||||
|
||||
struct {
|
||||
struct _NML3IPv4LL *ipv4ll;
|
||||
} ipv4ll_event;
|
||||
};
|
||||
} NML3ConfigNotifyData;
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,19 @@ _l3cfg_weak_notify(gpointer data, GObject *where_the_object_was)
|
|||
g_object_unref(self);
|
||||
}
|
||||
|
||||
NML3Cfg *
|
||||
nm_netns_get_l3cfg(NMNetns *self, int ifindex)
|
||||
{
|
||||
NMNetnsPrivate *priv;
|
||||
|
||||
g_return_val_if_fail(NM_IS_NETNS(self), NULL);
|
||||
g_return_val_if_fail(ifindex > 0, NULL);
|
||||
|
||||
priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
return g_hash_table_lookup(priv->l3cfgs, &ifindex);
|
||||
}
|
||||
|
||||
NML3Cfg *
|
||||
nm_netns_access_l3cfg(NMNetns *self, int ifindex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self);
|
|||
|
||||
#define NM_NETNS_GET (nm_netns_get())
|
||||
|
||||
NML3Cfg *nm_netns_get_l3cfg(NMNetns *self, int ifindex);
|
||||
|
||||
NML3Cfg *nm_netns_access_l3cfg(NMNetns *netns, int ifindex);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -6515,7 +6515,9 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
|
|||
route->plen,
|
||||
s_gateway,
|
||||
str_dev,
|
||||
route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric),
|
||||
route->metric_any
|
||||
? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??")
|
||||
: nm_sprintf_buf(str_metric, "%u", route->metric),
|
||||
route->mss,
|
||||
nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
|
||||
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
|
||||
|
|
@ -6639,7 +6641,9 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
|
|||
route->plen,
|
||||
s_gateway,
|
||||
str_dev,
|
||||
route->metric_any ? "??" : nm_sprintf_buf(str_metric, "%u", route->metric),
|
||||
route->metric_any
|
||||
? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??")
|
||||
: nm_sprintf_buf(str_metric, "%u", route->metric),
|
||||
route->mss,
|
||||
nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)),
|
||||
route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src)
|
||||
|
|
@ -7927,7 +7931,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip4_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->tos,
|
||||
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
|
||||
break;
|
||||
|
|
@ -7938,7 +7942,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip4_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->tos,
|
||||
/* on top of WEAK_ID: */
|
||||
obj->ifindex,
|
||||
|
|
@ -7970,7 +7974,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
obj->ifindex,
|
||||
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip4_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->gateway,
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
|
||||
_ip_route_scope_inv_get_normalized(obj),
|
||||
|
|
@ -7999,7 +8003,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
obj->ifindex,
|
||||
obj->network,
|
||||
obj->plen,
|
||||
nm_platform_ip4_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->gateway,
|
||||
obj->rt_source,
|
||||
obj->scope_inv,
|
||||
|
|
@ -8039,8 +8043,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
|
||||
NM_CMP_FIELD(a, b, plen);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
if (!a->metric_any)
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, tos);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
|
||||
NM_CMP_FIELD(a, b, ifindex);
|
||||
|
|
@ -8081,8 +8084,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_FIELD(a, b, network);
|
||||
NM_CMP_FIELD(a, b, plen);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
if (!a->metric_any)
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, gateway);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
|
||||
|
|
@ -8130,7 +8132,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip6_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
|
||||
obj->src_plen,
|
||||
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
|
||||
|
|
@ -8142,7 +8144,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip6_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
|
||||
obj->src_plen,
|
||||
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any),
|
||||
|
|
@ -8158,7 +8160,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
obj->ifindex,
|
||||
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
|
||||
obj->plen,
|
||||
nm_platform_ip6_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->gateway,
|
||||
obj->pref_src,
|
||||
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
|
||||
|
|
@ -8187,7 +8189,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
obj->table_coerced,
|
||||
obj->ifindex,
|
||||
obj->network,
|
||||
nm_platform_ip6_route_get_effective_metric(obj),
|
||||
obj->metric,
|
||||
obj->gateway,
|
||||
obj->pref_src,
|
||||
obj->src,
|
||||
|
|
@ -8228,8 +8230,7 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
|
|||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
|
||||
NM_CMP_FIELD(a, b, plen);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
if (!a->metric_any)
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen));
|
||||
NM_CMP_FIELD(a, b, src_plen);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
|
||||
|
|
@ -8254,8 +8255,7 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
|
|||
NM_CMP_FIELD_IN6ADDR(a, b, network);
|
||||
NM_CMP_FIELD(a, b, plen);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
if (!a->metric_any)
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD_IN6ADDR(a, b, gateway);
|
||||
NM_CMP_FIELD_IN6ADDR(a, b, pref_src);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
|
|
|
|||
|
|
@ -415,9 +415,9 @@ typedef union {
|
|||
* configures addresses. */
|
||||
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE ((guint32) 0u)
|
||||
|
||||
#define __NMPlatformIPRoute_COMMON \
|
||||
__NMPlatformObjWithIfindex_COMMON; \
|
||||
\
|
||||
#define __NMPlatformIPRoute_COMMON \
|
||||
__NMPlatformObjWithIfindex_COMMON; \
|
||||
\
|
||||
/* The NMIPConfigSource. For routes that we receive from cache this corresponds
|
||||
* to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
|
||||
* When adding a route, the source will be coerced to the protocol using
|
||||
|
|
@ -429,11 +429,11 @@ typedef union {
|
|||
*
|
||||
* When deleting an IPv4/IPv6 route, the rtm_protocol field must match (even
|
||||
* if it is not part of the primary key for IPv6) -- unless rtm_protocol is set
|
||||
* to zero, in which case the first matching route (with proto ignored) is deleted. */ \
|
||||
NMIPConfigSource rt_source; \
|
||||
\
|
||||
guint8 plen; \
|
||||
\
|
||||
* to zero, in which case the first matching route (with proto ignored) is deleted. */ \
|
||||
NMIPConfigSource rt_source; \
|
||||
\
|
||||
guint8 plen; \
|
||||
\
|
||||
/* RTA_METRICS:
|
||||
*
|
||||
* For IPv4 routes, these properties are part of their
|
||||
|
|
@ -444,24 +444,29 @@ typedef union {
|
|||
*
|
||||
* When deleting a route, kernel seems to ignore the RTA_METRICS properties.
|
||||
* That is a problem/bug for IPv4 because you cannot explicitly select which
|
||||
* route to delete. Kernel just picks the first. See rh#1475642. */ \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \
|
||||
bool lock_window : 1; \
|
||||
bool lock_cwnd : 1; \
|
||||
bool lock_initcwnd : 1; \
|
||||
bool lock_initrwnd : 1; \
|
||||
bool lock_mtu : 1; \
|
||||
\
|
||||
/* if TRUE, the "metric" field gets ignored and can be overridden with settings from
|
||||
* the device. This is to track routes that should be configured (e.g. from a DHCP
|
||||
* lease), but where the actual metric is determined by NMDevice. */ \
|
||||
bool metric_any : 1; \
|
||||
\
|
||||
* route to delete. Kernel just picks the first. See rh#1475642. */ \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \
|
||||
bool lock_window : 1; \
|
||||
bool lock_cwnd : 1; \
|
||||
bool lock_initcwnd : 1; \
|
||||
bool lock_initrwnd : 1; \
|
||||
bool lock_mtu : 1; \
|
||||
\
|
||||
/* if TRUE, the "metric" field is interpreted as an offset that is added to a default
|
||||
* metric. For example, form a DHCP lease we don't know the actually used metric, because
|
||||
* that is determined by upper layers (the configuration). However, we have a default
|
||||
* metric that should be used. So we set "metric_any" to %TRUE, which means to use
|
||||
* the default metric. However, we still treat the "metric" field as an offset that
|
||||
* will be added to the default metric. In most case, you want that "metric" is zero
|
||||
* when setting "metric_any". */ \
|
||||
bool metric_any : 1; \
|
||||
\
|
||||
/* like "metric_any", the table is determined by other layers of the code.
|
||||
* This field overrides "table_coerced" field. */ \
|
||||
bool table_any : 1; \
|
||||
\
|
||||
* This field overrides "table_coerced" field. If "table_any" is true, then
|
||||
* the "table_coerced" field is ignored (unlike for the metric). */ \
|
||||
bool table_any : 1; \
|
||||
\
|
||||
/* rtnh_flags
|
||||
*
|
||||
* Routes with rtm_flags RTM_F_CLONED are hidden by platform and
|
||||
|
|
@ -471,44 +476,46 @@ typedef union {
|
|||
* NOTE: currently we ignore all flags except RTM_F_CLONED
|
||||
* and RTNH_F_ONLINK.
|
||||
* We also may not properly consider the flags as part of the ID
|
||||
* in route-cmp. */ \
|
||||
unsigned r_rtm_flags; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
|
||||
guint32 mss; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
|
||||
guint32 window; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
|
||||
guint32 cwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
|
||||
guint32 initcwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
|
||||
guint32 initrwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
|
||||
guint32 mtu; \
|
||||
\
|
||||
/* RTA_PRIORITY (iproute2: metric) */ \
|
||||
guint32 metric; \
|
||||
\
|
||||
* in route-cmp. */ \
|
||||
unsigned r_rtm_flags; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
|
||||
guint32 mss; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
|
||||
guint32 window; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
|
||||
guint32 cwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
|
||||
guint32 initcwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
|
||||
guint32 initrwnd; \
|
||||
\
|
||||
/* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
|
||||
guint32 mtu; \
|
||||
\
|
||||
/* RTA_PRIORITY (iproute2: metric)
|
||||
* If "metric_any" is %TRUE, then this is interpreted as an offset that will be
|
||||
* added to a default base metric. In such cases, the offset is usually zero. */ \
|
||||
guint32 metric; \
|
||||
\
|
||||
/* rtm_table, RTA_TABLE.
|
||||
*
|
||||
* This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
|
||||
* zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
|
||||
* table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
|
||||
guint32 table_coerced; \
|
||||
\
|
||||
* table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
|
||||
guint32 table_coerced; \
|
||||
\
|
||||
/* rtm_type.
|
||||
*
|
||||
* This is not the original type, if type_coerced is 0 then
|
||||
* it means RTN_UNSPEC otherwise the type value is preserved.
|
||||
* */ \
|
||||
guint8 type_coerced; \
|
||||
\
|
||||
* */ \
|
||||
guint8 type_coerced; \
|
||||
\
|
||||
/*end*/
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -2078,18 +2085,18 @@ static inline guint32
|
|||
nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r)
|
||||
{
|
||||
nm_assert(r);
|
||||
nm_assert(!r->metric_any || r->metric == 0);
|
||||
|
||||
return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 : r->metric;
|
||||
return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, r->metric)
|
||||
: r->metric;
|
||||
}
|
||||
|
||||
static inline guint32
|
||||
nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r)
|
||||
{
|
||||
nm_assert(r);
|
||||
nm_assert(!r->metric_any || r->metric == 0);
|
||||
|
||||
return r->metric_any ? NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 : r->metric;
|
||||
return r->metric_any ? nm_add_u32_clamped(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, r->metric)
|
||||
: r->metric;
|
||||
}
|
||||
|
||||
static inline guint32
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@
|
|||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "test-common.h"
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sched.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
#include "test-common.h"
|
||||
#include "n-acd/src/n-acd.h"
|
||||
|
||||
#define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)"
|
||||
#define SIGNAL_DATA_ARG(data) \
|
||||
|
|
@ -2566,3 +2568,145 @@ main(int argc, char **argv)
|
|||
g_object_unref(NM_PLATFORM_GET);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct _NMTstpAcdDefender {
|
||||
int ifindex;
|
||||
in_addr_t ip_addr;
|
||||
NAcd * nacd;
|
||||
NAcdProbe *probe;
|
||||
GSource * source;
|
||||
gint8 announce_started;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
_l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
NMTstpAcdDefender *defender = user_data;
|
||||
int r;
|
||||
|
||||
r = n_acd_dispatch(defender->nacd);
|
||||
if (r == N_ACD_E_PREEMPTED)
|
||||
r = 0;
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
|
||||
while (TRUE) {
|
||||
NAcdEvent *event;
|
||||
|
||||
r = n_acd_pop_event(defender->nacd, &event);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
if (!event)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
switch (event->event) {
|
||||
case N_ACD_EVENT_READY:
|
||||
g_assert_cmpint(defender->announce_started, ==, 0);
|
||||
g_assert(defender->probe == event->ready.probe);
|
||||
defender->announce_started++;
|
||||
_LOGT("acd-defender[" NM_HASH_OBFUSCATE_PTR_FMT "]: start announcing",
|
||||
NM_HASH_OBFUSCATE_PTR(defender));
|
||||
r = n_acd_probe_announce(defender->probe, N_ACD_DEFEND_ALWAYS);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
break;
|
||||
case N_ACD_EVENT_DEFENDED:
|
||||
g_assert(defender->probe == event->defended.probe);
|
||||
g_assert_cmpint(event->defended.n_sender, ==, ETH_ALEN);
|
||||
_LOGT("acd-defender[" NM_HASH_OBFUSCATE_PTR_FMT
|
||||
"]: defended from " NM_ETHER_ADDR_FORMAT_STR,
|
||||
NM_HASH_OBFUSCATE_PTR(defender),
|
||||
NM_ETHER_ADDR_FORMAT_VAL((const NMEtherAddr *) event->defended.sender));
|
||||
break;
|
||||
case N_ACD_EVENT_USED:
|
||||
case N_ACD_EVENT_CONFLICT:
|
||||
case N_ACD_EVENT_DOWN:
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NMTstpAcdDefender *
|
||||
nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_addr)
|
||||
{
|
||||
NMTstpAcdDefender * defender;
|
||||
nm_auto(n_acd_config_freep) NAcdConfig * config = NULL;
|
||||
nm_auto(n_acd_unrefp) NAcd * nacd = NULL;
|
||||
nm_auto(n_acd_probe_config_freep) NAcdProbeConfig *probe_config = NULL;
|
||||
NAcdProbe * probe;
|
||||
int fd;
|
||||
int r;
|
||||
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
g_assert_cmpint(ifindex, >, 0);
|
||||
g_assert(mac_addr);
|
||||
|
||||
r = n_acd_config_new(&config);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert(config);
|
||||
|
||||
n_acd_config_set_ifindex(config, ifindex);
|
||||
n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET);
|
||||
n_acd_config_set_mac(config, (const guint8 *) mac_addr, sizeof(*mac_addr));
|
||||
|
||||
r = n_acd_new(&nacd, config);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert(nacd);
|
||||
|
||||
r = n_acd_probe_config_new(&probe_config);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert(probe_config);
|
||||
|
||||
n_acd_probe_config_set_ip(probe_config, (struct in_addr){ip_addr});
|
||||
n_acd_probe_config_set_timeout(probe_config, 0);
|
||||
|
||||
r = n_acd_probe(nacd, &probe, probe_config);
|
||||
g_assert_cmpint(r, ==, 0);
|
||||
g_assert(probe);
|
||||
|
||||
defender = g_slice_new(NMTstpAcdDefender);
|
||||
*defender = (NMTstpAcdDefender){
|
||||
.ifindex = ifindex,
|
||||
.ip_addr = ip_addr,
|
||||
.nacd = g_steal_pointer(&nacd),
|
||||
.probe = g_steal_pointer(&probe),
|
||||
};
|
||||
|
||||
_LOGT("acd-defender[" NM_HASH_OBFUSCATE_PTR_FMT
|
||||
"]: new for ifindex=%d, hwaddr=" NM_ETHER_ADDR_FORMAT_STR ", ipaddr=%s",
|
||||
NM_HASH_OBFUSCATE_PTR(defender),
|
||||
ifindex,
|
||||
NM_ETHER_ADDR_FORMAT_VAL(mac_addr),
|
||||
_nm_utils_inet4_ntop(ip_addr, sbuf_addr));
|
||||
|
||||
n_acd_probe_set_userdata(defender->probe, defender);
|
||||
|
||||
n_acd_get_fd(defender->nacd, &fd);
|
||||
g_assert_cmpint(fd, >=, 0);
|
||||
|
||||
defender->source = nm_g_source_attach(nm_g_unix_fd_source_new(fd,
|
||||
G_IO_IN,
|
||||
G_PRIORITY_DEFAULT,
|
||||
_l3_acd_nacd_event,
|
||||
defender,
|
||||
NULL),
|
||||
NULL);
|
||||
|
||||
return defender;
|
||||
}
|
||||
|
||||
void
|
||||
nmtstp_acd_defender_destroy(NMTstpAcdDefender *defender)
|
||||
{
|
||||
if (!defender)
|
||||
return;
|
||||
|
||||
_LOGT("acd-defender[" NM_HASH_OBFUSCATE_PTR_FMT "]: destroy", NM_HASH_OBFUSCATE_PTR(defender));
|
||||
|
||||
nm_clear_g_source_inst(&defender->source);
|
||||
nm_clear_pointer(&defender->nacd, n_acd_unref);
|
||||
nm_clear_pointer(&defender->probe, n_acd_probe_free);
|
||||
|
||||
nm_g_slice_free(defender);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -606,5 +606,14 @@ void nmtstp_setup_platform(void);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct _NMTstpAcdDefender NMTstpAcdDefender;
|
||||
|
||||
NMTstpAcdDefender *
|
||||
nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_addr);
|
||||
|
||||
void nmtstp_acd_defender_destroy(NMTstpAcdDefender *defender);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void _nmtstp_init_tests(int *argc, char ***argv);
|
||||
void _nmtstp_setup_tests(void);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "nm-default.h"
|
||||
|
||||
#include "nm-l3cfg.h"
|
||||
#include "nm-l3-ipv4ll.h"
|
||||
#include "nm-netns.h"
|
||||
#include "platform/nm-platform.h"
|
||||
|
||||
|
|
@ -10,6 +11,23 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NML3Cfg *
|
||||
_netns_access_l3cfg(NMNetns *netns, int ifindex)
|
||||
{
|
||||
NML3Cfg *l3cfg;
|
||||
|
||||
g_assert(NM_IS_NETNS(netns));
|
||||
g_assert(ifindex > 0);
|
||||
|
||||
g_assert(!nm_netns_get_l3cfg(netns, ifindex));
|
||||
|
||||
l3cfg = nm_netns_access_l3cfg(netns, ifindex);
|
||||
g_assert(NM_IS_L3CFG(l3cfg));
|
||||
return l3cfg;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int test_idx;
|
||||
NMPlatform * platform;
|
||||
|
|
@ -28,6 +46,8 @@ _test_fixture_1_setup(TestFixture1 *f, int test_idx)
|
|||
{
|
||||
const NMPlatformLink *l0;
|
||||
const NMPlatformLink *l1;
|
||||
const NMEtherAddr addr0 = NM_ETHER_ADDR_INIT(0xAA, 0xAA, test_idx, 0x00, 0x00, 0x00);
|
||||
const NMEtherAddr addr1 = NM_ETHER_ADDR_INIT(0xAA, 0xAA, test_idx, 0x00, 0x00, 0x11);
|
||||
|
||||
g_assert_cmpint(test_idx, >, 0);
|
||||
g_assert_cmpint(f->test_idx, ==, 0);
|
||||
|
|
@ -41,14 +61,26 @@ _test_fixture_1_setup(TestFixture1 *f, int test_idx)
|
|||
f->multiidx = nm_dedup_multi_index_ref(nm_platform_get_multi_idx(f->platform));
|
||||
f->netns = nm_netns_new(f->platform);
|
||||
|
||||
l0 = nmtstp_link_veth_add(f->platform, -1, f->ifname0, f->ifname1);
|
||||
nmtstp_link_veth_add(f->platform, -1, f->ifname0, f->ifname1);
|
||||
|
||||
l0 = nmtstp_link_get_typed(f->platform, -1, f->ifname0, NM_LINK_TYPE_VETH);
|
||||
l1 = nmtstp_link_get_typed(f->platform, -1, f->ifname1, NM_LINK_TYPE_VETH);
|
||||
|
||||
f->ifindex0 = l0->ifindex;
|
||||
f->hwaddr0 = l0->l_address;
|
||||
|
||||
f->ifindex1 = l1->ifindex;
|
||||
f->hwaddr1 = l1->l_address;
|
||||
|
||||
g_assert_cmpint(nm_platform_link_set_address(f->platform, f->ifindex0, &addr0, sizeof(addr0)),
|
||||
==,
|
||||
0);
|
||||
g_assert_cmpint(nm_platform_link_set_address(f->platform, f->ifindex1, &addr1, sizeof(addr1)),
|
||||
==,
|
||||
0);
|
||||
|
||||
l0 = nmtstp_link_get_typed(f->platform, f->ifindex0, f->ifname0, NM_LINK_TYPE_VETH);
|
||||
l1 = nmtstp_link_get_typed(f->platform, f->ifindex1, f->ifname1, NM_LINK_TYPE_VETH);
|
||||
|
||||
f->hwaddr0 = l0->l_address;
|
||||
f->hwaddr1 = l1->l_address;
|
||||
|
||||
g_assert(nm_platform_link_set_up(f->platform, f->ifindex0, NULL));
|
||||
g_assert(nm_platform_link_set_up(f->platform, f->ifindex1, NULL));
|
||||
|
|
@ -326,14 +358,13 @@ test_l3cfg(gconstpointer test_data)
|
|||
NULL);
|
||||
}
|
||||
|
||||
l3cfg0 = nm_netns_access_l3cfg(f->netns, f->ifindex0);
|
||||
g_assert(NM_IS_L3CFG(l3cfg0));
|
||||
l3cfg0 = _netns_access_l3cfg(f->netns, f->ifindex0);
|
||||
|
||||
g_signal_connect(l3cfg0, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_test_l3cfg_signal_notify), tdata);
|
||||
|
||||
commit_type_1 = nm_l3cfg_commit_type_register(l3cfg0, NM_L3_CFG_COMMIT_TYPE_UPDATE, NULL);
|
||||
|
||||
if ((nmtst_get_rand_uint32() % 4u) != 0) {
|
||||
if (!nmtst_get_rand_one_case_in(4)) {
|
||||
commit_type_2 =
|
||||
nm_l3cfg_commit_type_register(l3cfg0,
|
||||
nmtst_rand_select(NM_L3_CFG_COMMIT_TYPE_NONE,
|
||||
|
|
@ -374,7 +405,7 @@ test_l3cfg(gconstpointer test_data)
|
|||
NM_PLATFORM_IP6_ADDRESS_INIT(.address = *nmtst_inet6_from_string("1:2:3:4::45"),
|
||||
.plen = 64, ));
|
||||
|
||||
if (nmtst_get_rand_bool())
|
||||
if (nmtst_get_rand_one_case_in(2))
|
||||
nm_l3_config_data_seal(l3cd);
|
||||
l3cd_a = g_steal_pointer(&l3cd);
|
||||
break;
|
||||
|
|
@ -450,12 +481,12 @@ test_l3cfg(gconstpointer test_data)
|
|||
nm_l3cfg_commit_type_unregister(l3cfg0, commit_type_1);
|
||||
nm_l3cfg_commit_type_unregister(l3cfg0, commit_type_2);
|
||||
|
||||
if ((nmtst_get_rand_uint32() % 3) == 0)
|
||||
if (nmtst_get_rand_one_case_in(3))
|
||||
_test_fixture_1_teardown(&test_fixture);
|
||||
|
||||
nm_l3cfg_remove_config_all(l3cfg0, GINT_TO_POINTER('a'), FALSE);
|
||||
|
||||
if ((nmtst_get_rand_uint32() % 3) == 0)
|
||||
if (nmtst_get_rand_one_case_in(3))
|
||||
_test_fixture_1_teardown(&test_fixture);
|
||||
|
||||
_LOGD("test end (/l3cfg/%d)", TEST_IDX);
|
||||
|
|
@ -463,12 +494,293 @@ test_l3cfg(gconstpointer test_data)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define L3IPV4LL_ACD_TIMEOUT_MSEC 1500u
|
||||
|
||||
typedef struct {
|
||||
const TestFixture1 * f;
|
||||
NML3CfgCommitTypeHandle *l3cfg_commit_type_1;
|
||||
guint acd_timeout_msec;
|
||||
NML3IPv4LL * l3ipv4ll;
|
||||
bool has_addr4_101;
|
||||
gint8 ready_seen;
|
||||
gint8 addr_commit;
|
||||
in_addr_t addr_commit_addr;
|
||||
bool add_conflict_checked : 1;
|
||||
bool add_conflict_done;
|
||||
} TestL3IPv4LLData;
|
||||
|
||||
static gconstpointer
|
||||
TEST_L3_IPV4LL_TAG(const TestL3IPv4LLData *tdata, guint offset)
|
||||
{
|
||||
return (&(((const char *) tdata)[offset]));
|
||||
}
|
||||
|
||||
static void
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(const TestL3IPv4LLData *tdata,
|
||||
int ifindex,
|
||||
guint one_case_in_num,
|
||||
bool * has_addr,
|
||||
const char * addr)
|
||||
{
|
||||
if (has_addr) {
|
||||
if (*has_addr || !nmtst_get_rand_one_case_in(one_case_in_num))
|
||||
return;
|
||||
*has_addr = TRUE;
|
||||
}
|
||||
|
||||
if (ifindex == 0)
|
||||
ifindex = tdata->f->ifindex0;
|
||||
|
||||
g_assert_cmpint(ifindex, >, 0);
|
||||
|
||||
_LOGT("add test address: %s on ifindex=%d", addr, ifindex);
|
||||
|
||||
nmtstp_ip4_address_add(tdata->f->platform,
|
||||
-1,
|
||||
ifindex,
|
||||
nmtst_inet4_from_string(addr),
|
||||
24,
|
||||
nmtst_inet4_from_string(addr),
|
||||
100000,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_test_l3_ipv4ll_signal_notify(NML3Cfg * l3cfg,
|
||||
const NML3ConfigNotifyData *notify_data,
|
||||
TestL3IPv4LLData * tdata)
|
||||
{
|
||||
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
g_assert(NM_IS_L3CFG(l3cfg));
|
||||
g_assert(tdata);
|
||||
g_assert(notify_data);
|
||||
g_assert(_NM_INT_NOT_NEGATIVE(notify_data->notify_type));
|
||||
g_assert(notify_data->notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
|
||||
|
||||
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT) {
|
||||
g_assert(tdata->l3ipv4ll == notify_data->ipv4ll_event.ipv4ll);
|
||||
g_assert(NM_IN_SET(tdata->ready_seen, 0, 1));
|
||||
g_assert(NM_IN_SET(tdata->addr_commit, 0, 1));
|
||||
|
||||
if (nm_l3_ipv4ll_get_state(tdata->l3ipv4ll) == NM_L3_IPV4LL_STATE_READY) {
|
||||
g_assert_cmpint(tdata->ready_seen, ==, 0);
|
||||
g_assert_cmpint(tdata->addr_commit, ==, 0);
|
||||
tdata->ready_seen++;
|
||||
|
||||
if (tdata->f->test_idx == 2 && nmtst_get_rand_bool()) {
|
||||
tdata->addr_commit++;
|
||||
tdata->addr_commit_addr = nm_l3_ipv4ll_get_addr(tdata->l3ipv4ll);
|
||||
g_assert(nm_utils_ip4_address_is_link_local(tdata->addr_commit_addr));
|
||||
_LOGT("add address %s that passed ACD",
|
||||
_nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr));
|
||||
if (!nm_l3cfg_add_config(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
|
||||
TEST_L3_IPV4LL_TAG(tdata, 1),
|
||||
nmtst_get_rand_bool(),
|
||||
nm_l3_ipv4ll_get_l3cd(tdata->l3ipv4ll),
|
||||
NM_L3CFG_CONFIG_PRIORITY_IPV4LL,
|
||||
0,
|
||||
0,
|
||||
104,
|
||||
105,
|
||||
0,
|
||||
0,
|
||||
NM_L3_ACD_DEFEND_TYPE_ONCE,
|
||||
nmtst_get_rand_bool() ? tdata->acd_timeout_msec : 0u,
|
||||
NM_L3_CONFIG_MERGE_FLAGS_NONE))
|
||||
g_assert_not_reached();
|
||||
nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll));
|
||||
|
||||
tdata->l3cfg_commit_type_1 =
|
||||
nm_l3cfg_commit_type_register(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
|
||||
NM_L3_CFG_COMMIT_TYPE_UPDATE,
|
||||
tdata->l3cfg_commit_type_1);
|
||||
}
|
||||
} else if (nm_l3_ipv4ll_get_state(tdata->l3ipv4ll) != NM_L3_IPV4LL_STATE_DEFENDING
|
||||
&& tdata->ready_seen > 0) {
|
||||
g_assert_cmpint(tdata->ready_seen, ==, 1);
|
||||
tdata->ready_seen--;
|
||||
if (tdata->addr_commit > 0) {
|
||||
g_assert_cmpint(tdata->addr_commit, ==, 1);
|
||||
tdata->addr_commit--;
|
||||
g_assert(nm_utils_ip4_address_is_link_local(tdata->addr_commit_addr));
|
||||
_LOGT("remove address %s that previously passed ACD",
|
||||
_nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr));
|
||||
if (!nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
|
||||
TEST_L3_IPV4LL_TAG(tdata, 1),
|
||||
FALSE))
|
||||
g_assert_not_reached();
|
||||
nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll));
|
||||
nm_l3cfg_commit_type_unregister(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll),
|
||||
g_steal_pointer(&tdata->l3cfg_commit_type_1));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_l3_ipv4ll(gconstpointer test_data)
|
||||
{
|
||||
const int TEST_IDX = GPOINTER_TO_INT(test_data);
|
||||
nm_auto(_test_fixture_1_teardown) TestFixture1 test_fixture = {};
|
||||
const TestFixture1 * f;
|
||||
gs_unref_object NML3Cfg *l3cfg0 = NULL;
|
||||
TestL3IPv4LLData tdata_stack = {
|
||||
.f = NULL,
|
||||
};
|
||||
TestL3IPv4LLData *const tdata = &tdata_stack;
|
||||
NMTstpAcdDefender * acd_defender_1 = NULL;
|
||||
NMTstpAcdDefender * acd_defender_2 = NULL;
|
||||
nm_auto_unref_l3ipv4ll NML3IPv4LL * l3ipv4ll = NULL;
|
||||
gint64 start_time_msec;
|
||||
gint64 total_poll_time_msec;
|
||||
nm_auto_remove_l3ipv4ll_registration NML3IPv4LLRegistration *l3ipv4ll_reg = NULL;
|
||||
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
_LOGD("test start (/l3-ipv4ll/%d)", TEST_IDX);
|
||||
|
||||
if (nmtst_test_quick()) {
|
||||
gs_free char *msg =
|
||||
g_strdup_printf("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n",
|
||||
g_get_prgname() ?: "test-l3-ipv4ll");
|
||||
|
||||
g_test_skip(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
f = _test_fixture_1_setup(&test_fixture, TEST_IDX);
|
||||
|
||||
tdata->f = f;
|
||||
|
||||
if (tdata->f->test_idx == 1)
|
||||
tdata->acd_timeout_msec = 0;
|
||||
else
|
||||
tdata->acd_timeout_msec = L3IPV4LL_ACD_TIMEOUT_MSEC;
|
||||
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(tdata, 0, 4, &tdata->has_addr4_101, "192.168.133.101");
|
||||
|
||||
l3cfg0 = _netns_access_l3cfg(f->netns, f->ifindex0);
|
||||
|
||||
g_signal_connect(l3cfg0,
|
||||
NM_L3CFG_SIGNAL_NOTIFY,
|
||||
G_CALLBACK(_test_l3_ipv4ll_signal_notify),
|
||||
tdata);
|
||||
|
||||
l3ipv4ll = nm_l3_ipv4ll_new(l3cfg0);
|
||||
|
||||
tdata->l3ipv4ll = l3ipv4ll;
|
||||
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_ifindex(l3ipv4ll), ==, f->ifindex0);
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_state(l3ipv4ll), ==, NM_L3_IPV4LL_STATE_DISABLED);
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_addr(l3ipv4ll), ==, 0u);
|
||||
|
||||
if (tdata->f->test_idx == 1) {
|
||||
if (nmtst_get_rand_one_case_in(2))
|
||||
l3ipv4ll_reg = nm_l3_ipv4ll_register_new(l3ipv4ll, tdata->acd_timeout_msec);
|
||||
} else
|
||||
l3ipv4ll_reg = nm_l3_ipv4ll_register_new(l3ipv4ll, tdata->acd_timeout_msec);
|
||||
|
||||
g_assert(tdata->acd_timeout_msec == 0 || l3ipv4ll_reg);
|
||||
g_assert(!l3ipv4ll_reg || l3ipv4ll == nm_l3_ipv4ll_register_get_instance(l3ipv4ll_reg));
|
||||
|
||||
if (tdata->acd_timeout_msec == 0) {
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_state(l3ipv4ll), ==, NM_L3_IPV4LL_STATE_DISABLED);
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_addr(l3ipv4ll), ==, 0u);
|
||||
} else {
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_state(l3ipv4ll), ==, NM_L3_IPV4LL_STATE_PROBING);
|
||||
if (f->test_idx == 1) {
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_addr(l3ipv4ll),
|
||||
==,
|
||||
nmtst_inet4_from_string("169.254.30.158"));
|
||||
} else {
|
||||
g_assert_cmpint(nm_l3_ipv4ll_get_addr(l3ipv4ll),
|
||||
==,
|
||||
nmtst_inet4_from_string("169.254.17.45"));
|
||||
}
|
||||
g_assert(nm_l3_ipv4ll_get_l3cd(l3ipv4ll));
|
||||
}
|
||||
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(tdata, 0, 4, &tdata->has_addr4_101, "192.168.133.101");
|
||||
|
||||
if (tdata->f->test_idx == 2 && nmtst_get_rand_one_case_in(3)) {
|
||||
in_addr_t a = nm_l3_ipv4ll_get_addr(l3ipv4ll);
|
||||
|
||||
g_assert(nm_utils_ip4_address_is_link_local(a));
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(tdata,
|
||||
tdata->f->ifindex1,
|
||||
2,
|
||||
&tdata->add_conflict_done,
|
||||
_nm_utils_inet4_ntop(a, sbuf_addr));
|
||||
g_assert_cmpint(tdata->f->hwaddr1.len, ==, sizeof(NMEtherAddr));
|
||||
acd_defender_2 =
|
||||
nmtstp_acd_defender_new(tdata->f->ifindex1, a, &tdata->f->hwaddr1.ether_addr);
|
||||
}
|
||||
|
||||
start_time_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
total_poll_time_msec =
|
||||
(L3IPV4LL_ACD_TIMEOUT_MSEC * 3 / 2) + (nmtst_get_rand_uint32() % L3IPV4LL_ACD_TIMEOUT_MSEC);
|
||||
_LOGT("poll 1 start (wait %" G_GINT64_FORMAT " msec)", total_poll_time_msec);
|
||||
while (TRUE) {
|
||||
gint64 next_timeout_msec;
|
||||
|
||||
next_timeout_msec =
|
||||
start_time_msec + total_poll_time_msec - nm_utils_get_monotonic_timestamp_msec();
|
||||
if (next_timeout_msec <= 0)
|
||||
break;
|
||||
|
||||
next_timeout_msec = NM_MIN(next_timeout_msec, nmtst_get_rand_uint32() % 1000u);
|
||||
nmtst_main_context_iterate_until(NULL, next_timeout_msec, FALSE);
|
||||
_LOGT("poll 1 intermezzo");
|
||||
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(tdata,
|
||||
0,
|
||||
1 + total_poll_time_msec / 1000,
|
||||
&tdata->has_addr4_101,
|
||||
"192.168.133.101");
|
||||
|
||||
if (tdata->addr_commit == 1 && !tdata->add_conflict_checked) {
|
||||
tdata->add_conflict_checked = TRUE;
|
||||
_test_l3_ipv4ll_maybe_add_addr_4(
|
||||
tdata,
|
||||
tdata->f->ifindex1,
|
||||
2,
|
||||
&tdata->add_conflict_done,
|
||||
_nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr));
|
||||
if (tdata->add_conflict_done)
|
||||
total_poll_time_msec += L3IPV4LL_ACD_TIMEOUT_MSEC / 2;
|
||||
g_assert_cmpint(tdata->f->hwaddr1.len, ==, sizeof(NMEtherAddr));
|
||||
acd_defender_2 = nmtstp_acd_defender_new(tdata->f->ifindex1,
|
||||
tdata->addr_commit_addr,
|
||||
&tdata->f->hwaddr1.ether_addr);
|
||||
}
|
||||
}
|
||||
_LOGT("poll 1 end");
|
||||
|
||||
if (tdata->addr_commit || nmtst_get_rand_bool()) {
|
||||
nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(l3ipv4ll),
|
||||
TEST_L3_IPV4LL_TAG(tdata, 1),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
nmtstp_acd_defender_destory(g_steal_pointer(&acd_defender_1));
|
||||
nmtstp_acd_defender_destory(g_steal_pointer(&acd_defender_2));
|
||||
|
||||
nm_l3cfg_commit_type_unregister(l3cfg0, g_steal_pointer(&tdata->l3cfg_commit_type_1));
|
||||
|
||||
g_signal_handlers_disconnect_by_func(l3cfg0, G_CALLBACK(_test_l3_ipv4ll_signal_notify), tdata);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup;
|
||||
|
||||
void
|
||||
_nmtstp_init_tests(int *argc, char ***argv)
|
||||
{
|
||||
nmtst_init_with_logging(argc, argv, NULL, "ALL");
|
||||
nmtst_init_with_logging(argc, argv, "ERR", "ALL");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -478,4 +790,6 @@ _nmtstp_setup_tests(void)
|
|||
g_test_add_data_func("/l3cfg/2", GINT_TO_POINTER(2), test_l3cfg);
|
||||
g_test_add_data_func("/l3cfg/3", GINT_TO_POINTER(3), test_l3cfg);
|
||||
g_test_add_data_func("/l3cfg/4", GINT_TO_POINTER(4), test_l3cfg);
|
||||
g_test_add_data_func("/l3-ipv4ll/1", GINT_TO_POINTER(1), test_l3_ipv4ll);
|
||||
g_test_add_data_func("/l3-ipv4ll/2", GINT_TO_POINTER(2), test_l3_ipv4ll);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue