l3cfg: merge branch 'th/l3cfg-11'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/637
This commit is contained in:
Thomas Haller 2020-09-30 10:41:09 +02:00
commit 77ad359442
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
11 changed files with 892 additions and 609 deletions

View file

@ -96,6 +96,22 @@ typedef struct {
.ether_addr_octet = {__VA_ARGS__}, \
}
static inline int
nm_ether_addr_cmp(const NMEtherAddr *a, const NMEtherAddr *b)
{
NM_CMP_SELF(a, b);
NM_CMP_DIRECT_MEMCMP(a, b, sizeof(NMEtherAddr));
return 0;
}
static inline gboolean
nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b)
{
return nm_ether_addr_cmp(a, b) == 0;
}
/*****************************************************************************/
typedef struct {
union {
guint8 addr_ptr[1];
@ -248,126 +264,6 @@ gboolean nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr);
/*****************************************************************************/
#define NM_CMP_RETURN(c) \
G_STMT_START \
{ \
const int _cc = (c); \
if (_cc) \
return _cc < 0 ? -1 : 1; \
} \
G_STMT_END
#define NM_CMP_RETURN_DIRECT(c) \
G_STMT_START \
{ \
const int _cc = (c); \
if (_cc) \
return _cc; \
} \
G_STMT_END
#define NM_CMP_SELF(a, b) \
G_STMT_START \
{ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
\
if (_a == _b) \
return 0; \
if (!_a) \
return -1; \
if (!_b) \
return 1; \
} \
G_STMT_END
#define NM_CMP_DIRECT(a, b) \
G_STMT_START \
{ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
\
if (_a != _b) \
return (_a < _b) ? -1 : 1; \
} \
G_STMT_END
#define NM_CMP_DIRECT_UNSAFE(a, b) \
G_STMT_START \
{ \
if ((a) != (b)) \
return ((a) < (b)) ? -1 : 1; \
} \
G_STMT_END
/* In the general case, direct pointer comparison is undefined behavior in C.
* 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_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b)))
#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b)))
#define NM_CMP_DIRECT_IN6ADDR(a, b) \
G_STMT_START \
{ \
const struct in6_addr *const _a = (a); \
const struct in6_addr *const _b = (b); \
NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
} \
G_STMT_END
#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field))
#define NM_CMP_FIELD_UNSAFE(a, b, field) \
G_STMT_START \
{ \
/* it's unsafe, because it evaluates the arguments more then once.
* This is necessary for bitfields, for which typeof() doesn't work. */ \
if (((a)->field) != ((b)->field)) \
return ((a)->field < ((b)->field)) ? -1 : 1; \
} \
G_STMT_END
#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field))
#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field)))
#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \
G_STMT_START \
{ \
const char *_a = ((a)->field); \
const char *_b = ((b)->field); \
\
if (_a != _b) { \
NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \
} \
} \
G_STMT_END
#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field)))
#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))))
#define NM_CMP_FIELD_MEMCMP(a, b, field) \
NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field)))
#define NM_CMP_FIELD_IN6ADDR(a, b, field) \
G_STMT_START \
{ \
const struct in6_addr *const _a = &((a)->field); \
const struct in6_addr *const _b = &((b)->field); \
NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
} \
G_STMT_END
/*****************************************************************************/
gboolean nm_utils_memeqzero(gconstpointer data, gsize length);
/*****************************************************************************/

View file

@ -6,6 +6,7 @@
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
@ -43,6 +44,23 @@
/*****************************************************************************/
#ifdef __CHECKER__
#define _nm_bitwise __attribute__((__bitwise__))
#define _nm_force __attribute__((__force__))
#else
#define _nm_bitwise
#define _nm_force
#endif
typedef uint16_t _nm_bitwise nm_le16_t;
typedef uint16_t _nm_bitwise nm_be16_t;
typedef uint32_t _nm_bitwise nm_le32_t;
typedef uint32_t _nm_bitwise nm_be32_t;
typedef uint64_t _nm_bitwise nm_le64_t;
typedef uint64_t _nm_bitwise nm_be64_t;
/*****************************************************************************/
#ifdef thread_local
#define _nm_thread_local thread_local
/*
@ -749,6 +767,108 @@ nm_steal_fd(int *p_fd)
/*****************************************************************************/
#define NM_CMP_RETURN(c) \
do { \
const int _cc = (c); \
if (_cc) \
return _cc < 0 ? -1 : 1; \
} while (0)
#define NM_CMP_RETURN_DIRECT(c) \
do { \
const int _cc = (c); \
if (_cc) \
return _cc; \
} while (0)
#define NM_CMP_SELF(a, b) \
do { \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
\
if (_a == _b) \
return 0; \
if (!_a) \
return -1; \
if (!_b) \
return 1; \
} while (0)
#define NM_CMP_DIRECT(a, b) \
do { \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
\
if (_a != _b) \
return (_a < _b) ? -1 : 1; \
} while (0)
#define NM_CMP_DIRECT_UNSAFE(a, b) \
do { \
if ((a) != (b)) \
return ((a) < (b)) ? -1 : 1; \
} while (0)
/* In the general case, direct pointer comparison is undefined behavior in C.
* 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_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b)))
#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b)))
#define NM_CMP_DIRECT_IN6ADDR(a, b) \
do { \
const struct in6_addr *const _a = (a); \
const struct in6_addr *const _b = (b); \
NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
} while (0)
#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field))
#define NM_CMP_FIELD_UNSAFE(a, b, field) \
do { \
/* it's unsafe, because it evaluates the arguments more then once.
* This is necessary for bitfields, for which typeof() doesn't work. */ \
if (((a)->field) != ((b)->field)) \
return ((a)->field < ((b)->field)) ? -1 : 1; \
} while (0)
#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field))
#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field)))
#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \
do { \
const char *_a = ((a)->field); \
const char *_b = ((b)->field); \
\
if (_a != _b) { \
NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \
} \
} while (0)
#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field)))
#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))))
#define NM_CMP_FIELD_MEMCMP(a, b, field) \
NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field)))
#define NM_CMP_FIELD_IN6ADDR(a, b, field) \
do { \
const struct in6_addr *const _a = &((a)->field); \
const struct in6_addr *const _b = &((b)->field); \
NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
} while (0)
/*****************************************************************************/
#define NM_AF_UNSPEC 0 /* AF_UNSPEC */
#define NM_AF_INET 2 /* AF_INET */
#define NM_AF_INET6 10 /* AF_INET6 */

View file

