mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-09 02:28:18 +02:00
core: merge branch 'th/routing-rule-pt1'
https://github.com/NetworkManager/NetworkManager/pull/306
This commit is contained in:
commit
d62dd09772
20 changed files with 3141 additions and 265 deletions
|
|
@ -1795,6 +1795,8 @@ src_libNetworkManagerBase_la_SOURCES = \
|
||||||
src/platform/nm-platform-private.h \
|
src/platform/nm-platform-private.h \
|
||||||
src/platform/nm-linux-platform.c \
|
src/platform/nm-linux-platform.c \
|
||||||
src/platform/nm-linux-platform.h \
|
src/platform/nm-linux-platform.h \
|
||||||
|
src/platform/nmp-rules-manager.c \
|
||||||
|
src/platform/nmp-rules-manager.h \
|
||||||
src/platform/wifi/nm-wifi-utils-nl80211.c \
|
src/platform/wifi/nm-wifi-utils-nl80211.c \
|
||||||
src/platform/wifi/nm-wifi-utils-nl80211.h \
|
src/platform/wifi/nm-wifi-utils-nl80211.h \
|
||||||
src/platform/wifi/nm-wifi-utils-private.h \
|
src/platform/wifi/nm-wifi-utils-private.h \
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ NM-colorize() {
|
||||||
GREP_COLOR='01;31' grep -a --color=always '^\|^\(.* \)\?<\(warn> \|error>\) \[[0-9.]*\]' | \
|
GREP_COLOR='01;31' grep -a --color=always '^\|^\(.* \)\?<\(warn> \|error>\) \[[0-9.]*\]' | \
|
||||||
GREP_COLOR='01;33' grep -a --color=always '^\|^\(.* \)\?<info> \[[0-9.]*\]\( .*\<is starting\>.*$\)\?' | \
|
GREP_COLOR='01;33' grep -a --color=always '^\|^\(.* \)\?<info> \[[0-9.]*\]\( .*\<is starting\>.*$\)\?' | \
|
||||||
GREP_COLOR='01;37' grep -a --color=always '^\|\<platform:\( (.*)\)\? signal: .*$' | \
|
GREP_COLOR='01;37' grep -a --color=always '^\|\<platform:\( (.*)\)\? signal: .*$' | \
|
||||||
GREP_COLOR='01;34' grep -a --color=always '^\|\<platform\(-linux\)\?:\( (.*)\)\? link: \(add\|adding\|change\|setting\|deleting\)\>\|\<platform:\( (.*)\)\? address: \(deleting\|adding or updating\) IPv. address:\? \|\<platform:\( (.*)\)\? \(route\|ip4-route\|ip6-route\|qdisc\|tfilter\): \([a-z]\+\|adding or updating\|new\[0x[0-9A-Za-z]*\]\) \|\<platform-linux: sysctl: setting ' | \
|
GREP_COLOR='01;34' grep -a --color=always '^\|\<platform\(-linux\)\?:\( (.*)\)\? link: \(add\|adding\|change\|setting\|deleting\)\>\|\<platform: routing-rule: \(adding or updating:\|delete \)\|\<platform:\( (.*)\)\? address: \(deleting\|adding or updating\) IPv. address:\? \|\<platform:\( (.*)\)\? \(route\|ip4-route\|ip6-route\|qdisc\|tfilter\): \([a-z]\+\|adding or updating\|new\[0x[0-9A-Za-z]*\]\) \|\<platform-linux: sysctl: setting ' | \
|
||||||
GREP_COLOR='01;35' grep -a --color=always '^\|\<audit: .*$' | \
|
GREP_COLOR='01;35' grep -a --color=always '^\|\<audit: .*$' | \
|
||||||
GREP_COLOR='01;32' grep -a --color=always '^\|\<device (.*): state change: ' |
|
GREP_COLOR='01;32' grep -a --color=always '^\|\<device (.*): state change: ' |
|
||||||
if [[ "$NM_LOG_GREP" != "" ]]; then
|
if [[ "$NM_LOG_GREP" != "" ]]; then
|
||||||
|
|
@ -77,7 +77,7 @@ NM-log() {
|
||||||
fi
|
fi
|
||||||
) | \
|
) | \
|
||||||
NM_LOG_GREP="$NM_LOG_GREP" NM-colorize | \
|
NM_LOG_GREP="$NM_LOG_GREP" NM-colorize | \
|
||||||
LESS=FRSXM less -R
|
LESS=FRSXM less -R --shift=5
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ "$NM_not_sourced" != "" ]]; then
|
if [[ "$NM_not_sourced" != "" ]]; then
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,27 @@ void c_list_sort (CList *head,
|
||||||
CListSortCmp cmp,
|
CListSortCmp cmp,
|
||||||
const void *user_data);
|
const void *user_data);
|
||||||
|
|
||||||
|
/* c_list_length_is:
|
||||||
|
* @list: the #CList list head
|
||||||
|
* @check_len: the length to compare
|
||||||
|
*
|
||||||
|
* Returns: basically the same as (c_list_length (@list) == @check_len),
|
||||||
|
* but does not require to iterate the entire list first. There is only
|
||||||
|
* one real use: to find out whether there is exactly one element in the
|
||||||
|
* list, by passing @check_len as 1.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
c_list_length_is (const CList *list, unsigned long check_len) {
|
||||||
|
unsigned long n = 0;
|
||||||
|
const CList *iter;
|
||||||
|
|
||||||
|
c_list_for_each (iter, list) {
|
||||||
|
++n;
|
||||||
|
if (n > check_len)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n == check_len;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __C_LIST_UTIL_H__ */
|
#endif /* __C_LIST_UTIL_H__ */
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,11 @@ nm_hash_complete_u64 (NMHashState *state)
|
||||||
* from nm_hash_complete() in two ways:
|
* from nm_hash_complete() in two ways:
|
||||||
*
|
*
|
||||||
* - the type, guint64 vs. guint.
|
* - the type, guint64 vs. guint.
|
||||||
* - nm_hash_complete() never returns zero. */
|
* - nm_hash_complete() never returns zero.
|
||||||
|
*
|
||||||
|
* In practice, nm_hash*() API is implemented via siphash24, so this returns
|
||||||
|
* the siphash24 value. But that is not guaranteed by the API, and if you need
|
||||||
|
* siphash24 directly, use c_siphash_*() and nm_hash_siphash42*() API. */
|
||||||
return c_siphash_finalize (&state->_state);
|
return c_siphash_finalize (&state->_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,4 +291,25 @@ gboolean nm_pstr_equal (gconstpointer a, gconstpointer b);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define NM_HASH_OBFUSCATE_PTR_FMT "%016llx"
|
||||||
|
|
||||||
|
/* sometimes we want to log a pointer directly, for providing context/information about
|
||||||
|
* the message that get logged. Logging pointer values directly defeats ASLR, so we should
|
||||||
|
* not do that. This returns a "unsigned long long" value that can be used
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* Note that there is a chance that two different pointer values hash to the same obfuscated
|
||||||
|
* value. So beware of that when reviewing logs. However, such a collision is very unlikely. */
|
||||||
|
#define nm_hash_obfuscate_ptr(static_seed, val) \
|
||||||
|
({ \
|
||||||
|
NMHashState _h; \
|
||||||
|
const void *_val_obf_ptr = (val); \
|
||||||
|
\
|
||||||
|
nm_hash_init (&_h, (static_seed)); \
|
||||||
|
nm_hash_update_val (&_h, _val_obf_ptr); \
|
||||||
|
(unsigned long long) nm_hash_complete_u64 (&_h); \
|
||||||
|
})
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
#endif /* __NM_HASH_UTILS_H__ */
|
#endif /* __NM_HASH_UTILS_H__ */
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ sources = files(
|
||||||
'platform/nm-platform-utils.c',
|
'platform/nm-platform-utils.c',
|
||||||
'platform/nmp-netns.c',
|
'platform/nmp-netns.c',
|
||||||
'platform/nmp-object.c',
|
'platform/nmp-object.c',
|
||||||
|
'platform/nmp-rules-manager.c',
|
||||||
'main-utils.c',
|
'main-utils.c',
|
||||||
'NetworkManagerUtils.c',
|
'NetworkManagerUtils.c',
|
||||||
'nm-core-utils.c',
|
'nm-core-utils.c',
|
||||||
|
|
|
||||||
|
|
@ -115,13 +115,13 @@ _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
|
||||||
if (!obj_new) {
|
if (!obj_new) {
|
||||||
nm_assert (pl_new);
|
nm_assert (pl_new);
|
||||||
obj_new = nmp_object_stackinit (&obj_new_stackinit, idx_type->obj_type, pl_new);
|
obj_new = nmp_object_stackinit (&obj_new_stackinit, idx_type->obj_type, pl_new);
|
||||||
obj_new_stackinit.object.ifindex = ifindex;
|
NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (&obj_new_stackinit)->ifindex = ifindex;
|
||||||
} else {
|
} else {
|
||||||
nm_assert (!pl_new);
|
nm_assert (!pl_new);
|
||||||
nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type);
|
nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type);
|
||||||
if (obj_new->object.ifindex != ifindex) {
|
if (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_new)->ifindex != ifindex) {
|
||||||
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
|
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
|
||||||
obj_new_stackinit.object.ifindex = ifindex;
|
NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (&obj_new_stackinit)->ifindex = ifindex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type);
|
nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type);
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,11 @@
|
||||||
|
|
||||||
#include "nm-utils/nm-dedup-multi.h"
|
#include "nm-utils/nm-dedup-multi.h"
|
||||||
|
|
||||||
|
#include "NetworkManagerUtils.h"
|
||||||
|
#include "nm-core-internal.h"
|
||||||
#include "platform/nm-platform.h"
|
#include "platform/nm-platform.h"
|
||||||
#include "platform/nmp-netns.h"
|
#include "platform/nmp-netns.h"
|
||||||
#include "nm-core-internal.h"
|
#include "platform/nmp-rules-manager.h"
|
||||||
#include "NetworkManagerUtils.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -38,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NMPlatform *platform;
|
NMPlatform *platform;
|
||||||
NMPNetns *platform_netns;
|
NMPNetns *platform_netns;
|
||||||
|
NMPRulesManager *rules_manager;
|
||||||
} NMNetnsPrivate;
|
} NMNetnsPrivate;
|
||||||
|
|
||||||
struct _NMNetns {
|
struct _NMNetns {
|
||||||
|
|
@ -71,6 +73,12 @@ nm_netns_get_platform (NMNetns *self)
|
||||||
return NM_NETNS_GET_PRIVATE (self)->platform;
|
return NM_NETNS_GET_PRIVATE (self)->platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NMPRulesManager *
|
||||||
|
nm_netns_get_rules_manager (NMNetns *self)
|
||||||
|
{
|
||||||
|
return NM_NETNS_GET_PRIVATE (self)->rules_manager;
|
||||||
|
}
|
||||||
|
|
||||||
NMDedupMultiIndex *
|
NMDedupMultiIndex *
|
||||||
nm_netns_get_multi_idx (NMNetns *self)
|
nm_netns_get_multi_idx (NMNetns *self)
|
||||||
{
|
{
|
||||||
|
|
@ -118,6 +126,8 @@ constructed (GObject *object)
|
||||||
|
|
||||||
priv->platform_netns = nm_platform_netns_get (priv->platform);
|
priv->platform_netns = nm_platform_netns_get (priv->platform);
|
||||||
|
|
||||||
|
priv->rules_manager = nmp_rules_manager_new (priv->platform, TRUE);
|
||||||
|
|
||||||
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
|
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,6 +147,8 @@ dispose (GObject *object)
|
||||||
|
|
||||||
g_clear_object (&priv->platform);
|
g_clear_object (&priv->platform);
|
||||||
|
|
||||||
|
nm_clear_pointer (&priv->rules_manager, nmp_rules_manager_unref);
|
||||||
|
|
||||||
G_OBJECT_CLASS (nm_netns_parent_class)->dispose (object);
|
G_OBJECT_CLASS (nm_netns_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ NMNetns *nm_netns_new (NMPlatform *platform);
|
||||||
NMPlatform *nm_netns_get_platform (NMNetns *self);
|
NMPlatform *nm_netns_get_platform (NMNetns *self);
|
||||||
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
|
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
|
||||||
|
|
||||||
|
struct _NMPRulesManager *nm_netns_get_rules_manager (NMNetns *self);
|
||||||
|
|
||||||
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
|
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
|
||||||
|
|
||||||
#define NM_NETNS_GET (nm_netns_get ())
|
#define NM_NETNS_GET (nm_netns_get ())
|
||||||
|
|
|
||||||
|
|
@ -119,15 +119,16 @@ NM_IS_IP_CONFIG_SOURCE_RTPROT (NMIPConfigSource source)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* platform */
|
/* platform */
|
||||||
typedef struct _NMPlatform NMPlatform;
|
typedef struct _NMPlatform NMPlatform;
|
||||||
typedef struct _NMPlatformObject NMPlatformObject;
|
typedef struct _NMPlatformObject NMPlatformObject;
|
||||||
typedef struct _NMPlatformIP4Address NMPlatformIP4Address;
|
typedef struct _NMPlatformObjWithIfindex NMPlatformObjWithIfindex;
|
||||||
typedef struct _NMPlatformIP4Route NMPlatformIP4Route;
|
typedef struct _NMPlatformIP4Address NMPlatformIP4Address;
|
||||||
typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
|
typedef struct _NMPlatformIP4Route NMPlatformIP4Route;
|
||||||
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
|
typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
|
||||||
typedef struct _NMPlatformLink NMPlatformLink;
|
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
|
||||||
typedef struct _NMPNetns NMPNetns;
|
typedef struct _NMPlatformLink NMPlatformLink;
|
||||||
typedef struct _NMPObject NMPObject;
|
typedef struct _NMPNetns NMPNetns;
|
||||||
|
typedef struct _NMPObject NMPObject;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Please don't interpret type numbers outside nm-platform and use functions
|
/* Please don't interpret type numbers outside nm-platform and use functions
|
||||||
|
|
@ -192,6 +193,7 @@ typedef enum {
|
||||||
NMP_OBJECT_TYPE_IP6_ADDRESS,
|
NMP_OBJECT_TYPE_IP6_ADDRESS,
|
||||||
NMP_OBJECT_TYPE_IP4_ROUTE,
|
NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE,
|
NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||||
|
NMP_OBJECT_TYPE_ROUTING_RULE,
|
||||||
|
|
||||||
NMP_OBJECT_TYPE_QDISC,
|
NMP_OBJECT_TYPE_QDISC,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1119,7 +1119,7 @@ ipx_route_delete (NMPlatform *platform,
|
||||||
g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||||
g_assert (ifindex == -1);
|
g_assert (ifindex == -1);
|
||||||
ifindex = obj->object.ifindex;
|
ifindex = NMP_OBJECT_CAST_IP_ROUTE (obj)->ifindex;
|
||||||
obj_type = NMP_OBJECT_GET_TYPE (obj);
|
obj_type = NMP_OBJECT_GET_TYPE (obj);
|
||||||
} else {
|
} else {
|
||||||
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
|
#include <linux/fib_rules.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
||||||
#include <linux/if_link.h>
|
#include <linux/if_link.h>
|
||||||
|
|
@ -164,6 +165,19 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define FRA_TUN_ID 12
|
||||||
|
#define FRA_SUPPRESS_IFGROUP 13
|
||||||
|
#define FRA_SUPPRESS_PREFIXLEN 14
|
||||||
|
#define FRA_PAD 18
|
||||||
|
#define FRA_L3MDEV 19
|
||||||
|
#define FRA_UID_RANGE 20
|
||||||
|
#define FRA_PROTOCOL 21
|
||||||
|
#define FRA_IP_PROTO 22
|
||||||
|
#define FRA_SPORT_RANGE 23
|
||||||
|
#define FRA_DPORT_RANGE 24
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define IFLA_MACSEC_UNSPEC 0
|
#define IFLA_MACSEC_UNSPEC 0
|
||||||
#define IFLA_MACSEC_SCI 1
|
#define IFLA_MACSEC_SCI 1
|
||||||
#define IFLA_MACSEC_PORT 2
|
#define IFLA_MACSEC_PORT 2
|
||||||
|
|
@ -283,41 +297,64 @@ typedef struct {
|
||||||
};
|
};
|
||||||
} ChangeLinkData;
|
} ChangeLinkData;
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_LINKS,
|
_REFRESH_ALL_TYPE_FIRST = 0,
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES,
|
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES,
|
REFRESH_ALL_TYPE_LINKS = 0,
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES,
|
REFRESH_ALL_TYPE_IP4_ADDRESSES = 1,
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES,
|
REFRESH_ALL_TYPE_IP6_ADDRESSES = 2,
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS,
|
REFRESH_ALL_TYPE_IP4_ROUTES = 3,
|
||||||
DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS,
|
REFRESH_ALL_TYPE_IP6_ROUTES = 4,
|
||||||
_DELAYED_ACTION_IDX_REFRESH_ALL_NUM,
|
REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5,
|
||||||
};
|
REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6,
|
||||||
|
REFRESH_ALL_TYPE_QDISCS = 7,
|
||||||
|
REFRESH_ALL_TYPE_TFILTERS = 8,
|
||||||
|
|
||||||
|
_REFRESH_ALL_TYPE_NUM,
|
||||||
|
} RefreshAllType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPObjectType obj_type;
|
||||||
|
|
||||||
|
/* for NLM_F_DUMP, which address family to request. */
|
||||||
|
int addr_family;
|
||||||
|
} RefreshAllInfo;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DELAYED_ACTION_TYPE_NONE = 0,
|
DELAYED_ACTION_TYPE_NONE = 0,
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << /* 0 */ DELAYED_ACTION_IDX_REFRESH_ALL_LINKS),
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << /* 1 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES),
|
#define F(val, name) ((sizeof (char[(((val)) == (name)) ? 1 : -1]) * 0) + (val))
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F (0, REFRESH_ALL_TYPE_LINKS),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F (1, REFRESH_ALL_TYPE_IP4_ADDRESSES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F (2, REFRESH_ALL_TYPE_IP6_ADDRESSES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F (3, REFRESH_ALL_TYPE_IP4_ROUTES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = (1LL << /* 6 */ DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F (4, REFRESH_ALL_TYPE_IP6_ROUTES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 7),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 << F (5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4),
|
||||||
DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 11),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 << F (6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6),
|
||||||
DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 12),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F (7, REFRESH_ALL_TYPE_QDISCS),
|
||||||
DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 13),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F (8, REFRESH_ALL_TYPE_TFILTERS),
|
||||||
|
#undef F
|
||||||
|
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9,
|
||||||
|
DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10,
|
||||||
|
DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 11,
|
||||||
|
DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12,
|
||||||
|
|
||||||
__DELAYED_ACTION_TYPE_MAX,
|
__DELAYED_ACTION_TYPE_MAX,
|
||||||
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6,
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
|
||||||
|
|
||||||
DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1,
|
DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
||||||
|
|
||||||
|
DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1,
|
||||||
} DelayedActionType;
|
} DelayedActionType;
|
||||||
|
|
||||||
#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \
|
#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \
|
||||||
|
|
@ -387,7 +424,7 @@ typedef struct {
|
||||||
GIOChannel *event_channel;
|
GIOChannel *event_channel;
|
||||||
guint event_id;
|
guint event_id;
|
||||||
|
|
||||||
bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
|
guint32 pruning[_REFRESH_ALL_TYPE_NUM];
|
||||||
|
|
||||||
GHashTable *sysctl_get_prev_values;
|
GHashTable *sysctl_get_prev_values;
|
||||||
CList sysctl_list;
|
CList sysctl_list;
|
||||||
|
|
@ -401,7 +438,7 @@ typedef struct {
|
||||||
|
|
||||||
/* counter that a refresh all action is in progress, separated
|
/* counter that a refresh all action is in progress, separated
|
||||||
* by type. */
|
* by type. */
|
||||||
int refresh_all_in_progress[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
|
int refresh_all_in_progress[_REFRESH_ALL_TYPE_NUM];
|
||||||
|
|
||||||
GPtrArray *list_master_connected;
|
GPtrArray *list_master_connected;
|
||||||
GPtrArray *list_refresh_link;
|
GPtrArray *list_refresh_link;
|
||||||
|
|
@ -3339,6 +3376,165 @@ rta_multipath_done:
|
||||||
return g_steal_pointer (&obj);
|
return g_steal_pointer (&obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NMPObject *
|
||||||
|
_new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only)
|
||||||
|
{
|
||||||
|
static const struct nla_policy policy[] = {
|
||||||
|
[FRA_UNSPEC] = { },
|
||||||
|
[FRA_DST] = { /* struct in_addr, struct in6_addr */ },
|
||||||
|
[FRA_SRC] = { /* struct in_addr, struct in6_addr */ },
|
||||||
|
[FRA_IIFNAME] = { .type = NLA_STRING,
|
||||||
|
.maxlen = IFNAMSIZ, },
|
||||||
|
[FRA_GOTO] = { .type = NLA_U32, },
|
||||||
|
[FRA_UNUSED2] = { },
|
||||||
|
[FRA_PRIORITY] = { .type = NLA_U32, },
|
||||||
|
[FRA_UNUSED3] = { },
|
||||||
|
[FRA_UNUSED4] = { },
|
||||||
|
[FRA_UNUSED5] = { },
|
||||||
|
[FRA_FWMARK] = { .type = NLA_U32, },
|
||||||
|
[FRA_FLOW] = { .type = NLA_U32, },
|
||||||
|
[FRA_TUN_ID] = { .type = NLA_U64, },
|
||||||
|
[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32, },
|
||||||
|
[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32, },
|
||||||
|
[FRA_TABLE] = { .type = NLA_U32, },
|
||||||
|
[FRA_FWMASK] = { .type = NLA_U32, },
|
||||||
|
[FRA_OIFNAME] = { .type = NLA_STRING,
|
||||||
|
.maxlen = IFNAMSIZ, },
|
||||||
|
[FRA_PAD] = { .type = NLA_U32, },
|
||||||
|
[FRA_L3MDEV] = { .type = NLA_U8, },
|
||||||
|
[FRA_UID_RANGE] = { .minlen = sizeof(NMFibRuleUidRange),
|
||||||
|
.maxlen = sizeof(NMFibRuleUidRange), },
|
||||||
|
[FRA_PROTOCOL] = { .type = NLA_U8, },
|
||||||
|
[FRA_IP_PROTO] = { .type = NLA_U8, },
|
||||||
|
[FRA_SPORT_RANGE] = { .minlen = sizeof(NMFibRulePortRange),
|
||||||
|
.maxlen = sizeof(NMFibRulePortRange), },
|
||||||
|
[FRA_DPORT_RANGE] = { .minlen = sizeof(NMFibRulePortRange),
|
||||||
|
.maxlen = sizeof(NMFibRulePortRange), },
|
||||||
|
};
|
||||||
|
struct nlattr *tb[G_N_ELEMENTS (policy)];
|
||||||
|
const struct fib_rule_hdr *frh;
|
||||||
|
NMPlatformRoutingRule *props;
|
||||||
|
nm_auto_nmpobj NMPObject *obj = NULL;
|
||||||
|
int addr_family;
|
||||||
|
guint8 addr_size;
|
||||||
|
|
||||||
|
if (nlmsg_parse_arr (nlh, sizeof (*frh), tb, policy) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
frh = nlmsg_data (nlh);
|
||||||
|
|
||||||
|
addr_family = frh->family;
|
||||||
|
|
||||||
|
if (!NM_IN_SET (addr_family, AF_INET, AF_INET6)) {
|
||||||
|
/* we don't care about other address families. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_size = nm_utils_addr_family_to_size (addr_family);
|
||||||
|
|
||||||
|
obj = nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, NULL);
|
||||||
|
props = &obj->routing_rule;
|
||||||
|
|
||||||
|
props->addr_family = addr_family;
|
||||||
|
props->action = frh->action;
|
||||||
|
props->flags = frh->flags;
|
||||||
|
props->tos = frh->tos;
|
||||||
|
|
||||||
|
props->table = tb[FRA_TABLE]
|
||||||
|
? nla_get_u32 (tb[FRA_TABLE])
|
||||||
|
: frh->table;
|
||||||
|
|
||||||
|
if (tb[FRA_SUPPRESS_PREFIXLEN])
|
||||||
|
props->suppress_prefixlen_inverse = ~nla_get_u32 (tb[FRA_SUPPRESS_PREFIXLEN]);
|
||||||
|
|
||||||
|
if (tb[FRA_SUPPRESS_IFGROUP])
|
||||||
|
props->suppress_ifgroup_inverse = ~nla_get_u32 (tb[FRA_SUPPRESS_IFGROUP]);
|
||||||
|
|
||||||
|
if (tb[FRA_IIFNAME])
|
||||||
|
nla_strlcpy (props->iifname, tb[FRA_IIFNAME], sizeof (props->iifname));
|
||||||
|
|
||||||
|
if (tb[FRA_OIFNAME])
|
||||||
|
nla_strlcpy (props->oifname, tb[FRA_OIFNAME], sizeof (props->oifname));
|
||||||
|
|
||||||
|
if (tb[FRA_PRIORITY])
|
||||||
|
props->priority = nla_get_u32 (tb[FRA_PRIORITY]);
|
||||||
|
|
||||||
|
if (tb[FRA_FWMARK])
|
||||||
|
props->fwmark = nla_get_u32 (tb[FRA_FWMARK]);
|
||||||
|
|
||||||
|
if (tb[FRA_FWMASK])
|
||||||
|
props->fwmask = nla_get_u32 (tb[FRA_FWMASK]);
|
||||||
|
|
||||||
|
if (tb[FRA_GOTO])
|
||||||
|
props->goto_target = nla_get_u32 (tb[FRA_GOTO]);
|
||||||
|
|
||||||
|
props->src_len = frh->src_len;
|
||||||
|
if (props->src_len > addr_size * 8)
|
||||||
|
return NULL;
|
||||||
|
if (!tb[FRA_SRC]) {
|
||||||
|
if (props->src_len > 0)
|
||||||
|
return NULL;
|
||||||
|
} else if (!nm_ip_addr_set_from_untrusted (addr_family,
|
||||||
|
&props->src,
|
||||||
|
nla_data (tb[FRA_SRC]),
|
||||||
|
nla_len (tb[FRA_SRC]),
|
||||||
|
NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
props->dst_len = frh->dst_len;
|
||||||
|
if (props->dst_len > addr_size * 8)
|
||||||
|
return NULL;
|
||||||
|
if (!tb[FRA_DST]) {
|
||||||
|
if (props->dst_len > 0)
|
||||||
|
return NULL;
|
||||||
|
} else if (!nm_ip_addr_set_from_untrusted (addr_family,
|
||||||
|
&props->dst,
|
||||||
|
nla_data (tb[FRA_DST]),
|
||||||
|
nla_len (tb[FRA_DST]),
|
||||||
|
NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (tb[FRA_FLOW])
|
||||||
|
props->flow = nla_get_u32 (tb[FRA_FLOW]);
|
||||||
|
|
||||||
|
if (tb[FRA_TUN_ID])
|
||||||
|
props->tun_id = nla_get_be64 (tb[FRA_TUN_ID]);
|
||||||
|
|
||||||
|
if (tb[FRA_L3MDEV]) {
|
||||||
|
/* actually, kernel only allows this attribute to be missing or
|
||||||
|
* "1". Still, encode it as full uint8.
|
||||||
|
*
|
||||||
|
* Note that FRA_L3MDEV and FRA_TABLE are mutally exclusive. */
|
||||||
|
props->l3mdev = nla_get_u8 (tb[FRA_L3MDEV]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tb[FRA_PROTOCOL])
|
||||||
|
props->protocol = nla_get_u8 (tb[FRA_PROTOCOL]);
|
||||||
|
else
|
||||||
|
nm_assert (props->protocol == RTPROT_UNSPEC);
|
||||||
|
|
||||||
|
if (tb[FRA_IP_PROTO])
|
||||||
|
props->ip_proto = nla_get_u8 (tb[FRA_IP_PROTO]);
|
||||||
|
|
||||||
|
G_STATIC_ASSERT_EXPR (sizeof (NMFibRulePortRange) == 4);
|
||||||
|
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, start) == 0);
|
||||||
|
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, end) == 2);
|
||||||
|
|
||||||
|
nla_memcpy_checked_size (&props->sport_range, tb[FRA_SPORT_RANGE], sizeof (props->sport_range));
|
||||||
|
nla_memcpy_checked_size (&props->dport_range, tb[FRA_DPORT_RANGE], sizeof (props->dport_range));
|
||||||
|
|
||||||
|
G_STATIC_ASSERT_EXPR (sizeof (NMFibRuleUidRange) == 8);
|
||||||
|
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, start) == 0);
|
||||||
|
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, end) == 4);
|
||||||
|
|
||||||
|
if (tb[FRA_UID_RANGE]) {
|
||||||
|
nla_memcpy_checked_size (&props->uid_range, tb[FRA_UID_RANGE], sizeof (props->uid_range));
|
||||||
|
props->uid_range_has = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer (&obj);
|
||||||
|
}
|
||||||
|
|
||||||
static NMPObject *
|
static NMPObject *
|
||||||
_new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
|
_new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
|
||||||
{
|
{
|
||||||
|
|
@ -3438,6 +3634,10 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m
|
||||||
case RTM_DELROUTE:
|
case RTM_DELROUTE:
|
||||||
case RTM_GETROUTE:
|
case RTM_GETROUTE:
|
||||||
return _new_from_nl_route (msghdr, id_only);
|
return _new_from_nl_route (msghdr, id_only);
|
||||||
|
case RTM_NEWRULE:
|
||||||
|
case RTM_DELRULE:
|
||||||
|
case RTM_GETRULE:
|
||||||
|
return _new_from_nl_routing_rule (msghdr, id_only);
|
||||||
case RTM_NEWQDISC:
|
case RTM_NEWQDISC:
|
||||||
case RTM_DELQDISC:
|
case RTM_DELQDISC:
|
||||||
case RTM_GETQDISC:
|
case RTM_GETQDISC:
|
||||||
|
|
@ -3892,6 +4092,119 @@ nla_put_failure:
|
||||||
g_return_val_if_reached (NULL);
|
g_return_val_if_reached (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct nl_msg *
|
||||||
|
_nl_msg_new_routing_rule (int nlmsg_type,
|
||||||
|
int nlmsg_flags,
|
||||||
|
const NMPlatformRoutingRule *routing_rule)
|
||||||
|
{
|
||||||
|
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||||
|
const guint8 addr_size = nm_utils_addr_family_to_size (routing_rule->addr_family);
|
||||||
|
guint32 table;
|
||||||
|
|
||||||
|
msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
|
||||||
|
|
||||||
|
table = routing_rule->table;
|
||||||
|
|
||||||
|
if ( NM_IN_SET (routing_rule->addr_family, AF_INET, AF_INET6)
|
||||||
|
&& routing_rule->action == FR_ACT_TO_TBL
|
||||||
|
&& routing_rule->l3mdev == 0
|
||||||
|
&& table == RT_TABLE_UNSPEC) {
|
||||||
|
/* for IPv6, this setting is invalid and rejected by kernel. That's fine.
|
||||||
|
*
|
||||||
|
* for IPv4, kernel will automatically assign an unused table. That's not
|
||||||
|
* fine, because we don't know what we will get.
|
||||||
|
*
|
||||||
|
* The caller must not allow that to happen. */
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const struct fib_rule_hdr frh = {
|
||||||
|
.family = routing_rule->addr_family,
|
||||||
|
.src_len = routing_rule->src_len,
|
||||||
|
.dst_len = routing_rule->dst_len,
|
||||||
|
.tos = routing_rule->tos,
|
||||||
|
.table = table,
|
||||||
|
.action = routing_rule->action,
|
||||||
|
|
||||||
|
/* we only allow setting the "not" flag. */
|
||||||
|
.flags = routing_rule->flags & ((guint32) FIB_RULE_INVERT),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nlmsg_append_struct (msg, &frh) < 0)
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (table > G_MAXINT8)
|
||||||
|
NLA_PUT_U32 (msg, FRA_TABLE, table);
|
||||||
|
|
||||||
|
if (routing_rule->suppress_prefixlen_inverse != 0)
|
||||||
|
NLA_PUT_U32 (msg, FRA_SUPPRESS_PREFIXLEN, ~routing_rule->suppress_prefixlen_inverse);
|
||||||
|
|
||||||
|
if (routing_rule->suppress_ifgroup_inverse != 0)
|
||||||
|
NLA_PUT_U32 (msg, FRA_SUPPRESS_IFGROUP, ~routing_rule->suppress_ifgroup_inverse);
|
||||||
|
|
||||||
|
if (routing_rule->iifname[0] != '\0')
|
||||||
|
NLA_PUT_STRING (msg, FRA_IIFNAME, routing_rule->iifname);
|
||||||
|
|
||||||
|
if (routing_rule->oifname[0] != '\0')
|
||||||
|
NLA_PUT_STRING (msg, FRA_OIFNAME, routing_rule->oifname);
|
||||||
|
|
||||||
|
/* we always set the priority and don't support letting kernel pick one. */
|
||||||
|
NLA_PUT_U32 (msg, FRA_PRIORITY, routing_rule->priority);
|
||||||
|
|
||||||
|
if ( routing_rule->fwmark != 0
|
||||||
|
|| routing_rule->fwmask != 0) {
|
||||||
|
NLA_PUT_U32 (msg, FRA_FWMARK, routing_rule->fwmark);
|
||||||
|
NLA_PUT_U32 (msg, FRA_FWMASK, routing_rule->fwmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->src_len > 0)
|
||||||
|
NLA_PUT (msg, FRA_SRC, addr_size, &routing_rule->src);
|
||||||
|
|
||||||
|
if (routing_rule->dst_len > 0)
|
||||||
|
NLA_PUT (msg, FRA_DST, addr_size, &routing_rule->dst);
|
||||||
|
|
||||||
|
if (routing_rule->flow != 0) {
|
||||||
|
/* only relevant for IPv4. */
|
||||||
|
NLA_PUT_U32 (msg, FRA_FLOW, routing_rule->flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->tun_id != 0)
|
||||||
|
NLA_PUT_U64 (msg, FRA_TUN_ID, htobe64 (routing_rule->tun_id));
|
||||||
|
|
||||||
|
if (routing_rule->l3mdev)
|
||||||
|
NLA_PUT_U8 (msg, FRA_L3MDEV, routing_rule->l3mdev);
|
||||||
|
|
||||||
|
if (routing_rule->protocol != RTPROT_UNSPEC)
|
||||||
|
NLA_PUT_U8 (msg, FRA_PROTOCOL, routing_rule->protocol);
|
||||||
|
|
||||||
|
if (routing_rule->ip_proto != 0)
|
||||||
|
NLA_PUT_U8 (msg, FRA_IP_PROTO, routing_rule->ip_proto);
|
||||||
|
|
||||||
|
if ( routing_rule->sport_range.start
|
||||||
|
|| routing_rule->sport_range.end)
|
||||||
|
NLA_PUT (msg, FRA_SPORT_RANGE, sizeof (routing_rule->sport_range), &routing_rule->sport_range);
|
||||||
|
|
||||||
|
if ( routing_rule->dport_range.start
|
||||||
|
|| routing_rule->dport_range.end)
|
||||||
|
NLA_PUT (msg, FRA_DPORT_RANGE, sizeof (routing_rule->dport_range), &routing_rule->dport_range);
|
||||||
|
|
||||||
|
if (routing_rule->uid_range_has)
|
||||||
|
NLA_PUT (msg, FRA_UID_RANGE, sizeof (routing_rule->uid_range), &routing_rule->uid_range);
|
||||||
|
|
||||||
|
switch (routing_rule->action) {
|
||||||
|
case FR_ACT_GOTO:
|
||||||
|
NLA_PUT_U32 (msg, FRA_GOTO, routing_rule->goto_target);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer (&msg);
|
||||||
|
|
||||||
|
nla_put_failure:
|
||||||
|
g_return_val_if_reached (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static struct nl_msg *
|
static struct nl_msg *
|
||||||
_nl_msg_new_qdisc (int nlmsg_type,
|
_nl_msg_new_qdisc (int nlmsg_type,
|
||||||
int nlmsg_flags,
|
int nlmsg_flags,
|
||||||
|
|
@ -4347,57 +4660,131 @@ process_events (NMPlatform *platform)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObjectType, DelayedActionType,
|
static const RefreshAllInfo *
|
||||||
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (DELAYED_ACTION_TYPE_NONE),
|
refresh_all_type_get_info (RefreshAllType refresh_all_type)
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_LINK, DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS),
|
{
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES),
|
static const RefreshAllInfo infos[] = {
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES),
|
#define R(_refresh_all_type, _obj_type, _addr_family) [_refresh_all_type] = { .obj_type = _obj_type, .addr_family = _addr_family, }
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES),
|
R (REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC),
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES),
|
R (REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC),
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS),
|
R (REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC),
|
||||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_TFILTER, DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS),
|
R (REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC),
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
R (REFRESH_ALL_TYPE_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC),
|
||||||
);
|
R (REFRESH_ALL_TYPE_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET),
|
||||||
|
R (REFRESH_ALL_TYPE_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6),
|
||||||
|
R (REFRESH_ALL_TYPE_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC),
|
||||||
|
R (REFRESH_ALL_TYPE_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC),
|
||||||
|
#undef R
|
||||||
|
};
|
||||||
|
|
||||||
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_to_object_type, DelayedActionType, NMPObjectType,
|
nm_assert (_NM_INT_NOT_NEGATIVE (refresh_all_type));
|
||||||
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (NMP_OBJECT_TYPE_UNKNOWN),
|
nm_assert (refresh_all_type < G_N_ELEMENTS (infos));
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, NMP_OBJECT_TYPE_LINK),
|
nm_assert (nmp_class_from_type (infos[refresh_all_type].obj_type));
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS),
|
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS),
|
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE),
|
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE),
|
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, NMP_OBJECT_TYPE_QDISC),
|
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NMP_OBJECT_TYPE_TFILTER),
|
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
|
||||||
);
|
|
||||||
|
|
||||||
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActionType, guint,
|
return &infos[refresh_all_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_type_to_refresh_all_type, DelayedActionType, RefreshAllType,
|
||||||
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0),
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, DELAYED_ACTION_IDX_REFRESH_ALL_LINKS),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, REFRESH_ALL_TYPE_IP4_ADDRESSES),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, REFRESH_ALL_TYPE_IP6_ADDRESSES),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, REFRESH_ALL_TYPE_IP4_ROUTES),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, REFRESH_ALL_TYPE_IP6_ROUTES),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, REFRESH_ALL_TYPE_ROUTING_RULES_IP4),
|
||||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS),
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, REFRESH_ALL_TYPE_QDISCS),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, REFRESH_ALL_TYPE_TFILTERS),
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static DelayedActionType
|
||||||
|
delayed_action_type_from_refresh_all_type (RefreshAllType refresh_all_type)
|
||||||
|
{
|
||||||
|
DelayedActionType t;
|
||||||
|
|
||||||
|
nm_assert (refresh_all_type_get_info (refresh_all_type));
|
||||||
|
|
||||||
|
t = (((DelayedActionType) 1) << refresh_all_type);
|
||||||
|
|
||||||
|
nm_assert (refresh_all_type == delayed_action_type_to_refresh_all_type (t));
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RefreshAllType
|
||||||
|
refresh_all_type_from_needle_object (const NMPObject *obj_needle)
|
||||||
|
{
|
||||||
|
switch (NMP_OBJECT_GET_TYPE (obj_needle)) {
|
||||||
|
case NMP_OBJECT_TYPE_LINK: return REFRESH_ALL_TYPE_LINKS;
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ADDRESS: return REFRESH_ALL_TYPE_IP4_ADDRESSES;
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ADDRESS: return REFRESH_ALL_TYPE_IP6_ADDRESSES;
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ROUTE: return REFRESH_ALL_TYPE_IP4_ROUTES;
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ROUTE: return REFRESH_ALL_TYPE_IP6_ROUTES;
|
||||||
|
case NMP_OBJECT_TYPE_QDISC: return REFRESH_ALL_TYPE_QDISCS;
|
||||||
|
case NMP_OBJECT_TYPE_TFILTER: return REFRESH_ALL_TYPE_TFILTERS;
|
||||||
|
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||||
|
switch (NMP_OBJECT_CAST_ROUTING_RULE (obj_needle)->addr_family) {
|
||||||
|
case AF_INET: return REFRESH_ALL_TYPE_ROUTING_RULES_IP4;
|
||||||
|
case AF_INET6: return REFRESH_ALL_TYPE_ROUTING_RULES_IP6;
|
||||||
|
}
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NMPLookup *
|
||||||
|
refresh_all_type_init_lookup (RefreshAllType refresh_all_type,
|
||||||
|
NMPLookup *lookup)
|
||||||
|
{
|
||||||
|
const RefreshAllInfo *refresh_all_info;
|
||||||
|
|
||||||
|
nm_assert (lookup);
|
||||||
|
|
||||||
|
refresh_all_info = refresh_all_type_get_info (refresh_all_type);
|
||||||
|
|
||||||
|
nm_assert (refresh_all_info);
|
||||||
|
|
||||||
|
if (NM_IN_SET (refresh_all_info->obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)) {
|
||||||
|
return nmp_lookup_init_object_by_addr_family (lookup,
|
||||||
|
refresh_all_info->obj_type,
|
||||||
|
refresh_all_info->addr_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not yet implemented. */
|
||||||
|
nm_assert (refresh_all_info->addr_family == AF_UNSPEC);
|
||||||
|
|
||||||
|
return nmp_lookup_init_obj_type (lookup,
|
||||||
|
refresh_all_info->obj_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DelayedActionType
|
||||||
|
delayed_action_refresh_from_needle_object (const NMPObject *obj_needle)
|
||||||
|
{
|
||||||
|
return delayed_action_type_from_refresh_all_type (refresh_all_type_from_needle_object (obj_needle));
|
||||||
|
}
|
||||||
|
|
||||||
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType,
|
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType,
|
||||||
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, "refresh-all-ip4-addresses"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, "refresh-all-ip4-addresses"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, "refresh-all-ip6-addresses"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, "refresh-all-routing-rules-ip4"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, "refresh-all-routing-rules-ip6"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"),
|
||||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"),
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"),
|
||||||
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"),
|
||||||
|
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"),
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_NONE),
|
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_NONE),
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL),
|
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL),
|
||||||
|
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL),
|
||||||
NM_UTILS_LOOKUP_ITEM_IGNORE (__DELAYED_ACTION_TYPE_MAX),
|
NM_UTILS_LOOKUP_ITEM_IGNORE (__DELAYED_ACTION_TYPE_MAX),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -4455,6 +4842,7 @@ static gboolean
|
||||||
delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType action_type)
|
delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType action_type)
|
||||||
{
|
{
|
||||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
|
RefreshAllType refresh_all_type;
|
||||||
|
|
||||||
nm_assert (nm_utils_is_power_of_two (action_type));
|
nm_assert (nm_utils_is_power_of_two (action_type));
|
||||||
nm_assert (NM_FLAGS_ANY (action_type, DELAYED_ACTION_TYPE_REFRESH_ALL));
|
nm_assert (NM_FLAGS_ANY (action_type, DELAYED_ACTION_TYPE_REFRESH_ALL));
|
||||||
|
|
@ -4463,10 +4851,8 @@ delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType
|
||||||
if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type))
|
if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (action_type)] > 0)
|
refresh_all_type = delayed_action_type_to_refresh_all_type (action_type);
|
||||||
return TRUE;
|
return (priv->delayed_action.refresh_all_in_progress[refresh_all_type] > 0);
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -4764,25 +5150,33 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type)
|
cache_prune_one_type (NMPlatform *platform,
|
||||||
|
const NMPLookup *lookup)
|
||||||
{
|
{
|
||||||
NMDedupMultiIter iter;
|
NMDedupMultiIter iter;
|
||||||
const NMPObject *obj;
|
const NMPObject *obj;
|
||||||
NMPCacheOpsType cache_op;
|
NMPCacheOpsType cache_op;
|
||||||
NMPLookup lookup;
|
|
||||||
NMPCache *cache = nm_platform_get_cache (platform);
|
NMPCache *cache = nm_platform_get_cache (platform);
|
||||||
|
|
||||||
nmp_lookup_init_obj_type (&lookup,
|
|
||||||
obj_type);
|
|
||||||
nm_dedup_multi_iter_init (&iter,
|
nm_dedup_multi_iter_init (&iter,
|
||||||
nmp_cache_lookup (cache,
|
nmp_cache_lookup (cache,
|
||||||
&lookup));
|
lookup));
|
||||||
while (nm_dedup_multi_iter_next (&iter)) {
|
while (nm_dedup_multi_iter_next (&iter)) {
|
||||||
if (iter.current->dirty) {
|
const NMDedupMultiEntry *main_entry;
|
||||||
|
|
||||||
|
/* we only track the dirty flag for the OBJECT-TYPE index. That means,
|
||||||
|
* for other lookup types we need to check the dirty flag of the main-entry. */
|
||||||
|
main_entry = nmp_cache_reresolve_main_entry (cache, iter.current, lookup);
|
||||||
|
if (!main_entry->dirty)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
obj = main_entry->obj;
|
||||||
|
|
||||||
|
_LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
||||||
|
|
||||||
|
{
|
||||||
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
||||||
|
|
||||||
obj = iter.current->obj;
|
|
||||||
_LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
|
||||||
cache_op = nmp_cache_remove (cache, obj, TRUE, TRUE, &obj_old);
|
cache_op = nmp_cache_remove (cache, obj, TRUE, TRUE, &obj_old);
|
||||||
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||||
cache_on_change (platform, cache_op, obj_old, NULL);
|
cache_on_change (platform, cache_op, obj_old, NULL);
|
||||||
|
|
@ -4795,16 +5189,19 @@ static void
|
||||||
cache_prune_all (NMPlatform *platform)
|
cache_prune_all (NMPlatform *platform)
|
||||||
{
|
{
|
||||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
DelayedActionType iflags, action_type;
|
RefreshAllType refresh_all_type;
|
||||||
|
|
||||||
action_type = DELAYED_ACTION_TYPE_REFRESH_ALL;
|
for (refresh_all_type = _REFRESH_ALL_TYPE_FIRST; refresh_all_type < _REFRESH_ALL_TYPE_NUM; refresh_all_type++) {
|
||||||
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
|
NMPLookup lookup;
|
||||||
bool *p = &priv->pruning[delayed_action_refresh_all_to_idx (iflags)];
|
|
||||||
|
|
||||||
if (*p) {
|
if (priv->pruning[refresh_all_type] == 0)
|
||||||
*p = FALSE;
|
continue;
|
||||||
cache_prune_one_type (platform, delayed_action_refresh_to_object_type (iflags));
|
priv->pruning[refresh_all_type] -= 1;
|
||||||
}
|
if (priv->pruning[refresh_all_type] > 0)
|
||||||
|
continue;
|
||||||
|
refresh_all_type_init_lookup (refresh_all_type,
|
||||||
|
&lookup);
|
||||||
|
cache_prune_one_type (platform, &lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4876,6 +5273,7 @@ cache_on_change (NMPlatform *platform,
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -5166,7 +5564,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha
|
||||||
|
|
||||||
entry = nmp_cache_lookup_entry_link (nm_platform_get_cache (platform), ifindex);
|
entry = nmp_cache_lookup_entry_link (nm_platform_get_cache (platform), ifindex);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
priv->pruning[DELAYED_ACTION_IDX_REFRESH_ALL_LINKS] = TRUE;
|
priv->pruning[REFRESH_ALL_TYPE_LINKS] += 1;
|
||||||
nm_dedup_multi_entry_set_dirty (entry, TRUE);
|
nm_dedup_multi_entry_set_dirty (entry, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5234,6 +5632,7 @@ _nl_msg_new_dump (NMPObjectType obj_type,
|
||||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
|
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||||
{
|
{
|
||||||
const struct rtgenmsg gmsg = {
|
const struct rtgenmsg gmsg = {
|
||||||
.rtgen_family = preferred_addr_family,
|
.rtgen_family = preferred_addr_family,
|
||||||
|
|
@ -5254,42 +5653,68 @@ static void
|
||||||
do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type)
|
do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type)
|
||||||
{
|
{
|
||||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
|
DelayedActionType action_type_prune;
|
||||||
DelayedActionType iflags;
|
DelayedActionType iflags;
|
||||||
|
|
||||||
nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL));
|
nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL));
|
||||||
action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL;
|
action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL;
|
||||||
|
|
||||||
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
|
action_type_prune = action_type;
|
||||||
|
|
||||||
|
/* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra
|
||||||
|
* cache lookup for every entry.
|
||||||
|
*
|
||||||
|
* Avoid that, by special casing routing-rules here. */
|
||||||
|
if (NM_FLAGS_ALL (action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL)) {
|
||||||
NMPLookup lookup;
|
NMPLookup lookup;
|
||||||
|
|
||||||
priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE;
|
priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1;
|
||||||
nmp_lookup_init_obj_type (&lookup,
|
priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1;
|
||||||
delayed_action_refresh_to_object_type (iflags));
|
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
nmp_cache_dirty_set_all (nm_platform_get_cache (platform),
|
nmp_cache_dirty_set_all_main (nm_platform_get_cache (platform),
|
||||||
&lookup);
|
&lookup);
|
||||||
|
action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) {
|
||||||
|
RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type (iflags);
|
||||||
|
NMPLookup lookup;
|
||||||
|
|
||||||
|
priv->pruning[refresh_all_type] += 1;
|
||||||
|
refresh_all_type_init_lookup (refresh_all_type,
|
||||||
|
&lookup);
|
||||||
|
nmp_cache_dirty_set_all_main (nm_platform_get_cache (platform),
|
||||||
|
&lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
|
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
|
||||||
NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags);
|
RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type (iflags);
|
||||||
|
const RefreshAllInfo *refresh_all_info = refresh_all_type_get_info (refresh_all_type);
|
||||||
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
||||||
int *out_refresh_all_in_progress;
|
int *out_refresh_all_in_progress;
|
||||||
|
|
||||||
out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)];
|
out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[refresh_all_type];
|
||||||
nm_assert (*out_refresh_all_in_progress >= 0);
|
nm_assert (*out_refresh_all_in_progress >= 0);
|
||||||
*out_refresh_all_in_progress += 1;
|
*out_refresh_all_in_progress += 1;
|
||||||
|
|
||||||
/* clear any delayed action that request a refresh of this object type. */
|
/* clear any delayed action that request a refresh of this object type. */
|
||||||
priv->delayed_action.flags &= ~iflags;
|
priv->delayed_action.flags &= ~iflags;
|
||||||
_LOGt_delayed_action (iflags, NULL, "handle (do-request-all)");
|
_LOGt_delayed_action (iflags, NULL, "handle (do-request-all)");
|
||||||
if (obj_type == NMP_OBJECT_TYPE_LINK) {
|
|
||||||
priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
|
if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) {
|
||||||
g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
|
nm_assert ( (priv->delayed_action.list_refresh_link->len > 0)
|
||||||
_LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)");
|
== NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK));
|
||||||
|
if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) {
|
||||||
|
_LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)");
|
||||||
|
priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
|
||||||
|
g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event_handler_read_netlink (platform, FALSE);
|
event_handler_read_netlink (platform, FALSE);
|
||||||
|
|
||||||
nlmsg = _nl_msg_new_dump (obj_type, AF_UNSPEC);
|
nlmsg = _nl_msg_new_dump (refresh_all_info->obj_type,
|
||||||
|
refresh_all_info->addr_family);
|
||||||
if (!nlmsg)
|
if (!nlmsg)
|
||||||
goto next_after_fail;
|
goto next_after_fail;
|
||||||
|
|
||||||
|
|
@ -5310,9 +5735,9 @@ next_after_fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_request_one_type (NMPlatform *platform, NMPObjectType obj_type)
|
do_request_one_type_by_needle_object (NMPlatform *platform, const NMPObject *obj_needle)
|
||||||
{
|
{
|
||||||
do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_object_type (obj_type));
|
do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_needle_object (obj_needle));
|
||||||
delayed_action_handle_all (platform, FALSE);
|
delayed_action_handle_all (platform, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5408,6 +5833,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
||||||
if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK,
|
if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK,
|
||||||
RTM_DELADDR,
|
RTM_DELADDR,
|
||||||
RTM_DELROUTE,
|
RTM_DELROUTE,
|
||||||
|
RTM_DELRULE,
|
||||||
RTM_DELQDISC,
|
RTM_DELQDISC,
|
||||||
RTM_DELTFILTER)) {
|
RTM_DELTFILTER)) {
|
||||||
/* The event notifies about a deleted object. We don't need to initialize all
|
/* The event notifies about a deleted object. We don't need to initialize all
|
||||||
|
|
@ -5426,10 +5852,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
||||||
&& NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR,
|
&& NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR,
|
||||||
RTM_NEWLINK,
|
RTM_NEWLINK,
|
||||||
RTM_NEWROUTE,
|
RTM_NEWROUTE,
|
||||||
|
RTM_NEWRULE,
|
||||||
RTM_NEWQDISC,
|
RTM_NEWQDISC,
|
||||||
RTM_NEWTFILTER)) {
|
RTM_NEWTFILTER)) {
|
||||||
is_dump = delayed_action_refresh_all_in_progress (platform,
|
is_dump = delayed_action_refresh_all_in_progress (platform,
|
||||||
delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)));
|
delayed_action_refresh_from_needle_object (obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGT ("event-notification: %s%s: %s",
|
_LOGT ("event-notification: %s%s: %s",
|
||||||
|
|
@ -5445,10 +5872,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
||||||
|
|
||||||
switch (msghdr->nlmsg_type) {
|
switch (msghdr->nlmsg_type) {
|
||||||
|
|
||||||
case RTM_NEWLINK:
|
|
||||||
case RTM_NEWADDR:
|
|
||||||
case RTM_GETLINK:
|
case RTM_GETLINK:
|
||||||
|
case RTM_NEWADDR:
|
||||||
|
case RTM_NEWLINK:
|
||||||
case RTM_NEWQDISC:
|
case RTM_NEWQDISC:
|
||||||
|
case RTM_NEWRULE:
|
||||||
case RTM_NEWTFILTER:
|
case RTM_NEWTFILTER:
|
||||||
cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
|
cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
|
||||||
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
|
@ -5537,16 +5965,17 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
||||||
* netlink events. This needs investigation. */
|
* netlink events. This needs investigation. */
|
||||||
_LOGT ("schedule resync of routes after RTM_NEWROUTE");
|
_LOGT ("schedule resync of routes after RTM_NEWROUTE");
|
||||||
delayed_action_schedule (platform,
|
delayed_action_schedule (platform,
|
||||||
delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)),
|
delayed_action_refresh_from_needle_object (obj),
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RTM_DELLINK:
|
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
case RTM_DELROUTE:
|
case RTM_DELLINK:
|
||||||
case RTM_DELQDISC:
|
case RTM_DELQDISC:
|
||||||
|
case RTM_DELROUTE:
|
||||||
|
case RTM_DELRULE:
|
||||||
case RTM_DELTFILTER:
|
case RTM_DELTFILTER:
|
||||||
cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new);
|
cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new);
|
||||||
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
|
@ -5657,7 +6086,7 @@ do_add_addrroute (NMPlatform *platform,
|
||||||
*
|
*
|
||||||
* rh#1484434 */
|
* rh#1484434 */
|
||||||
if (!nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id))
|
if (!nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id))
|
||||||
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
|
do_request_one_type_by_needle_object (platform, obj_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return wait_for_nl_response_to_nmerr (seq_result);
|
return wait_for_nl_response_to_nmerr (seq_result);
|
||||||
|
|
@ -5722,7 +6151,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
|
||||||
*
|
*
|
||||||
* rh#1484434 */
|
* rh#1484434 */
|
||||||
if (nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id))
|
if (nmp_cache_lookup_obj (nm_platform_get_cache (platform), obj_id))
|
||||||
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
|
do_request_one_type_by_needle_object (platform, obj_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|
@ -5891,12 +6320,6 @@ link_refresh (NMPlatform *platform, int ifindex)
|
||||||
return !!nm_platform_link_get_obj (platform, ifindex, TRUE);
|
return !!nm_platform_link_get_obj (platform, ifindex, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
refresh_all (NMPlatform *platform, NMPObjectType obj_type)
|
|
||||||
{
|
|
||||||
do_request_one_type (platform, obj_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
link_set_netns (NMPlatform *platform,
|
link_set_netns (NMPlatform *platform,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
|
|
@ -7606,6 +8029,9 @@ object_delete (NMPlatform *platform,
|
||||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj);
|
nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj);
|
||||||
break;
|
break;
|
||||||
|
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||||
|
nlmsg = _nl_msg_new_routing_rule (RTM_DELRULE, 0, NMP_OBJECT_CAST_ROUTING_RULE (obj));
|
||||||
|
break;
|
||||||
case NMP_OBJECT_TYPE_QDISC:
|
case NMP_OBJECT_TYPE_QDISC:
|
||||||
nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj));
|
nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj));
|
||||||
break;
|
break;
|
||||||
|
|
@ -7702,6 +8128,47 @@ ip_route_get (NMPlatform *platform,
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
routing_rule_add (NMPlatform *platform,
|
||||||
|
NMPNlmFlags flags,
|
||||||
|
const NMPlatformRoutingRule *routing_rule)
|
||||||
|
{
|
||||||
|
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
|
||||||
|
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||||
|
gs_free char *errmsg = NULL;
|
||||||
|
char s_buf[256];
|
||||||
|
int nle;
|
||||||
|
|
||||||
|
msg = _nl_msg_new_routing_rule (RTM_NEWRULE, flags, routing_rule);
|
||||||
|
|
||||||
|
event_handler_read_netlink (platform, FALSE);
|
||||||
|
|
||||||
|
nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
|
||||||
|
if (nle < 0) {
|
||||||
|
_LOGE ("do-add-rule: failed sending netlink request \"%s\" (%d)",
|
||||||
|
nm_strerror (nle), -nle);
|
||||||
|
return -NME_PL_NETLINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
delayed_action_handle_all (platform, FALSE);
|
||||||
|
|
||||||
|
nm_assert (seq_result);
|
||||||
|
|
||||||
|
_NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
|
||||||
|
? LOGL_DEBUG
|
||||||
|
: LOGL_WARN,
|
||||||
|
"do-add-rule: %s",
|
||||||
|
wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)));
|
||||||
|
|
||||||
|
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
|
||||||
|
return 0;
|
||||||
|
if (seq_result < 0)
|
||||||
|
return seq_result;
|
||||||
|
return -NME_UNSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qdisc_add (NMPlatform *platform,
|
qdisc_add (NMPlatform *platform,
|
||||||
NMPNlmFlags flags,
|
NMPNlmFlags flags,
|
||||||
|
|
@ -7736,7 +8203,8 @@ qdisc_add (NMPlatform *platform,
|
||||||
|
|
||||||
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
|
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (seq_result < 0)
|
||||||
|
return seq_result;
|
||||||
return -NME_UNSPEC;
|
return -NME_UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8053,6 +8521,7 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -8318,9 +8787,13 @@ constructed (GObject *_object)
|
||||||
g_assert (!nle);
|
g_assert (!nle);
|
||||||
|
|
||||||
nle = nl_socket_add_memberships (priv->nlh,
|
nle = nl_socket_add_memberships (priv->nlh,
|
||||||
|
RTNLGRP_IPV4_IFADDR,
|
||||||
|
RTNLGRP_IPV4_ROUTE,
|
||||||
|
RTNLGRP_IPV4_RULE,
|
||||||
|
RTNLGRP_IPV6_RULE,
|
||||||
|
RTNLGRP_IPV6_IFADDR,
|
||||||
|
RTNLGRP_IPV6_ROUTE,
|
||||||
RTNLGRP_LINK,
|
RTNLGRP_LINK,
|
||||||
RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
|
|
||||||
RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE,
|
|
||||||
RTNLGRP_TC,
|
RTNLGRP_TC,
|
||||||
0);
|
0);
|
||||||
g_assert (!nle);
|
g_assert (!nle);
|
||||||
|
|
@ -8347,6 +8820,7 @@ constructed (GObject *_object)
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES |
|
||||||
|
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS |
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -8457,7 +8931,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
||||||
platform_class->link_add = link_add;
|
platform_class->link_add = link_add;
|
||||||
platform_class->link_delete = link_delete;
|
platform_class->link_delete = link_delete;
|
||||||
|
|
||||||
platform_class->refresh_all = refresh_all;
|
|
||||||
platform_class->link_refresh = link_refresh;
|
platform_class->link_refresh = link_refresh;
|
||||||
|
|
||||||
platform_class->link_set_netns = link_set_netns;
|
platform_class->link_set_netns = link_set_netns;
|
||||||
|
|
@ -8543,6 +9016,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
||||||
platform_class->ip_route_add = ip_route_add;
|
platform_class->ip_route_add = ip_route_add;
|
||||||
platform_class->ip_route_get = ip_route_get;
|
platform_class->ip_route_get = ip_route_get;
|
||||||
|
|
||||||
|
platform_class->routing_rule_add = routing_rule_add;
|
||||||
|
|
||||||
platform_class->qdisc_add = qdisc_add;
|
platform_class->qdisc_add = qdisc_add;
|
||||||
platform_class->tfilter_add = tfilter_add;
|
platform_class->tfilter_add = tfilter_add;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <linux/fib_rules.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
|
|
@ -1188,21 +1189,6 @@ nm_platform_link_supports_slaves (NMPlatform *self, int ifindex)
|
||||||
return (nm_platform_link_get_type (self, ifindex) & 0x20000);
|
return (nm_platform_link_get_type (self, ifindex) & 0x20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* nm_platform_refresh_all:
|
|
||||||
* @self: platform instance
|
|
||||||
* @obj_type: The object type to request.
|
|
||||||
*
|
|
||||||
* Resync and re-request all objects from kernel of a certain @obj_type.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type)
|
|
||||||
{
|
|
||||||
_CHECK_SELF_VOID (self, klass);
|
|
||||||
|
|
||||||
klass->refresh_all (self, obj_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_platform_link_refresh:
|
* nm_platform_link_refresh:
|
||||||
* @self: platform instance
|
* @self: platform instance
|
||||||
|
|
@ -4264,14 +4250,13 @@ nm_platform_ip_route_sync (NMPlatform *self,
|
||||||
gboolean success = TRUE;
|
gboolean success = TRUE;
|
||||||
char sbuf1[sizeof (_nm_utils_to_string_buffer)];
|
char sbuf1[sizeof (_nm_utils_to_string_buffer)];
|
||||||
char sbuf2[sizeof (_nm_utils_to_string_buffer)];
|
char sbuf2[sizeof (_nm_utils_to_string_buffer)];
|
||||||
|
const gboolean IS_IPv4 = (addr_family == AF_INET);
|
||||||
|
|
||||||
nm_assert (NM_IS_PLATFORM (self));
|
nm_assert (NM_IS_PLATFORM (self));
|
||||||
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||||
nm_assert (ifindex > 0);
|
nm_assert (ifindex > 0);
|
||||||
|
|
||||||
vt = addr_family == AF_INET
|
vt = &nm_platform_vtable_route.vx[IS_IPv4];
|
||||||
? &nm_platform_vtable_route_v4
|
|
||||||
: &nm_platform_vtable_route_v6;
|
|
||||||
|
|
||||||
for (i_type = 0; routes && i_type < 2; i_type++) {
|
for (i_type = 0; routes && i_type < 2; i_type++) {
|
||||||
for (i = 0; i < routes->len; i++) {
|
for (i = 0; i < routes->len; i++) {
|
||||||
|
|
@ -4578,7 +4563,7 @@ _ip_route_add (NMPlatform *self,
|
||||||
nm_assert (route);
|
nm_assert (route);
|
||||||
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||||
|
|
||||||
ifindex = ((NMPlatformObject *)route)->ifindex;
|
ifindex = ((const NMPlatformIPRoute *) route)->ifindex;
|
||||||
_LOG3D ("route: %-10s IPv%c route: %s",
|
_LOG3D ("route: %-10s IPv%c route: %s",
|
||||||
_nmp_nlm_flag_to_string (flags & NMP_NLM_FLAG_FMASK),
|
_nmp_nlm_flag_to_string (flags & NMP_NLM_FLAG_FMASK),
|
||||||
nm_utils_addr_family_to_char (addr_family),
|
nm_utils_addr_family_to_char (addr_family),
|
||||||
|
|
@ -4630,18 +4615,28 @@ gboolean
|
||||||
nm_platform_object_delete (NMPlatform *self,
|
nm_platform_object_delete (NMPlatform *self,
|
||||||
const NMPObject *obj)
|
const NMPObject *obj)
|
||||||
{
|
{
|
||||||
int ifindex = obj->object.ifindex;
|
int ifindex;
|
||||||
|
|
||||||
_CHECK_SELF (self, klass, FALSE);
|
_CHECK_SELF (self, klass, FALSE);
|
||||||
|
|
||||||
if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
switch (NMP_OBJECT_GET_TYPE (obj)) {
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE,
|
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||||
NMP_OBJECT_TYPE_QDISC,
|
_LOGD ("%s: delete %s",
|
||||||
NMP_OBJECT_TYPE_TFILTER))
|
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
|
||||||
|
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
|
||||||
|
break;
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
|
case NMP_OBJECT_TYPE_QDISC:
|
||||||
|
case NMP_OBJECT_TYPE_TFILTER:
|
||||||
|
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj)->ifindex;
|
||||||
|
_LOG3D ("%s: delete %s",
|
||||||
|
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
|
||||||
|
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
g_return_val_if_reached (FALSE);
|
g_return_val_if_reached (FALSE);
|
||||||
|
}
|
||||||
_LOG3D ("%s: delete %s",
|
|
||||||
NMP_OBJECT_GET_CLASS (obj)->obj_type_name,
|
|
||||||
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
|
|
||||||
|
|
||||||
return klass->object_delete (self, obj);
|
return klass->object_delete (self, obj);
|
||||||
}
|
}
|
||||||
|
|
@ -4970,6 +4965,21 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
nm_platform_routing_rule_add (NMPlatform *self,
|
||||||
|
NMPNlmFlags flags,
|
||||||
|
const NMPlatformRoutingRule *routing_rule)
|
||||||
|
{
|
||||||
|
_CHECK_SELF (self, klass, -NME_BUG);
|
||||||
|
|
||||||
|
g_return_val_if_fail (routing_rule, -NME_BUG);
|
||||||
|
|
||||||
|
_LOGD ("routing-rule: adding or updating: %s", nm_platform_routing_rule_to_string (routing_rule, NULL, 0));
|
||||||
|
return klass->routing_rule_add (self, flags, routing_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
nm_platform_qdisc_add (NMPlatform *self,
|
nm_platform_qdisc_add (NMPlatform *self,
|
||||||
NMPNlmFlags flags,
|
NMPNlmFlags flags,
|
||||||
|
|
@ -6076,6 +6086,253 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_routing_rule_addr_to_string (char **buf,
|
||||||
|
gsize *len,
|
||||||
|
int addr_family,
|
||||||
|
const NMIPAddr *addr,
|
||||||
|
guint8 plen,
|
||||||
|
gboolean is_src)
|
||||||
|
{
|
||||||
|
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
|
gboolean is_zero;
|
||||||
|
gsize addr_size;
|
||||||
|
|
||||||
|
nm_assert_addr_family (addr_family);
|
||||||
|
nm_assert (addr);
|
||||||
|
|
||||||
|
addr_size = nm_utils_addr_family_to_size (addr_family);
|
||||||
|
|
||||||
|
is_zero = nm_utils_memeqzero (addr, addr_size);
|
||||||
|
|
||||||
|
if ( plen == 0
|
||||||
|
&& is_zero) {
|
||||||
|
if (is_src)
|
||||||
|
nm_utils_strbuf_append_str (buf, len, " from all");
|
||||||
|
else
|
||||||
|
nm_utils_strbuf_append_str (buf, len, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm_utils_strbuf_append_str (buf, len, is_src ? " from " : " to ");
|
||||||
|
|
||||||
|
nm_utils_strbuf_append_str (buf, len, nm_utils_inet_ntop (addr_family, addr, s_addr));
|
||||||
|
|
||||||
|
if (plen != (addr_size * 8))
|
||||||
|
nm_utils_strbuf_append (buf, len, "/%u", plen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_routing_rule_port_range_to_string (char **buf,
|
||||||
|
gsize *len,
|
||||||
|
const NMFibRulePortRange *port_range,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
if ( port_range->start == 0
|
||||||
|
&& port_range->end == 0)
|
||||||
|
nm_utils_strbuf_append_str (buf, len, "");
|
||||||
|
else {
|
||||||
|
nm_utils_strbuf_append (buf, len, " %s %u", name, port_range->start);
|
||||||
|
if (port_range->start != port_range->end)
|
||||||
|
nm_utils_strbuf_append (buf, len, "-%u", port_range->end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
nm_platform_routing_rule_to_string (const NMPlatformRoutingRule *routing_rule, char *buf, gsize len)
|
||||||
|
{
|
||||||
|
const char *buf0;
|
||||||
|
guint32 rr_flags;
|
||||||
|
|
||||||
|
if (!nm_utils_to_string_buffer_init_null (routing_rule, &buf, &len))
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
if (!NM_IN_SET (routing_rule->addr_family, AF_INET, AF_INET6)) {
|
||||||
|
/* invalid addr-family. The other fields are undefined. */
|
||||||
|
if (routing_rule->addr_family == AF_UNSPEC)
|
||||||
|
g_snprintf (buf, len, "[routing-rule]");
|
||||||
|
else
|
||||||
|
g_snprintf (buf, len, "[routing-rule family:%u]", routing_rule->addr_family);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf0 = buf;
|
||||||
|
|
||||||
|
rr_flags = routing_rule->flags;
|
||||||
|
|
||||||
|
rr_flags = NM_FLAGS_UNSET (rr_flags, FIB_RULE_INVERT);
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
"[%c] " /* addr-family */
|
||||||
|
"%u:" /* priority */
|
||||||
|
"%s", /* not/FIB_RULE_INVERT */
|
||||||
|
nm_utils_addr_family_to_char (routing_rule->addr_family),
|
||||||
|
routing_rule->priority,
|
||||||
|
( NM_FLAGS_HAS (routing_rule->flags, FIB_RULE_INVERT)
|
||||||
|
? " not"
|
||||||
|
: ""));
|
||||||
|
|
||||||
|
_routing_rule_addr_to_string (&buf, &len,
|
||||||
|
routing_rule->addr_family,
|
||||||
|
&routing_rule->src,
|
||||||
|
routing_rule->src_len,
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
_routing_rule_addr_to_string (&buf, &len,
|
||||||
|
routing_rule->addr_family,
|
||||||
|
&routing_rule->dst,
|
||||||
|
routing_rule->dst_len,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if (routing_rule->tos)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " tos 0x%02x", routing_rule->tos);
|
||||||
|
|
||||||
|
if ( routing_rule->fwmark != 0
|
||||||
|
|| routing_rule->fwmask != 0) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " fwmark %#x", (unsigned) routing_rule->fwmark);
|
||||||
|
if (routing_rule->fwmark != 0xFFFFFFFFu)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, "/%#x", (unsigned) routing_rule->fwmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->iifname[0]) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " iif %s", routing_rule->iifname);
|
||||||
|
rr_flags = NM_FLAGS_UNSET (rr_flags, FIB_RULE_IIF_DETACHED);
|
||||||
|
if (NM_FLAGS_HAS (routing_rule->flags, FIB_RULE_IIF_DETACHED))
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " [detached]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->oifname[0]) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " oif %s", routing_rule->oifname);
|
||||||
|
rr_flags = NM_FLAGS_UNSET (rr_flags, FIB_RULE_OIF_DETACHED);
|
||||||
|
if (NM_FLAGS_HAS (routing_rule->flags, FIB_RULE_OIF_DETACHED))
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " [detached]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->l3mdev != 0) {
|
||||||
|
if (routing_rule->l3mdev == 1)
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " lookup [l3mdev-table]");
|
||||||
|
else {
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " lookup [l3mdev-table/%u]", (unsigned) routing_rule->l3mdev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( routing_rule->uid_range_has
|
||||||
|
|| routing_rule->uid_range.start
|
||||||
|
|| routing_rule->uid_range.end) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" uidrange %u-%u%s",
|
||||||
|
routing_rule->uid_range.start,
|
||||||
|
routing_rule->uid_range.end,
|
||||||
|
routing_rule->uid_range_has ? "" : "(?)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->ip_proto != 0) {
|
||||||
|
/* we don't call getprotobynumber(), just print the numeric value.
|
||||||
|
* This differs from what ip-rule prints. */
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" ipproto %u",
|
||||||
|
routing_rule->ip_proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
_routing_rule_port_range_to_string (&buf, &len,
|
||||||
|
&routing_rule->sport_range,
|
||||||
|
"sport");
|
||||||
|
|
||||||
|
_routing_rule_port_range_to_string (&buf, &len,
|
||||||
|
&routing_rule->dport_range,
|
||||||
|
"dport");
|
||||||
|
|
||||||
|
if (routing_rule->tun_id != 0) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" tun_id %"G_GUINT64_FORMAT,
|
||||||
|
routing_rule->tun_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->table != 0) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" lookup %u",
|
||||||
|
routing_rule->table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->suppress_prefixlen_inverse != 0) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" suppress_prefixlen %d",
|
||||||
|
(int) (~routing_rule->suppress_prefixlen_inverse));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->suppress_ifgroup_inverse != 0) {
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" suppress_ifgroup %d",
|
||||||
|
(int) (~routing_rule->suppress_ifgroup_inverse));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->flow) {
|
||||||
|
/* FRA_FLOW is only for IPv4, but we want to print the value for all address-families,
|
||||||
|
* to see when it is set. In practice, this should not be set except for IPv4.
|
||||||
|
*
|
||||||
|
* We don't follow the style how ip-rule prints flow/realms. It's confusing. Just
|
||||||
|
* print the value hex. */
|
||||||
|
nm_utils_strbuf_append (&buf, &len,
|
||||||
|
" realms 0x%08x",
|
||||||
|
routing_rule->flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->action == RTN_NAT) {
|
||||||
|
G_STATIC_ASSERT_EXPR (RTN_NAT == 10);
|
||||||
|
|
||||||
|
/* NAT is deprecated for many years. We don't support RTA_GATEWAY/FRA_UNUSED2
|
||||||
|
* for the gateway, and so do recent kernels ignore that parameter. */
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " masquerade");
|
||||||
|
} else if (routing_rule->action == FR_ACT_GOTO) {
|
||||||
|
if (routing_rule->goto_target != 0)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " goto %u", routing_rule->goto_target);
|
||||||
|
else
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " goto none");
|
||||||
|
rr_flags = NM_FLAGS_UNSET (rr_flags, FIB_RULE_UNRESOLVED);
|
||||||
|
if (NM_FLAGS_HAS (routing_rule->flags, FIB_RULE_UNRESOLVED))
|
||||||
|
nm_utils_strbuf_append_str (&buf, &len, " unresolved");
|
||||||
|
} else if (routing_rule->action != FR_ACT_TO_TBL) {
|
||||||
|
const char *ss;
|
||||||
|
char ss_buf[60];
|
||||||
|
|
||||||
|
#define _V(v1, v2) ((sizeof (char[(((int) (v1)) == ((int) (v2))) ? 1 : -1]) * 0) + (v1))
|
||||||
|
switch (routing_rule->action) {
|
||||||
|
case _V (FR_ACT_UNSPEC, RTN_UNSPEC) : ss = "none"; break;
|
||||||
|
case _V (FR_ACT_TO_TBL, RTN_UNICAST) : ss = "unicast"; break;
|
||||||
|
case _V (FR_ACT_GOTO, RTN_LOCAL) : ss = "local"; break;
|
||||||
|
case _V (FR_ACT_NOP, RTN_BROADCAST) : ss = "nop"; break;
|
||||||
|
case _V (FR_ACT_RES3, RTN_ANYCAST) : ss = "anycast"; break;
|
||||||
|
case _V (FR_ACT_RES4, RTN_MULTICAST) : ss = "multicast"; break;
|
||||||
|
case _V (FR_ACT_BLACKHOLE, RTN_BLACKHOLE) : ss = "blackhole"; break;
|
||||||
|
case _V (FR_ACT_UNREACHABLE, RTN_UNREACHABLE) : ss = "unreachable"; break;
|
||||||
|
case _V (FR_ACT_PROHIBIT, RTN_PROHIBIT) : ss = "prohibit"; break;
|
||||||
|
case RTN_THROW : ss = "throw"; break;
|
||||||
|
case RTN_NAT : ss = "nat"; break;
|
||||||
|
case RTN_XRESOLVE : ss = "xresolve"; break;
|
||||||
|
default:
|
||||||
|
ss = nm_sprintf_buf (ss_buf, "action-%u", routing_rule->action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef _V
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " %s", ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routing_rule->protocol != RTPROT_UNSPEC)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " protocol %u", routing_rule->protocol);
|
||||||
|
|
||||||
|
if ( routing_rule->goto_target != 0
|
||||||
|
&& routing_rule->action != FR_ACT_GOTO) {
|
||||||
|
/* a trailing target is set for an unexpected action. Print it. */
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " goto-target %u", routing_rule->goto_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rr_flags != 0) {
|
||||||
|
/* we have some flags we didn't print about yet. */
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " remaining-flags %x", rr_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
|
nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
|
||||||
{
|
{
|
||||||
|
|
@ -7034,6 +7291,186 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _ROUTING_RULE_FLAGS_IGNORE ( FIB_RULE_UNRESOLVED \
|
||||||
|
| FIB_RULE_IIF_DETACHED \
|
||||||
|
| FIB_RULE_OIF_DETACHED)
|
||||||
|
|
||||||
|
void
|
||||||
|
nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj,
|
||||||
|
NMPlatformRoutingRuleCmpType cmp_type,
|
||||||
|
NMHashState *h)
|
||||||
|
{
|
||||||
|
gboolean cmp_full = TRUE;
|
||||||
|
gsize addr_size;
|
||||||
|
guint32 flags_mask = G_MAXUINT32;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!NM_IN_SET (obj->addr_family, AF_INET, AF_INET6))) {
|
||||||
|
/* the address family is not one of the supported ones. That means, the
|
||||||
|
* instance will only compare equal to itself (pointer-equality). */
|
||||||
|
nm_hash_update_val (h, (gconstpointer) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmp_type) {
|
||||||
|
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID:
|
||||||
|
|
||||||
|
flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE;
|
||||||
|
|
||||||
|
/* fall-through */
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY:
|
||||||
|
|
||||||
|
cmp_full = FALSE;
|
||||||
|
|
||||||
|
/* fall-through */
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL:
|
||||||
|
|
||||||
|
|
||||||
|
nm_hash_update_vals (h,
|
||||||
|
obj->addr_family,
|
||||||
|
obj->tun_id,
|
||||||
|
obj->table,
|
||||||
|
obj->flags & flags_mask,
|
||||||
|
obj->priority,
|
||||||
|
obj->fwmark,
|
||||||
|
obj->fwmask,
|
||||||
|
( ( cmp_full
|
||||||
|
|| ( cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY
|
||||||
|
&& obj->action == FR_ACT_GOTO))
|
||||||
|
? obj->goto_target
|
||||||
|
: (guint32) 0u),
|
||||||
|
( ( cmp_full
|
||||||
|
|| obj->addr_family == AF_INET)
|
||||||
|
? obj->flow
|
||||||
|
: (guint32) 0u),
|
||||||
|
NM_HASH_COMBINE_BOOLS (guint8,
|
||||||
|
obj->uid_range_has),
|
||||||
|
obj->suppress_prefixlen_inverse,
|
||||||
|
obj->suppress_ifgroup_inverse,
|
||||||
|
( cmp_full
|
||||||
|
? obj->l3mdev
|
||||||
|
: (guint8) !!obj->l3mdev),
|
||||||
|
obj->action,
|
||||||
|
obj->tos,
|
||||||
|
obj->src_len,
|
||||||
|
obj->dst_len,
|
||||||
|
obj->protocol,
|
||||||
|
obj->ip_proto);
|
||||||
|
addr_size = nm_utils_addr_family_to_size (obj->addr_family);
|
||||||
|
if (cmp_full || obj->src_len > 0)
|
||||||
|
nm_hash_update (h, &obj->src, addr_size);
|
||||||
|
if (cmp_full || obj->dst_len > 0)
|
||||||
|
nm_hash_update (h, &obj->dst, addr_size);
|
||||||
|
if (cmp_full || obj->uid_range_has)
|
||||||
|
nm_hash_update_valp (h, &obj->uid_range);
|
||||||
|
nm_hash_update_valp (h, &obj->sport_range);
|
||||||
|
nm_hash_update_valp (h, &obj->dport_range);
|
||||||
|
nm_hash_update_str (h, obj->iifname);
|
||||||
|
nm_hash_update_str (h, obj->oifname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a,
|
||||||
|
const NMPlatformRoutingRule *b,
|
||||||
|
NMPlatformRoutingRuleCmpType cmp_type)
|
||||||
|
{
|
||||||
|
gboolean cmp_full = TRUE;
|
||||||
|
gsize addr_size;
|
||||||
|
bool valid;
|
||||||
|
guint32 flags_mask = G_MAXUINT32;
|
||||||
|
|
||||||
|
NM_CMP_SELF (a, b);
|
||||||
|
|
||||||
|
valid = NM_IN_SET (a->addr_family, AF_INET, AF_INET6);
|
||||||
|
NM_CMP_DIRECT (valid,
|
||||||
|
(bool) NM_IN_SET (b->addr_family, AF_INET, AF_INET6));
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!valid)) {
|
||||||
|
/* the address family is not one of the supported ones. That means, the
|
||||||
|
* instance will only compare equal to itself. */
|
||||||
|
NM_CMP_DIRECT ((uintptr_t) a, (uintptr_t) b);
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmp_type) {
|
||||||
|
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID:
|
||||||
|
|
||||||
|
flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE;
|
||||||
|
|
||||||
|
/* fall-through */
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY:
|
||||||
|
|
||||||
|
cmp_full = FALSE;
|
||||||
|
|
||||||
|
/* fall-through */
|
||||||
|
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL:
|
||||||
|
NM_CMP_FIELD (a, b, addr_family);
|
||||||
|
NM_CMP_FIELD (a, b, action);
|
||||||
|
NM_CMP_FIELD (a, b, priority);
|
||||||
|
NM_CMP_FIELD (a, b, tun_id);
|
||||||
|
|
||||||
|
if (cmp_full)
|
||||||
|
NM_CMP_FIELD (a, b, l3mdev);
|
||||||
|
else
|
||||||
|
NM_CMP_FIELD_BOOL (a, b, l3mdev);
|
||||||
|
|
||||||
|
if (cmp_full || !a->l3mdev)
|
||||||
|
NM_CMP_FIELD (a, b, table);
|
||||||
|
|
||||||
|
NM_CMP_DIRECT (a->flags & flags_mask, b->flags & flags_mask);
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, fwmark);
|
||||||
|
NM_CMP_FIELD (a, b, fwmask);
|
||||||
|
|
||||||
|
if ( cmp_full
|
||||||
|
|| ( cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY
|
||||||
|
&& a->action == FR_ACT_GOTO))
|
||||||
|
NM_CMP_FIELD (a, b, goto_target);
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, suppress_prefixlen_inverse);
|
||||||
|
NM_CMP_FIELD (a, b, suppress_ifgroup_inverse);
|
||||||
|
NM_CMP_FIELD (a, b, tos);
|
||||||
|
|
||||||
|
if (cmp_full || a->addr_family == AF_INET)
|
||||||
|
NM_CMP_FIELD (a, b, flow);
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, protocol);
|
||||||
|
NM_CMP_FIELD (a, b, ip_proto);
|
||||||
|
addr_size = nm_utils_addr_family_to_size (a->addr_family);
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, src_len);
|
||||||
|
if (cmp_full || a->src_len > 0)
|
||||||
|
NM_CMP_FIELD_MEMCMP_LEN (a, b, src, addr_size);
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, dst_len);
|
||||||
|
if (cmp_full || a->dst_len > 0)
|
||||||
|
NM_CMP_FIELD_MEMCMP_LEN (a, b, dst, addr_size);
|
||||||
|
|
||||||
|
NM_CMP_FIELD_UNSAFE (a, b, uid_range_has);
|
||||||
|
if (cmp_full || a->uid_range_has) {
|
||||||
|
NM_CMP_FIELD (a, b, uid_range.start);
|
||||||
|
NM_CMP_FIELD (a, b, uid_range.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
NM_CMP_FIELD (a, b, sport_range.start);
|
||||||
|
NM_CMP_FIELD (a, b, sport_range.end);
|
||||||
|
NM_CMP_FIELD (a, b, dport_range.start);
|
||||||
|
NM_CMP_FIELD (a, b, dport_range.end);
|
||||||
|
NM_CMP_FIELD_STR (a, b, iifname);
|
||||||
|
NM_CMP_FIELD_STR (a, b, oifname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_platform_ip_address_cmp_expiry:
|
* nm_platform_ip_address_cmp_expiry:
|
||||||
* @a: a NMPlatformIPAddress to compare
|
* @a: a NMPlatformIPAddress to compare
|
||||||
|
|
@ -7130,6 +7567,13 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform
|
||||||
_LOG3D ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0));
|
_LOG3D ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
log_routing_rule (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformRoutingRule *routing_rule, NMPlatformSignalChangeType change_type, gpointer user_data)
|
||||||
|
{
|
||||||
|
/* routing rules don't have an ifindex. We probably should refactor the signals that are emitted for platform changes. */
|
||||||
|
_LOG3D ("signal: rt-rule %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_routing_rule_to_string (routing_rule, NULL, 0));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdisc *qdisc, NMPlatformSignalChangeType change_type, gpointer user_data)
|
log_qdisc (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformQdisc *qdisc, NMPlatformSignalChangeType change_type, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
|
@ -7196,9 +7640,13 @@ nm_platform_cache_update_emit_signal (NMPlatform *self,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ifindex = o->object.ifindex;
|
|
||||||
klass = NMP_OBJECT_GET_CLASS (o);
|
klass = NMP_OBJECT_GET_CLASS (o);
|
||||||
|
|
||||||
|
if (klass->obj_type == NMP_OBJECT_TYPE_ROUTING_RULE)
|
||||||
|
ifindex = 0;
|
||||||
|
else
|
||||||
|
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (o)->ifindex;
|
||||||
|
|
||||||
if ( klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
|
if ( klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
|
||||||
&& NM_PLATFORM_GET_PRIVATE (self)->ip4_dev_route_blacklist_gc_timeout_id
|
&& NM_PLATFORM_GET_PRIVATE (self)->ip4_dev_route_blacklist_gc_timeout_id
|
||||||
&& NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED))
|
&& NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED))
|
||||||
|
|
@ -7214,7 +7662,7 @@ nm_platform_cache_update_emit_signal (NMPlatform *self,
|
||||||
_nm_platform_signal_id_get (klass->signal_type_id),
|
_nm_platform_signal_id_get (klass->signal_type_id),
|
||||||
0,
|
0,
|
||||||
(int) klass->obj_type,
|
(int) klass->obj_type,
|
||||||
o->object.ifindex,
|
ifindex,
|
||||||
&o->object,
|
&o->object,
|
||||||
(int) cache_op);
|
(int) cache_op);
|
||||||
nmp_object_unref (o);
|
nmp_object_unref (o);
|
||||||
|
|
@ -7261,24 +7709,25 @@ _vtr_v4_metric_normalize (guint32 metric)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
|
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
|
||||||
.is_ip4 = TRUE,
|
.v4 = {
|
||||||
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
.is_ip4 = TRUE,
|
||||||
.addr_family = AF_INET,
|
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
.sizeof_route = sizeof (NMPlatformIP4Route),
|
.addr_family = AF_INET,
|
||||||
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
|
.sizeof_route = sizeof (NMPlatformIP4Route),
|
||||||
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
|
||||||
.metric_normalize = _vtr_v4_metric_normalize,
|
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
||||||
};
|
.metric_normalize = _vtr_v4_metric_normalize,
|
||||||
|
},
|
||||||
const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
|
.v6 = {
|
||||||
.is_ip4 = FALSE,
|
.is_ip4 = FALSE,
|
||||||
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
|
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||||
.addr_family = AF_INET6,
|
.addr_family = AF_INET6,
|
||||||
.sizeof_route = sizeof (NMPlatformIP6Route),
|
.sizeof_route = sizeof (NMPlatformIP6Route),
|
||||||
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp,
|
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp,
|
||||||
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
|
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
|
||||||
.metric_normalize = nm_utils_ip6_route_metric_normalize,
|
.metric_normalize = nm_utils_ip6_route_metric_normalize,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -7338,8 +7787,9 @@ constructor (GType type,
|
||||||
|
|
||||||
priv->multi_idx = nm_dedup_multi_index_new ();
|
priv->multi_idx = nm_dedup_multi_index_new ();
|
||||||
|
|
||||||
priv->cache = nmp_cache_new (nm_platform_get_multi_idx (self),
|
priv->cache = nmp_cache_new (priv->multi_idx,
|
||||||
priv->use_udev);
|
priv->use_udev);
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7411,11 +7861,12 @@ nm_platform_class_init (NMPlatformClass *platform_class)
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
/* Signals */
|
/* Signals */
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_LINK, NM_PLATFORM_SIGNAL_LINK_CHANGED, log_link);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_LINK, NM_PLATFORM_SIGNAL_LINK_CHANGED, log_link);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, log_ip4_address);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, log_ip4_address);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_ROUTING_RULE, NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED, log_routing_rule);
|
||||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter);
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc);
|
||||||
|
SIGNAL (NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,14 @@ typedef enum {
|
||||||
|
|
||||||
} NMPlatformIPRouteCmpType;
|
} NMPlatformIPRouteCmpType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
|
||||||
|
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY,
|
||||||
|
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL,
|
||||||
|
} NMPlatformRoutingRuleCmpType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
/* match-flags are strictly inclusive. That means,
|
/* match-flags are strictly inclusive. That means,
|
||||||
|
|
@ -181,12 +189,22 @@ typedef enum {
|
||||||
|
|
||||||
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
|
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
|
||||||
|
|
||||||
#define __NMPlatformObject_COMMON \
|
struct _NMPlatformObject {
|
||||||
|
/* the object type has no fields of its own, it is only used to having
|
||||||
|
* a special pointer type that can be used to indicate "any" type. */
|
||||||
|
char _dummy_don_t_use_me;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define __NMPlatformObjWithIfindex_COMMON \
|
||||||
int ifindex; \
|
int ifindex; \
|
||||||
;
|
;
|
||||||
|
|
||||||
|
struct _NMPlatformObjWithIfindex {
|
||||||
|
__NMPlatformObjWithIfindex_COMMON;
|
||||||
|
};
|
||||||
|
|
||||||
struct _NMPlatformLink {
|
struct _NMPlatformLink {
|
||||||
__NMPlatformObject_COMMON;
|
__NMPlatformObjWithIfindex_COMMON;
|
||||||
char name[NMP_IFNAMSIZ];
|
char name[NMP_IFNAMSIZ];
|
||||||
NMLinkType type;
|
NMLinkType type;
|
||||||
|
|
||||||
|
|
@ -246,6 +264,7 @@ typedef enum { /*< skip >*/
|
||||||
NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
|
NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
|
||||||
NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
|
NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
|
||||||
NM_PLATFORM_SIGNAL_ID_IP6_ROUTE,
|
NM_PLATFORM_SIGNAL_ID_IP6_ROUTE,
|
||||||
|
NM_PLATFORM_SIGNAL_ID_ROUTING_RULE,
|
||||||
NM_PLATFORM_SIGNAL_ID_QDISC,
|
NM_PLATFORM_SIGNAL_ID_QDISC,
|
||||||
NM_PLATFORM_SIGNAL_ID_TFILTER,
|
NM_PLATFORM_SIGNAL_ID_TFILTER,
|
||||||
_NM_PLATFORM_SIGNAL_ID_LAST,
|
_NM_PLATFORM_SIGNAL_ID_LAST,
|
||||||
|
|
@ -260,15 +279,11 @@ typedef enum {
|
||||||
NM_PLATFORM_SIGNAL_REMOVED,
|
NM_PLATFORM_SIGNAL_REMOVED,
|
||||||
} NMPlatformSignalChangeType;
|
} NMPlatformSignalChangeType;
|
||||||
|
|
||||||
struct _NMPlatformObject {
|
|
||||||
__NMPlatformObject_COMMON;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NM_PLATFORM_IP_ADDRESS_CAST(address) \
|
#define NM_PLATFORM_IP_ADDRESS_CAST(address) \
|
||||||
NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address)
|
NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address)
|
||||||
|
|
||||||
#define __NMPlatformIPAddress_COMMON \
|
#define __NMPlatformIPAddress_COMMON \
|
||||||
__NMPlatformObject_COMMON; \
|
__NMPlatformObjWithIfindex_COMMON; \
|
||||||
NMIPConfigSource addr_source; \
|
NMIPConfigSource addr_source; \
|
||||||
\
|
\
|
||||||
/* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*().
|
/* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*().
|
||||||
|
|
@ -370,7 +385,7 @@ typedef union {
|
||||||
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
|
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0
|
||||||
|
|
||||||
#define __NMPlatformIPRoute_COMMON \
|
#define __NMPlatformIPRoute_COMMON \
|
||||||
__NMPlatformObject_COMMON; \
|
__NMPlatformObjWithIfindex_COMMON; \
|
||||||
\
|
\
|
||||||
/* The NMIPConfigSource. For routes that we receive from cache this corresponds
|
/* 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).
|
* to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
|
||||||
|
|
@ -540,7 +555,49 @@ typedef union {
|
||||||
#undef __NMPlatformIPRoute_COMMON
|
#undef __NMPlatformIPRoute_COMMON
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__NMPlatformObject_COMMON;
|
/* struct fib_rule_uid_range */
|
||||||
|
guint32 start;
|
||||||
|
guint32 end;
|
||||||
|
} NMFibRuleUidRange;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* struct fib_rule_port_range */
|
||||||
|
guint16 start;
|
||||||
|
guint16 end;
|
||||||
|
} NMFibRulePortRange;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMIPAddr src; /* FRA_SRC */
|
||||||
|
NMIPAddr dst; /* FRA_DST */
|
||||||
|
guint64 tun_id; /* betoh64(FRA_TUN_ID) */
|
||||||
|
guint32 table; /* (struct fib_rule_hdr).table, FRA_TABLE */
|
||||||
|
guint32 flags; /* (struct fib_rule_hdr).flags */
|
||||||
|
guint32 priority; /* RA_PRIORITY */
|
||||||
|
guint32 fwmark; /* FRA_FWMARK */
|
||||||
|
guint32 fwmask; /* FRA_FWMASK */
|
||||||
|
guint32 goto_target; /* FRA_GOTO */
|
||||||
|
guint32 flow; /* FRA_FLOW */
|
||||||
|
guint32 suppress_prefixlen_inverse; /* ~(FRA_SUPPRESS_PREFIXLEN) */
|
||||||
|
guint32 suppress_ifgroup_inverse; /* ~(FRA_SUPPRESS_IFGROUP) */
|
||||||
|
NMFibRuleUidRange uid_range; /* FRA_UID_RANGE */
|
||||||
|
NMFibRulePortRange sport_range; /* FRA_SPORT_RANGE */
|
||||||
|
NMFibRulePortRange dport_range; /* FRA_DPORT_RANGE */
|
||||||
|
char iifname[NMP_IFNAMSIZ]; /* FRA_IIFNAME */
|
||||||
|
char oifname[NMP_IFNAMSIZ]; /* FRA_OIFNAME */
|
||||||
|
guint8 addr_family; /* (struct fib_rule_hdr).family */
|
||||||
|
guint8 action; /* (struct fib_rule_hdr).action */
|
||||||
|
guint8 tos; /* (struct fib_rule_hdr).tos */
|
||||||
|
guint8 src_len; /* (struct fib_rule_hdr).src_len */
|
||||||
|
guint8 dst_len; /* (struct fib_rule_hdr).dst_len */
|
||||||
|
guint8 l3mdev; /* FRA_L3MDEV */
|
||||||
|
guint8 protocol; /* FRA_PROTOCOL */
|
||||||
|
guint8 ip_proto; /* FRA_IP_PROTO */
|
||||||
|
|
||||||
|
bool uid_range_has:1; /* has(FRA_UID_RANGE) */
|
||||||
|
} NMPlatformRoutingRule;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__NMPlatformObjWithIfindex_COMMON;
|
||||||
const char *kind;
|
const char *kind;
|
||||||
int addr_family;
|
int addr_family;
|
||||||
guint32 handle;
|
guint32 handle;
|
||||||
|
|
@ -562,7 +619,7 @@ typedef struct {
|
||||||
#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple"
|
#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__NMPlatformObject_COMMON;
|
__NMPlatformObjWithIfindex_COMMON;
|
||||||
const char *kind;
|
const char *kind;
|
||||||
int addr_family;
|
int addr_family;
|
||||||
guint32 handle;
|
guint32 handle;
|
||||||
|
|
@ -571,7 +628,7 @@ typedef struct {
|
||||||
NMPlatformAction action;
|
NMPlatformAction action;
|
||||||
} NMPlatformTfilter;
|
} NMPlatformTfilter;
|
||||||
|
|
||||||
#undef __NMPlatformObject_COMMON
|
#undef __NMPlatformObjWithIfindex_COMMON
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gboolean is_ip4;
|
gboolean is_ip4;
|
||||||
|
|
@ -583,8 +640,15 @@ typedef struct {
|
||||||
guint32 (*metric_normalize) (guint32 metric);
|
guint32 (*metric_normalize) (guint32 metric);
|
||||||
} NMPlatformVTableRoute;
|
} NMPlatformVTableRoute;
|
||||||
|
|
||||||
extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
|
typedef union {
|
||||||
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
|
struct {
|
||||||
|
NMPlatformVTableRoute v6;
|
||||||
|
NMPlatformVTableRoute v4;
|
||||||
|
};
|
||||||
|
NMPlatformVTableRoute vx[2];
|
||||||
|
} _NMPlatformVTableRouteUnion;
|
||||||
|
|
||||||
|
extern const _NMPlatformVTableRouteUnion nm_platform_vtable_route;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
guint16 id;
|
guint16 id;
|
||||||
|
|
@ -793,8 +857,6 @@ typedef struct {
|
||||||
gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
|
gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
|
||||||
char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
|
char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
|
||||||
|
|
||||||
void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type);
|
|
||||||
|
|
||||||
int (*link_add) (NMPlatform *,
|
int (*link_add) (NMPlatform *,
|
||||||
const char *name,
|
const char *name,
|
||||||
NMLinkType type,
|
NMLinkType type,
|
||||||
|
|
@ -973,6 +1035,10 @@ typedef struct {
|
||||||
int oif_ifindex,
|
int oif_ifindex,
|
||||||
NMPObject **out_route);
|
NMPObject **out_route);
|
||||||
|
|
||||||
|
int (*routing_rule_add) (NMPlatform *self,
|
||||||
|
NMPNlmFlags flags,
|
||||||
|
const NMPlatformRoutingRule *routing_rule);
|
||||||
|
|
||||||
int (*qdisc_add) (NMPlatform *self,
|
int (*qdisc_add) (NMPlatform *self,
|
||||||
NMPNlmFlags flags,
|
NMPNlmFlags flags,
|
||||||
const NMPlatformQdisc *qdisc);
|
const NMPlatformQdisc *qdisc);
|
||||||
|
|
@ -1001,6 +1067,7 @@ typedef struct {
|
||||||
#define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed"
|
#define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed"
|
||||||
#define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed"
|
#define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed"
|
||||||
#define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed"
|
#define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed"
|
||||||
|
#define NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED "routing-rule-changed"
|
||||||
#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed"
|
#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed"
|
||||||
#define NM_PLATFORM_SIGNAL_TFILTER_CHANGED "tfilter-changed"
|
#define NM_PLATFORM_SIGNAL_TFILTER_CHANGED "tfilter-changed"
|
||||||
|
|
||||||
|
|
@ -1167,8 +1234,6 @@ gboolean nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (NMPlatform *self,
|
||||||
const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */);
|
const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */);
|
||||||
int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname);
|
int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname);
|
||||||
|
|
||||||
void nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type);
|
|
||||||
|
|
||||||
const NMPObject *nm_platform_link_get_obj (NMPlatform *self,
|
const NMPObject *nm_platform_link_get_obj (NMPlatform *self,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
gboolean visible_only);
|
gboolean visible_only);
|
||||||
|
|
@ -1482,6 +1547,10 @@ int nm_platform_ip_route_get (NMPlatform *self,
|
||||||
int oif_ifindex,
|
int oif_ifindex,
|
||||||
NMPObject **out_route);
|
NMPObject **out_route);
|
||||||
|
|
||||||
|
int nm_platform_routing_rule_add (NMPlatform *self,
|
||||||
|
NMPNlmFlags flags,
|
||||||
|
const NMPlatformRoutingRule *routing_rule);
|
||||||
|
|
||||||
int nm_platform_qdisc_add (NMPlatform *self,
|
int nm_platform_qdisc_add (NMPlatform *self,
|
||||||
NMPNlmFlags flags,
|
NMPNlmFlags flags,
|
||||||
const NMPlatformQdisc *qdisc);
|
const NMPlatformQdisc *qdisc);
|
||||||
|
|
@ -1512,6 +1581,7 @@ const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *addre
|
||||||
const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len);
|
const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len);
|
||||||
const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len);
|
const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len);
|
||||||
const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
|
const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
|
||||||
|
const char *nm_platform_routing_rule_to_string (const NMPlatformRoutingRule *routing_rule, char *buf, gsize len);
|
||||||
const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len);
|
const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len);
|
||||||
const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len);
|
const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len);
|
||||||
const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len);
|
const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len);
|
||||||
|
|
@ -1556,6 +1626,14 @@ nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6
|
||||||
return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
return nm_platform_ip6_route_cmp (a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a, const NMPlatformRoutingRule *b, NMPlatformRoutingRuleCmpType cmp_type);
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
nm_platform_routing_rule_cmp_full (const NMPlatformRoutingRule *a, const NMPlatformRoutingRule *b)
|
||||||
|
{
|
||||||
|
return nm_platform_routing_rule_cmp (a, b, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b);
|
int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b);
|
||||||
int nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b);
|
int nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b);
|
||||||
|
|
||||||
|
|
@ -1564,6 +1642,7 @@ void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHas
|
||||||
void nm_platform_ip6_address_hash_update (const NMPlatformIP6Address *obj, NMHashState *h);
|
void nm_platform_ip6_address_hash_update (const NMPlatformIP6Address *obj, NMHashState *h);
|
||||||
void nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type, NMHashState *h);
|
void nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type, NMHashState *h);
|
||||||
void nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpType cmp_type, NMHashState *h);
|
void nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpType cmp_type, NMHashState *h);
|
||||||
|
void nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, NMPlatformRoutingRuleCmpType cmp_type, NMHashState *h);
|
||||||
void nm_platform_lnk_gre_hash_update (const NMPlatformLnkGre *obj, NMHashState *h);
|
void nm_platform_lnk_gre_hash_update (const NMPlatformLnkGre *obj, NMHashState *h);
|
||||||
void nm_platform_lnk_infiniband_hash_update (const NMPlatformLnkInfiniband *obj, NMHashState *h);
|
void nm_platform_lnk_infiniband_hash_update (const NMPlatformLnkInfiniband *obj, NMHashState *h);
|
||||||
void nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState *h);
|
void nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState *h);
|
||||||
|
|
|
||||||
|
|
@ -389,16 +389,16 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
||||||
nm_hash_update_val (h, obj_a);
|
nm_hash_update_val (h, obj_a);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
nm_assert (obj_a->object.ifindex > 0);
|
nm_assert (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_a)->ifindex > 0);
|
||||||
if (obj_b) {
|
if (obj_b) {
|
||||||
return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b)
|
return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b)
|
||||||
&& obj_a->object.ifindex == obj_b->object.ifindex
|
&& NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_a)->ifindex == NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_b)->ifindex
|
||||||
&& nmp_object_is_visible (obj_b);
|
&& nmp_object_is_visible (obj_b);
|
||||||
}
|
}
|
||||||
if (h) {
|
if (h) {
|
||||||
nm_hash_update_vals (h,
|
nm_hash_update_vals (h,
|
||||||
idx_type->cache_id_type,
|
idx_type->cache_id_type,
|
||||||
obj_a->object.ifindex);
|
NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_a)->ifindex);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -406,14 +406,14 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
||||||
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
||||||
if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
|
if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE)
|
NMP_OBJECT_TYPE_IP6_ROUTE)
|
||||||
|| obj_a->object.ifindex <= 0) {
|
|| NMP_OBJECT_CAST_IP_ROUTE (obj_a)->ifindex <= 0) {
|
||||||
if (h)
|
if (h)
|
||||||
nm_hash_update_val (h, obj_a);
|
nm_hash_update_val (h, obj_a);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (obj_b) {
|
if (obj_b) {
|
||||||
return obj_type == NMP_OBJECT_GET_TYPE (obj_b)
|
return obj_type == NMP_OBJECT_GET_TYPE (obj_b)
|
||||||
&& obj_b->object.ifindex > 0
|
&& NMP_OBJECT_CAST_IP_ROUTE (obj_b)->ifindex > 0
|
||||||
&& (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
|
&& (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
|
||||||
? (nm_platform_ip4_route_cmp (&obj_a->ip4_route, &obj_b->ip4_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0)
|
? (nm_platform_ip4_route_cmp (&obj_a->ip4_route, &obj_b->ip4_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0)
|
||||||
: (nm_platform_ip6_route_cmp (&obj_a->ip6_route, &obj_b->ip6_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0));
|
: (nm_platform_ip6_route_cmp (&obj_a->ip6_route, &obj_b->ip6_route, NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) == 0));
|
||||||
|
|
@ -427,6 +427,25 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY:
|
||||||
|
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
||||||
|
/* currently, only routing rules are supported for this cache-id-type. */
|
||||||
|
if ( obj_type != NMP_OBJECT_TYPE_ROUTING_RULE
|
||||||
|
|| !NM_IN_SET (obj_a->routing_rule.addr_family, AF_INET, AF_INET6)) {
|
||||||
|
if (h)
|
||||||
|
nm_hash_update_val (h, obj_a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (obj_b) {
|
||||||
|
return NMP_OBJECT_GET_TYPE (obj_b) == NMP_OBJECT_TYPE_ROUTING_RULE
|
||||||
|
&& obj_a->routing_rule.addr_family == obj_b->routing_rule.addr_family;
|
||||||
|
}
|
||||||
|
if (h) {
|
||||||
|
nm_hash_update_vals (h, idx_type->cache_id_type,
|
||||||
|
obj_a->routing_rule.addr_family);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
case NMP_CACHE_ID_TYPE_NONE:
|
case NMP_CACHE_ID_TYPE_NONE:
|
||||||
case __NMP_CACHE_ID_TYPE_MAX:
|
case __NMP_CACHE_ID_TYPE_MAX:
|
||||||
break;
|
break;
|
||||||
|
|
@ -712,16 +731,6 @@ _nmp_object_fixup_link_master_connected (NMPObject **obj_new, NMPObject *obj_ori
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
const NMPClass *
|
|
||||||
nmp_class_from_type (NMPObjectType obj_type)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (obj_type > NMP_OBJECT_TYPE_UNKNOWN && obj_type <= NMP_OBJECT_TYPE_MAX, NULL);
|
|
||||||
|
|
||||||
return &_nmp_classes[obj_type - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_vt_cmd_obj_dispose_link (NMPObject *obj)
|
_vt_cmd_obj_dispose_link (NMPObject *obj)
|
||||||
{
|
{
|
||||||
|
|
@ -1369,6 +1378,10 @@ _vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
nm_assert (nm_platform_ip6_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0);
|
nm_assert (nm_platform_ip6_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0);
|
||||||
});
|
});
|
||||||
|
_vt_cmd_plobj_id_copy (routing_rule, NMPlatformRoutingRule, {
|
||||||
|
*dst = *src;
|
||||||
|
nm_assert (nm_platform_routing_rule_cmp (dst, src, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0);
|
||||||
|
});
|
||||||
|
|
||||||
/* Uses internally nmp_object_copy(), hence it also violates the const
|
/* Uses internally nmp_object_copy(), hence it also violates the const
|
||||||
* promise for @obj.
|
* promise for @obj.
|
||||||
|
|
@ -1469,6 +1482,12 @@ _vt_cmd_plobj_id_cmp_ip6_route (const NMPlatformObject *obj1, const NMPlatformOb
|
||||||
return nm_platform_ip6_route_cmp ((NMPlatformIP6Route *) obj1, (NMPlatformIP6Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
return nm_platform_ip6_route_cmp ((NMPlatformIP6Route *) obj1, (NMPlatformIP6Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_vt_cmd_plobj_id_cmp_routing_rule (const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||||
|
{
|
||||||
|
return nm_platform_routing_rule_cmp ((NMPlatformRoutingRule *) obj1, (NMPlatformRoutingRule *) obj2, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nmp_object_id_hash_update (const NMPObject *obj, NMHashState *h)
|
nmp_object_id_hash_update (const NMPObject *obj, NMHashState *h)
|
||||||
{
|
{
|
||||||
|
|
@ -1534,6 +1553,9 @@ _vt_cmd_plobj_id_hash_update (ip4_route, NMPlatformIP4Route, {
|
||||||
_vt_cmd_plobj_id_hash_update (ip6_route, NMPlatformIP6Route, {
|
_vt_cmd_plobj_id_hash_update (ip6_route, NMPlatformIP6Route, {
|
||||||
nm_platform_ip6_route_hash_update (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h);
|
nm_platform_ip6_route_hash_update (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h);
|
||||||
})
|
})
|
||||||
|
_vt_cmd_plobj_id_hash_update (routing_rule, NMPlatformRoutingRule, {
|
||||||
|
nm_platform_routing_rule_hash_update (obj, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID, h);
|
||||||
|
})
|
||||||
_vt_cmd_plobj_id_hash_update (qdisc, NMPlatformQdisc, {
|
_vt_cmd_plobj_id_hash_update (qdisc, NMPlatformQdisc, {
|
||||||
nm_hash_update_vals (h,
|
nm_hash_update_vals (h,
|
||||||
obj->ifindex,
|
obj->ifindex,
|
||||||
|
|
@ -1557,6 +1579,12 @@ _vt_cmd_plobj_hash_update_ip6_route (const NMPlatformObject *obj, NMHashState *h
|
||||||
return nm_platform_ip6_route_hash_update ((const NMPlatformIP6Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h);
|
return nm_platform_ip6_route_hash_update ((const NMPlatformIP6Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_vt_cmd_plobj_hash_update_routing_rule (const NMPlatformObject *obj, NMHashState *h)
|
||||||
|
{
|
||||||
|
return nm_platform_routing_rule_hash_update ((const NMPlatformRoutingRule *) obj, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL, h);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nmp_object_is_alive (const NMPObject *obj)
|
nmp_object_is_alive (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
|
|
@ -1574,13 +1602,14 @@ nmp_object_is_alive (const NMPObject *obj)
|
||||||
static gboolean
|
static gboolean
|
||||||
_vt_cmd_obj_is_alive_link (const NMPObject *obj)
|
_vt_cmd_obj_is_alive_link (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
return obj->object.ifindex > 0 && (obj->_link.netlink.is_in_netlink || obj->_link.udev.device);
|
return NMP_OBJECT_CAST_LINK (obj)->ifindex > 0
|
||||||
|
&& (obj->_link.netlink.is_in_netlink || obj->_link.udev.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_vt_cmd_obj_is_alive_ipx_address (const NMPObject *obj)
|
_vt_cmd_obj_is_alive_ipx_address (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
return obj->object.ifindex > 0;
|
return NMP_OBJECT_CAST_IP_ADDRESS (obj)->ifindex > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -1601,20 +1630,26 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj)
|
||||||
* Instead we create a dead object, and nmp_cache_update_netlink()
|
* Instead we create a dead object, and nmp_cache_update_netlink()
|
||||||
* will remove the old version of the update.
|
* will remove the old version of the update.
|
||||||
**/
|
**/
|
||||||
return obj->object.ifindex > 0
|
return NMP_OBJECT_CAST_IP_ROUTE (obj)->ifindex > 0
|
||||||
&& !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED);
|
&& !NM_FLAGS_HAS (obj->ip_route.r_rtm_flags, RTM_F_CLONED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_vt_cmd_obj_is_alive_routing_rule (const NMPObject *obj)
|
||||||
|
{
|
||||||
|
return NM_IN_SET (obj->routing_rule.addr_family, AF_INET, AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj)
|
_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
return obj->object.ifindex > 0;
|
return NMP_OBJECT_CAST_QDISC (obj)->ifindex > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_vt_cmd_obj_is_alive_tfilter (const NMPObject *obj)
|
_vt_cmd_obj_is_alive_tfilter (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
return obj->object.ifindex > 0;
|
return NMP_OBJECT_CAST_TFILTER (obj)->ifindex > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
@ -1672,6 +1707,12 @@ static const guint8 _supported_cache_ids_ipx_route[] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const guint8 _supported_cache_ids_routing_rules[] = {
|
||||||
|
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||||
|
NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -1949,6 +1990,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup,
|
||||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
|
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||||
case NMP_OBJECT_TYPE_QDISC:
|
case NMP_OBJECT_TYPE_QDISC:
|
||||||
case NMP_OBJECT_TYPE_TFILTER:
|
case NMP_OBJECT_TYPE_TFILTER:
|
||||||
_nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
_nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
||||||
|
|
@ -1998,7 +2040,7 @@ nmp_lookup_init_object (NMPLookup *lookup,
|
||||||
}
|
}
|
||||||
|
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
||||||
o->object.ifindex = ifindex;
|
o->obj_with_ifindex.ifindex = ifindex;
|
||||||
lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX;
|
lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX;
|
||||||
return _L (lookup);
|
return _L (lookup);
|
||||||
}
|
}
|
||||||
|
|
@ -2014,7 +2056,7 @@ nmp_lookup_init_route_default (NMPLookup *lookup,
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||||
|
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
||||||
o->object.ifindex = 1;
|
o->ip_route.ifindex = 1;
|
||||||
lookup->cache_id_type = NMP_CACHE_ID_TYPE_DEFAULT_ROUTES;
|
lookup->cache_id_type = NMP_CACHE_ID_TYPE_DEFAULT_ROUTES;
|
||||||
return _L (lookup);
|
return _L (lookup);
|
||||||
}
|
}
|
||||||
|
|
@ -2062,9 +2104,9 @@ nmp_lookup_init_ip4_route_by_weak_id (NMPLookup *lookup,
|
||||||
nm_assert (lookup);
|
nm_assert (lookup);
|
||||||
|
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
||||||
o->object.ifindex = 1;
|
o->ip4_route.ifindex = 1;
|
||||||
o->ip_route.plen = plen;
|
o->ip4_route.plen = plen;
|
||||||
o->ip_route.metric = metric;
|
o->ip4_route.metric = metric;
|
||||||
if (network)
|
if (network)
|
||||||
o->ip4_route.network = network;
|
o->ip4_route.network = network;
|
||||||
o->ip4_route.tos = tos;
|
o->ip4_route.tos = tos;
|
||||||
|
|
@ -2085,9 +2127,9 @@ nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
||||||
nm_assert (lookup);
|
nm_assert (lookup);
|
||||||
|
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
||||||
o->object.ifindex = 1;
|
o->ip6_route.ifindex = 1;
|
||||||
o->ip_route.plen = plen;
|
o->ip6_route.plen = plen;
|
||||||
o->ip_route.metric = metric;
|
o->ip6_route.metric = metric;
|
||||||
if (network)
|
if (network)
|
||||||
o->ip6_route.network = *network;
|
o->ip6_route.network = *network;
|
||||||
if (src)
|
if (src)
|
||||||
|
|
@ -2097,6 +2139,23 @@ nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
||||||
return _L (lookup);
|
return _L (lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NMPLookup *
|
||||||
|
nmp_lookup_init_object_by_addr_family (NMPLookup *lookup,
|
||||||
|
NMPObjectType obj_type,
|
||||||
|
int addr_family)
|
||||||
|
{
|
||||||
|
NMPObject *o;
|
||||||
|
|
||||||
|
nm_assert (lookup);
|
||||||
|
nm_assert_addr_family (addr_family);
|
||||||
|
nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_ROUTING_RULE));
|
||||||
|
|
||||||
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (o)->addr_family = addr_family;
|
||||||
|
lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY;
|
||||||
|
return _L (lookup);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
GArray *
|
GArray *
|
||||||
|
|
@ -2920,15 +2979,25 @@ nmp_cache_update_link_master_connected (NMPCache *cache,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
nmp_cache_dirty_set_all (NMPCache *cache,
|
nmp_cache_dirty_set_all_main (NMPCache *cache,
|
||||||
const NMPLookup *lookup)
|
const NMPLookup *lookup)
|
||||||
{
|
{
|
||||||
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
|
||||||
nm_assert (cache);
|
nm_assert (cache);
|
||||||
nm_assert (lookup);
|
nm_assert (lookup);
|
||||||
|
|
||||||
nm_dedup_multi_index_dirty_set_head (cache->multi_idx,
|
head_entry = nmp_cache_lookup (cache, lookup);
|
||||||
_idx_type_get (cache, lookup->cache_id_type),
|
|
||||||
&lookup->selector_obj);
|
nm_dedup_multi_iter_init (&iter, head_entry);
|
||||||
|
while (nm_dedup_multi_iter_next (&iter)) {
|
||||||
|
const NMDedupMultiEntry *main_entry;
|
||||||
|
|
||||||
|
main_entry = nmp_cache_reresolve_main_entry (cache, iter.current, lookup);
|
||||||
|
|
||||||
|
nm_dedup_multi_entry_set_dirty (main_entry, TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -3076,6 +3145,25 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
||||||
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route,
|
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route,
|
||||||
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full,
|
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full,
|
||||||
},
|
},
|
||||||
|
[NMP_OBJECT_TYPE_ROUTING_RULE - 1] = {
|
||||||
|
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
||||||
|
.obj_type = NMP_OBJECT_TYPE_ROUTING_RULE,
|
||||||
|
.sizeof_data = sizeof (NMPObjectRoutingRule),
|
||||||
|
.sizeof_public = sizeof (NMPlatformRoutingRule),
|
||||||
|
.obj_type_name = "routing-rule",
|
||||||
|
.rtm_gettype = RTM_GETRULE,
|
||||||
|
.signal_type_id = NM_PLATFORM_SIGNAL_ID_ROUTING_RULE,
|
||||||
|
.signal_type = NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED,
|
||||||
|
.supported_cache_ids = _supported_cache_ids_routing_rules,
|
||||||
|
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_routing_rule,
|
||||||
|
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_routing_rule,
|
||||||
|
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_routing_rule,
|
||||||
|
.cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_routing_rule,
|
||||||
|
.cmd_plobj_to_string_id = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_routing_rule_to_string,
|
||||||
|
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_routing_rule_to_string,
|
||||||
|
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_routing_rule,
|
||||||
|
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_routing_rule_cmp_full,
|
||||||
|
},
|
||||||
[NMP_OBJECT_TYPE_QDISC - 1] = {
|
[NMP_OBJECT_TYPE_QDISC - 1] = {
|
||||||
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
||||||
.obj_type = NMP_OBJECT_TYPE_QDISC,
|
.obj_type = NMP_OBJECT_TYPE_QDISC,
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,11 @@ typedef enum { /*< skip >*/
|
||||||
* cache-resync. */
|
* cache-resync. */
|
||||||
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
|
||||||
|
/* a filter for objects that track an explicit address family.
|
||||||
|
*
|
||||||
|
* Note that currently on NMPObjectRoutingRule is indexed by this filter. */
|
||||||
|
NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY,
|
||||||
|
|
||||||
__NMP_CACHE_ID_TYPE_MAX,
|
__NMP_CACHE_ID_TYPE_MAX,
|
||||||
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
|
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
|
||||||
} NMPCacheIdType;
|
} NMPCacheIdType;
|
||||||
|
|
@ -324,6 +329,10 @@ typedef struct {
|
||||||
NMPlatformIP6Route _public;
|
NMPlatformIP6Route _public;
|
||||||
} NMPObjectIP6Route;
|
} NMPObjectIP6Route;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMPlatformRoutingRule _public;
|
||||||
|
} NMPObjectRoutingRule;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NMPlatformQdisc _public;
|
NMPlatformQdisc _public;
|
||||||
} NMPObjectQdisc;
|
} NMPObjectQdisc;
|
||||||
|
|
@ -340,6 +349,8 @@ struct _NMPObject {
|
||||||
union {
|
union {
|
||||||
NMPlatformObject object;
|
NMPlatformObject object;
|
||||||
|
|
||||||
|
NMPlatformObjWithIfindex obj_with_ifindex;
|
||||||
|
|
||||||
NMPlatformLink link;
|
NMPlatformLink link;
|
||||||
NMPObjectLink _link;
|
NMPObjectLink _link;
|
||||||
|
|
||||||
|
|
@ -390,6 +401,9 @@ struct _NMPObject {
|
||||||
NMPObjectIP4Route _ip4_route;
|
NMPObjectIP4Route _ip4_route;
|
||||||
NMPObjectIP6Route _ip6_route;
|
NMPObjectIP6Route _ip6_route;
|
||||||
|
|
||||||
|
NMPlatformRoutingRule routing_rule;
|
||||||
|
NMPObjectRoutingRule _routing_rule;
|
||||||
|
|
||||||
NMPlatformQdisc qdisc;
|
NMPlatformQdisc qdisc;
|
||||||
NMPObjectQdisc _qdisc;
|
NMPObjectQdisc _qdisc;
|
||||||
NMPlatformTfilter tfilter;
|
NMPlatformTfilter tfilter;
|
||||||
|
|
@ -397,6 +411,8 @@ struct _NMPObject {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
NMP_CLASS_IS_VALID (const NMPClass *klass)
|
NMP_CLASS_IS_VALID (const NMPClass *klass)
|
||||||
{
|
{
|
||||||
|
|
@ -405,6 +421,17 @@ NMP_CLASS_IS_VALID (const NMPClass *klass)
|
||||||
&& ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0;
|
&& ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline const NMPClass *
|
||||||
|
nmp_class_from_type (NMPObjectType obj_type)
|
||||||
|
{
|
||||||
|
nm_assert (obj_type > 0);
|
||||||
|
nm_assert (obj_type <= G_N_ELEMENTS (_nmp_classes));
|
||||||
|
nm_assert (_nmp_classes[obj_type - 1].obj_type == obj_type);
|
||||||
|
nm_assert (NMP_CLASS_IS_VALID (&_nmp_classes[obj_type - 1]));
|
||||||
|
|
||||||
|
return &_nmp_classes[obj_type - 1];
|
||||||
|
}
|
||||||
|
|
||||||
static inline NMPObject *
|
static inline NMPObject *
|
||||||
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
|
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
|
||||||
{
|
{
|
||||||
|
|
@ -454,11 +481,65 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN;
|
return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
_NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMPObjectType obj_type)
|
||||||
|
{
|
||||||
|
switch (obj_type) {
|
||||||
|
case NMP_OBJECT_TYPE_LINK:
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
|
|
||||||
|
case NMP_OBJECT_TYPE_QDISC:
|
||||||
|
|
||||||
|
case NMP_OBJECT_TYPE_TFILTER:
|
||||||
|
|
||||||
|
case NMP_OBJECT_TYPE_LNK_GRE:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_GRETAP:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_INFINIBAND:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_IP6TNL:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_IP6GRE:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_IP6GRETAP:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_IPIP:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_MACSEC:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_MACVLAN:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_MACVTAP:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_SIT:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_TUN:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_VLAN:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_VXLAN:
|
||||||
|
case NMP_OBJECT_TYPE_LNK_WIREGUARD:
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
nm_assert (nmp_class_from_type (obj_type));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NMP_OBJECT_CAST_OBJECT(obj) \
|
||||||
|
({ \
|
||||||
|
typeof (obj) _obj = (obj); \
|
||||||
|
\
|
||||||
|
nm_assert ( !_obj \
|
||||||
|
|| nmp_class_from_type (NMP_OBJECT_GET_TYPE (_obj)))); \
|
||||||
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->object : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj) \
|
||||||
|
({ \
|
||||||
|
typeof (obj) _obj = (obj); \
|
||||||
|
\
|
||||||
|
nm_assert ( !_obj \
|
||||||
|
|| _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMP_OBJECT_GET_TYPE (_obj))); \
|
||||||
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->obj_with_ifindex : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
#define NMP_OBJECT_CAST_LINK(obj) \
|
#define NMP_OBJECT_CAST_LINK(obj) \
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_LINK); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_LINK); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->link : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->link : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -482,7 +563,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -490,7 +571,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -514,7 +595,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -522,15 +603,23 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define NMP_OBJECT_CAST_ROUTING_RULE(obj) \
|
||||||
|
({ \
|
||||||
|
typeof (obj) _obj = (obj); \
|
||||||
|
\
|
||||||
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_ROUTING_RULE); \
|
||||||
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->routing_rule : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
#define NMP_OBJECT_CAST_QDISC(obj) \
|
#define NMP_OBJECT_CAST_QDISC(obj) \
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_QDISC); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_QDISC); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -538,12 +627,10 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
|
||||||
({ \
|
({ \
|
||||||
typeof (obj) _obj = (obj); \
|
typeof (obj) _obj = (obj); \
|
||||||
\
|
\
|
||||||
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_TFILTER); \
|
nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_TFILTER); \
|
||||||
_obj ? &NM_CONSTCAST (NMPObject, _obj)->tfilter : NULL; \
|
_obj ? &NM_CONSTCAST (NMPObject, _obj)->tfilter : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
const NMPClass *nmp_class_from_type (NMPObjectType obj_type);
|
|
||||||
|
|
||||||
static inline const NMPObject *
|
static inline const NMPObject *
|
||||||
nmp_object_ref (const NMPObject *obj)
|
nmp_object_ref (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
|
|
@ -565,9 +652,11 @@ nmp_object_ref (const NMPObject *obj)
|
||||||
static inline void
|
static inline void
|
||||||
nmp_object_unref (const NMPObject *obj)
|
nmp_object_unref (const NMPObject *obj)
|
||||||
{
|
{
|
||||||
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
|
if (obj) {
|
||||||
|
nm_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj);
|
nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define nm_clear_nmp_object(ptr) \
|
#define nm_clear_nmp_object(ptr) \
|
||||||
|
|
@ -695,6 +784,9 @@ const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
||||||
guint32 metric,
|
guint32 metric,
|
||||||
const struct in6_addr *src,
|
const struct in6_addr *src,
|
||||||
guint8 src_plen);
|
guint8 src_plen);
|
||||||
|
const NMPLookup *nmp_lookup_init_object_by_addr_family (NMPLookup *lookup,
|
||||||
|
NMPObjectType obj_type,
|
||||||
|
int addr_family);
|
||||||
|
|
||||||
GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
|
GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
|
||||||
NMPObjectType obj_type,
|
NMPObjectType obj_type,
|
||||||
|
|
@ -784,8 +876,34 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache,
|
||||||
const NMPObject **out_obj_old,
|
const NMPObject **out_obj_old,
|
||||||
const NMPObject **out_obj_new);
|
const NMPObject **out_obj_new);
|
||||||
|
|
||||||
void nmp_cache_dirty_set_all (NMPCache *cache,
|
static inline const NMDedupMultiEntry *
|
||||||
const NMPLookup *lookup);
|
nmp_cache_reresolve_main_entry (NMPCache *cache,
|
||||||
|
const NMDedupMultiEntry *entry,
|
||||||
|
const NMPLookup *lookup)
|
||||||
|
{
|
||||||
|
const NMDedupMultiEntry *main_entry;
|
||||||
|
|
||||||
|
nm_assert (cache);
|
||||||
|
nm_assert (entry);
|
||||||
|
nm_assert (lookup);
|
||||||
|
|
||||||
|
if (lookup->cache_id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) {
|
||||||
|
nm_assert (entry == nmp_cache_lookup_entry (cache, entry->obj));
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we only track the dirty flag for the OBJECT-TYPE index. That means,
|
||||||
|
* for other lookup types we need to check the dirty flag of the main-entry. */
|
||||||
|
main_entry = nmp_cache_lookup_entry (cache, entry->obj);
|
||||||
|
|
||||||
|
nm_assert (main_entry);
|
||||||
|
nm_assert (main_entry->obj == entry->obj);
|
||||||
|
|
||||||
|
return main_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nmp_cache_dirty_set_all_main (NMPCache *cache,
|
||||||
|
const NMPLookup *lookup);
|
||||||
|
|
||||||
NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev);
|
NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev);
|
||||||
void nmp_cache_free (NMPCache *cache);
|
void nmp_cache_free (NMPCache *cache);
|
||||||
|
|
|
||||||
660
src/platform/nmp-rules-manager.c
Normal file
660
src/platform/nmp-rules-manager.c
Normal file
|
|
@ -0,0 +1,660 @@
|
||||||
|
/*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nm-default.h"
|
||||||
|
|
||||||
|
#include "nmp-rules-manager.h"
|
||||||
|
|
||||||
|
#include <linux/fib_rules.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#include "nm-utils/c-list-util.h"
|
||||||
|
#include "nmp-object.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
struct _NMPRulesManager {
|
||||||
|
NMPlatform *platform;
|
||||||
|
GHashTable *by_obj;
|
||||||
|
GHashTable *by_user_tag;
|
||||||
|
GHashTable *by_data;
|
||||||
|
guint ref_count;
|
||||||
|
bool track_default:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static void _rules_init (NMPRulesManager *self);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define _NMLOG_DOMAIN LOGD_PLATFORM
|
||||||
|
#define _NMLOG_PREFIX_NAME "rules-manager"
|
||||||
|
|
||||||
|
#define _NMLOG(level, ...) \
|
||||||
|
G_STMT_START { \
|
||||||
|
const NMLogLevel __level = (level); \
|
||||||
|
\
|
||||||
|
if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \
|
||||||
|
_nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \
|
||||||
|
"%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
|
||||||
|
_NMLOG_PREFIX_NAME \
|
||||||
|
_NM_UTILS_MACRO_REST (__VA_ARGS__)); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
NMP_IS_RULES_MANAGER (gpointer self)
|
||||||
|
{
|
||||||
|
return self
|
||||||
|
&& ((NMPRulesManager *) self)->ref_count > 0
|
||||||
|
&& NM_IS_PLATFORM (((NMPRulesManager *) self)->platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _USER_TAG_LOG(user_tag) nm_hash_obfuscate_ptr (1240261787u, (user_tag))
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const NMPObject *obj;
|
||||||
|
gconstpointer user_tag;
|
||||||
|
CList obj_lst;
|
||||||
|
CList user_tag_lst;
|
||||||
|
|
||||||
|
guint32 priority_val;
|
||||||
|
bool priority_present;
|
||||||
|
|
||||||
|
bool dirty:1;
|
||||||
|
} RulesData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const NMPObject *obj;
|
||||||
|
CList obj_lst_head;
|
||||||
|
|
||||||
|
/* indicates that we configured the rule (during sync()). We need that, so
|
||||||
|
* if the rule gets untracked, that we know to remove it on the next
|
||||||
|
* sync().
|
||||||
|
*
|
||||||
|
* This makes NMPRulesManager stateful (beyond the configuration that indicates
|
||||||
|
* which rules are tracked).
|
||||||
|
* After a restart, NetworkManager would no longer remember which rules were added
|
||||||
|
* by us. That would need to be fixed by persisting the state and reloading it after
|
||||||
|
* restart. */
|
||||||
|
bool added_by_us:1;
|
||||||
|
} RulesObjData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gconstpointer user_tag;
|
||||||
|
CList user_tag_lst_head;
|
||||||
|
} RulesUserTagData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_data_assert (const RulesData *rules_data, gboolean linked)
|
||||||
|
{
|
||||||
|
nm_assert (rules_data);
|
||||||
|
nm_assert (NMP_OBJECT_GET_TYPE (rules_data->obj) == NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
nm_assert (nmp_object_is_visible (rules_data->obj));
|
||||||
|
nm_assert (rules_data->user_tag);
|
||||||
|
nm_assert (!linked || !c_list_is_empty (&rules_data->obj_lst));
|
||||||
|
nm_assert (!linked || !c_list_is_empty (&rules_data->user_tag_lst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
_rules_data_hash (gconstpointer data)
|
||||||
|
{
|
||||||
|
const RulesData *rules_data = data;
|
||||||
|
NMHashState h;
|
||||||
|
|
||||||
|
_rules_data_assert (rules_data, FALSE);
|
||||||
|
|
||||||
|
nm_hash_init (&h, 269297543u);
|
||||||
|
nm_platform_routing_rule_hash_update (NMP_OBJECT_CAST_ROUTING_RULE (rules_data->obj),
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
|
||||||
|
&h);
|
||||||
|
nm_hash_update_val (&h, rules_data->user_tag);
|
||||||
|
return nm_hash_complete (&h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_rules_data_equal (gconstpointer data_a, gconstpointer data_b)
|
||||||
|
{
|
||||||
|
const RulesData *rules_data_a = data_a;
|
||||||
|
const RulesData *rules_data_b = data_b;
|
||||||
|
|
||||||
|
_rules_data_assert (rules_data_a, FALSE);
|
||||||
|
_rules_data_assert (rules_data_b, FALSE);
|
||||||
|
|
||||||
|
return rules_data_a->user_tag == rules_data_b->user_tag
|
||||||
|
&& (nm_platform_routing_rule_cmp (NMP_OBJECT_CAST_ROUTING_RULE (rules_data_a->obj),
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (rules_data_b->obj),
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_data_destroy (gpointer data)
|
||||||
|
{
|
||||||
|
RulesData *rules_data = data;
|
||||||
|
|
||||||
|
_rules_data_assert (rules_data, FALSE);
|
||||||
|
|
||||||
|
c_list_unlink_stale (&rules_data->obj_lst);
|
||||||
|
c_list_unlink_stale (&rules_data->user_tag_lst);
|
||||||
|
nmp_object_unref (rules_data->obj);
|
||||||
|
g_slice_free (RulesData, rules_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const RulesData *
|
||||||
|
_rules_obj_get_best_data (RulesObjData *obj_data)
|
||||||
|
{
|
||||||
|
RulesData *rules_data;
|
||||||
|
const RulesData *rd_best = NULL;
|
||||||
|
|
||||||
|
nm_assert (!c_list_is_empty (&obj_data->obj_lst_head));
|
||||||
|
|
||||||
|
c_list_for_each_entry (rules_data, &obj_data->obj_lst_head, obj_lst) {
|
||||||
|
|
||||||
|
_rules_data_assert (rules_data, TRUE);
|
||||||
|
|
||||||
|
if (rd_best) {
|
||||||
|
if (rd_best->priority_val > rules_data->priority_val)
|
||||||
|
continue;
|
||||||
|
if (rd_best->priority_val == rules_data->priority_val) {
|
||||||
|
if ( rd_best->priority_present
|
||||||
|
|| !rules_data->priority_present)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rd_best = rules_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rd_best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
_rules_obj_hash (gconstpointer data)
|
||||||
|
{
|
||||||
|
const RulesObjData *obj_data = data;
|
||||||
|
NMHashState h;
|
||||||
|
|
||||||
|
nm_hash_init (&h, 432817559u);
|
||||||
|
nm_platform_routing_rule_hash_update (NMP_OBJECT_CAST_ROUTING_RULE (obj_data->obj),
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
|
||||||
|
&h);
|
||||||
|
return nm_hash_complete (&h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_rules_obj_equal (gconstpointer data_a, gconstpointer data_b)
|
||||||
|
{
|
||||||
|
const RulesObjData *obj_data_a = data_a;
|
||||||
|
const RulesObjData *obj_data_b = data_b;
|
||||||
|
|
||||||
|
return (nm_platform_routing_rule_cmp (NMP_OBJECT_CAST_ROUTING_RULE (obj_data_a->obj),
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (obj_data_b->obj),
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_obj_destroy (gpointer data)
|
||||||
|
{
|
||||||
|
RulesObjData *obj_data = data;
|
||||||
|
|
||||||
|
c_list_unlink_stale (&obj_data->obj_lst_head);
|
||||||
|
nmp_object_unref (obj_data->obj);
|
||||||
|
g_slice_free (RulesObjData, obj_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
_rules_user_tag_hash (gconstpointer data)
|
||||||
|
{
|
||||||
|
const RulesUserTagData *user_tag_data = data;
|
||||||
|
|
||||||
|
return nm_hash_val (644693447u, user_tag_data->user_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_rules_user_tag_equal (gconstpointer data_a, gconstpointer data_b)
|
||||||
|
{
|
||||||
|
const RulesUserTagData *user_tag_data_a = data_a;
|
||||||
|
const RulesUserTagData *user_tag_data_b = data_b;
|
||||||
|
|
||||||
|
return user_tag_data_a->user_tag == user_tag_data_b->user_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_user_tag_destroy (gpointer data)
|
||||||
|
{
|
||||||
|
RulesUserTagData *user_tag_data = data;
|
||||||
|
|
||||||
|
c_list_unlink_stale (&user_tag_data->user_tag_lst_head);
|
||||||
|
g_slice_free (RulesUserTagData, user_tag_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RulesData *
|
||||||
|
_rules_data_lookup (GHashTable *by_data,
|
||||||
|
const NMPObject *obj,
|
||||||
|
gconstpointer user_tag)
|
||||||
|
{
|
||||||
|
RulesData rules_data_needle = {
|
||||||
|
.obj = obj,
|
||||||
|
.user_tag = user_tag,
|
||||||
|
};
|
||||||
|
|
||||||
|
return g_hash_table_lookup (by_data, &rules_data_needle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_track (NMPRulesManager *self,
|
||||||
|
const NMPlatformRoutingRule *routing_rule,
|
||||||
|
gint32 priority,
|
||||||
|
gconstpointer user_tag)
|
||||||
|
{
|
||||||
|
NMPObject obj_stack;
|
||||||
|
const NMPObject *p_obj_stack;
|
||||||
|
RulesData *rules_data;
|
||||||
|
RulesObjData *obj_data;
|
||||||
|
RulesUserTagData *user_tag_data;
|
||||||
|
gboolean changed = FALSE;
|
||||||
|
guint32 priority_val;
|
||||||
|
gboolean priority_present;
|
||||||
|
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
g_return_if_fail (routing_rule);
|
||||||
|
g_return_if_fail (user_tag);
|
||||||
|
nm_assert (priority != G_MININT32);
|
||||||
|
|
||||||
|
_rules_init (self);
|
||||||
|
|
||||||
|
p_obj_stack = nmp_object_stackinit (&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule);
|
||||||
|
|
||||||
|
nm_assert (nmp_object_is_visible (p_obj_stack));
|
||||||
|
|
||||||
|
if (priority >= 0) {
|
||||||
|
priority_val = priority;
|
||||||
|
priority_present = TRUE;
|
||||||
|
} else {
|
||||||
|
priority_val = -priority;
|
||||||
|
priority_present = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rules_data = _rules_data_lookup (self->by_data, p_obj_stack, user_tag);
|
||||||
|
|
||||||
|
if (!rules_data) {
|
||||||
|
rules_data = g_slice_new (RulesData);
|
||||||
|
*rules_data = (RulesData) {
|
||||||
|
.obj = nm_dedup_multi_index_obj_intern (nm_platform_get_multi_idx (self->platform),
|
||||||
|
p_obj_stack),
|
||||||
|
.user_tag = user_tag,
|
||||||
|
.priority_val = priority_val,
|
||||||
|
.priority_present = priority_present,
|
||||||
|
.dirty = FALSE,
|
||||||
|
};
|
||||||
|
g_hash_table_add (self->by_data, rules_data);
|
||||||
|
|
||||||
|
obj_data = g_hash_table_lookup (self->by_obj, &rules_data->obj);
|
||||||
|
if (!obj_data) {
|
||||||
|
obj_data = g_slice_new (RulesObjData);
|
||||||
|
*obj_data = (RulesObjData) {
|
||||||
|
.obj = nmp_object_ref (rules_data->obj),
|
||||||
|
.obj_lst_head = C_LIST_INIT (obj_data->obj_lst_head),
|
||||||
|
.added_by_us = FALSE,
|
||||||
|
};
|
||||||
|
g_hash_table_add (self->by_obj, obj_data);
|
||||||
|
}
|
||||||
|
c_list_link_tail (&obj_data->obj_lst_head, &rules_data->obj_lst);
|
||||||
|
|
||||||
|
user_tag_data = g_hash_table_lookup (self->by_user_tag, &rules_data->user_tag);
|
||||||
|
if (!user_tag_data) {
|
||||||
|
user_tag_data = g_slice_new (RulesUserTagData);
|
||||||
|
*user_tag_data = (RulesUserTagData) {
|
||||||
|
.user_tag = user_tag,
|
||||||
|
.user_tag_lst_head = C_LIST_INIT (user_tag_data->user_tag_lst_head),
|
||||||
|
};
|
||||||
|
g_hash_table_add (self->by_user_tag, user_tag_data);
|
||||||
|
}
|
||||||
|
c_list_link_tail (&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst);
|
||||||
|
changed = TRUE;
|
||||||
|
} else {
|
||||||
|
rules_data->dirty = FALSE;
|
||||||
|
if ( rules_data->priority_val != priority_val
|
||||||
|
|| rules_data->priority_present != priority_present) {
|
||||||
|
rules_data->priority_val = priority_val;
|
||||||
|
rules_data->priority_present = priority_present;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_rules_data_assert (rules_data, TRUE);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
_LOGD ("routing-rule: track ["NM_HASH_OBFUSCATE_PTR_FMT",%c%u] \"%s\")",
|
||||||
|
_USER_TAG_LOG (rules_data->user_tag),
|
||||||
|
rules_data->priority_present ? '+' : '-',
|
||||||
|
(guint) rules_data->priority_val,
|
||||||
|
nmp_object_to_string (rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_data_untrack (NMPRulesManager *self,
|
||||||
|
RulesData *rules_data,
|
||||||
|
gboolean remove_user_tag_data)
|
||||||
|
{
|
||||||
|
RulesObjData *obj_data;
|
||||||
|
|
||||||
|
nm_assert (NMP_IS_RULES_MANAGER (self));
|
||||||
|
_rules_data_assert (rules_data, TRUE);
|
||||||
|
nm_assert (self->by_data);
|
||||||
|
nm_assert (g_hash_table_lookup (self->by_data, rules_data) == rules_data);
|
||||||
|
|
||||||
|
_LOGD ("routing-rule: untrack ["NM_HASH_OBFUSCATE_PTR_FMT"] \"%s\"",
|
||||||
|
_USER_TAG_LOG (rules_data->user_tag),
|
||||||
|
nmp_object_to_string (rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
|
||||||
|
|
||||||
|
#if NM_MORE_ASSERTS
|
||||||
|
{
|
||||||
|
RulesUserTagData *user_tag_data;
|
||||||
|
|
||||||
|
user_tag_data = g_hash_table_lookup (self->by_user_tag, &rules_data->user_tag);
|
||||||
|
nm_assert (user_tag_data);
|
||||||
|
nm_assert (c_list_contains (&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nm_assert (!c_list_is_empty (&rules_data->user_tag_lst));
|
||||||
|
if ( remove_user_tag_data
|
||||||
|
&& c_list_length_is (&rules_data->user_tag_lst, 1))
|
||||||
|
g_hash_table_remove (self->by_user_tag, &rules_data->user_tag);
|
||||||
|
|
||||||
|
obj_data = g_hash_table_lookup (self->by_obj, &rules_data->obj);
|
||||||
|
nm_assert (obj_data);
|
||||||
|
nm_assert (c_list_contains (&obj_data->obj_lst_head, &rules_data->obj_lst));
|
||||||
|
nm_assert (obj_data == g_hash_table_lookup (self->by_obj, &rules_data->obj));
|
||||||
|
|
||||||
|
/* if obj_data is marked to be "added_by_us", we need to keep this entry around
|
||||||
|
* for the next sync -- so that we can remove the rule that was added. */
|
||||||
|
if ( !obj_data->added_by_us
|
||||||
|
&& c_list_length_is (&rules_data->obj_lst, 1))
|
||||||
|
g_hash_table_remove (self->by_obj, &rules_data->obj);
|
||||||
|
|
||||||
|
g_hash_table_remove (self->by_data, rules_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_untrack (NMPRulesManager *self,
|
||||||
|
const NMPlatformRoutingRule *routing_rule,
|
||||||
|
gconstpointer user_tag)
|
||||||
|
{
|
||||||
|
NMPObject obj_stack;
|
||||||
|
const NMPObject *p_obj_stack;
|
||||||
|
RulesData *rules_data;
|
||||||
|
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
g_return_if_fail (routing_rule);
|
||||||
|
g_return_if_fail (user_tag);
|
||||||
|
|
||||||
|
_rules_init (self);
|
||||||
|
|
||||||
|
p_obj_stack = nmp_object_stackinit (&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule);
|
||||||
|
|
||||||
|
nm_assert (nmp_object_is_visible (p_obj_stack));
|
||||||
|
|
||||||
|
rules_data = _rules_data_lookup (self->by_data, p_obj_stack, user_tag);
|
||||||
|
if (rules_data)
|
||||||
|
_rules_data_untrack (self, rules_data, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_set_dirty (NMPRulesManager *self,
|
||||||
|
gconstpointer user_tag)
|
||||||
|
{
|
||||||
|
RulesData *rules_data;
|
||||||
|
RulesUserTagData *user_tag_data;
|
||||||
|
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
g_return_if_fail (user_tag);
|
||||||
|
|
||||||
|
if (!self->by_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
user_tag_data = g_hash_table_lookup (self->by_user_tag, &user_tag);
|
||||||
|
if (!user_tag_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
c_list_for_each_entry (rules_data, &user_tag_data->user_tag_lst_head, user_tag_lst)
|
||||||
|
rules_data->dirty = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_untrack_all (NMPRulesManager *self,
|
||||||
|
gconstpointer user_tag,
|
||||||
|
gboolean all /* or only dirty */)
|
||||||
|
{
|
||||||
|
RulesData *rules_data;
|
||||||
|
RulesData *rules_data_safe;
|
||||||
|
RulesUserTagData *user_tag_data;
|
||||||
|
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
g_return_if_fail (user_tag);
|
||||||
|
|
||||||
|
if (!self->by_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
user_tag_data = g_hash_table_lookup (self->by_user_tag, &user_tag);
|
||||||
|
if (!user_tag_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
c_list_for_each_entry_safe (rules_data, rules_data_safe, &user_tag_data->user_tag_lst_head, user_tag_lst) {
|
||||||
|
if ( all
|
||||||
|
|| rules_data->dirty)
|
||||||
|
_rules_data_untrack (self, rules_data, FALSE);
|
||||||
|
}
|
||||||
|
if (c_list_is_empty (&user_tag_data->user_tag_lst_head))
|
||||||
|
g_hash_table_remove (self->by_user_tag, user_tag_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_sync (NMPRulesManager *self)
|
||||||
|
{
|
||||||
|
const NMDedupMultiHeadEntry *pl_head_entry;
|
||||||
|
NMDedupMultiIter pl_iter;
|
||||||
|
const NMPObject *plobj;
|
||||||
|
gs_unref_ptrarray GPtrArray *rules_to_delete = NULL;
|
||||||
|
RulesObjData *obj_data;
|
||||||
|
GHashTableIter h_iter;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
|
||||||
|
if (!self->by_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_LOGD ("sync");
|
||||||
|
|
||||||
|
pl_head_entry = nm_platform_lookup_obj_type (self->platform, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
if (pl_head_entry) {
|
||||||
|
nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) {
|
||||||
|
obj_data = g_hash_table_lookup (self->by_obj, &plobj);
|
||||||
|
|
||||||
|
if (!obj_data) {
|
||||||
|
/* this rule is not tracked. It was externally added, hence we
|
||||||
|
* ignore it. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_list_is_empty (&obj_data->obj_lst_head)) {
|
||||||
|
nm_assert (obj_data->added_by_us);
|
||||||
|
g_hash_table_remove (self->by_obj, obj_data);
|
||||||
|
} else {
|
||||||
|
if (_rules_obj_get_best_data (obj_data)->priority_present)
|
||||||
|
continue;
|
||||||
|
obj_data->added_by_us = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rules_to_delete)
|
||||||
|
rules_to_delete = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
|
||||||
|
|
||||||
|
g_ptr_array_add (rules_to_delete, (gpointer) nmp_object_ref (plobj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rules_to_delete) {
|
||||||
|
for (i = 0; i < rules_to_delete->len; i++)
|
||||||
|
nm_platform_object_delete (self->platform, rules_to_delete->pdata[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&h_iter, self->by_obj);
|
||||||
|
while (g_hash_table_iter_next (&h_iter, (gpointer *) &obj_data, NULL)) {
|
||||||
|
|
||||||
|
if (c_list_is_empty (&obj_data->obj_lst_head)) {
|
||||||
|
nm_assert (obj_data->added_by_us);
|
||||||
|
g_hash_table_iter_remove (&h_iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_rules_obj_get_best_data (obj_data)->priority_present)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
plobj = nm_platform_lookup_obj (self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj);
|
||||||
|
if (plobj)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
obj_data->added_by_us = TRUE;
|
||||||
|
nm_platform_routing_rule_add (self->platform, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_ROUTING_RULE (obj_data->obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_track_default (NMPRulesManager *self,
|
||||||
|
int addr_family,
|
||||||
|
int priority,
|
||||||
|
gconstpointer user_tag)
|
||||||
|
{
|
||||||
|
/* track the default rules. See also `man ip-rule`. */
|
||||||
|
|
||||||
|
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
|
||||||
|
nmp_rules_manager_track (self,
|
||||||
|
&((NMPlatformRoutingRule) {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 0,
|
||||||
|
.table = RT_TABLE_LOCAL,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
}),
|
||||||
|
priority,
|
||||||
|
user_tag);
|
||||||
|
nmp_rules_manager_track (self,
|
||||||
|
&((NMPlatformRoutingRule) {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 32766,
|
||||||
|
.table = RT_TABLE_MAIN,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
}),
|
||||||
|
priority,
|
||||||
|
user_tag);
|
||||||
|
nmp_rules_manager_track (self,
|
||||||
|
&((NMPlatformRoutingRule) {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 32767,
|
||||||
|
.table = RT_TABLE_DEFAULT,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
}),
|
||||||
|
priority,
|
||||||
|
user_tag);
|
||||||
|
}
|
||||||
|
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
|
||||||
|
nmp_rules_manager_track (self,
|
||||||
|
&((NMPlatformRoutingRule) {
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.priority = 0,
|
||||||
|
.table = RT_TABLE_LOCAL,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
}),
|
||||||
|
priority,
|
||||||
|
user_tag);
|
||||||
|
nmp_rules_manager_track (self,
|
||||||
|
&((NMPlatformRoutingRule) {
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.priority = 32766,
|
||||||
|
.table = RT_TABLE_MAIN,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
}),
|
||||||
|
priority,
|
||||||
|
user_tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_rules_init (NMPRulesManager *self)
|
||||||
|
{
|
||||||
|
if (self->by_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self->by_data = g_hash_table_new_full (_rules_data_hash, _rules_data_equal, NULL, _rules_data_destroy);
|
||||||
|
self->by_obj = g_hash_table_new_full (_rules_obj_hash, _rules_obj_equal, NULL, _rules_obj_destroy);
|
||||||
|
self->by_user_tag = g_hash_table_new_full (_rules_user_tag_hash, _rules_user_tag_equal, NULL, _rules_user_tag_destroy);
|
||||||
|
|
||||||
|
if (self->track_default)
|
||||||
|
nmp_rules_manager_track_default (self, AF_UNSPEC, 0, &self->by_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
NMPRulesManager *
|
||||||
|
nmp_rules_manager_new (NMPlatform *platform,
|
||||||
|
gboolean track_default)
|
||||||
|
{
|
||||||
|
NMPRulesManager *self;
|
||||||
|
|
||||||
|
g_return_val_if_fail (NM_IS_PLATFORM (platform), NULL);
|
||||||
|
|
||||||
|
self = g_slice_new (NMPRulesManager);
|
||||||
|
*self = (NMPRulesManager) {
|
||||||
|
.ref_count = 1,
|
||||||
|
.platform = g_object_ref (platform),
|
||||||
|
.track_default = track_default,
|
||||||
|
};
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nmp_rules_manager_ref (NMPRulesManager *self)
|
||||||
|
{
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
|
||||||
|
self->ref_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nmp_rules_manager_unref (NMPRulesManager *self)
|
||||||
|
{
|
||||||
|
g_return_if_fail (NMP_IS_RULES_MANAGER (self));
|
||||||
|
|
||||||
|
if (--self->ref_count > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (self->by_data) {
|
||||||
|
g_hash_table_destroy (self->by_user_tag);
|
||||||
|
g_hash_table_destroy (self->by_obj);
|
||||||
|
g_hash_table_destroy (self->by_data);
|
||||||
|
}
|
||||||
|
g_object_unref (self->platform);
|
||||||
|
g_slice_free (NMPRulesManager, self);
|
||||||
|
}
|
||||||
61
src/platform/nmp-rules-manager.h
Normal file
61
src/platform/nmp-rules-manager.h
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NMP_RULES_MANAGER_H__
|
||||||
|
#define __NMP_RULES_MANAGER_H__
|
||||||
|
|
||||||
|
#include "nm-platform.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
typedef struct _NMPRulesManager NMPRulesManager;
|
||||||
|
|
||||||
|
NMPRulesManager *nmp_rules_manager_new (NMPlatform *platform,
|
||||||
|
gboolean track_default);
|
||||||
|
|
||||||
|
void nmp_rules_manager_ref (NMPRulesManager *self);
|
||||||
|
void nmp_rules_manager_unref (NMPRulesManager *self);
|
||||||
|
|
||||||
|
#define nm_auto_unref_rules_manager nm_auto (_nmp_rules_manager_unref)
|
||||||
|
NM_AUTO_DEFINE_FCN0 (NMPRulesManager *, _nmp_rules_manager_unref, nmp_rules_manager_unref)
|
||||||
|
|
||||||
|
void nmp_rules_manager_track (NMPRulesManager *self,
|
||||||
|
const NMPlatformRoutingRule *routing_rule,
|
||||||
|
gint32 priority,
|
||||||
|
gconstpointer user_tag);
|
||||||
|
|
||||||
|
void nmp_rules_manager_track_default (NMPRulesManager *self,
|
||||||
|
int addr_family,
|
||||||
|
int priority,
|
||||||
|
gconstpointer user_tag);
|
||||||
|
|
||||||
|
void nmp_rules_manager_untrack (NMPRulesManager *self,
|
||||||
|
const NMPlatformRoutingRule *routing_rule,
|
||||||
|
gconstpointer user_tag);
|
||||||
|
|
||||||
|
void nmp_rules_manager_set_dirty (NMPRulesManager *self,
|
||||||
|
gconstpointer user_tag);
|
||||||
|
|
||||||
|
void nmp_rules_manager_untrack_all (NMPRulesManager *self,
|
||||||
|
gconstpointer user_tag,
|
||||||
|
gboolean all /* or only dirty */);
|
||||||
|
|
||||||
|
void nmp_rules_manager_sync (NMPRulesManager *self);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __NMP_RULES_MANAGER_H__ */
|
||||||
|
|
@ -273,6 +273,58 @@ nmtstp_ip6_route_get_all (NMPlatform *platform,
|
||||||
GArray *nmtstp_platform_ip4_address_get_all (NMPlatform *self, int ifindex);
|
GArray *nmtstp_platform_ip4_address_get_all (NMPlatform *self, int ifindex);
|
||||||
GArray *nmtstp_platform_ip6_address_get_all (NMPlatform *self, int ifindex);
|
GArray *nmtstp_platform_ip6_address_get_all (NMPlatform *self, int ifindex);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
_nmtstp_platform_routing_rules_get_all_predicate (const NMPObject *obj,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
int addr_family = GPOINTER_TO_INT (user_data);
|
||||||
|
|
||||||
|
g_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
|
||||||
|
return addr_family == AF_UNSPEC
|
||||||
|
|| NMP_OBJECT_CAST_ROUTING_RULE (obj)->addr_family == addr_family;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GPtrArray *
|
||||||
|
nmtstp_platform_routing_rules_get_all (NMPlatform *platform, int addr_family)
|
||||||
|
{
|
||||||
|
NMPLookup lookup;
|
||||||
|
|
||||||
|
g_assert (NM_IS_PLATFORM (platform));
|
||||||
|
g_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
|
||||||
|
|
||||||
|
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
return nm_platform_lookup_clone (platform,
|
||||||
|
&lookup,
|
||||||
|
_nmtstp_platform_routing_rules_get_all_predicate,
|
||||||
|
GINT_TO_POINTER (addr_family));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline guint
|
||||||
|
nmtstp_platform_routing_rules_get_count (NMPlatform *platform, int addr_family)
|
||||||
|
{
|
||||||
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
const NMPObject *obj;
|
||||||
|
NMPLookup lookup;
|
||||||
|
guint n;
|
||||||
|
|
||||||
|
g_assert (NM_IS_PLATFORM (platform));
|
||||||
|
g_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
|
||||||
|
|
||||||
|
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
head_entry = nm_platform_lookup (platform, &lookup);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
nmp_cache_iter_for_each (&iter, head_entry, &obj) {
|
||||||
|
if (_nmtstp_platform_routing_rules_get_all_predicate (obj, GINT_TO_POINTER (addr_family)))
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
|
gboolean nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
|
||||||
gboolean nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
|
gboolean nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ _nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, const NMPObject **ou
|
||||||
g_assert (cache);
|
g_assert (cache);
|
||||||
g_assert (NMP_OBJECT_IS_VALID (obj));
|
g_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
|
||||||
obj_prev = nmp_cache_lookup_link (cache, obj->object.ifindex);
|
obj_prev = nmp_cache_lookup_link (cache, NMP_OBJECT_CAST_LINK (obj)->ifindex);
|
||||||
obj_new_expected = nmp_object_clone (obj, FALSE);
|
obj_new_expected = nmp_object_clone (obj, FALSE);
|
||||||
if (obj_prev && obj_prev->_link.udev.device)
|
if (obj_prev && obj_prev->_link.udev.device)
|
||||||
obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device);
|
obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@
|
||||||
#include "nm-default.h"
|
#include "nm-default.h"
|
||||||
|
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <linux/fib_rules.h>
|
||||||
|
|
||||||
#include "nm-core-utils.h"
|
#include "nm-core-utils.h"
|
||||||
#include "platform/nm-platform-utils.h"
|
#include "platform/nm-platform-utils.h"
|
||||||
|
#include "platform/nmp-rules-manager.h"
|
||||||
|
|
||||||
#include "test-common.h"
|
#include "test-common.h"
|
||||||
|
|
||||||
|
|
@ -873,6 +875,822 @@ again_find_idx:
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define FRA_SUPPRESS_IFGROUP 13
|
||||||
|
#define FRA_SUPPRESS_PREFIXLEN 14
|
||||||
|
#define FRA_L3MDEV 19
|
||||||
|
#define FRA_UID_RANGE 20
|
||||||
|
#define FRA_PROTOCOL 21
|
||||||
|
#define FRA_IP_PROTO 22
|
||||||
|
#define FRA_SPORT_RANGE 23
|
||||||
|
#define FRA_DPORT_RANGE 24
|
||||||
|
|
||||||
|
static const NMPObject *
|
||||||
|
_rule_find_by_priority (NMPlatform *platform,
|
||||||
|
guint32 priority)
|
||||||
|
{
|
||||||
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
const NMPObject *o;
|
||||||
|
const NMPObject *obj = NULL;
|
||||||
|
NMPLookup lookup;
|
||||||
|
|
||||||
|
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
head_entry = nm_platform_lookup (platform, &lookup);
|
||||||
|
nmp_cache_iter_for_each (&iter, head_entry, &o) {
|
||||||
|
if (NMP_OBJECT_CAST_ROUTING_RULE (o)->priority != priority)
|
||||||
|
continue;
|
||||||
|
g_assert (!obj);
|
||||||
|
obj = o;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NMPObject *
|
||||||
|
_rule_check_kernel_support_one (NMPlatform *platform,
|
||||||
|
const NMPlatformRoutingRule *rr)
|
||||||
|
{
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
g_assert (!_rule_find_by_priority (platform, rr->priority));
|
||||||
|
|
||||||
|
r = nm_platform_routing_rule_add (platform, NMP_NLM_FLAG_ADD, rr);
|
||||||
|
g_assert_cmpint (r, ==, 0);
|
||||||
|
|
||||||
|
obj = nmp_object_ref (_rule_find_by_priority (platform, rr->priority));
|
||||||
|
g_assert (obj);
|
||||||
|
|
||||||
|
r = nm_platform_object_delete (platform, obj);
|
||||||
|
g_assert_cmpint (r, ==, TRUE);
|
||||||
|
|
||||||
|
g_assert (!_rule_find_by_priority (platform, rr->priority));
|
||||||
|
|
||||||
|
return g_steal_pointer (&obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_rule_check_kernel_support (NMPlatform *platform,
|
||||||
|
int attribute)
|
||||||
|
{
|
||||||
|
static int support[] = {
|
||||||
|
[FRA_SUPPRESS_IFGROUP] = 0,
|
||||||
|
[FRA_SUPPRESS_PREFIXLEN] = 0,
|
||||||
|
[FRA_L3MDEV] = 0,
|
||||||
|
[FRA_UID_RANGE] = 0,
|
||||||
|
[FRA_PROTOCOL] = 0,
|
||||||
|
[FRA_IP_PROTO] = 0,
|
||||||
|
[FRA_SPORT_RANGE] = 0,
|
||||||
|
[FRA_DPORT_RANGE] = 0,
|
||||||
|
};
|
||||||
|
const guint32 PROBE_PRORITY = 12033;
|
||||||
|
gboolean sup;
|
||||||
|
|
||||||
|
g_assert (NM_IS_PLATFORM (platform));
|
||||||
|
g_assert (attribute >= 0 && attribute < G_N_ELEMENTS (support));
|
||||||
|
|
||||||
|
if (support[attribute] != 0)
|
||||||
|
return support[attribute] >= 0;
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case FRA_SUPPRESS_IFGROUP: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.suppress_ifgroup_inverse = ~((guint32) 1245),
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->suppress_prefixlen_inverse == rr.suppress_ifgroup_inverse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_SUPPRESS_PREFIXLEN: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.suppress_prefixlen_inverse = ~((guint32) 1245),
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->suppress_prefixlen_inverse == rr.suppress_prefixlen_inverse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_L3MDEV: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.l3mdev = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->l3mdev != 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_UID_RANGE: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.uid_range = {
|
||||||
|
.start = 0,
|
||||||
|
.end = 0,
|
||||||
|
},
|
||||||
|
.uid_range_has = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->uid_range_has;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_PROTOCOL: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.protocol = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->protocol == 30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_IP_PROTO: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj = NULL;
|
||||||
|
const NMPlatformRoutingRule rr = {
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = PROBE_PRORITY,
|
||||||
|
.ip_proto = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
obj = _rule_check_kernel_support_one (platform, &rr);
|
||||||
|
|
||||||
|
sup = NMP_OBJECT_CAST_ROUTING_RULE (obj)->ip_proto == 30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FRA_SPORT_RANGE:
|
||||||
|
case FRA_DPORT_RANGE:
|
||||||
|
/* these were added at the same time as FRA_IP_PROTO. */
|
||||||
|
sup = _rule_check_kernel_support (platform, FRA_IP_PROTO);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
support[attribute] = sup ? 1 : -1;
|
||||||
|
|
||||||
|
_LOGD ("kernel support for routing rule attribute #%d %s", attribute, sup ? "detected" : "not detected");
|
||||||
|
return sup;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NMPObject *
|
||||||
|
_platform_has_routing_rule (NMPlatform *platform,
|
||||||
|
const NMPObject *obj)
|
||||||
|
{
|
||||||
|
const NMPObject *o;
|
||||||
|
|
||||||
|
g_assert (NM_IS_PLATFORM (platform));
|
||||||
|
g_assert (NMP_OBJECT_IS_VALID (obj));
|
||||||
|
g_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
|
|
||||||
|
o = nm_platform_lookup_obj (platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj);
|
||||||
|
if (o)
|
||||||
|
g_assert (nm_platform_routing_rule_cmp (NMP_OBJECT_CAST_ROUTING_RULE (obj), NMP_OBJECT_CAST_ROUTING_RULE (o), NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const NMPObject *
|
||||||
|
_rule_create_random (NMPlatform *platform)
|
||||||
|
{
|
||||||
|
NMPObject *obj;
|
||||||
|
NMPlatformRoutingRule *rr;
|
||||||
|
guint32 p;
|
||||||
|
int addr_size;
|
||||||
|
guint i;
|
||||||
|
char saddr[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
|
static struct {
|
||||||
|
guint32 uid;
|
||||||
|
guint32 euid;
|
||||||
|
bool initialized;
|
||||||
|
} uids;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!uids.initialized)) {
|
||||||
|
uids.uid = getuid ();
|
||||||
|
uids.euid = geteuid ();
|
||||||
|
uids.initialized = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, NULL);
|
||||||
|
rr = NMP_OBJECT_CAST_ROUTING_RULE (obj);
|
||||||
|
|
||||||
|
rr->addr_family = nmtst_rand_select (AF_INET, AF_INET6);
|
||||||
|
|
||||||
|
addr_size = nm_utils_addr_family_to_size (rr->addr_family);
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 250)
|
||||||
|
rr->priority = 10000 + (p / 50);
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 60)
|
||||||
|
nm_sprintf_buf (rr->iifname, "t-iif-%u", p / 20);
|
||||||
|
else if (p < 120)
|
||||||
|
nm_sprintf_buf (rr->iifname, "%s", DEVICE_NAME);
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 60)
|
||||||
|
nm_sprintf_buf (rr->oifname, "t-oif-%d", p / 20);
|
||||||
|
else if (p < 120)
|
||||||
|
nm_sprintf_buf (rr->oifname, "%s", DEVICE_NAME);
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 60)
|
||||||
|
nm_sprintf_buf (rr->iifname, "t-iif-%d", p / 20);
|
||||||
|
else if (p < 120)
|
||||||
|
nm_sprintf_buf (rr->iifname, "%s", DEVICE_NAME);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
NMIPAddr *p_addr = i ? &rr->src : &rr->dst;
|
||||||
|
guint8 *p_len = i ? &rr->src_len : &rr->dst_len;
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 300) {
|
||||||
|
/* if we set src_len/dst_len to zero, the src/dst is actually ignored.
|
||||||
|
*
|
||||||
|
* For fuzzying, still set the address. It shall have no further effect.
|
||||||
|
* */
|
||||||
|
*p_len = p % (addr_size * 8 + 1);
|
||||||
|
p = nmtst_get_rand_int () % 750;
|
||||||
|
if (p <= 255) {
|
||||||
|
if (rr->addr_family == AF_INET)
|
||||||
|
p_addr->addr4 = nmtst_inet4_from_string (nm_sprintf_buf (saddr, "192.192.5.%u", p));
|
||||||
|
else
|
||||||
|
p_addr->addr6 = *nmtst_inet6_from_string (nm_sprintf_buf (saddr, "1:2:3:4::f:%02x", p));
|
||||||
|
} else if (p <= 512)
|
||||||
|
nmtst_rand_buf (NULL, p_addr, addr_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 50)
|
||||||
|
rr->tun_id = 10000 + p;
|
||||||
|
|
||||||
|
again_action:
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 300)
|
||||||
|
rr->action = FR_ACT_UNSPEC;
|
||||||
|
else if (p < 700)
|
||||||
|
rr->action = p % 12;
|
||||||
|
else
|
||||||
|
rr->action = p % 0xFF;
|
||||||
|
|
||||||
|
rr->priority = nmtst_rand_select (0,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ());
|
||||||
|
if ( rr->action == FR_ACT_GOTO
|
||||||
|
&& rr->priority == G_MAXINT32)
|
||||||
|
goto again_action;
|
||||||
|
|
||||||
|
again_goto_target:
|
||||||
|
rr->goto_target = nmtst_rand_select (0,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int (),
|
||||||
|
rr->priority + 1);
|
||||||
|
if ( rr->action == FR_ACT_GOTO
|
||||||
|
&& rr->goto_target <= rr->priority)
|
||||||
|
goto again_goto_target;
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 50) {
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_L3MDEV)) {
|
||||||
|
rr->l3mdev = TRUE;
|
||||||
|
rr->table = RT_TABLE_UNSPEC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
again_table:
|
||||||
|
if (!rr->l3mdev) {
|
||||||
|
rr->table = nmtst_rand_select (RT_TABLE_UNSPEC,
|
||||||
|
RT_TABLE_MAIN,
|
||||||
|
10000 + nmtst_get_rand_int () % 10);
|
||||||
|
if ( rr->action == FR_ACT_TO_TBL
|
||||||
|
&& rr->table == RT_TABLE_UNSPEC)
|
||||||
|
goto again_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->fwmark = nmtst_rand_select (0,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ());
|
||||||
|
rr->fwmask = nmtst_rand_select (0u,
|
||||||
|
0xFFFFFFFFu,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ());
|
||||||
|
|
||||||
|
rr->flow = nmtst_rand_select (0u,
|
||||||
|
0xFFFFFFFFu,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ());
|
||||||
|
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_PROTOCOL)) {
|
||||||
|
rr->protocol = nmtst_rand_select (0u,
|
||||||
|
255u,
|
||||||
|
nmtst_get_rand_int () % 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IPTOS_TOS_MASK 0x1E
|
||||||
|
|
||||||
|
again_tos:
|
||||||
|
rr->tos = nmtst_rand_select (0u,
|
||||||
|
255u,
|
||||||
|
nmtst_get_rand_int () % 256);
|
||||||
|
if ( rr->addr_family == AF_INET
|
||||||
|
&& rr->tos & ~IPTOS_TOS_MASK)
|
||||||
|
goto again_tos;
|
||||||
|
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_IP_PROTO)) {
|
||||||
|
rr->ip_proto = nmtst_rand_select (0u,
|
||||||
|
255u,
|
||||||
|
nmtst_get_rand_int () % 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_SUPPRESS_PREFIXLEN)) {
|
||||||
|
rr->suppress_prefixlen_inverse = ~((guint32) nmtst_rand_select (0u,
|
||||||
|
0xFFFFFFFFu,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_SUPPRESS_IFGROUP)) {
|
||||||
|
rr->suppress_ifgroup_inverse = ~((guint32) nmtst_rand_select (0u,
|
||||||
|
0xFFFFFFFFu,
|
||||||
|
nmtst_get_rand_int () % 100,
|
||||||
|
nmtst_get_rand_int ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
again_uid_range:
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 100) {
|
||||||
|
if (_rule_check_kernel_support (platform, FRA_UID_RANGE))
|
||||||
|
rr->uid_range_has = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->uid_range.start = nmtst_rand_select (0u, uids.uid, uids.euid);
|
||||||
|
rr->uid_range.end = nmtst_rand_select (0u, uids.uid, uids.euid);
|
||||||
|
if (rr->uid_range.end < rr->uid_range.start)
|
||||||
|
NMTST_SWAP (rr->uid_range.start, rr->uid_range.end);
|
||||||
|
|
||||||
|
if ( rr->uid_range.start == ((guint32) -1)
|
||||||
|
|| rr->uid_range.end == ((guint32) -1))
|
||||||
|
goto again_uid_range;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
NMFibRulePortRange *range = i ? &rr->sport_range : &rr->dport_range;
|
||||||
|
int attribute = i ? FRA_SPORT_RANGE : FRA_DPORT_RANGE;
|
||||||
|
|
||||||
|
if (!_rule_check_kernel_support (platform, attribute))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int ();
|
||||||
|
if ((p % 1000u) < 100) {
|
||||||
|
while (range->start == 0) {
|
||||||
|
p = p ^ nmtst_get_rand_int ();
|
||||||
|
range->start = nmtst_rand_select (1u, 0xFFFEu, ((p ) % 0xFFFEu) + 1);
|
||||||
|
range->end = nmtst_rand_select (1u, 0xFFFEu, ((p >> 16) % 0xFFFEu) + 1, range->start);
|
||||||
|
if (range->end < range->start)
|
||||||
|
NMTST_SWAP (range->start, range->end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = nmtst_get_rand_int () % 1000u;
|
||||||
|
if (p < 100)
|
||||||
|
rr->flags |= FIB_RULE_INVERT;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_rule_fuzzy_equal (const NMPObject *obj,
|
||||||
|
const NMPObject *obj_comp,
|
||||||
|
int op_type)
|
||||||
|
{
|
||||||
|
const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (obj);
|
||||||
|
NMPlatformRoutingRule rr_co = *NMP_OBJECT_CAST_ROUTING_RULE (obj_comp);
|
||||||
|
|
||||||
|
switch (op_type) {
|
||||||
|
case RTM_NEWRULE:
|
||||||
|
/* when adding rules with RTM_NEWRULE, kernel checks whether an existing
|
||||||
|
* rule already exists and may fail with EEXIST. This check has issues
|
||||||
|
* and reject legitimate rules (rh#1686075).
|
||||||
|
*
|
||||||
|
* Work around that. */
|
||||||
|
if (rr->src_len == 0)
|
||||||
|
rr_co.src_len = 0;
|
||||||
|
if (rr->dst_len == 0)
|
||||||
|
rr_co.dst_len = 0;
|
||||||
|
if (rr->flow == 0)
|
||||||
|
rr_co.flow = 0;
|
||||||
|
if (rr->tos == 0)
|
||||||
|
rr_co.tos = 0;
|
||||||
|
break;
|
||||||
|
case RTM_DELRULE:
|
||||||
|
/* when deleting a rule with RTM_DELRULE, kernel tries to find the
|
||||||
|
* cadidate to delete. It might delete the wrong rule (rh#1685816). */
|
||||||
|
if (rr->action == FR_ACT_UNSPEC)
|
||||||
|
rr_co.action = FR_ACT_UNSPEC;
|
||||||
|
if (rr->iifname[0] == '\0')
|
||||||
|
rr_co.iifname[0] = '\0';
|
||||||
|
if (rr->oifname[0] == '\0')
|
||||||
|
rr_co.oifname[0] = '\0';
|
||||||
|
if (rr->src_len == 0)
|
||||||
|
rr_co.src_len = 0;
|
||||||
|
if (rr->dst_len == 0)
|
||||||
|
rr_co.dst_len = 0;
|
||||||
|
if (rr->tun_id == 0)
|
||||||
|
rr_co.tun_id = 0;
|
||||||
|
if (rr->fwmark == 0)
|
||||||
|
rr_co.fwmark = 0;
|
||||||
|
if (rr->fwmask == 0)
|
||||||
|
rr_co.fwmask = 0;
|
||||||
|
if (rr->flow == 0)
|
||||||
|
rr_co.flow = 0;
|
||||||
|
if (rr->protocol == 0)
|
||||||
|
rr_co.protocol = 0;
|
||||||
|
if (rr->table == RT_TABLE_UNSPEC)
|
||||||
|
rr_co.table = RT_TABLE_UNSPEC;
|
||||||
|
if (rr->l3mdev == 0)
|
||||||
|
rr_co.l3mdev = 0;
|
||||||
|
if (rr->tos == 0)
|
||||||
|
rr_co.tos = 0;
|
||||||
|
if (rr->ip_proto == 0)
|
||||||
|
rr_co.ip_proto = 0;
|
||||||
|
if (rr->suppress_prefixlen_inverse == 0)
|
||||||
|
rr_co.suppress_prefixlen_inverse = 0;
|
||||||
|
if (rr->suppress_ifgroup_inverse == 0)
|
||||||
|
rr_co.suppress_ifgroup_inverse = 0;
|
||||||
|
if (!rr->uid_range_has)
|
||||||
|
rr_co.uid_range_has = FALSE;
|
||||||
|
if (rr->sport_range.start == 0 && rr->sport_range.end == 0) {
|
||||||
|
rr_co.sport_range.start = 0;
|
||||||
|
rr_co.sport_range.end = 0;
|
||||||
|
}
|
||||||
|
if (rr->dport_range.start == 0 && rr->dport_range.end == 0) {
|
||||||
|
rr_co.dport_range.start = 0;
|
||||||
|
rr_co.dport_range.end = 0;
|
||||||
|
}
|
||||||
|
if (!NM_FLAGS_HAS (rr->flags, FIB_RULE_INVERT))
|
||||||
|
rr_co.flags &= ~((guint32) FIB_RULE_INVERT);
|
||||||
|
else
|
||||||
|
rr_co.flags |= ((guint32) FIB_RULE_INVERT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nm_platform_routing_rule_cmp (rr, &rr_co, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_rule (gconstpointer test_data)
|
||||||
|
{
|
||||||
|
const int TEST_IDX = GPOINTER_TO_INT (test_data);
|
||||||
|
const gboolean TEST_SYNC = (TEST_IDX == 4);
|
||||||
|
gs_unref_ptrarray GPtrArray *objs = NULL;
|
||||||
|
gs_unref_ptrarray GPtrArray *objs_initial = NULL;
|
||||||
|
NMPlatform *platform = NM_PLATFORM_GET;
|
||||||
|
guint i, j, n;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
nm_platform_process_events (platform);
|
||||||
|
|
||||||
|
objs_initial = nmtstp_platform_routing_rules_get_all (platform, AF_UNSPEC);
|
||||||
|
g_assert (objs_initial);
|
||||||
|
g_assert_cmpint (objs_initial->len, ==, 5);
|
||||||
|
|
||||||
|
nmtstp_run_command_check ("ip rule add table 766");
|
||||||
|
nm_platform_process_events (platform);
|
||||||
|
|
||||||
|
for (i = 6; i > 0; i--) {
|
||||||
|
gs_unref_ptrarray GPtrArray *objs_extern = NULL;
|
||||||
|
const NMPObject *obj;
|
||||||
|
|
||||||
|
objs_extern = nmtstp_platform_routing_rules_get_all (platform, AF_UNSPEC);
|
||||||
|
|
||||||
|
g_assert (objs_extern);
|
||||||
|
g_assert_cmpint (objs_extern->len, ==, i);
|
||||||
|
|
||||||
|
if (TEST_IDX != 1)
|
||||||
|
nmtst_rand_perm (NULL, objs_extern->pdata, NULL, sizeof (gpointer), objs_extern->len);
|
||||||
|
|
||||||
|
obj = objs_extern->pdata[0];
|
||||||
|
|
||||||
|
r = nm_platform_object_delete (platform, obj);
|
||||||
|
g_assert_cmpint (r, ==, TRUE);
|
||||||
|
|
||||||
|
g_assert (!_platform_has_routing_rule (platform, obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, 0);
|
||||||
|
|
||||||
|
#define RR(...) \
|
||||||
|
nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, \
|
||||||
|
(const NMPlatformObject *) &((NMPlatformRoutingRule) { \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
}))
|
||||||
|
|
||||||
|
objs = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 10,
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 400,
|
||||||
|
.action = FR_ACT_GOTO,
|
||||||
|
.goto_target = 10000,
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.action = FR_ACT_TO_TBL,
|
||||||
|
.table = RT_TABLE_MAIN,
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.priority = 30,
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.priority = 50,
|
||||||
|
.iifname = "t-iif-1",
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET6,
|
||||||
|
.priority = 50,
|
||||||
|
.iifname = "t-oif-1",
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 50,
|
||||||
|
.iifname = "t-oif-2",
|
||||||
|
));
|
||||||
|
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.priority = 51,
|
||||||
|
.iifname = DEVICE_NAME,
|
||||||
|
));
|
||||||
|
|
||||||
|
if (TEST_IDX == 1) {
|
||||||
|
g_ptr_array_add (objs, RR (
|
||||||
|
.addr_family = AF_INET,
|
||||||
|
.table = 10000,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_IDX != 1) {
|
||||||
|
nmtst_rand_perm (NULL, objs->pdata, NULL, sizeof (gpointer), objs->len);
|
||||||
|
g_ptr_array_set_size (objs, nmtst_get_rand_int () % (objs->len + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
n = (TEST_IDX != 1) ? nmtst_get_rand_int () % 50u : 0u;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
nm_auto_nmpobj const NMPObject *o = NULL;
|
||||||
|
guint try = 0;
|
||||||
|
|
||||||
|
again:
|
||||||
|
o = _rule_create_random (platform);
|
||||||
|
for (j = 0; j < objs->len; j++) {
|
||||||
|
if (nm_platform_routing_rule_cmp (NMP_OBJECT_CAST_ROUTING_RULE (o),
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs->pdata[j]),
|
||||||
|
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0) {
|
||||||
|
try++;
|
||||||
|
g_assert (try < 200);
|
||||||
|
nm_clear_pointer (&o, nmp_object_unref);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_ptr_array_add (objs, (gpointer) g_steal_pointer (&o));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_IDX != 1)
|
||||||
|
nmtst_rand_perm (NULL, objs->pdata, NULL, sizeof (gpointer), objs->len);
|
||||||
|
|
||||||
|
if (TEST_SYNC) {
|
||||||
|
gs_unref_hashtable GHashTable *unique_priorities = g_hash_table_new (NULL, NULL);
|
||||||
|
nm_auto_unref_rules_manager NMPRulesManager *rules_manager = nmp_rules_manager_new (platform, FALSE);
|
||||||
|
gs_unref_ptrarray GPtrArray *objs_sync = NULL;
|
||||||
|
gconstpointer USER_TAG_1 = &platform;
|
||||||
|
gconstpointer USER_TAG_2 = &unique_priorities;
|
||||||
|
|
||||||
|
objs_sync = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
|
||||||
|
|
||||||
|
/* ensure that priorities are unique. Otherwise it confuses the test, because
|
||||||
|
* kernel may wrongly be unable to add/delete routes based on a wrong match
|
||||||
|
* (rh#1685816, rh#1685816). */
|
||||||
|
for (i = 0; i < objs->len; i++) {
|
||||||
|
const NMPObject *obj = objs->pdata[i];
|
||||||
|
guint32 prio = NMP_OBJECT_CAST_ROUTING_RULE (obj)->priority;
|
||||||
|
|
||||||
|
if ( !NM_IN_SET (prio, 0, 32766, 32767)
|
||||||
|
&& !g_hash_table_contains (unique_priorities, GUINT_TO_POINTER (prio))) {
|
||||||
|
g_hash_table_add (unique_priorities, GUINT_TO_POINTER (prio));
|
||||||
|
g_ptr_array_add (objs_sync, (gpointer) nmp_object_ref (obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < objs_sync->len; i++) {
|
||||||
|
nmp_rules_manager_track (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
1,
|
||||||
|
USER_TAG_1);
|
||||||
|
if (nmtst_get_rand_bool ()) {
|
||||||
|
/* this has no effect, because a negative priority (of same absolute value)
|
||||||
|
* has lower priority than the positive priority above. */
|
||||||
|
nmp_rules_manager_track (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
-1,
|
||||||
|
USER_TAG_2);
|
||||||
|
}
|
||||||
|
if (nmtst_get_rand_int () % objs_sync->len == 0) {
|
||||||
|
nmp_rules_manager_sync (rules_manager);
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nmp_rules_manager_sync (rules_manager);
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len);
|
||||||
|
|
||||||
|
for (i = 0; i < objs_sync->len; i++) {
|
||||||
|
switch (nmtst_get_rand_int () % 3) {
|
||||||
|
case 0:
|
||||||
|
nmp_rules_manager_untrack (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
USER_TAG_1);
|
||||||
|
nmp_rules_manager_untrack (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
USER_TAG_1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
nmp_rules_manager_track (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
-1,
|
||||||
|
USER_TAG_1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
nmp_rules_manager_track (rules_manager,
|
||||||
|
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
|
||||||
|
-2,
|
||||||
|
USER_TAG_2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nmtst_get_rand_int () % objs_sync->len == 0) {
|
||||||
|
nmp_rules_manager_sync (rules_manager);
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len - i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nmp_rules_manager_sync (rules_manager);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < objs->len;) {
|
||||||
|
const NMPObject *obj = objs->pdata[i];
|
||||||
|
|
||||||
|
for (j = 0; j < objs->len; j++)
|
||||||
|
g_assert ((j < i) == (!!_platform_has_routing_rule (platform, objs->pdata[j])));
|
||||||
|
|
||||||
|
r = nm_platform_routing_rule_add (platform, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_ROUTING_RULE (obj));
|
||||||
|
|
||||||
|
if (r == -EEXIST) {
|
||||||
|
g_assert (!_platform_has_routing_rule (platform, obj));
|
||||||
|
/* this should not happen, but there are bugs in kernel (rh#1686075). */
|
||||||
|
for (j = 0; j < i; j++) {
|
||||||
|
const NMPObject *obj2 = objs->pdata[j];
|
||||||
|
|
||||||
|
g_assert (_platform_has_routing_rule (platform, obj2));
|
||||||
|
|
||||||
|
if (_rule_fuzzy_equal (obj, obj2, RTM_NEWRULE)) {
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
/* OK, the rule is shadowed by another rule, and kernel does not allow
|
||||||
|
* us to add this one (rh#1686075). Drop this from the test. */
|
||||||
|
g_ptr_array_remove_index (objs, i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r != 0) {
|
||||||
|
g_print (">>> failing...\n");
|
||||||
|
nmtstp_run_command_check ("ip rule");
|
||||||
|
nmtstp_run_command_check ("ip -6 rule");
|
||||||
|
g_assert_cmpint (r, ==, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (_platform_has_routing_rule (platform, obj));
|
||||||
|
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, i + 1);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_IDX != 1)
|
||||||
|
nmtst_rand_perm (NULL, objs->pdata, NULL, sizeof (gpointer), objs->len);
|
||||||
|
|
||||||
|
if (_LOGD_ENABLED ()) {
|
||||||
|
nmtstp_run_command_check ("ip rule");
|
||||||
|
nmtstp_run_command_check ("ip -6 rule");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < objs->len; i++) {
|
||||||
|
const NMPObject *obj = objs->pdata[i];
|
||||||
|
const NMPObject *obj2;
|
||||||
|
|
||||||
|
for (j = 0; j < objs->len; j++)
|
||||||
|
g_assert ((j < i) == (!_platform_has_routing_rule (platform, objs->pdata[j])));
|
||||||
|
|
||||||
|
g_assert (_platform_has_routing_rule (platform, obj));
|
||||||
|
|
||||||
|
r = nm_platform_object_delete (platform, obj);
|
||||||
|
g_assert_cmpint (r, ==, TRUE);
|
||||||
|
|
||||||
|
obj2 = _platform_has_routing_rule (platform, obj);
|
||||||
|
|
||||||
|
if (obj2) {
|
||||||
|
guint k;
|
||||||
|
|
||||||
|
/* When deleting a rule, kernel does a fuzzy match, ignoring for example:
|
||||||
|
* - action, if it is FR_ACT_UNSPEC
|
||||||
|
* - iifname,oifname if it is unspecified
|
||||||
|
* rh#1685816
|
||||||
|
*
|
||||||
|
* That means, we may have deleted the wrong rule. Which one? */
|
||||||
|
k = i;
|
||||||
|
for (j = i + 1; j < objs->len; j++) {
|
||||||
|
if (!_platform_has_routing_rule (platform, objs->pdata[j])) {
|
||||||
|
g_assert_cmpint (k, ==, i);
|
||||||
|
k = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_assert_cmpint (k, >, i);
|
||||||
|
|
||||||
|
if (!_rule_fuzzy_equal (obj, objs->pdata[k], RTM_DELRULE)) {
|
||||||
|
g_print (">>> failing...\n");
|
||||||
|
g_print (">>> no fuzzy match between: %s\n", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
||||||
|
g_print (">>> and: %s\n", nmp_object_to_string (objs->pdata[k], NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
objs->pdata[i] = objs->pdata[k];
|
||||||
|
objs->pdata[k] = (gpointer) obj;
|
||||||
|
obj2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (!obj2);
|
||||||
|
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs->len -i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, 0);
|
||||||
|
|
||||||
|
for (i = 0; i < objs_initial->len; i++) {
|
||||||
|
const NMPObject *obj = objs_initial->pdata[i];
|
||||||
|
|
||||||
|
for (j = 0; j < objs_initial->len; j++)
|
||||||
|
g_assert ((j < i) == (!!_platform_has_routing_rule (platform, objs_initial->pdata[j])));
|
||||||
|
|
||||||
|
r = nm_platform_routing_rule_add (platform, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_ROUTING_RULE (obj));
|
||||||
|
g_assert_cmpint (r, ==, 0);
|
||||||
|
}
|
||||||
|
for (j = 0; j < objs_initial->len; j++)
|
||||||
|
g_assert (_platform_has_routing_rule (platform, objs_initial->pdata[j]));
|
||||||
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_initial->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
|
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -902,4 +1720,11 @@ _nmtstp_setup_tests (void)
|
||||||
add_test_func ("/route/ip6_route_get", test_ip6_route_get);
|
add_test_func ("/route/ip6_route_get", test_ip6_route_get);
|
||||||
add_test_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
|
add_test_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nmtstp_is_root_test ()) {
|
||||||
|
add_test_func_data ("/route/rule/1", test_rule, GINT_TO_POINTER (1));
|
||||||
|
add_test_func_data ("/route/rule/2", test_rule, GINT_TO_POINTER (2));
|
||||||
|
add_test_func_data ("/route/rule/3", test_rule, GINT_TO_POINTER (3));
|
||||||
|
add_test_func_data ("/route/rule/4", test_rule, GINT_TO_POINTER (4));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue