diff options
author | Thomas Haller <thaller@redhat.com> | 2019-02-14 13:08:12 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-03-04 14:28:19 +0100 |
commit | f2deacc7aa13e8730c94471a973a0468af3daa11 (patch) | |
tree | d2733aa273c83c4ee714d691aadb0687aea00bd3 | |
parent | 169eb23299595fdb96445c8661ba4d6123298dbc (diff) | |
download | NetworkManager-th/routing-rule.tar.gz |
platform: add support for routing-ruleth/routing-rule
https://bugzilla.redhat.com/show_bug.cgi?id=1652653
-rw-r--r-- | src/nm-types.h | 1 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 230 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 451 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 62 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 87 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 23 |
6 files changed, 836 insertions, 18 deletions
diff --git a/src/nm-types.h b/src/nm-types.h index f30cc19920..03ee99299b 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -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, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a4816d4197..c687758c9f 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -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> @@ -291,8 +292,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,14 +316,16 @@ 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, @@ -329,6 +334,8 @@ typedef enum { 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_IP4 | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, @@ -3353,6 +3360,166 @@ rta_multipath_done: } 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(struct fib_rule_uid_range), + .maxlen = sizeof(struct fib_rule_uid_range) }, + [FRA_PROTOCOL] = { .type = NLA_U8 }, + [FRA_IP_PROTO] = { .type = NLA_U8 }, + [FRA_SPORT_RANGE] = { .minlen = sizeof(struct fib_rule_port_range), + .maxlen = sizeof(struct fib_rule_port_range) }, + [FRA_DPORT_RANGE] = { .minlen = sizeof(struct fib_rule_port_range), + .maxlen = sizeof(struct fib_rule_port_range) }, + }; + 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; + + if (tb[FRA_TABLE]) + props->table_coerced = nm_platform_route_table_coerce (nla_get_u32 (tb[FRA_TABLE])); + else + props->table_coerced = nm_platform_route_table_coerce (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) == sizeof (struct fib_rule_port_range)); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, start) == G_STRUCT_OFFSET (struct fib_rule_port_range, start)); + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRulePortRange, end) == G_STRUCT_OFFSET (struct fib_rule_port_range, end)); + + 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)); + + if (tb[FRA_UID_RANGE]) { + const struct fib_rule_uid_range *r; + + r = nla_data_as (struct fib_rule_uid_range, tb[FRA_UID_RANGE]); + props->uid_range = (NMFibRuleUidRange) { + .start = r->start, + .end = r->end, + }; + props->uid_range_has = TRUE; + } + + return g_steal_pointer (&obj); +} + +static NMPObject * _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { @@ -3451,6 +3618,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: @@ -4370,6 +4541,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 @@ -4389,6 +4562,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 (), @@ -4419,6 +4594,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; @@ -4426,12 +4608,23 @@ refresh_all_type_from_needle_object (const NMPObject *obj_needle) } static const NMPLookup * -refresh_all_info_init_lookup (const RefreshAllInfo *refresh_all_info, +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); @@ -4452,6 +4645,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"), @@ -4864,7 +5059,7 @@ cache_prune_all (NMPlatform *platform) priv->pruning[refresh_all_type] -= 1; if (priv->pruning[refresh_all_type] > 0) continue; - refresh_all_info_init_lookup (refresh_all_type_get_info (refresh_all_type), + refresh_all_type_init_lookup (refresh_all_type, &lookup); cache_prune_one_type (platform, &lookup); } @@ -4938,6 +5133,8 @@ 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_IP4 | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); @@ -5296,6 +5493,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, @@ -5326,7 +5524,7 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio NMPLookup lookup; priv->pruning[refresh_all_type] += 1; - refresh_all_info_init_lookup (refresh_all_type_get_info (refresh_all_type), + refresh_all_type_init_lookup (refresh_all_type, &lookup); nmp_cache_dirty_set_all (nm_platform_get_cache (platform), &lookup); @@ -5478,6 +5676,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 @@ -5496,6 +5695,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, @@ -5518,6 +5718,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWLINK: case RTM_NEWADDR: case RTM_GETLINK: + case RTM_NEWRULE: + //XXX case RTM_NEWQDISC: case RTM_NEWTFILTER: cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new); @@ -5616,6 +5818,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_DELLINK: case RTM_DELADDR: case RTM_DELROUTE: + case RTM_DELRULE: + //XXX case RTM_DELQDISC: case RTM_DELTFILTER: cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new); @@ -8117,6 +8321,8 @@ 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_IP4 | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); @@ -8411,6 +8617,8 @@ 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_IP4 | + DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, NULL); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index a72159fb86..320234259c 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -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> @@ -6062,6 +6063,258 @@ 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"); + + if (!is_zero) + nm_utils_strbuf_append_str (buf, len, nm_utils_inet_ntop (addr_family, addr, s_addr)); + else + nm_utils_strbuf_append_str (buf, len, "0"); + + 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_table; + 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, + " uid-range %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); + } + + rr_table = nm_platform_route_table_uncoerce (routing_rule->table_coerced, FALSE); + if (rr_table != 0) { + /* ip-rule prints this as "lookup". I find that confusing, deviate from + * that. */ + nm_utils_strbuf_append (&buf, &len, + " table %u", + rr_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 == FRA_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]; + + switch (routing_rule->action) { + case FR_ACT_UNSPEC /*RTN_UNSPEC*/ : ss = "none"; break; + case FR_ACT_TO_TBL /*RTN_UNICAST*/ : ss = "unicast"; break; + case FR_ACT_GOTO /*RTN_LOCAL*/ : ss = "local"; break; + case FR_ACT_NOP /*RTN_BROADCAST*/ : ss = "nop"; break; + case FR_ACT_RES3 /*RTN_ANYCAST*/ : ss = "anycast"; break; + case FR_ACT_RES4 /*RTN_MULTICAST*/ : ss = "multicast"; break; + case FR_ACT_BLACKHOLE /*RTN_BLACKHOLE*/ : ss = "blackhole"; break; + case FR_ACT_UNREACHABLE /*RTN_UNREACHABLE*/ : ss = "unreachable"; break; + case 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; + } + 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 != FRA_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) { @@ -7020,6 +7273,182 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route return 0; } +void +nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, + NMPlatformRoutingRuleCmpType cmp_type, + NMHashState *h) +{ + gboolean cmp_full = TRUE; + gsize addr_size; + guint32 table; + + // see systemd: routing_policy_rule_hash_func + + 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: + /* for the moment, ID is the same as a full (sementical) comparison. We might + * refine that in the future. */ + + /* fall-through */ + case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY: + cmp_full = FALSE; + /* fall-through */ + case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL: + + /* for semantic comparison, we cannot hash the table for IPv4 + * rules. See also nm_platform_routing_rule_cmp(). */ + if (cmp_full) + table = obj->table_coerced; + else if (obj->l3mdev) + table = 0; + else if (obj->addr_family != AF_INET) + table = obj->table_coerced; + else + table = 0; + + nm_hash_update_vals (h, + obj->addr_family, + obj->tun_id, + table, + obj->flags, + obj->priority, + obj->fwmark, + obj->fwmask, + obj->goto_target, + obj->flow, + 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); + nm_hash_update (h, &obj->src, addr_size); + 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; + + 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: + /* for the moment, ID is the same as a full (sementical) comparison. We might + * refine that in the future. */ + + /* 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, tun_id); + if (cmp_full) + NM_CMP_FIELD (a, b, l3mdev); + else + NM_CMP_FIELD_BOOL (a, b, l3mdev); + + if (cmp_full) + NM_CMP_FIELD (a, b, table_coerced); + else if (a->l3mdev) { + /* the table is ignored for semantic comparison. */ + } else if (a->addr_family != AF_INET) + NM_CMP_FIELD (a, b, table_coerced); + else { + guint32 tb_a = nm_platform_route_table_uncoerce (a->table_coerced, FALSE); + guint32 tb_b = nm_platform_route_table_uncoerce (b->table_coerced, FALSE); + + /* `ip rule add table 0` lets kernel create a new table and use + * it. For semantic comparison, if one of the tables is RT_TABLE_UNSPEC, + * we assume that the rules might match. + * + * This special case is done by kernel only for IPv4. + * + * For IPv6, kernel considers RT_TABLE_UNSPEC as invalid, so it's fine + * to always compare the tables (above). */ + if ( tb_a != RT_TABLE_UNSPEC + && tb_b != RT_TABLE_UNSPEC) { + NM_CMP_DIRECT (tb_a, tb_b); + } + } + + NM_CMP_FIELD (a, b, flags); + NM_CMP_FIELD (a, b, priority); + NM_CMP_FIELD (a, b, fwmark); + NM_CMP_FIELD (a, b, fwmask); + 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, action); + NM_CMP_FIELD (a, b, tos); + NM_CMP_FIELD (a, b, src_len); + NM_CMP_FIELD (a, b, dst_len); + 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_MEMCMP_LEN (a, b, src, addr_size); + 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 +7546,13 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform } 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) { _LOG3D ("signal: qdisc %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_qdisc_to_string (qdisc, NULL, 0)); @@ -7399,11 +7835,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); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 9b626fb4a0..a8a62f897b 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -152,6 +152,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, * by default nothing is matched, but if you enable a particular @@ -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, @@ -546,6 +555,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_coerced; /* (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; @@ -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); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 0b5a0dbd80..91195b65eb 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -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) { @@ -1597,6 +1635,12 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) } 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 NMP_OBJECT_CAST_QDISC (obj)->ifindex > 0; @@ -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 * @@ -3067,6 +3135,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, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f0665ae7a5..30d9697a15 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -161,6 +161,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; @@ -312,6 +317,10 @@ typedef struct { } NMPObjectIP6Route; typedef struct { + NMPlatformRoutingRule _public; +} NMPObjectRoutingRule; + +typedef struct { NMPlatformQdisc _public; } NMPObjectQdisc; @@ -379,6 +388,9 @@ struct _NMPObject { NMPObjectIP4Route _ip4_route; NMPObjectIP6Route _ip6_route; + NMPlatformRoutingRule routing_rule; + NMPObjectRoutingRule _routing_rule; + NMPlatformQdisc qdisc; NMPObjectQdisc _qdisc; NMPlatformTfilter tfilter; @@ -582,6 +594,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 ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_ROUTING_RULE); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->routing_rule : NULL; \ + }) + #define NMP_OBJECT_CAST_QDISC(obj) \ ({ \ typeof (obj) _obj = (obj); \ @@ -751,6 +771,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, |