@ -2514,17 +2514,34 @@ void
nm_l3_config_data_merge(NML3ConfigData * self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
const guint32 * default_route_table_x /* length 2, for IS_IPv4 */,
const guint32 * default_route_metric_x /* length 2, for IS_IPv4 */,
const guint32 * default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data)
{
NMDedupMultiIter iter;
const NMPObject *obj;
int IS_IPv4;
static const guint32 x_default_route_table_x[2] = {RT_TABLE_MAIN, RT_TABLE_MAIN};
static const guint32 x_default_route_metric_x[2] = {NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4};
static const guint32 x_default_route_penalty_x[2] = {0, 0};
NMDedupMultiIter iter;
const NMPObject * obj;
int IS_IPv4;
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(src, TRUE));
if (!default_route_table_x)
default_route_table_x = x_default_route_table_x;
if (!default_route_metric_x)
default_route_metric_x = x_default_route_metric_x;
if (!default_route_penalty_x)
default_route_penalty_x = x_default_route_penalty_x;
nm_assert(default_route_table_x[0] != 0);
nm_assert(default_route_table_x[1] != 0);
nm_assert(default_route_metric_x[0] != 0); /* IPv6 route metric cannot be zero. */
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
const int addr_family = IS_IPv4 ? AF_INET : AF_INET6;
const NML3ConfigDatFlags has_dns_priority_flag =
@ -2546,41 +2563,58 @@ nm_l3_config_data_merge(NML3ConfigData * self,
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES)) {
nm_l3_config_data_iter_obj_for_each(&iter, src, &obj, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))
{
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(NMP_OBJECT_CAST_IP_ROUTE(obj))) {
const NMPlatformIPRoute *r_src = NMP_OBJECT_CAST_IP_ROUTE(obj);
NMPlatformIPXRoute r;
#define _ensure_r() \
G_STMT_START \
{ \
if (r_src != &r.rx) { \
r_src = &r.rx; \
if (IS_IPv4) \
r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE(obj); \
else \
r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE(obj); \
r.rx.ifindex = self->ifindex; \
} \
} \
G_STMT_END
if (r_src->table_any) {
_ensure_r();
r.rx.table_any = FALSE;
r.rx.table_coerced = default_route_table_x[IS_IPv4];
}
if (r_src->metric_any) {
_ensure_r();
r.rx.metric_any = FALSE;
r.rx.metric_any = default_route_metric_x[IS_IPv4];
}
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES)
&& !NM_FLAGS_HAS(src->flags,
NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES))
continue;
if (default_route_penalty_x && default_route_penalty_x[IS_IPv4] > 0) {
NMPlatformIPXRoute r;
if (IS_IPv4)
r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE(obj);
else
r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE(obj);
r.rx.ifindex = self->ifindex;
_ensure_r();
r.rx.metric =
nm_utils_ip_route_metric_penalize(r.rx.metric,
default_route_penalty_x[IS_IPv4]);
nm_l3_config_data_add_route_full(self,
addr_family,
NULL,
&r.rx,
NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE,
NULL,
NULL);
continue;
}
}
nm_l3_config_data_add_route_full(self,
addr_family,
obj,
NULL,
r_src == &r.rx ? NULL : obj,
r_src == &r.rx ? r_src : NULL,
NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE,
NULL,
NULL);
}
#undef _ensure_r
}
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS))
@ -2666,6 +2700,6 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex)
ifindex = src->ifindex;
self = nm_l3_config_data_new(src->multi_idx, ifindex);
nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL);
nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL, NULL, NULL);
return self;
}

View file

