platform: add support for routing-rule objects and cache them in platform

Add and implement NMPlatformRoutingRule types and let the platform cache
handle rules.

Rules are special in two ways:

- they don't have an ifindex. That makes them different from all other
  currently existing NMPlatform* types, which have an "ifindex" field and
  "implement" NMPlatformObjWithIfindex.

- they have an address family, but contrary to addresses and routes, there
  is only one NMPlatformRoutingRule object to handle both address
  families.

Both of these points require some special considerations.

Kernel treats routing-rules quite similar to routes. That is, kernel
allows to add different rules/routes, as long as they differ in certain
fields. These "fields" make up the identity of the rules/routes. But
in practice, it's not defined which fields contribute to the identity
of these objects. That makes using the netlink API very hard. For
example, when kernel gains support for a new attribute which
NetworkManager does not know yet, then users can add two rules/routes
that look the same to NetworkManager. That can easily result in cache
inconsistencies.

Another problem is, that older kernel versions may not yet support all
fields, which NetworkManager (and newer kernels) considers for identity.
The older kernel will not simply reject netlink messages with these unknown
keys, instead it will proceed adding the route/rule without it. That means,
the added route/rule will have a different identity than what NetworkManager
intended to add.
This commit is contained in:
Thomas Haller 2019-02-14 13:08:12 +01:00
parent b9ee40b86b
commit 9934a6a0e3
6 changed files with 874 additions and 26 deletions

View file

@ -193,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,

View file

@ -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
@ -291,8 +305,10 @@ typedef enum {
REFRESH_ALL_TYPE_IP6_ADDRESSES = 2,
REFRESH_ALL_TYPE_IP4_ROUTES = 3,
REFRESH_ALL_TYPE_IP6_ROUTES = 4,
REFRESH_ALL_TYPE_QDISCS = 5,
REFRESH_ALL_TYPE_TFILTERS = 6,
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;
@ -313,22 +329,28 @@ typedef enum {
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_QDISCS = 1 << F (5, REFRESH_ALL_TYPE_QDISCS),
DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F (6, REFRESH_ALL_TYPE_TFILTERS),
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 << 7,
DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 8,
DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 9,
DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 10,
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_ROUTING_RULES_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 |
DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6,
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,
@ -3354,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)
{
@ -3453,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:
@ -4372,6 +4557,8 @@ refresh_all_type_get_info (RefreshAllType refresh_all_type)
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
@ -4391,6 +4578,8 @@ _NM_UTILS_LOOKUP_DEFINE (static, delayed_action_type_to_refresh_all_type, Delaye
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 (),
@ -4410,7 +4599,7 @@ delayed_action_type_from_refresh_all_type (RefreshAllType refresh_all_type)
return t;
}
static DelayedActionType
static RefreshAllType
refresh_all_type_from_needle_object (const NMPObject *obj_needle)
{
switch (NMP_OBJECT_GET_TYPE (obj_needle)) {
@ -4421,6 +4610,13 @@ refresh_all_type_from_needle_object (const NMPObject *obj_needle)
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;
@ -4439,6 +4635,12 @@ refresh_all_type_init_lookup (RefreshAllType 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);
@ -4459,6 +4661,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType,
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"),
@ -4467,6 +4671,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType,
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),
);
@ -4955,6 +5160,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);
@ -5313,6 +5519,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,
@ -5333,12 +5540,30 @@ 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[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;
@ -5495,6 +5720,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
@ -5513,6 +5739,7 @@ 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,
@ -5532,10 +5759,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) {
@ -5630,10 +5858,11 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
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) {
@ -7817,7 +8046,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;
}
@ -8134,6 +8364,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);
@ -8399,9 +8630,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);
@ -8428,6 +8663,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);

View file

@ -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>
@ -6063,6 +6064,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)
{
@ -7021,6 +7269,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
@ -7117,6 +7545,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)
{
@ -7183,10 +7618,13 @@ nm_platform_cache_update_emit_signal (NMPlatform *self,
return;
}
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX (o)->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))
@ -7400,11 +7838,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);
}

View file

@ -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,
@ -256,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,
@ -545,6 +554,48 @@ typedef union {
#undef __NMPlatformIPRoute_COMMON
typedef struct {
/* 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;
@ -1012,6 +1063,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"
@ -1521,6 +1573,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);
@ -1565,6 +1618,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);
@ -1573,6 +1634,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);

View file

@ -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;
@ -1359,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.
@ -1459,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)
{
@ -1524,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,
@ -1547,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)
{
@ -1596,6 +1634,12 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj)
&& !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)
{
@ -1663,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
@ -1940,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);
@ -2088,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 *
@ -3077,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,

View file

@ -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;
@ -392,6 +401,9 @@ struct _NMPObject {
NMPObjectIP4Route _ip4_route;
NMPObjectIP6Route _ip6_route;
NMPlatformRoutingRule routing_rule;
NMPObjectRoutingRule _routing_rule;
NMPlatformQdisc qdisc;
NMPObjectQdisc _qdisc;
NMPlatformTfilter tfilter;
@ -595,6 +607,14 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMPObjectType obj_type)
_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); \
@ -764,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,