mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 08:20:08 +01: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-linux-platform.c \
|
||||
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.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;33' grep -a --color=always '^\|^\(.* \)\?<info> \[[0-9.]*\]\( .*\<is starting\>.*$\)\?' | \
|
||||
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;32' grep -a --color=always '^\|\<device (.*): state change: ' |
|
||||
if [[ "$NM_LOG_GREP" != "" ]]; then
|
||||
|
|
@ -77,7 +77,7 @@ NM-log() {
|
|||
fi
|
||||
) | \
|
||||
NM_LOG_GREP="$NM_LOG_GREP" NM-colorize | \
|
||||
LESS=FRSXM less -R
|
||||
LESS=FRSXM less -R --shift=5
|
||||
}
|
||||
|
||||
if [[ "$NM_not_sourced" != "" ]]; then
|
||||
|
|
|
|||
|
|
@ -40,4 +40,27 @@ void c_list_sort (CList *head,
|
|||
CListSortCmp cmp,
|
||||
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__ */
|
||||
|
|
|
|||
|
|
@ -83,7 +83,11 @@ nm_hash_complete_u64 (NMHashState *state)
|
|||
* from nm_hash_complete() in two ways:
|
||||
*
|
||||
* - 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);
|
||||
}
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ sources = files(
|
|||
'platform/nm-platform-utils.c',
|
||||
'platform/nmp-netns.c',
|
||||
'platform/nmp-object.c',
|
||||
'platform/nmp-rules-manager.c',
|
||||
'main-utils.c',
|
||||
'NetworkManagerUtils.c',
|
||||
'nm-core-utils.c',
|
||||
|
|
|
|||
|
|
@ -115,13 +115,13 @@ _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
|
|||
if (!obj_new) {
|
||||
nm_assert (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 {
|
||||
nm_assert (!pl_new);
|
||||
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_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);
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@
|
|||
|
||||
#include "nm-utils/nm-dedup-multi.h"
|
||||
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "platform/nm-platform.h"
|
||||
#include "platform/nmp-netns.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "platform/nmp-rules-manager.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
|||
typedef struct {
|
||||
NMPlatform *platform;
|
||||
NMPNetns *platform_netns;
|
||||
NMPRulesManager *rules_manager;
|
||||
} NMNetnsPrivate;
|
||||
|
||||
struct _NMNetns {
|
||||
|
|
@ -71,6 +73,12 @@ nm_netns_get_platform (NMNetns *self)
|
|||
return NM_NETNS_GET_PRIVATE (self)->platform;
|
||||
}
|
||||
|
||||
NMPRulesManager *
|
||||
nm_netns_get_rules_manager (NMNetns *self)
|
||||
{
|
||||
return NM_NETNS_GET_PRIVATE (self)->rules_manager;
|
||||
}
|
||||
|
||||
NMDedupMultiIndex *
|
||||
nm_netns_get_multi_idx (NMNetns *self)
|
||||
{
|
||||
|
|
@ -118,6 +126,8 @@ constructed (GObject *object)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -137,6 +147,8 @@ dispose (GObject *object)
|
|||
|
||||
g_clear_object (&priv->platform);
|
||||
|
||||
nm_clear_pointer (&priv->rules_manager, nmp_rules_manager_unref);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#define NM_NETNS_GET (nm_netns_get ())
|
||||
|
|
|
|||
|
|
@ -119,15 +119,16 @@ NM_IS_IP_CONFIG_SOURCE_RTPROT (NMIPConfigSource source)
|
|||
}
|
||||
|
||||
/* platform */
|
||||
typedef struct _NMPlatform NMPlatform;
|
||||
typedef struct _NMPlatformObject NMPlatformObject;
|
||||
typedef struct _NMPlatformIP4Address NMPlatformIP4Address;
|
||||
typedef struct _NMPlatformIP4Route NMPlatformIP4Route;
|
||||
typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
|
||||
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
|
||||
typedef struct _NMPlatformLink NMPlatformLink;
|
||||
typedef struct _NMPNetns NMPNetns;
|
||||
typedef struct _NMPObject NMPObject;
|
||||
typedef struct _NMPlatform NMPlatform;
|
||||
typedef struct _NMPlatformObject NMPlatformObject;
|
||||
typedef struct _NMPlatformObjWithIfindex NMPlatformObjWithIfindex;
|
||||
typedef struct _NMPlatformIP4Address NMPlatformIP4Address;
|
||||
typedef struct _NMPlatformIP4Route NMPlatformIP4Route;
|
||||
typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
|
||||
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
|
||||
typedef struct _NMPlatformLink NMPlatformLink;
|
||||
typedef struct _NMPNetns NMPNetns;
|
||||
typedef struct _NMPObject NMPObject;
|
||||
|
||||
typedef enum {
|
||||
/* 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_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
NMP_OBJECT_TYPE_ROUTING_RULE,
|
||||
|
||||
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,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
g_assert (ifindex == -1);
|
||||
ifindex = obj->object.ifindex;
|
||||
ifindex = NMP_OBJECT_CAST_IP_ROUTE (obj)->ifindex;
|
||||
obj_type = NMP_OBJECT_GET_TYPE (obj);
|
||||
} else {
|
||||
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <endian.h>
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/fib_rules.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_arp.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_SCI 1
|
||||
#define IFLA_MACSEC_PORT 2
|
||||
|
|
@ -283,41 +297,64 @@ typedef struct {
|
|||
};
|
||||
} ChangeLinkData;
|
||||
|
||||
enum {
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_LINKS,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS,
|
||||
DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS,
|
||||
_DELAYED_ACTION_IDX_REFRESH_ALL_NUM,
|
||||
};
|
||||
typedef enum {
|
||||
_REFRESH_ALL_TYPE_FIRST = 0,
|
||||
|
||||
REFRESH_ALL_TYPE_LINKS = 0,
|
||||
REFRESH_ALL_TYPE_IP4_ADDRESSES = 1,
|
||||
REFRESH_ALL_TYPE_IP6_ADDRESSES = 2,
|
||||
REFRESH_ALL_TYPE_IP4_ROUTES = 3,
|
||||
REFRESH_ALL_TYPE_IP6_ROUTES = 4,
|
||||
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 {
|
||||
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),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << /* 2 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << /* 3 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << /* 4 */ DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = (1LL << /* 5 */ DELAYED_ACTION_IDX_REFRESH_ALL_QDISCS),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = (1LL << /* 6 */ DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS),
|
||||
DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 7),
|
||||
DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 11),
|
||||
DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 12),
|
||||
DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 13),
|
||||
DELAYED_ACTION_TYPE_NONE = 0,
|
||||
|
||||
#define F(val, name) ((sizeof (char[(((val)) == (name)) ? 1 : -1]) * 0) + (val))
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F (0, REFRESH_ALL_TYPE_LINKS),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F (1, REFRESH_ALL_TYPE_IP4_ADDRESSES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F (2, REFRESH_ALL_TYPE_IP6_ADDRESSES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F (3, REFRESH_ALL_TYPE_IP4_ROUTES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F (4, REFRESH_ALL_TYPE_IP6_ROUTES),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 << F (5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 << F (6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6),
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F (7, REFRESH_ALL_TYPE_QDISCS),
|
||||
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_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_QDISCS |
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS,
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 |
|
||||
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6,
|
||||
|
||||
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;
|
||||
|
||||
#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \
|
||||
|
|
@ -387,7 +424,7 @@ typedef struct {
|
|||
GIOChannel *event_channel;
|
||||
guint event_id;
|
||||
|
||||
bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
|
||||
guint32 pruning[_REFRESH_ALL_TYPE_NUM];
|
||||
|
||||
GHashTable *sysctl_get_prev_values;
|
||||
CList sysctl_list;
|
||||
|
|
@ -401,7 +438,7 @@ typedef struct {
|
|||
|
||||
/* counter that a refresh all action is in progress, separated
|
||||
* 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_refresh_link;
|
||||
|
|
@ -3339,6 +3376,165 @@ rta_multipath_done:
|
|||
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 *
|
||||
_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_GETROUTE:
|
||||
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_DELQDISC:
|
||||
case RTM_GETQDISC:
|
||||
|
|
@ -3892,6 +4092,119 @@ nla_put_failure:
|
|||
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 *
|
||||
_nl_msg_new_qdisc (int nlmsg_type,
|
||||
int nlmsg_flags,
|
||||
|
|
@ -4347,57 +4660,131 @@ process_events (NMPlatform *platform)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObjectType, DelayedActionType,
|
||||
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (DELAYED_ACTION_TYPE_NONE),
|
||||
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),
|
||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ADDRESS, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES),
|
||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP4_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES),
|
||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_IP6_ROUTE, DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES),
|
||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_QDISC, DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS),
|
||||
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_TFILTER, DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS),
|
||||
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
||||
);
|
||||
static const RefreshAllInfo *
|
||||
refresh_all_type_get_info (RefreshAllType refresh_all_type)
|
||||
{
|
||||
static const RefreshAllInfo infos[] = {
|
||||
#define R(_refresh_all_type, _obj_type, _addr_family) [_refresh_all_type] = { .obj_type = _obj_type, .addr_family = _addr_family, }
|
||||
R (REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC),
|
||||
R (REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC),
|
||||
R (REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC),
|
||||
R (REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC),
|
||||
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_UTILS_LOOKUP_DEFAULT_NM_ASSERT (NMP_OBJECT_TYPE_UNKNOWN),
|
||||
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, NMP_OBJECT_TYPE_LINK),
|
||||
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_assert (_NM_INT_NOT_NEGATIVE (refresh_all_type));
|
||||
nm_assert (refresh_all_type < G_N_ELEMENTS (infos));
|
||||
nm_assert (nmp_class_from_type (infos[refresh_all_type].obj_type));
|
||||
|
||||
_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_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, DELAYED_ACTION_IDX_REFRESH_ALL_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_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_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_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_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_TFILTERS, DELAYED_ACTION_IDX_REFRESH_ALL_TFILTERS),
|
||||
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, REFRESH_ALL_TYPE_IP4_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, REFRESH_ALL_TYPE_IP4_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_ROUTING_RULES_IP4, REFRESH_ALL_TYPE_ROUTING_RULES_IP4),
|
||||
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 (),
|
||||
);
|
||||
|
||||
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_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_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_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_QDISCS, "refresh-all-qdiscs"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"),
|
||||
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_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_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_IP6_ROUTES, "refresh-all-ip6-routes"),
|
||||
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_ROUTING_RULES_IP6, "refresh-all-routing-rules-ip6"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"),
|
||||
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_REFRESH_ALL),
|
||||
NM_UTILS_LOOKUP_ITEM_IGNORE (DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL),
|
||||
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)
|
||||
{
|
||||
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_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))
|
||||
return TRUE;
|
||||
|
||||
if (priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (action_type)] > 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
refresh_all_type = delayed_action_type_to_refresh_all_type (action_type);
|
||||
return (priv->delayed_action.refresh_all_in_progress[refresh_all_type] > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4764,25 +5150,33 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type)
|
||||
cache_prune_one_type (NMPlatform *platform,
|
||||
const NMPLookup *lookup)
|
||||
{
|
||||
NMDedupMultiIter iter;
|
||||
const NMPObject *obj;
|
||||
NMPCacheOpsType cache_op;
|
||||
NMPLookup lookup;
|
||||
NMPCache *cache = nm_platform_get_cache (platform);
|
||||
|
||||
nmp_lookup_init_obj_type (&lookup,
|
||||
obj_type);
|
||||
nm_dedup_multi_iter_init (&iter,
|
||||
nmp_cache_lookup (cache,
|
||||
&lookup));
|
||||
lookup));
|
||||
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;
|
||||
|
||||
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);
|
||||
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||
cache_on_change (platform, cache_op, obj_old, NULL);
|
||||
|
|
@ -4795,16 +5189,19 @@ static void
|
|||
cache_prune_all (NMPlatform *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_EACH_DELAYED_ACTION (iflags, action_type) {
|
||||
bool *p = &priv->pruning[delayed_action_refresh_all_to_idx (iflags)];
|
||||
for (refresh_all_type = _REFRESH_ALL_TYPE_FIRST; refresh_all_type < _REFRESH_ALL_TYPE_NUM; refresh_all_type++) {
|
||||
NMPLookup lookup;
|
||||
|
||||
if (*p) {
|
||||
*p = FALSE;
|
||||
cache_prune_one_type (platform, delayed_action_refresh_to_object_type (iflags));
|
||||
}
|
||||
if (priv->pruning[refresh_all_type] == 0)
|
||||
continue;
|
||||
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_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,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -5234,6 +5632,7 @@ _nl_msg_new_dump (NMPObjectType obj_type,
|
|||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||
{
|
||||
const struct rtgenmsg gmsg = {
|
||||
.rtgen_family = preferred_addr_family,
|
||||
|
|
@ -5254,42 +5653,68 @@ static void
|
|||
do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
DelayedActionType action_type_prune;
|
||||
DelayedActionType iflags;
|
||||
|
||||
nm_assert (!NM_FLAGS_ANY (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;
|
||||
|
||||
priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE;
|
||||
nmp_lookup_init_obj_type (&lookup,
|
||||
delayed_action_refresh_to_object_type (iflags));
|
||||
nmp_cache_dirty_set_all (nm_platform_get_cache (platform),
|
||||
&lookup);
|
||||
priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1;
|
||||
priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1;
|
||||
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||
nmp_cache_dirty_set_all_main (nm_platform_get_cache (platform),
|
||||
&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) {
|
||||
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;
|
||||
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);
|
||||
*out_refresh_all_in_progress += 1;
|
||||
|
||||
/* clear any delayed action that request a refresh of this object type. */
|
||||
priv->delayed_action.flags &= ~iflags;
|
||||
_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;
|
||||
g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
|
||||
_LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)");
|
||||
|
||||
if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) {
|
||||
nm_assert ( (priv->delayed_action.list_refresh_link->len > 0)
|
||||
== 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);
|
||||
|
||||
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)
|
||||
goto next_after_fail;
|
||||
|
||||
|
|
@ -5310,9 +5735,9 @@ next_after_fail:
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -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,
|
||||
RTM_DELADDR,
|
||||
RTM_DELROUTE,
|
||||
RTM_DELRULE,
|
||||
RTM_DELQDISC,
|
||||
RTM_DELTFILTER)) {
|
||||
/* 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,
|
||||
RTM_NEWLINK,
|
||||
RTM_NEWROUTE,
|
||||
RTM_NEWRULE,
|
||||
RTM_NEWQDISC,
|
||||
RTM_NEWTFILTER)) {
|
||||
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",
|
||||
|
|
@ -5445,10 +5872,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
|||
|
||||
switch (msghdr->nlmsg_type) {
|
||||
|
||||
case RTM_NEWLINK:
|
||||
case RTM_NEWADDR:
|
||||
case RTM_GETLINK:
|
||||
case RTM_NEWADDR:
|
||||
case RTM_NEWLINK:
|
||||
case RTM_NEWQDISC:
|
||||
case RTM_NEWRULE:
|
||||
case RTM_NEWTFILTER:
|
||||
cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
|
||||
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. */
|
||||
_LOGT ("schedule resync of routes after RTM_NEWROUTE");
|
||||
delayed_action_schedule (platform,
|
||||
delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)),
|
||||
delayed_action_refresh_from_needle_object (obj),
|
||||
NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RTM_DELLINK:
|
||||
case RTM_DELADDR:
|
||||
case RTM_DELROUTE:
|
||||
case RTM_DELLINK:
|
||||
case RTM_DELQDISC:
|
||||
case RTM_DELROUTE:
|
||||
case RTM_DELRULE:
|
||||
case RTM_DELTFILTER:
|
||||
cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new);
|
||||
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||
|
|
@ -5657,7 +6086,7 @@ do_add_addrroute (NMPlatform *platform,
|
|||
*
|
||||
* rh#1484434 */
|
||||
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);
|
||||
|
|
@ -5722,7 +6151,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
|
|||
*
|
||||
* rh#1484434 */
|
||||
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;
|
||||
|
|
@ -5891,12 +6320,6 @@ link_refresh (NMPlatform *platform, int ifindex)
|
|||
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
|
||||
link_set_netns (NMPlatform *platform,
|
||||
int ifindex,
|
||||
|
|
@ -7606,6 +8029,9 @@ object_delete (NMPlatform *platform,
|
|||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, obj);
|
||||
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:
|
||||
nlmsg = _nl_msg_new_qdisc (RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC (obj));
|
||||
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
|
||||
qdisc_add (NMPlatform *platform,
|
||||
NMPNlmFlags flags,
|
||||
|
|
@ -7736,7 +8203,8 @@ qdisc_add (NMPlatform *platform,
|
|||
|
||||
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
|
||||
return 0;
|
||||
|
||||
if (seq_result < 0)
|
||||
return seq_result;
|
||||
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_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,
|
||||
NULL);
|
||||
|
|
@ -8318,9 +8787,13 @@ constructed (GObject *_object)
|
|||
g_assert (!nle);
|
||||
|
||||
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_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
|
||||
RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE,
|
||||
RTNLGRP_TC,
|
||||
0);
|
||||
g_assert (!nle);
|
||||
|
|
@ -8347,6 +8820,7 @@ constructed (GObject *_object)
|
|||
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,
|
||||
NULL);
|
||||
|
|
@ -8457,7 +8931,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
platform_class->link_add = link_add;
|
||||
platform_class->link_delete = link_delete;
|
||||
|
||||
platform_class->refresh_all = refresh_all;
|
||||
platform_class->link_refresh = link_refresh;
|
||||
|
||||
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_get = ip_route_get;
|
||||
|
||||
platform_class->routing_rule_add = routing_rule_add;
|
||||
|
||||
platform_class->qdisc_add = qdisc_add;
|
||||
platform_class->tfilter_add = tfilter_add;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <linux/fib_rules.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if.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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* @self: platform instance
|
||||
|
|
@ -4264,14 +4250,13 @@ nm_platform_ip_route_sync (NMPlatform *self,
|
|||
gboolean success = TRUE;
|
||||
char sbuf1[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_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||
nm_assert (ifindex > 0);
|
||||
|
||||
vt = addr_family == AF_INET
|
||||
? &nm_platform_vtable_route_v4
|
||||
: &nm_platform_vtable_route_v6;
|
||||
vt = &nm_platform_vtable_route.vx[IS_IPv4];
|
||||
|
||||
for (i_type = 0; routes && i_type < 2; i_type++) {
|
||||
for (i = 0; i < routes->len; i++) {
|
||||
|
|
@ -4578,7 +4563,7 @@ _ip_route_add (NMPlatform *self,
|
|||
nm_assert (route);
|
||||
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",
|
||||
_nmp_nlm_flag_to_string (flags & NMP_NLM_FLAG_FMASK),
|
||||
nm_utils_addr_family_to_char (addr_family),
|
||||
|
|
@ -4630,18 +4615,28 @@ gboolean
|
|||
nm_platform_object_delete (NMPlatform *self,
|
||||
const NMPObject *obj)
|
||||
{
|
||||
int ifindex = obj->object.ifindex;
|
||||
int ifindex;
|
||||
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
|
||||
if (!NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
NMP_OBJECT_TYPE_QDISC,
|
||||
NMP_OBJECT_TYPE_TFILTER))
|
||||
switch (NMP_OBJECT_GET_TYPE (obj)) {
|
||||
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||
_LOGD ("%s: delete %s",
|
||||
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);
|
||||
|
||||
_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);
|
||||
}
|
||||
|
|
@ -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
|
||||
nm_platform_qdisc_add (NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
|
|
@ -6076,6 +6086,253 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
|
|||
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 *
|
||||
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;
|
||||
}
|
||||
|
||||
#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:
|
||||
* @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));
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
ifindex = o->object.ifindex;
|
||||
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
|
||||
&& 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))
|
||||
|
|
@ -7214,7 +7662,7 @@ nm_platform_cache_update_emit_signal (NMPlatform *self,
|
|||
_nm_platform_signal_id_get (klass->signal_type_id),
|
||||
0,
|
||||
(int) klass->obj_type,
|
||||
o->object.ifindex,
|
||||
ifindex,
|
||||
&o->object,
|
||||
(int) cache_op);
|
||||
nmp_object_unref (o);
|
||||
|
|
@ -7261,24 +7709,25 @@ _vtr_v4_metric_normalize (guint32 metric)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
|
||||
.is_ip4 = TRUE,
|
||||
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
.addr_family = AF_INET,
|
||||
.sizeof_route = sizeof (NMPlatformIP4Route),
|
||||
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
|
||||
.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 = {
|
||||
.is_ip4 = FALSE,
|
||||
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
.addr_family = AF_INET6,
|
||||
.sizeof_route = sizeof (NMPlatformIP6Route),
|
||||
.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,
|
||||
.metric_normalize = nm_utils_ip6_route_metric_normalize,
|
||||
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
|
||||
.v4 = {
|
||||
.is_ip4 = TRUE,
|
||||
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
.addr_family = AF_INET,
|
||||
.sizeof_route = sizeof (NMPlatformIP4Route),
|
||||
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
|
||||
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
||||
.metric_normalize = _vtr_v4_metric_normalize,
|
||||
},
|
||||
.v6 = {
|
||||
.is_ip4 = FALSE,
|
||||
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
.addr_family = AF_INET6,
|
||||
.sizeof_route = sizeof (NMPlatformIP6Route),
|
||||
.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,
|
||||
.metric_normalize = nm_utils_ip6_route_metric_normalize,
|
||||
},
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -7338,8 +7787,9 @@ constructor (GType type,
|
|||
|
||||
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);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
@ -7411,11 +7861,12 @@ nm_platform_class_init (NMPlatformClass *platform_class)
|
|||
} G_STMT_END
|
||||
|
||||
/* Signals */
|
||||
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_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_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_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter);
|
||||
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_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_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route);
|
||||
SIGNAL (NM_PLATFORM_SIGNAL_ID_ROUTING_RULE, NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED, log_routing_rule);
|
||||
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;
|
||||
|
||||
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 {
|
||||
|
||||
/* match-flags are strictly inclusive. That means,
|
||||
|
|
@ -181,12 +189,22 @@ typedef enum {
|
|||
|
||||
#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; \
|
||||
;
|
||||
|
||||
struct _NMPlatformObjWithIfindex {
|
||||
__NMPlatformObjWithIfindex_COMMON;
|
||||
};
|
||||
|
||||
struct _NMPlatformLink {
|
||||
__NMPlatformObject_COMMON;
|
||||
__NMPlatformObjWithIfindex_COMMON;
|
||||
char name[NMP_IFNAMSIZ];
|
||||
NMLinkType type;
|
||||
|
||||
|
|
@ -246,6 +264,7 @@ typedef enum { /*< skip >*/
|
|||
NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
|
||||
NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
|
||||
NM_PLATFORM_SIGNAL_ID_IP6_ROUTE,
|
||||
NM_PLATFORM_SIGNAL_ID_ROUTING_RULE,
|
||||
NM_PLATFORM_SIGNAL_ID_QDISC,
|
||||
NM_PLATFORM_SIGNAL_ID_TFILTER,
|
||||
_NM_PLATFORM_SIGNAL_ID_LAST,
|
||||
|
|
@ -260,15 +279,11 @@ typedef enum {
|
|||
NM_PLATFORM_SIGNAL_REMOVED,
|
||||
} NMPlatformSignalChangeType;
|
||||
|
||||
struct _NMPlatformObject {
|
||||
__NMPlatformObject_COMMON;
|
||||
};
|
||||
|
||||
#define NM_PLATFORM_IP_ADDRESS_CAST(address) \
|
||||
NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address)
|
||||
|
||||
#define __NMPlatformIPAddress_COMMON \
|
||||
__NMPlatformObject_COMMON; \
|
||||
__NMPlatformObjWithIfindex_COMMON; \
|
||||
NMIPConfigSource addr_source; \
|
||||
\
|
||||
/* 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 __NMPlatformIPRoute_COMMON \
|
||||
__NMPlatformObject_COMMON; \
|
||||
__NMPlatformObjWithIfindex_COMMON; \
|
||||
\
|
||||
/* The NMIPConfigSource. For routes that we receive from cache this corresponds
|
||||
* to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
|
||||
|
|
@ -540,7 +555,49 @@ typedef union {
|
|||
#undef __NMPlatformIPRoute_COMMON
|
||||
|
||||
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;
|
||||
int addr_family;
|
||||
guint32 handle;
|
||||
|
|
@ -562,7 +619,7 @@ typedef struct {
|
|||
#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple"
|
||||
|
||||
typedef struct {
|
||||
__NMPlatformObject_COMMON;
|
||||
__NMPlatformObjWithIfindex_COMMON;
|
||||
const char *kind;
|
||||
int addr_family;
|
||||
guint32 handle;
|
||||
|
|
@ -571,7 +628,7 @@ typedef struct {
|
|||
NMPlatformAction action;
|
||||
} NMPlatformTfilter;
|
||||
|
||||
#undef __NMPlatformObject_COMMON
|
||||
#undef __NMPlatformObjWithIfindex_COMMON
|
||||
|
||||
typedef struct {
|
||||
gboolean is_ip4;
|
||||
|
|
@ -583,8 +640,15 @@ typedef struct {
|
|||
guint32 (*metric_normalize) (guint32 metric);
|
||||
} NMPlatformVTableRoute;
|
||||
|
||||
extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
|
||||
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
|
||||
typedef union {
|
||||
struct {
|
||||
NMPlatformVTableRoute v6;
|
||||
NMPlatformVTableRoute v4;
|
||||
};
|
||||
NMPlatformVTableRoute vx[2];
|
||||
} _NMPlatformVTableRouteUnion;
|
||||
|
||||
extern const _NMPlatformVTableRouteUnion nm_platform_vtable_route;
|
||||
|
||||
typedef struct {
|
||||
guint16 id;
|
||||
|
|
@ -793,8 +857,6 @@ typedef struct {
|
|||
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);
|
||||
|
||||
void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type);
|
||||
|
||||
int (*link_add) (NMPlatform *,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
|
|
@ -973,6 +1035,10 @@ typedef struct {
|
|||
int oif_ifindex,
|
||||
NMPObject **out_route);
|
||||
|
||||
int (*routing_rule_add) (NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPlatformRoutingRule *routing_rule);
|
||||
|
||||
int (*qdisc_add) (NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPlatformQdisc *qdisc);
|
||||
|
|
@ -1001,6 +1067,7 @@ typedef struct {
|
|||
#define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-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_ROUTING_RULE_CHANGED "routing-rule-changed"
|
||||
#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-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 */);
|
||||
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,
|
||||
int ifindex,
|
||||
gboolean visible_only);
|
||||
|
|
@ -1482,6 +1547,10 @@ int nm_platform_ip_route_get (NMPlatform *self,
|
|||
int oif_ifindex,
|
||||
NMPObject **out_route);
|
||||
|
||||
int nm_platform_routing_rule_add (NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPlatformRoutingRule *routing_rule);
|
||||
|
||||
int nm_platform_qdisc_add (NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
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_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_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_tfilter_to_string (const NMPlatformTfilter *tfilter, 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);
|
||||
}
|
||||
|
||||
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_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_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_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_infiniband_hash_update (const NMPlatformLnkInfiniband *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);
|
||||
return 0;
|
||||
}
|
||||
nm_assert (obj_a->object.ifindex > 0);
|
||||
nm_assert (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_a)->ifindex > 0);
|
||||
if (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);
|
||||
}
|
||||
if (h) {
|
||||
nm_hash_update_vals (h,
|
||||
idx_type->cache_id_type,
|
||||
obj_a->object.ifindex);
|
||||
NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (obj_a)->ifindex);
|
||||
}
|
||||
return 1;
|
||||
|
||||
|
|
@ -406,14 +406,14 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
|||
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
||||
if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE)
|
||||
|| obj_a->object.ifindex <= 0) {
|
||||
|| NMP_OBJECT_CAST_IP_ROUTE (obj_a)->ifindex <= 0) {
|
||||
if (h)
|
||||
nm_hash_update_val (h, obj_a);
|
||||
return 0;
|
||||
}
|
||||
if (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
|
||||
? (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));
|
||||
|
|
@ -427,6 +427,25 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
|||
}
|
||||
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_MAX:
|
||||
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
|
||||
_vt_cmd_obj_dispose_link (NMPObject *obj)
|
||||
{
|
||||
|
|
@ -1369,6 +1378,10 @@ _vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
|
|||
*dst = *src;
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
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
|
||||
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, {
|
||||
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, {
|
||||
nm_hash_update_vals (h,
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
nmp_object_is_alive (const NMPObject *obj)
|
||||
{
|
||||
|
|
@ -1574,13 +1602,14 @@ nmp_object_is_alive (const NMPObject *obj)
|
|||
static gboolean
|
||||
_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
|
||||
_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
|
||||
|
|
@ -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()
|
||||
* 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);
|
||||
}
|
||||
|
||||
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
|
||||
_vt_cmd_obj_is_alive_qdisc (const NMPObject *obj)
|
||||
{
|
||||
return obj->object.ifindex > 0;
|
||||
return NMP_OBJECT_CAST_QDISC (obj)->ifindex > 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_vt_cmd_obj_is_alive_tfilter (const NMPObject *obj)
|
||||
{
|
||||
return obj->object.ifindex > 0;
|
||||
return NMP_OBJECT_CAST_TFILTER (obj)->ifindex > 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -1672,6 +1707,12 @@ static const guint8 _supported_cache_ids_ipx_route[] = {
|
|||
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
|
||||
|
|
@ -1949,6 +1990,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup,
|
|||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||
case NMP_OBJECT_TYPE_QDISC:
|
||||
case NMP_OBJECT_TYPE_TFILTER:
|
||||
_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->object.ifindex = ifindex;
|
||||
o->obj_with_ifindex.ifindex = ifindex;
|
||||
lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX;
|
||||
return _L (lookup);
|
||||
}
|
||||
|
|
@ -2014,7 +2056,7 @@ nmp_lookup_init_route_default (NMPLookup *lookup,
|
|||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
|
||||
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;
|
||||
return _L (lookup);
|
||||
}
|
||||
|
|
@ -2062,9 +2104,9 @@ nmp_lookup_init_ip4_route_by_weak_id (NMPLookup *lookup,
|
|||
nm_assert (lookup);
|
||||
|
||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
||||
o->object.ifindex = 1;
|
||||
o->ip_route.plen = plen;
|
||||
o->ip_route.metric = metric;
|
||||
o->ip4_route.ifindex = 1;
|
||||
o->ip4_route.plen = plen;
|
||||
o->ip4_route.metric = metric;
|
||||
if (network)
|
||||
o->ip4_route.network = network;
|
||||
o->ip4_route.tos = tos;
|
||||
|
|
@ -2085,9 +2127,9 @@ nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
|||
nm_assert (lookup);
|
||||
|
||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
||||
o->object.ifindex = 1;
|
||||
o->ip_route.plen = plen;
|
||||
o->ip_route.metric = metric;
|
||||
o->ip6_route.ifindex = 1;
|
||||
o->ip6_route.plen = plen;
|
||||
o->ip6_route.metric = metric;
|
||||
if (network)
|
||||
o->ip6_route.network = *network;
|
||||
if (src)
|
||||
|
|
@ -2097,6 +2139,23 @@ nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *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 *
|
||||
|
|
@ -2920,15 +2979,25 @@ nmp_cache_update_link_master_connected (NMPCache *cache,
|
|||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
nmp_cache_dirty_set_all (NMPCache *cache,
|
||||
const NMPLookup *lookup)
|
||||
nmp_cache_dirty_set_all_main (NMPCache *cache,
|
||||
const NMPLookup *lookup)
|
||||
{
|
||||
const NMDedupMultiHeadEntry *head_entry;
|
||||
NMDedupMultiIter iter;
|
||||
|
||||
nm_assert (cache);
|
||||
nm_assert (lookup);
|
||||
|
||||
nm_dedup_multi_index_dirty_set_head (cache->multi_idx,
|
||||
_idx_type_get (cache, lookup->cache_id_type),
|
||||
&lookup->selector_obj);
|
||||
head_entry = nmp_cache_lookup (cache, lookup);
|
||||
|
||||
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_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] = {
|
||||
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
||||
.obj_type = NMP_OBJECT_TYPE_QDISC,
|
||||
|
|
|
|||
|
|
@ -174,6 +174,11 @@ typedef enum { /*< skip >*/
|
|||
* cache-resync. */
|
||||
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 - 1,
|
||||
} NMPCacheIdType;
|
||||
|
|
@ -324,6 +329,10 @@ typedef struct {
|
|||
NMPlatformIP6Route _public;
|
||||
} NMPObjectIP6Route;
|
||||
|
||||
typedef struct {
|
||||
NMPlatformRoutingRule _public;
|
||||
} NMPObjectRoutingRule;
|
||||
|
||||
typedef struct {
|
||||
NMPlatformQdisc _public;
|
||||
} NMPObjectQdisc;
|
||||
|
|
@ -340,6 +349,8 @@ struct _NMPObject {
|
|||
union {
|
||||
NMPlatformObject object;
|
||||
|
||||
NMPlatformObjWithIfindex obj_with_ifindex;
|
||||
|
||||
NMPlatformLink link;
|
||||
NMPObjectLink _link;
|
||||
|
||||
|
|
@ -390,6 +401,9 @@ struct _NMPObject {
|
|||
NMPObjectIP4Route _ip4_route;
|
||||
NMPObjectIP6Route _ip6_route;
|
||||
|
||||
NMPlatformRoutingRule routing_rule;
|
||||
NMPObjectRoutingRule _routing_rule;
|
||||
|
||||
NMPlatformQdisc qdisc;
|
||||
NMPObjectQdisc _qdisc;
|
||||
NMPlatformTfilter tfilter;
|
||||
|
|
@ -397,6 +411,8 @@ struct _NMPObject {
|
|||
};
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline gboolean
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
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;
|
||||
}
|
||||
|
||||
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) \
|
||||
({ \
|
||||
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; \
|
||||
})
|
||||
|
||||
|
|
@ -482,7 +563,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *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; \
|
||||
})
|
||||
|
||||
|
|
@ -490,7 +571,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *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; \
|
||||
})
|
||||
|
||||
|
|
@ -514,7 +595,7 @@ NMP_OBJECT_GET_TYPE (const NMPObject *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; \
|
||||
})
|
||||
|
||||
|
|
@ -522,15 +603,23 @@ NMP_OBJECT_GET_TYPE (const NMPObject *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; \
|
||||
})
|
||||
|
||||
#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) \
|
||||
({ \
|
||||
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; \
|
||||
})
|
||||
|
||||
|
|
@ -538,12 +627,10 @@ NMP_OBJECT_GET_TYPE (const NMPObject *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; \
|
||||
})
|
||||
|
||||
const NMPClass *nmp_class_from_type (NMPObjectType obj_type);
|
||||
|
||||
static inline const NMPObject *
|
||||
nmp_object_ref (const NMPObject *obj)
|
||||
{
|
||||
|
|
@ -565,9 +652,11 @@ nmp_object_ref (const NMPObject *obj)
|
|||
static inline void
|
||||
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) \
|
||||
|
|
@ -695,6 +784,9 @@ const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
|||
guint32 metric,
|
||||
const struct in6_addr *src,
|
||||
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,
|
||||
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_new);
|
||||
|
||||
void nmp_cache_dirty_set_all (NMPCache *cache,
|
||||
const NMPLookup *lookup);
|
||||
static inline const NMDedupMultiEntry *
|
||||
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);
|
||||
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_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_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 (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);
|
||||
if (obj_prev && 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 <linux/rtnetlink.h>
|
||||
#include <linux/fib_rules.h>
|
||||
|
||||
#include "nm-core-utils.h"
|
||||
#include "platform/nm-platform-utils.h"
|
||||
#include "platform/nmp-rules-manager.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;
|
||||
|
||||
void
|
||||
|
|
@ -902,4 +1720,11 @@ _nmtstp_setup_tests (void)
|
|||
add_test_func ("/route/ip6_route_get", test_ip6_route_get);
|
||||
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