@ -46,6 +46,15 @@ typedef enum {
/**
* NML3ConfigMergeFlags:
* @NM_L3_CONFIG_MERGE_FLAGS_NONE: no flags set
* @NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD: if this merge flag is set,
* the the NML3ConfigData doesn't get merged and it's information won't be
* synced. The only purpose is to run ACD on its IPv4 addresses, but
* regardless whether ACD succeeds/fails, the IP addresses won't be configured.
* The point is to run ACD first (without configuring it), and only
* commit the settings if requested. That can either happen by
* nm_l3cfg_add_config() the same NML3Cfg again (with a different
* tag), or by calling nm_l3cfg_add_config() again with this flag
* cleared (and the same tag).
* @NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES: don't merge routes
* @NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES: don't merge default routes.
* Note that if the respective NML3ConfigData has NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES
@ -54,9 +63,10 @@ typedef enum {
*/
typedef enum _nm_packed {
NM_L3_CONFIG_MERGE_FLAGS_NONE = 0,
NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 0),
NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 1),
NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 2),
NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD = (1LL << 0),
NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 1),
NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 2),
NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 3),
} NML3ConfigMergeFlags;
/*****************************************************************************/
@ -136,6 +146,8 @@ typedef gboolean (*NML3ConfigMergeHookAddObj)(const NML3ConfigData *l3cd,
void nm_l3_config_data_merge(NML3ConfigData * self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
const guint32 *default_route_table_x /* length 2, for IS_IPv4 */,
const guint32 *default_route_metric_x /* length 2, for IS_IPv4 */,
const guint32 *default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data);

View file

@ -6,6 +6,7 @@
#include <net/if.h>
#include <linux/if_addr.h>
#include <linux/rtnetlink.h>
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
@ -111,6 +112,20 @@ struct _NML3CfgCommitTypeHandle {
typedef struct {
const NML3ConfigData *l3cd;
NML3ConfigMergeFlags merge_flags;
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];
};
union {
struct {
guint32 default_route_penalty_6;
@ -163,7 +178,7 @@ typedef struct _NML3CfgPrivate {
/* This is for rate-limiting the creation of nacd instance. */
GSource *nacd_instance_ensure_retry;
GSource *acd_ready_on_idle_source;
GSource *commit_on_idle_source;
guint64 pseudo_timestamp_counter;
@ -232,6 +247,8 @@ G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
/*****************************************************************************/
static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle);
static void _property_emit_notify(NML3Cfg *self, NML3CfgPropertyEmitType emit_type);
static void _l3_acd_data_notify_acd_completed_all(NML3Cfg *self);
@ -266,6 +283,7 @@ static NM_UTILS_ENUM2STR_DEFINE(
_l3_config_notify_type_to_string,
NML3ConfigNotifyType,
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, "acd-complete"),
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"),
NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
@ -275,10 +293,9 @@ static NM_UTILS_ENUM2STR_DEFINE(
/*****************************************************************************/
static const char *
_l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *payload,
char * sbuf,
gsize sbuf_size)
_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;
@ -287,22 +304,31 @@ _l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType noti
nm_assert(sbuf);
nm_assert(sbuf_size > 0);
_l3_config_notify_type_to_string(notify_type, s, l);
_l3_config_notify_type_to_string(notify_data->notify_type, s, l);
nm_utils_strbuf_seek_end(&s, &l);
switch (notify_type) {
switch (notify_data->notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
nm_utils_strbuf_append(&s,
&l,
", addr=%s, probe-result=%d",
_nm_utils_inet4_ntop(payload->acd_completed.addr, sbuf_addr),
(int) payload->acd_completed.probe_result);
_nm_utils_inet4_ntop(notify_data->acd_completed.addr, sbuf_addr),
(int) notify_data->acd_completed.probe_result);
break;
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
nm_utils_strbuf_append(
&s,
&l,
", obj-type=%s, change=%s, obj=",
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);
break;
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
nm_utils_strbuf_append(&s,
&l,
", obj-type-flags=0x%x",
payload->platform_change_on_idle.obj_type_flags);
notify_data->platform_change_on_idle.obj_type_flags);
break;
default:
break;
@ -312,23 +338,26 @@ _l3_config_notify_type_and_payload_to_string(NML3ConfigNotifyType noti
}
void
_nm_l3cfg_emit_signal_notify(NML3Cfg * self,
NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *payload)
_nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_data)
{
char sbuf[100];
char sbuf[sizeof(_nm_utils_to_string_buffer)];
nm_assert(_NM_INT_NOT_NEGATIVE(notify_type));
nm_assert(notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
nm_assert((!!payload)
== NM_IN_SET(notify_type,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE));
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);
_LOGT("emit signal (%s)",
_l3_config_notify_type_and_payload_to_string(notify_type, payload, sbuf, sizeof(sbuf)));
_LOGT("emit signal (%s)", _l3_config_notify_data_to_string(notify_data, sbuf, sizeof(sbuf)));
g_signal_emit(self, signals[SIGNAL_NOTIFY], 0, (int) notify_type, payload);
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, &notify_data);
}
/*****************************************************************************/
@ -581,13 +610,19 @@ _load_link(NML3Cfg *self, gboolean initial)
gboolean nacd_link_now_up;
AcdData * acd_data;
obj = nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE);
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));
}
if (initial && obj == self->priv.pllink)
if (initial && obj == self->priv.plobj)
return;
obj_old = g_steal_pointer(&self->priv.pllink);
self->priv.pllink = nmp_object_ref(obj);
obj_old = g_steal_pointer(&self->priv.plobj);
self->priv.plobj = nmp_object_ref(obj);
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)))
@ -613,7 +648,7 @@ _load_link(NML3Cfg *self, gboolean initial)
} else if (nacd_new_valid)
nacd_changed = TRUE;
ifname_old = nmp_object_link_get_ifname(obj_old);
ifname = nmp_object_link_get_ifname(self->priv.pllink);
ifname = nmp_object_link_get_ifname(self->priv.plobj);
if (initial) {
_LOGT("link ifname changed: %s%s%s (initial)", NM_PRINT_FMT_QUOTE_STRING(ifname));
@ -641,18 +676,16 @@ _load_link(NML3Cfg *self, gboolean initial)
void
_nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags)
{
NML3ConfigNotifyPayload payload;
NML3ConfigNotifyData notify_data;
if (NM_FLAGS_ANY(obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_LINK)))
if (self->priv.plobj_next != self->priv.plobj)
_load_link(self, FALSE);
payload = (NML3ConfigNotifyPayload){
.platform_change_on_idle =
{
.obj_type_flags = obj_type_flags,
},
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,
};
_nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, &payload);
_nm_l3cfg_emit_signal_notify(self, &notify_data);
_l3_acd_data_notify_acd_completed_all(self);
@ -667,9 +700,23 @@ _nm_l3cfg_notify_platform_change(NML3Cfg * self,
NMPlatformSignalChangeType change_type,
const NMPObject * obj)
{
NML3ConfigNotifyData notify_data;
NMPObjectType obj_type;
nm_assert(NMP_OBJECT_IS_VALID(obj));
switch (NMP_OBJECT_GET_TYPE(obj)) {
obj_type = NMP_OBJECT_GET_TYPE(obj);
switch (obj_type) {
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;
}
case NMP_OBJECT_TYPE_IP4_ADDRESS:
_l3_acd_ipv4_addresses_on_link_update(self,
NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address,
@ -682,6 +729,15 @@ _nm_l3cfg_notify_platform_change(NML3Cfg * self,
default:
break;
}
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,
};
_nm_l3cfg_emit_signal_notify(self, &notify_data);
nm_assert(NMP_OBJECT_IS_VALID(obj));
}
/*****************************************************************************/
@ -920,18 +976,6 @@ _acd_data_find_track(const AcdData * acd_data,
/*****************************************************************************/
static void
_l3_acd_platform_commit_acd_update(NML3Cfg *self)
{
/* The idea with NML3Cfg is that multiple users (NMDevice/NMVpnConnection) share one layer 3 configuration
* and push their (portion of) IP configuration to it. That implies, that any user may issue nm_l3cfg_platform_commit()
* at any time, in order to say that a new configuration is ready.
*
* This makes the mechanism also suitable for internally triggering a commit when ACD completes. */
_LOGT("acd: acd update now");
nm_l3cfg_platform_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
}
static gboolean
_acd_has_valid_link(const NMPObject *obj,
const guint8 ** out_addr_bin,
@ -1035,9 +1079,9 @@ _l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data)
_LOGW("IPv4 address collision detection sees conflict on interface %i%s%s%s for "
"address %s from host %s",
self->priv.ifindex,
NM_PRINT_FMT_QUOTED(self->priv.pllink,
NM_PRINT_FMT_QUOTED(self->priv.plobj,
" (",
NMP_OBJECT_CAST_LINK(self->priv.pllink)->name,
NMP_OBJECT_CAST_LINK(self->priv.plobj)->name,
")",
""),
addr_str ?: _nm_utils_inet4_ntop(acd_data->addr, sbuf_addr),
@ -1084,8 +1128,7 @@ _l3_acd_nacd_instance_ensure_retry_cb(gpointer user_data)
nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry);
_l3_changed_configs_set_dirty(self);
_l3_acd_platform_commit_acd_update(self);
nm_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
return G_SOURCE_REMOVE;
}
@ -1106,12 +1149,8 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d
switch (start_timer) {
case NM_TERNARY_FALSE:
self->priv.p->nacd_instance_ensure_retry =
nm_g_idle_source_new(G_PRIORITY_DEFAULT,
_l3_acd_nacd_instance_ensure_retry_cb,
self,
NULL);
g_source_attach(self->priv.p->nacd_instance_ensure_retry, NULL);
_l3_changed_configs_set_dirty(self);
nm_l3cfg_commit_on_idle_schedule(self);
break;
case NM_TERNARY_TRUE:
self->priv.p->nacd_instance_ensure_retry =
@ -1161,7 +1200,7 @@ again:
return NULL;
}
valid = _acd_has_valid_link(self->priv.pllink, &addr_bin, &acd_not_supported);
valid = _acd_has_valid_link(self->priv.plobj, &addr_bin, &acd_not_supported);
if (!valid)
goto failed_create_acd;
@ -1383,20 +1422,6 @@ _l3_acd_data_add_all(NML3Cfg *self, const L3ConfigData *const *infos, guint info
_l3_acd_data_state_change(self, acd_data, ACD_STATE_CHANGE_MODE_INIT, NULL);
}
static gboolean
_l3_acd_ready_on_idle_cb(gpointer user_data)
{
NML3Cfg *self = user_data;
nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
_LOGT("acd: handle ACD changes on idle");
_l3_acd_platform_commit_acd_update(self);
return G_SOURCE_REMOVE;
}
static gboolean
_l3_acd_data_timeout_cb(gpointer user_data)
{
@ -1502,7 +1527,7 @@ _l3_acd_data_notify_acd_completed(NML3Cfg *self, AcdData *acd_data, gboolean for
{
gs_free NML3ConfigNotifyPayloadAcdFailedSource *sources_free = NULL;
NML3ConfigNotifyPayloadAcdFailedSource * sources = NULL;
NML3ConfigNotifyPayload payload;
NML3ConfigNotifyData notify_data;
AcdTrackData * acd_track;
guint i, n;
NMTernary acd_failed_notified_selector;
@ -1547,17 +1572,14 @@ _l3_acd_data_notify_acd_completed(NML3Cfg *self, AcdData *acd_data, gboolean for
}
nm_assert(i == n);
payload = (NML3ConfigNotifyPayload){
.acd_completed =
{
.addr = acd_data->addr,
.probe_result = acd_data->probe_result,
.sources_len = n,
.sources = sources,
},
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED;
notify_data.acd_completed = (typeof(notify_data.acd_completed)){
.addr = acd_data->addr,
.probe_result = acd_data->probe_result,
.sources_len = n,
.sources = sources,
};
_nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, &payload);
_nm_l3cfg_emit_signal_notify(self, &notify_data);
for (i = 0; i < n; i++) {
nmp_object_unref(sources[i].obj);
@ -2131,13 +2153,9 @@ handle_probe_done:
/* probing just completed. Schedule handling the change. */
_LOGT_acd(acd_data, "state: acd probe succeed");
_l3_acd_data_notify_acd_completed_queue(self, acd_data);
if (!self->priv.p->acd_ready_on_idle_source) {
if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
_l3_changed_configs_set_dirty(self);
self->priv.p->acd_ready_on_idle_source =
nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_acd_ready_on_idle_cb, self, NULL);
g_source_attach(self->priv.p->acd_ready_on_idle_source, NULL);
}
if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
_l3_changed_configs_set_dirty(self);
nm_l3cfg_commit_on_idle_schedule(self);
}
if (!acd_data->nacd_probe) {
@ -2213,6 +2231,33 @@ _l3_acd_data_process_changes(NML3Cfg *self)
/*****************************************************************************/
static gboolean
_l3_commit_on_idle_cb(gpointer user_data)
{
NML3Cfg *self = user_data;
nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
_LOGT("platform commit on idle");
_l3_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO, TRUE);
return G_SOURCE_REMOVE;
}
void
nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self)
{
nm_assert(NM_IS_L3CFG(self));
if (self->priv.p->commit_on_idle_source)
return;
self->priv.p->commit_on_idle_source =
nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_commit_on_idle_cb, self, NULL);
g_source_attach(self->priv.p->commit_on_idle_source, NULL);
}
/*****************************************************************************/
#define _l3_config_datas_at(l3_config_datas, idx) \
(&g_array_index((l3_config_datas), L3ConfigData, (idx)))
@ -2342,6 +2387,10 @@ nm_l3cfg_add_config(NML3Cfg * self,
gboolean replace_same_tag,
const NML3ConfigData *l3cd,
int priority,
guint32 default_route_table_4,
guint32 default_route_table_6,
guint32 default_route_metric_4,
guint32 default_route_metric_6,
guint32 default_route_penalty_4,
guint32 default_route_penalty_6,
guint32 acd_timeout_msec,
@ -2356,6 +2405,13 @@ nm_l3cfg_add_config(NML3Cfg * self,
nm_assert(l3cd);
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
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;
if (!self->priv.p->l3_config_datas) {
self->priv.p->l3_config_datas = g_array_new(FALSE, FALSE, sizeof(L3ConfigData));
g_object_ref(self);
@ -2396,6 +2452,10 @@ nm_l3cfg_add_config(NML3Cfg * self,
.tag = tag,
.l3cd = nm_l3_config_data_ref_and_seal(l3cd),
.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,
.acd_timeout_msec = acd_timeout_msec,
@ -2417,6 +2477,22 @@ nm_l3cfg_add_config(NML3Cfg * self,
l3_config_data->merge_flags = merge_flags;
changed = TRUE;
}
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;
}
if (l3_config_data->default_route_penalty_4 != default_route_penalty_4) {
l3_config_data->default_route_penalty_4 = default_route_penalty_4;
changed = TRUE;
@ -2569,11 +2645,18 @@ _l3cfg_update_combined_config(NML3Cfg * self,
self->priv.ifindex);
for (i = 0; i < l3_config_datas_len; i++) {
hook_data.tag = l3_config_datas_sorted[i]->tag;
const L3ConfigData *l3cd_data = l3_config_datas_sorted[i];
if (NM_FLAGS_HAS(l3cd_data->merge_flags, NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD))
continue;
hook_data.tag = l3cd_data->tag;
nm_l3_config_data_merge(l3cd,
l3_config_datas_sorted[i]->l3cd,
l3_config_datas_sorted[i]->merge_flags,
l3_config_datas_sorted[i]->default_route_penalty_x,
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,
_l3_hook_add_addr_cb,
&hook_data);
}
@ -2666,11 +2749,10 @@ _routes_temporary_not_available_timeout(gpointer user_data)
if (any_expired) {
/* a route expired. We emit a signal, but we don't schedule it again. That will
* only happen if the user calls nm_l3cfg_platform_commit() again. */
_nm_l3cfg_emit_signal_notify(
* only happen if the user calls nm_l3cfg_commit() again. */
_nm_l3cfg_emit_signal_notify_simple(
self,
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
NULL);
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED);
return G_SOURCE_REMOVE;
}
@ -2792,10 +2874,7 @@ out_prune:
/*****************************************************************************/
static gboolean
_platform_commit(NML3Cfg * self,
int addr_family,
NML3CfgCommitType commit_type,
gboolean * out_final_failure_for_temporary_not_available)
_l3_commit_one(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type)
{
const gboolean IS_IPv4 = NM_IS_IPv4(addr_family);
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
@ -2920,19 +2999,19 @@ _platform_commit(NML3Cfg * self,
routes_temporary_not_available_arr))
final_failure_for_temporary_not_available = TRUE;
if (final_failure_for_temporary_not_available)
NM_SET_OUT(out_final_failure_for_temporary_not_available, TRUE);
/* FIXME(l3cfg) */
(void) final_failure_for_temporary_not_available;
return success;
}
gboolean
nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
static void
_l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
{
gboolean commit_type_detected = FALSE;
gboolean success = TRUE;
char sbuf_ct[30];
g_return_val_if_fail(NM_IS_L3CFG(self), FALSE);
g_return_if_fail(NM_IS_L3CFG(self));
nm_assert(NM_IN_SET(commit_type,
NM_L3_CFG_COMMIT_TYPE_NONE,
NM_L3_CFG_COMMIT_TYPE_AUTO,
@ -2964,30 +3043,33 @@ nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
break;
}
_LOGT("platform-commit %s%s",
_LOGT("platform-commit %s%s%s",
_l3_cfg_commit_type_to_string(commit_type, sbuf_ct, sizeof(sbuf_ct)),
commit_type_detected ? " (auto)" : "");
commit_type_detected ? " (auto)" : "",
is_idle ? " (idle handler)" : "");
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
return TRUE;
return;
nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
_l3cfg_externally_removed_objs_drop(self);
/* FIXME(l3cfg): handle items currently not configurable in kernel. */
if (!_platform_commit(self, AF_INET, commit_type, NULL))
success = FALSE;
if (!_platform_commit(self, AF_INET6, commit_type, NULL))
success = FALSE;
_l3_commit_one(self, AF_INET, commit_type);
_l3_commit_one(self, AF_INET6, commit_type);
_l3_acd_data_process_changes(self);
_nm_l3cfg_emit_signal_notify(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, NULL);
_nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT);
}
return success;
void
nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type)
{
_l3_commit(self, commit_type, FALSE);
}
/*****************************************************************************/
@ -3015,7 +3097,7 @@ nm_l3cfg_commit_type_get(NML3Cfg *self)
* 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
* nm_l3cfg_platform_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
* nm_l3cfg_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
*
* Returns: a handle tracking the registration, or %NULL of @commit_type
* is %NM_L3_CFG_COMMIT_TYPE_NONE.
@ -3231,7 +3313,7 @@ finalize(GObject *object)
nm_assert(c_list_is_empty(&self->priv.p->commit_type_lst_head));
nm_clear_g_source_inst(&self->priv.p->acd_ready_on_idle_source);
nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source);
nm_assert(nm_g_array_len(self->priv.p->property_emit_list) == 0u);
@ -3257,7 +3339,8 @@ finalize(GObject *object)
nm_clear_l3cd(&self->priv.p->combined_l3cd_merged);
nm_clear_l3cd(&self->priv.p->combined_l3cd_commited);
nm_clear_pointer(&self->priv.pllink, nmp_object_unref);
nm_clear_pointer(&self->priv.plobj, nmp_object_unref);
nm_clear_pointer(&self->priv.plobj_next, nmp_object_unref);
nm_clear_pointer(&self->priv.p->acd_ipv4_addresses_on_link, g_hash_table_unref);
@ -3300,9 +3383,8 @@ nm_l3cfg_class_init(NML3CfgClass *klass)
0,
NULL,
NULL,
NULL,
g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE,
2,
G_TYPE_INT /* NML3ConfigNotifyType */,
G_TYPE_POINTER /* (const NML3ConfigNotifyPayload *) */);
1,
G_TYPE_POINTER /* (const NML3ConfigNotifyData *) */);
}

View file

@ -26,6 +26,12 @@ typedef enum {
/* emitted at the end of nm_l3cfg_platform_commit(). */
NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT,
/* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
* It re-emits the platform signal.
* Contrary to NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, this even
* is re-emitted synchronously. */
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
/* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
* It re-emits the signal on an idle handler. The purpose is for something
* like NMDevice which is already subscribed to these signals, it can get the
@ -42,6 +48,7 @@ typedef struct {
} NML3ConfigNotifyPayloadAcdFailedSource;
typedef struct {
NML3ConfigNotifyType notify_type;
union {
struct {
in_addr_t addr;
@ -50,11 +57,16 @@ typedef struct {
const NML3ConfigNotifyPayloadAcdFailedSource *sources;
} acd_completed;
struct {
const NMPObject * obj;
NMPlatformSignalChangeType change_type;
} platform_change;
struct {
guint32 obj_type_flags;
} platform_change_on_idle;
};
} NML3ConfigNotifyPayload;
} NML3ConfigNotifyData;
struct _NML3CfgPrivate;
@ -64,7 +76,8 @@ struct _NML3Cfg {
struct _NML3CfgPrivate *p;
NMNetns * netns;
NMPlatform * platform;
const NMPObject * pllink;
const NMPObject * plobj;
const NMPObject * plobj_next;
int ifindex;
bool changed_configs : 1;
} priv;
@ -86,6 +99,18 @@ void _nm_l3cfg_notify_platform_change(NML3Cfg * self,
/*****************************************************************************/
struct _NMDedupMultiIndex;
struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self);
static inline struct _NMDedupMultiIndex *
nm_l3cfg_get_multi_idx(const NML3Cfg *self)
{
return nm_netns_get_multi_idx(self->priv.netns);
}
/*****************************************************************************/
static inline int
nm_l3cfg_get_ifindex(const NML3Cfg *self)
{
@ -94,34 +119,36 @@ nm_l3cfg_get_ifindex(const NML3Cfg *self)
return self->priv.ifindex;
}
static inline const char *
nm_l3cfg_get_ifname(const NML3Cfg *self)
{
nm_assert(NM_IS_L3CFG(self));
return nmp_object_link_get_ifname(self->priv.pllink);
}
static inline const NMPObject *
nm_l3cfg_get_plobj(const NML3Cfg *self)
nm_l3cfg_get_plobj(const NML3Cfg *self, gboolean get_next)
{
if (!self)
return NULL;
nm_assert(NM_IS_L3CFG(self));
return self->priv.pllink;
if (get_next) {
/* This is the instance that we just got reported in the last signal from
* the platform cache. It's probably exactly the same as if you would look
* into the platform cache.
*
* On the other hand, we pick up changes only on an idle handler. So the last
* decisions were not made based on this, but instead of "plobj". */
return self->priv.plobj_next;
}
return self->priv.plobj;
}
static inline const NMPlatformLink *
nm_l3cfg_get_pllink(const NML3Cfg *self)
nm_l3cfg_get_pllink(const NML3Cfg *self, gboolean get_next)
{
if (!self)
return NULL;
return NMP_OBJECT_CAST_LINK(nm_l3cfg_get_plobj(self, get_next));
}
nm_assert(NM_IS_L3CFG(self));
return NMP_OBJECT_CAST_LINK(self->priv.pllink);
static inline const char *
nm_l3cfg_get_ifname(const NML3Cfg *self, gboolean get_next)
{
return nmp_object_link_get_ifname(nm_l3cfg_get_plobj(self, get_next));
}
static inline NMNetns *
@ -144,9 +171,7 @@ gboolean nm_l3cfg_get_acd_is_pending(NML3Cfg *self);
/*****************************************************************************/
void _nm_l3cfg_emit_signal_notify(NML3Cfg * self,
NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *pay_load);
void _nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_data);
/*****************************************************************************/
@ -174,6 +199,10 @@ gboolean nm_l3cfg_add_config(NML3Cfg * self,
gboolean replace_same_tag,
const NML3ConfigData *l3cd,
int priority,
guint32 default_route_table_4,
guint32 default_route_table_6,
guint32 default_route_metric_4,
guint32 default_route_metric_6,
guint32 default_route_penalty_4,
guint32 default_route_penalty_6,
guint32 acd_timeout_msec,
@ -215,7 +244,9 @@ typedef enum _nm_packed {
} NML3CfgCommitType;
gboolean nm_l3cfg_platform_commit(NML3Cfg *self, NML3CfgCommitType commit_type);
void nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type);
void nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self);
/*****************************************************************************/

View file

@ -95,7 +95,7 @@ nm_netns_get_multi_idx(NMNetns *self)
typedef struct {
int ifindex;
guint32 signal_pending_flag;
guint32 signal_pending_obj_type_flags;
NML3Cfg *l3cfg;
CList signal_pending_lst;
} L3CfgData;
@ -192,8 +192,9 @@ _platform_signal_on_idle_cb(gpointer user_data)
while ((l3cfg_data = c_list_first_entry(&work_list, L3CfgData, signal_pending_lst))) {
nm_assert(NM_IS_L3CFG(l3cfg_data->l3cfg));
c_list_unlink(&l3cfg_data->signal_pending_lst);
_nm_l3cfg_notify_platform_change_on_idle(l3cfg_data->l3cfg,
nm_steal_int(&l3cfg_data->signal_pending_flag));
_nm_l3cfg_notify_platform_change_on_idle(
l3cfg_data->l3cfg,
nm_steal_int(&l3cfg_data->signal_pending_obj_type_flags));
}
return G_SOURCE_REMOVE;
@ -217,7 +218,7 @@ _platform_signal_cb(NMPlatform * platform,
if (!l3cfg_data)
return;
l3cfg_data->signal_pending_flag |= nmp_object_type_to_flags(obj_type);
l3cfg_data->signal_pending_obj_type_flags |= nmp_object_type_to_flags(obj_type);
if (c_list_is_empty(&l3cfg_data->signal_pending_lst)) {
c_list_link_tail(&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst);

View file

@ -4704,7 +4704,10 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
NLA_PUT(msg, RTA_SRC, addr_len, &obj->ip6_route.src);
}
NLA_PUT_U32(msg, RTA_PRIORITY, obj->ip_route.metric);
NLA_PUT_U32(msg,
RTA_PRIORITY,
is_v4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route)
: nm_platform_ip6_route_get_effective_metric(&obj->ip6_route));
if (table > 0xFF)
NLA_PUT_U32(msg, RTA_TABLE, table);

View file

@ -3437,7 +3437,8 @@ nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_dat
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(obj->ip_route.table_coerced);
return nm_platform_route_table_is_main(
nm_platform_ip_route_get_effective_table(&obj->ip_route));
}
gboolean
@ -3446,7 +3447,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj
{
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
return nm_platform_route_table_is_main(obj->ip_route.table_coerced)
return nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&obj->ip_route))
&& obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
}
@ -4395,11 +4396,12 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
if (nm_platform_route_table_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced, TRUE)
if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
== RT_TABLE_LOCAL)
continue;
} else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) {
if (!nm_platform_route_table_is_main(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced))
if (!nm_platform_route_table_is_main(
nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))))
continue;
} else
nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
@ -4488,7 +4490,9 @@ nm_platform_ip_route_sync(NMPlatform *self,
continue;
}
if (!IS_IPv4 && NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->metric == 0) {
if (!IS_IPv4
&& nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
== 0) {
/* User space cannot add routes with metric 0. However, kernel can, and we might track such
* routes in @route as they are present external. Skip them silently. */
continue;
@ -4582,29 +4586,33 @@ sync_route_add:
if (vt->is_ip4) {
const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o);
nmp_object_stackinit(&oo,
NMP_OBJECT_TYPE_IP4_ROUTE,
&((NMPlatformIP4Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 32,
.metric = rt->metric,
.rt_source = rt->rt_source,
.table_coerced = rt->table_coerced,
}));
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP4_ROUTE,
&((NMPlatformIP4Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 32,
.metric = nm_platform_ip4_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
} else {
const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o);
nmp_object_stackinit(&oo,
NMP_OBJECT_TYPE_IP6_ROUTE,
&((NMPlatformIP6Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 128,
.metric = rt->metric,
.rt_source = rt->rt_source,
.table_coerced = rt->table_coerced,
}));
nmp_object_stackinit(
&oo,
NMP_OBJECT_TYPE_IP6_ROUTE,
&((NMPlatformIP6Route){
.ifindex = rt->ifindex,
.network = rt->gateway,
.plen = 128,
.metric = nm_platform_ip6_route_get_effective_metric(rt),
.rt_source = rt->rt_source,
.table_coerced = nm_platform_ip_route_get_effective_table(
NM_PLATFORM_IP_ROUTE_CAST(rt)),
}));
}
_LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct "
@ -4760,21 +4768,25 @@ nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route)
NMPlatformIP4Route *r4;
NMPlatformIP6Route *r6;
route->table_coerced =
nm_platform_route_table_coerce(nm_platform_ip_route_get_effective_table(route));
route->table_any = FALSE;
route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source);
switch (addr_family) {
case AF_INET:
r4 = (NMPlatformIP4Route *) route;
r4->table_coerced = nm_platform_route_table_coerce(
nm_platform_route_table_uncoerce(r4->table_coerced, TRUE));
r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r4->rt_source);
r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
route->metric = nm_platform_ip4_route_get_effective_metric(r4);
route->metric_any = FALSE;
r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen);
r4->scope_inv = _ip_route_scope_inv_get_normalized(r4);
break;
case AF_INET6:
r6 = (NMPlatformIP6Route *) route;
r6->table_coerced = nm_platform_route_table_coerce(
nm_platform_route_table_uncoerce(r6->table_coerced, TRUE));
route->metric = nm_platform_ip6_route_get_effective_metric(r6);
route->metric_any = FALSE;
nm_utils_ip6_address_clear_host_address(&r6->network, &r6->network, r6->plen);
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(r6->rt_source),
nm_utils_ip6_address_clear_host_address(&r6->src, &r6->src, r6->src_plen);
break;
default:
@ -6453,6 +6465,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_type[30];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@ -6470,30 +6483,33 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
"%s/%d"
" via %s"
"%s"
" metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* rtm_flags */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
" metric %s"
" mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* rtm_flags */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: "",
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: ""),
s_network,
route->plen,
s_gateway,
str_dev,
route->metric,
route->metric_any ? "??" : 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),
@ -6568,6 +6584,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
char str_initrwnd[32];
char str_mtu[32];
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
char str_metric[30];
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
return buf;
@ -6582,81 +6599,84 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
_to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
g_snprintf(buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
" via %s"
"%s"
" metric %" G_GUINT32_FORMAT " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* source */
"%s" /* rtm_flags */
"%s%s" /* pref-src */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* pref */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_coerced
g_snprintf(
buf,
len,
"type %s " /* type */
"%s" /* table */
"%s/%d"
" via %s"
"%s"
" metric %s"
" mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
"%s" /* source */
"%s" /* rtm_flags */
"%s%s" /* pref-src */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"%s" /* pref */
"",
nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced),
str_type,
sizeof(str_type)),
route->table_any
? "table ?? "
: (route->table_coerced
? nm_sprintf_buf(str_table,
"table %u ",
nm_platform_route_table_uncoerce(route->table_coerced, FALSE))
: "",
s_network,
route->plen,
s_gateway,
str_dev,
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)
? nm_sprintf_buf(s_src_all,
" src %s/%u",
_nm_utils_inet6_ntop(&route->src, s_src),
(unsigned) route->src_plen)
: "",
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->window || route->lock_window
? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->rt_pref ? nm_sprintf_buf(
str_pref,
" pref %s",
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
: "");
: ""),
s_network,
route->plen,
s_gateway,
str_dev,
route->metric_any ? "??" : 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)
? nm_sprintf_buf(s_src_all,
" src %s/%u",
_nm_utils_inet6_ntop(&route->src, s_src),
(unsigned) route->src_plen)
: "",
_rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags),
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->window || route->lock_window ? nm_sprintf_buf(str_window,
" window %s%" G_GUINT32_FORMAT,
route->lock_window ? "lock " : "",
route->window)
: "",
route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd,
" cwnd %s%" G_GUINT32_FORMAT,
route->lock_cwnd ? "lock " : "",
route->cwnd)
: "",
route->initcwnd || route->lock_initcwnd
? nm_sprintf_buf(str_initcwnd,
" initcwnd %s%" G_GUINT32_FORMAT,
route->lock_initcwnd ? "lock " : "",
route->initcwnd)
: "",
route->initrwnd || route->lock_initrwnd
? nm_sprintf_buf(str_initrwnd,
" initrwnd %s%" G_GUINT32_FORMAT,
route->lock_initrwnd ? "lock " : "",
route->initrwnd)
: "",
route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu,
" mtu %s%" G_GUINT32_FORMAT,
route->lock_mtu ? "lock " : "",
route->mtu)
: "",
route->rt_pref ? nm_sprintf_buf(
str_pref,
" pref %s",
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
: "");
return buf;
}
@ -7891,67 +7911,75 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
{
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(h,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos);
nm_hash_update_vals(
h,
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->tos,
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->tos,
/* on top of WEAK_ID: */
obj->ifindex,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->gateway,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & RTNH_F_ONLINK,
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
nm_hash_update_vals(
h,
obj->type_coerced,
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->tos,
/* on top of WEAK_ID: */
obj->ifindex,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->gateway,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & RTNH_F_ONLINK,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
obj->ifindex,
nm_utils_ip4_address_clear_host_address(obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(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->gateway,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
_ip_route_scope_inv_get_normalized(obj),
obj->tos,
obj->mss,
obj->pref_src,
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK),
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@ -7960,7 +7988,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->ifindex,
obj->network,
obj->plen,
obj->metric,
nm_platform_ip4_route_get_effective_metric(obj),
obj->gateway,
obj->rt_source,
obj->scope_inv,
@ -7974,6 +8002,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
obj->mtu,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@ -7992,11 +8022,14 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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);
@ -8024,9 +8057,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@ -8035,7 +8069,9 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
else
NM_CMP_FIELD(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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),
@ -8078,54 +8114,61 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
nm_hash_update_vals(h,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen);
nm_hash_update_vals(
h,
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),
*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));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
/* on top of WEAK_ID: */
obj->ifindex,
obj->gateway);
nm_hash_update_vals(
h,
obj->type_coerced,
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),
*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),
/* on top of WEAK_ID: */
obj->ifindex,
obj->gateway);
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
nm_hash_update_vals(h,
obj->type_coerced,
nm_platform_route_table_uncoerce(obj->table_coerced, TRUE),
obj->ifindex,
*nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen),
obj->plen,
obj->metric,
obj->gateway,
obj->pref_src,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
obj->mss,
obj->r_rtm_flags & RTM_F_CLONED,
NM_HASH_COMBINE_BOOLS(guint8,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
_route_pref_normalize(obj->rt_pref));
nm_hash_update_vals(
h,
obj->type_coerced,
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(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->gateway,
obj->pref_src,
*nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen),
obj->src_plen,
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
obj->mss,
obj->r_rtm_flags & RTM_F_CLONED,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
obj->lock_initrwnd,
obj->lock_mtu),
obj->window,
obj->cwnd,
obj->initcwnd,
obj->initrwnd,
obj->mtu,
_route_pref_normalize(obj->rt_pref));
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
nm_hash_update_vals(h,
@ -8133,8 +8176,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->table_coerced,
obj->ifindex,
obj->network,
obj->plen,
obj->metric,
nm_platform_ip6_route_get_effective_metric(obj),
obj->gateway,
obj->pref_src,
obj->src,
@ -8143,6 +8185,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
obj->mss,
obj->r_rtm_flags,
NM_HASH_COMBINE_BOOLS(guint8,
obj->metric_any,
obj->table_any,
obj->lock_window,
obj->lock_cwnd,
obj->lock_initcwnd,
@ -8167,11 +8211,14 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
switch (cmp_type) {
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_FIELD_UNSAFE(a, b, table_any);
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen));
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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) {
@ -8183,9 +8230,10 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL:
NM_CMP_FIELD(a, b, type_coerced);
NM_CMP_FIELD_UNSAFE(a, b, table_any);
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
NM_CMP_DIRECT(nm_platform_route_table_uncoerce(a->table_coerced, TRUE),
nm_platform_route_table_uncoerce(b->table_coerced, TRUE));
NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)),
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b)));
} else
NM_CMP_FIELD(a, b, table_coerced);
NM_CMP_FIELD(a, b, ifindex);
@ -8194,7 +8242,9 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
else
NM_CMP_FIELD_IN6ADDR(a, b, network);
NM_CMP_FIELD(a, b, plen);
NM_CMP_FIELD(a, b, metric);
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
if (!a->metric_any)
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) {

View file

@ -148,10 +148,17 @@ typedef enum {
} NMPlatformRoutingRuleCmpType;
typedef struct {
guint8 data[20 /* NM_UTILS_HWADDR_LEN_MAX */];
union {
guint8 data[20 /* NM_UTILS_HWADDR_LEN_MAX */];
NMEtherAddr ether_addr;
};
guint8 len;
} NMPLinkAddress;
/* assert that NMEtherAddr does not affect the alignment of NMPLinkAddress struct. */
G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) == 1);
G_STATIC_ASSERT(_nm_alignof(NMPLinkAddress) == 1);
gconstpointer nmp_link_address_get(const NMPLinkAddress *addr, size_t *length);
GBytes * nmp_link_address_get_as_bytes(const NMPLinkAddress *addr);
@ -390,22 +397,22 @@ typedef union {
* Note that contrary to IPv6, you can add routes with metric 0 and it is even
* the default.
*/
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 ((guint32) 0u)
/* Default value for adding an IPv6 route. This is also what iproute2 does.
* Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024).
*
* Note that kernel doesn't allow adding IPv6 routes with metric zero via netlink.
* It however can itself add routes with metric zero. */
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 ((guint32) 1024u)
/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user
* configures addresses. */
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
#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
@ -417,11 +424,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
@ -432,15 +439,24 @@ 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; \
\
* 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; \
\
/* like "metric_any", the table is determined by other layers of the code.
* This field overrides "table_coerced" field. */ \
bool table_any : 1; \
\
/* rtnh_flags
*
* Routes with rtm_flags RTM_F_CLONED are hidden by platform and
@ -450,44 +466,44 @@ 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) */ \
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 {
@ -1311,7 +1327,7 @@ nm_platform_route_table_coerce(guint32 table)
/**
* nm_platform_route_table_uncoerce:
* @table: the route table, in its coerced value
* @table_coerced: the route table, in its coerced value
* @normalize: whether to normalize RT_TABLE_UNSPEC to
* RT_TABLE_MAIN. For kernel, routes with a table id
* RT_TABLE_UNSPEC do not exist and are treated like
@ -2053,6 +2069,34 @@ nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddre
void nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route);
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;
}
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;
}
static inline guint32
nm_platform_ip_route_get_effective_table(const NMPlatformIPRoute *r)
{
nm_assert(r);
nm_assert(!r->table_any || r->table_coerced == 0);
return r->table_any ? 254u /* RT_TABLE_MAIN */
: nm_platform_route_table_uncoerce(r->table_coerced, TRUE);
}
static inline gconstpointer
nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route)
{

View file

@ -116,43 +116,45 @@ _test_l3cfg_data_set_notify_type(TestL3cfgData *tdata, TestL3cfgNotifyType notif
}
static void
_test_l3cfg_signal_notify(NML3Cfg * l3cfg,
int notify_type_i,
const NML3ConfigNotifyPayload *payload,
TestL3cfgData * tdata)
_test_l3cfg_signal_notify(NML3Cfg * l3cfg,
const NML3ConfigNotifyData *notify_data,
TestL3cfgData * tdata)
{
NML3ConfigNotifyType l3_notify_type = notify_type_i;
g_assert(NM_IS_L3CFG(l3cfg));
g_assert(tdata);
g_assert((!!payload)
== NM_IN_SET(l3_notify_type,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED));
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 (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
g_assert(payload->platform_change_on_idle.obj_type_flags != 0u);
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
g_assert(notify_data->platform_change_on_idle.obj_type_flags != 0u);
else if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE) {
g_assert(NMP_OBJECT_IS_VALID(notify_data->platform_change.obj));
g_assert(notify_data->platform_change.change_type != 0);
}
switch (tdata->notify_type) {
case TEST_L3CFG_NOTIFY_TYPE_NONE:
g_assert_not_reached();
break;
case TEST_L3CFG_NOTIFY_TYPE_IDLE_ASSERT_NO_SIGNAL:
if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
if (NM_IN_SET(notify_data->notify_type,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE))
return;
g_assert_not_reached();
return;
case TEST_L3CFG_NOTIFY_TYPE_COMMIT_1:
g_assert_cmpint(tdata->post_commit_event_count, ==, 0);
switch (l3_notify_type) {
switch (notify_data->notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
tdata->post_commit_event_count++;
return;
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
switch (tdata->f->test_idx) {
case 2:
nmtst_assert_ip4_address(payload->acd_completed.addr, "192.167.133.45");
g_assert(payload->acd_completed.probe_result);
nmtst_assert_ip4_address(notify_data->acd_completed.addr, "192.167.133.45");
g_assert(notify_data->acd_completed.probe_result);
g_assert(tdata->general_event_count == 0);
tdata->general_event_count++;
return;
@ -160,19 +162,23 @@ _test_l3cfg_signal_notify(NML3Cfg * l3cfg,
g_assert_not_reached();
return;
}
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
return;
default:
g_assert_not_reached();
return;
}
case TEST_L3CFG_NOTIFY_TYPE_WAIT_FOR_ACD_READY_1:
if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE)
if (NM_IN_SET(notify_data->notify_type,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE))
return;
if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED) {
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED) {
g_assert(tdata->notify_data.wait_for_acd_ready_1.cb_count == 0);
tdata->notify_data.wait_for_acd_ready_1.cb_count++;
return;
}
if (l3_notify_type == NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT) {
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT) {
g_assert(tdata->notify_data.wait_for_acd_ready_1.cb_count == 1);
tdata->notify_data.wait_for_acd_ready_1.cb_count++;
nmtstp_platform_ip_addresses_assert(tdata->f->platform,
@ -276,6 +282,10 @@ test_l3cfg(gconstpointer test_data)
'a',
0,
0,
NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
0,
0,
acd_timeout_msec,
NM_L3_CONFIG_MERGE_FLAGS_NONE);
}
@ -287,7 +297,7 @@ test_l3cfg(gconstpointer test_data)
LOGD_PLATFORM);
_test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_COMMIT_1);
nm_l3cfg_platform_commit(l3cfg0, NM_L3_CFG_COMMIT_TYPE_REAPPLY);
nm_l3cfg_commit(l3cfg0, NM_L3_CFG_COMMIT_TYPE_REAPPLY);
g_assert_cmpint(tdata->post_commit_event_count, ==, 1);
_test_l3cfg_data_set_notify_type(tdata, TEST_L3CFG_NOTIFY_TYPE_NONE);