diff options
author | Thomas Haller <thaller@redhat.com> | 2022-07-20 10:40:16 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-07-20 10:40:16 +0200 |
commit | 571f3c57bdf97200726f1b0326406cc6dc73040a (patch) | |
tree | 54f0c9180ffc1865624fc1ad7f474f18585d1c73 | |
parent | 93372e81001baa2278cee1c83115b55f077033a6 (diff) | |
parent | 1a0c8772b0d9bfce14e8f1bd8d290d00d824dbb5 (diff) | |
download | NetworkManager-571f3c57bdf97200726f1b0326406cc6dc73040a.tar.gz |
platform: merge branch 'th/platform-genl-4'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1304
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-hash-utils.h | 2 | ||||
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 21 | ||||
-rw-r--r-- | src/libnm-platform/nm-netlink.c | 1 | ||||
-rw-r--r-- | src/libnm-platform/nm-netlink.h | 1 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 87 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 36 | ||||
-rw-r--r-- | src/libnm-platform/nmp-base.h | 2 | ||||
-rw-r--r-- | src/libnm-platform/nmp-object.c | 147 | ||||
-rw-r--r-- | src/libnm-platform/nmp-object.h | 11 | ||||
-rw-r--r-- | src/libnm-std-aux/nm-std-aux.h | 13 | ||||
-rw-r--r-- | src/linux-headers/mptcp.h | 232 |
12 files changed, 490 insertions, 66 deletions
diff --git a/Makefile.am b/Makefile.am index eac85f15b1..f78d60d4d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -590,8 +590,9 @@ src_libnm_platform_libnm_platform_la_CPPFLAGS = \ src_libnm_platform_libnm_platform_la_SOURCES = \ \ src/linux-headers/ethtool.h \ - src/linux-headers/nl802154.h \ + src/linux-headers/mptcp.h \ src/linux-headers/nl80211-vnd-intel.h \ + src/linux-headers/nl802154.h \ \ src/libnm-platform/nm-linux-platform.c \ src/libnm-platform/nm-linux-platform.h \ diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h index b7ee4dd17a..e6c7e74adc 100644 --- a/src/libnm-glib-aux/nm-hash-utils.h +++ b/src/libnm-glib-aux/nm-hash-utils.h @@ -140,7 +140,7 @@ nm_hash_update_bool(NMHashState *state, bool val) #define NM_HASH_COMBINE_VALS(var, ...) \ const struct _nm_packed { \ NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_TYPE_OP, __VA_ARGS__) \ - } var _nm_alignas(guint64) = { \ + } var _nm_alignas(max_align_t) = { \ NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_INIT_OP, __VA_ARGS__)} /* nm_hash_update_vals() is faster then nm_hash_update_val() as it combines multiple diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 185c9aed3e..01505c5b82 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -23,6 +23,7 @@ #include <linux/if_vlan.h> #include <linux/ip6_tunnel.h> #include <linux/tc_act/tc_mirred.h> +#include <linux-headers/mptcp.h> #include <netinet/icmp6.h> #include <netinet/in.h> #include <net/if_arp.h> @@ -50,6 +51,14 @@ /*****************************************************************************/ +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SIGNAL == MPTCP_PM_ADDR_FLAG_SIGNAL); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW == MPTCP_PM_ADDR_FLAG_SUBFLOW); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_BACKUP == MPTCP_PM_ADDR_FLAG_BACKUP); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_FULLMESH == MPTCP_PM_ADDR_FLAG_FULLMESH); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_IMPLICIT == MPTCP_PM_ADDR_FLAG_IMPLICIT); + +/*****************************************************************************/ + /* re-implement <linux/tc_act/tc_defact.h> to build against kernel * headers that lack this. */ @@ -4780,7 +4789,7 @@ _nl_msg_new_address(uint16_t nlmsg_type, guint8 plen, gconstpointer peer_address, guint32 flags, - int scope, + guint8 scope, guint32 lifetime, guint32 preferred, in_addr_t ip4_broadcast_address, @@ -4792,6 +4801,7 @@ _nl_msg_new_address(uint16_t nlmsg_type, .ifa_index = ifindex, .ifa_prefixlen = plen, .ifa_flags = flags, + .ifa_scope = scope, }; gsize addr_len; @@ -4800,15 +4810,6 @@ _nl_msg_new_address(uint16_t nlmsg_type, msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); - if (scope == -1) { - /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */ - if (family == AF_INET && address && *((char *) address) == 127) - scope = RT_SCOPE_HOST; - else - scope = RT_SCOPE_UNIVERSE; - } - am.ifa_scope = scope, - addr_len = family == AF_INET ? sizeof(in_addr_t) : sizeof(struct in6_addr); if (nlmsg_append_struct(msg, &am) < 0) diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index cb5bd4a896..ecb700fc9b 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -619,6 +619,7 @@ nla_nest_end(struct nl_msg *msg, struct nlattr *start) static const uint8_t nla_attr_minlen[NLA_TYPE_MAX + 1] = { [NLA_U8] = sizeof(uint8_t), [NLA_U16] = sizeof(uint16_t), + [NLA_S32] = sizeof(int32_t), [NLA_U32] = sizeof(uint32_t), [NLA_U64] = sizeof(uint64_t), [NLA_STRING] = 1, diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 852c9c8f6d..ccd4b787c7 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -31,6 +31,7 @@ enum { NLA_UNSPEC, /* Unspecified type, binary data chunk */ NLA_U8, /* 8 bit integer */ NLA_U16, /* 16 bit integer */ + NLA_S32, /* 32 bit integer */ NLA_U32, /* 32 bit integer */ NLA_U64, /* 64 bit integer */ NLA_STRING, /* NUL terminated character string */ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 961c617cc6..bfe80c0d4c 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -7586,6 +7586,93 @@ nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b) return 0; } +static NM_UTILS_FLAGS2STR_DEFINE(_mptcp_flags_to_string, + guint32, + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SIGNAL, "signal"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW, "subflow"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_BACKUP, "backup"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh")); + +const char * +nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len) +{ + char str_addr[30 + NM_UTILS_INET_ADDRSTRLEN]; + char str_port[30]; + char str_id[30]; + char str_flags[200]; + char str_flags2[30 + sizeof(str_flags)]; + char str_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null(mptcp_addr, &buf, &len)) + return buf; + + if (mptcp_addr->addr_family == 0) + nm_sprintf_buf(str_addr, "no-addr"); + else if (NM_IN_SET(mptcp_addr->addr_family, AF_INET, AF_INET6)) + nm_utils_inet_ntop(mptcp_addr->addr_family, &mptcp_addr->addr, str_addr); + else + nm_sprintf_buf(str_addr, "af %d", mptcp_addr->addr_family); + + if (mptcp_addr->flags != 0) + _mptcp_flags_to_string(mptcp_addr->flags, str_flags, sizeof(str_flags)); + else + str_flags[0] = '\0'; + + g_snprintf(buf, + len, + "%s" /* in_kernel */ + "%s" /* address */ + "%s" /* port */ + "%s" /* id */ + "%s" /* flags */ + "%s" /* ifindex */ + "", + mptcp_addr->in_kernel ? "" : "[nm] ", + str_addr, + mptcp_addr->port == 0 ? "" : nm_sprintf_buf(str_port, " port %u", mptcp_addr->port), + mptcp_addr->id == 0 ? "" : nm_sprintf_buf(str_id, " id %u", mptcp_addr->id), + str_flags[0] == '\0' ? "" : nm_sprintf_buf(str_flags2, " flags %s", str_flags), + mptcp_addr->ifindex == 0 + ? "" + : nm_sprintf_buf(str_ifindex, " ifindex %d", mptcp_addr->ifindex)); + return buf; +} + +void +nm_platform_mptcp_addr_hash_update(const NMPlatformMptcpAddr *obj, NMHashState *h) +{ + nm_assert(obj); + nm_assert_addr_family_or_unspec(obj->addr_family); + + nm_hash_update_vals(h, + obj->id, + obj->flags, + obj->port, + obj->addr_family, + (bool) obj->in_kernel, + obj->ifindex); + if (NM_IN_SET(obj->addr_family, AF_INET, AF_INET6)) + nm_hash_update(h, &obj->addr, nm_utils_addr_family_to_size(obj->addr_family)); +} + +int +nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b) +{ + NM_CMP_SELF(a, b); + + nm_assert_addr_family_or_unspec(a->addr_family); + nm_assert_addr_family_or_unspec(b->addr_family); + + NM_CMP_FIELD(a, b, id); + NM_CMP_FIELD_UNSAFE(a, b, in_kernel); + NM_CMP_FIELD(a, b, addr_family); + if (NM_IN_SET(a->addr_family, AF_INET, AF_INET6)) + NM_CMP_FIELD_MEMCMP_LEN(a, b, addr, nm_utils_addr_family_to_size(a->addr_family)); + NM_CMP_FIELD(a, b, ifindex); + + return 0; +} + const char * nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 984ad79cba..19b00c961d 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -61,6 +61,12 @@ typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_d #define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ +#define NM_MPTCP_PM_ADDR_FLAG_SIGNAL ((guint32) (1 << 0)) +#define NM_MPTCP_PM_ADDR_FLAG_SUBFLOW ((guint32) (1 << 1)) +#define NM_MPTCP_PM_ADDR_FLAG_BACKUP ((guint32) (1 << 2)) +#define NM_MPTCP_PM_ADDR_FLAG_FULLMESH ((guint32) (1 << 3)) +#define NM_MPTCP_PM_ADDR_FLAG_IMPLICIT ((guint32) (1 << 4)) + /* Redefine this in host's endianness */ #define NM_GRE_KEY 0x2000 @@ -782,8 +788,6 @@ typedef struct { NMPlatformAction action; } NMPlatformTfilter; -#undef __NMPlatformObjWithIfindex_COMMON - typedef struct { bool is_ip4; NMPObjectType obj_type; @@ -1045,6 +1049,27 @@ typedef enum { typedef void (*NMPlatformAsyncCallback)(GError *error, gpointer user_data); +typedef struct { + __NMPlatformObjWithIfindex_COMMON; + + guint32 id; + guint32 flags; + guint16 port; + NMIPAddr addr; + gint8 addr_family; + + /* If TRUE, then the instance was received by kernel and is inside NMPlatform + * cache. In that case, the "id" is set and acts as primary key for the instance. + * + * If FALSE, this instance is not yet configured in kernel. In this case, + * the tuple (id, addr_family, addr) is the primary key of the instance. + * This way, we can track mptcp addresses in NetworkManager internally, + * before configuring them in kernel. */ + bool in_kernel : 1; +} NMPlatformMptcpAddr; + +#undef __NMPlatformObjWithIfindex_COMMON + /*****************************************************************************/ typedef struct _NMPlatformCsmeConnInfo { @@ -2355,6 +2380,9 @@ const char *nm_platform_vlan_qos_mapping_to_string(const char *name, const char * nm_platform_wireguard_peer_to_string(const struct _NMPWireGuardPeer *peer, char *buf, gsize len); +const char * +nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len); + int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b); int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); @@ -2433,6 +2461,8 @@ int nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a, gboolean compare_handle); int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b); +int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b); + void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h); void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); @@ -2462,6 +2492,8 @@ void nm_platform_lnk_wireguard_hash_update(const NMPlatformLnkWireGuard *obj, NM void nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h); void nm_platform_tfilter_hash_update(const NMPlatformTfilter *obj, NMHashState *h); +void nm_platform_mptcp_addr_hash_update(const NMPlatformMptcpAddr *obj, NMHashState *h); + #define NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN ((gsize) 162) const char *nm_platform_link_flags2str(unsigned flags, char *buf, gsize len); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 4863168855..02420ebf4b 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -148,6 +148,8 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_LNK_VXLAN, NMP_OBJECT_TYPE_LNK_WIREGUARD, + NMP_OBJECT_TYPE_MPTCP_ADDR, + __NMP_OBJECT_TYPE_LAST, NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, } NMPObjectType; diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index d411043d0f..eb5306a66d 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -20,25 +20,26 @@ /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG(level, obj, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - const NMPObject *const __obj = (obj); \ - \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "nmp-object[%p/%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __obj, \ - (__obj ? NMP_OBJECT_GET_CLASS(__obj)->obj_type_name \ - : "???") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, obj, ...) \ + G_STMT_START \ + { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ + const NMPObject *const __obj = (obj); \ + \ + _nm_log(__level, \ + _NMLOG_DOMAIN, \ + 0, \ + NULL, \ + NULL, \ + "nmp-object[" NM_HASH_OBFUSCATE_PTR_FMT "" \ + "/%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(__obj), \ + (__obj ? NMP_OBJECT_GET_CLASS(__obj)->obj_type_name \ + : "???") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ @@ -380,7 +381,8 @@ _idx_obj_part(const DedupMultiIdxType *idx_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER) + NMP_OBJECT_TYPE_TFILTER, + NMP_OBJECT_TYPE_MPTCP_ADDR) || !nmp_object_is_visible(obj_a)) { if (h) nm_hash_update_val(h, obj_a); @@ -840,6 +842,17 @@ nmp_object_stackinit_id(NMPObject *obj, const NMPObject *src) _nmp_object_stackinit_from_class(obj, klass); if (klass->cmd_plobj_id_copy) klass->cmd_plobj_id_copy(&obj->object, &src->object); + else { + /* This object must not implement cmd_obj_copy(). + * If it would, it would mean that we require a deep copy + * of the data. As @obj is stack-allocated, it cannot track + * ownership. The caller must not use nmp_object_stackinit_id() + * with an object of such a type. */ + nm_assert(!klass->cmd_obj_copy); + + /* plain memcpy of the public part suffices. */ + memcpy(&obj->object, &src->object, klass->sizeof_data); + } return obj; } @@ -900,7 +913,7 @@ nmp_object_to_string(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: if (!klass->cmd_plobj_to_string_id) { - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; } return klass->cmd_plobj_to_string_id(&obj->object, buf, buf_size); @@ -908,9 +921,9 @@ nmp_object_to_string(const NMPObject *obj, g_snprintf( buf, buf_size, - "[%s,%p,%u,%calive,%cvisible; %s]", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s]", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -939,14 +952,15 @@ _vt_cmd_obj_to_string_link(const NMPObject *obj, case NMP_OBJECT_TO_STRING_ALL: nm_strbuf_append(&b, &buf_size, - "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT + ",%u,%calive,%cvisible,%cin-nl," NM_HASH_OBFUSCATE_PTR_FMT "; ", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device); + NM_HASH_OBFUSCATE_PTR(obj->_link.udev.device)); NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); nm_strbuf_seek_end(&b, &buf_size); if (obj->_link.netlink.lnk) { @@ -984,15 +998,15 @@ _vt_cmd_obj_to_string_lnk_vlan(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; case NMP_OBJECT_TO_STRING_ALL: g_snprintf(buf, buf_size, - "[%s,%p,%u,%calive,%cvisible; %s]", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s]", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -1048,17 +1062,17 @@ _vt_cmd_obj_to_string_lnk_wireguard(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; case NMP_OBJECT_TO_STRING_ALL: b = buf; nm_strbuf_append(&b, &buf_size, - "[%s,%p,%u,%calive,%cvisible; %s" + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s" "%s", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -1420,21 +1434,6 @@ _vt_cmd_plobj_id_copy(ip6_address, NMPlatformIP6Address, { dst->address = src->address; }); -_vt_cmd_plobj_id_copy(ip4_route, NMPlatformIP4Route, { - *dst = *src; - nm_assert(nm_platform_ip4_route_cmp(dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0); -}); - -_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. * */ @@ -1553,6 +1552,21 @@ _vt_cmd_plobj_id_cmp_routing_rule(const NMPlatformObject *obj1, const NMPlatform NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID); } +_vt_cmd_plobj_id_cmp(mptcp_addr, NMPlatformMptcpAddr, { + NM_CMP_FIELD(obj1, obj2, id); + NM_CMP_FIELD_UNSAFE(obj1, obj2, in_kernel); + if (!obj1->in_kernel) { + /* See comment NMPlatformMptcpAddr.in_kernel for why. */ + NM_CMP_FIELD(obj1, obj2, addr_family); + + /* nm_utils_addr_family_to_size() asserts that addr-family is either AF_INET or AF_INET6. + * This means, we cannot compare totally bogus objects. That is in particular fine + * for instances which are not "in_kernel". While we might receive unexpected values + * from kernel, we should not create them for internal purposes. */ + NM_CMP_FIELD_MEMCMP_LEN(obj1, obj2, addr, nm_utils_addr_family_to_size(obj1->addr_family)); + } +}); + void nmp_object_id_hash_update(const NMPObject *obj, NMHashState *h) { @@ -1638,6 +1652,16 @@ _vt_cmd_plobj_id_hash_update(tfilter, NMPlatformTfilter, { nm_hash_update_vals(h, obj->ifindex, obj->handle); }); +_vt_cmd_plobj_id_hash_update(mptcp_addr, NMPlatformMptcpAddr, { + if (obj->in_kernel) { + nm_hash_update_val(h, obj->id); + } else { + /* _vt_cmd_plobj_id_cmp_mptcp_addr for why. */ + nm_hash_update_vals(h, obj->id, obj->addr_family); + nm_hash_update(h, &obj->addr, nm_utils_addr_family_to_size(obj->addr_family)); + } +}); + static void _vt_cmd_plobj_hash_update_ip4_route(const NMPlatformObject *obj, NMHashState *h) { @@ -1746,6 +1770,12 @@ _vt_cmd_obj_is_alive_tfilter(const NMPObject *obj) return NMP_OBJECT_CAST_TFILTER(obj)->ifindex > 0; } +static gboolean +_vt_cmd_obj_is_alive_mptcp_addr(const NMPObject *obj) +{ + return NM_IN_SET(obj->mptcp_addr.addr_family, AF_INET, AF_INET6); +} + gboolean nmp_object_is_visible(const NMPObject *obj) { @@ -2091,6 +2121,7 @@ nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type) case NMP_OBJECT_TYPE_ROUTING_RULE: case NMP_OBJECT_TYPE_QDISC: case NMP_OBJECT_TYPE_TFILTER: + case NMP_OBJECT_TYPE_MPTCP_ADDR: _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L(lookup); @@ -2125,7 +2156,8 @@ nmp_lookup_init_object_by_ifindex(NMPLookup *lookup, NMPObjectType obj_type, int NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER)); + NMP_OBJECT_TYPE_TFILTER, + NMP_OBJECT_TYPE_MPTCP_ADDR)); nm_assert(ifindex > 0 || (ifindex == 0 && NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE))); @@ -3166,7 +3198,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, .supported_cache_ids = _supported_cache_ids_ipx_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route, .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route, .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip4_route, .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip4_route_to_string, @@ -3187,7 +3218,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .signal_type = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, .supported_cache_ids = _supported_cache_ids_ipx_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route, .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_route, .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_route, .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip6_route_to_string, @@ -3207,7 +3237,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = (CmdPlobjToStringIdFunc) nm_platform_routing_rule_to_string, @@ -3468,4 +3497,20 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_wireguard_hash_update, .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_wireguard_cmp, }, + [NMP_OBJECT_TYPE_MPTCP_ADDR - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_MPTCP_ADDR, + .sizeof_data = sizeof(NMPObjectMptcpAddr), + .sizeof_public = sizeof(NMPlatformMptcpAddr), + .obj_type_name = "mptcp-addr", + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_mptcp_addr, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_mptcp_addr, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_mptcp_addr, + .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_mptcp_addr_to_string, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_mptcp_addr_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_mptcp_addr_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_mptcp_addr_cmp, + }, }; diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index 7d2ebf979a..5b789404a4 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -331,6 +331,10 @@ typedef struct { NMPlatformTfilter _public; } NMPObjectTfilter; +typedef struct { + NMPlatformMptcpAddr _public; +} NMPObjectMptcpAddr; + struct _NMPObject { union { NMDedupMultiObj parent; @@ -404,6 +408,9 @@ struct _NMPObject { NMPObjectQdisc _qdisc; NMPlatformTfilter tfilter; NMPObjectTfilter _tfilter; + + NMPlatformMptcpAddr mptcp_addr; + NMPObjectMptcpAddr _mptcp_addr; }; }; @@ -504,6 +511,8 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_LNK_VRF: case NMP_OBJECT_TYPE_LNK_VXLAN: case NMP_OBJECT_TYPE_LNK_WIREGUARD: + + case NMP_OBJECT_TYPE_MPTCP_ADDR: return TRUE; case NMP_OBJECT_TYPE_ROUTING_RULE: @@ -565,6 +574,8 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) _NMP_OBJECT_CAST(obj, lnk_wireguard, NMP_OBJECT_TYPE_LNK_WIREGUARD) #define NMP_OBJECT_CAST_LNK_BRIDGE(obj) \ _NMP_OBJECT_CAST(obj, lnk_bridge, NMP_OBJECT_TYPE_LNK_BRIDGE) +#define NMP_OBJECT_CAST_MPTCP_ADDR(obj) \ + _NMP_OBJECT_CAST(obj, mptcp_addr, NMP_OBJECT_TYPE_MPTCP_ADDR) static inline int NMP_OBJECT_TYPE_TO_ADDR_FAMILY(NMPObjectType obj_type) diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h index 059b6b83fa..02a2942f8f 100644 --- a/src/libnm-std-aux/nm-std-aux.h +++ b/src/libnm-std-aux/nm-std-aux.h @@ -487,6 +487,17 @@ nm_streq0(const char *s1, const char *s2) return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0); } +static inline int +nm_memcmp(const void *s1, const void *s2, size_t n) +{ + /* Workaround undefined behavior in memcmp() with NULL pointers. */ + if (n == 0) + return 0; + nm_assert(s1); + nm_assert(s2); + return memcmp(s1, s2, n); +} + /* * Very similar to g_str_has_prefix() with the obvious meaning. * Differences: @@ -1163,7 +1174,7 @@ nm_ptr_to_uintptr(const void *p) #define NM_CMP_DIRECT_BOOL(a, b) NM_CMP_DIRECT(!!(a), !!(b)) -#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size))) +#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(nm_memcmp((a), (b), (size))) #define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b))) diff --git a/src/linux-headers/mptcp.h b/src/linux-headers/mptcp.h new file mode 100644 index 0000000000..ca502f1edc --- /dev/null +++ b/src/linux-headers/mptcp.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#ifndef _MPTCP_H +#define _MPTCP_H + +#include <linux/const.h> +#include <linux/types.h> +#include <linux/in.h> /* for sockaddr_in */ +#include <linux/in6.h> /* for sockaddr_in6 */ +#include <linux/socket.h> /* for sockaddr_storage and sa_family */ + +#include <sys/socket.h> /* for struct sockaddr */ + +#define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0) +#define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1) +#define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2) +#define MPTCP_SUBFLOW_FLAG_JOIN_LOC _BITUL(3) +#define MPTCP_SUBFLOW_FLAG_BKUP_REM _BITUL(4) +#define MPTCP_SUBFLOW_FLAG_BKUP_LOC _BITUL(5) +#define MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED _BITUL(6) +#define MPTCP_SUBFLOW_FLAG_CONNECTED _BITUL(7) +#define MPTCP_SUBFLOW_FLAG_MAPVALID _BITUL(8) + +enum { + MPTCP_SUBFLOW_ATTR_UNSPEC, + MPTCP_SUBFLOW_ATTR_TOKEN_REM, + MPTCP_SUBFLOW_ATTR_TOKEN_LOC, + MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ, + MPTCP_SUBFLOW_ATTR_MAP_SEQ, + MPTCP_SUBFLOW_ATTR_MAP_SFSEQ, + MPTCP_SUBFLOW_ATTR_SSN_OFFSET, + MPTCP_SUBFLOW_ATTR_MAP_DATALEN, + MPTCP_SUBFLOW_ATTR_FLAGS, + MPTCP_SUBFLOW_ATTR_ID_REM, + MPTCP_SUBFLOW_ATTR_ID_LOC, + MPTCP_SUBFLOW_ATTR_PAD, + __MPTCP_SUBFLOW_ATTR_MAX +}; + +#define MPTCP_SUBFLOW_ATTR_MAX (__MPTCP_SUBFLOW_ATTR_MAX - 1) + +/* netlink interface */ +#define MPTCP_PM_NAME "mptcp_pm" +#define MPTCP_PM_CMD_GRP_NAME "mptcp_pm_cmds" +#define MPTCP_PM_EV_GRP_NAME "mptcp_pm_events" +#define MPTCP_PM_VER 0x1 + +/* + * ATTR types defined for MPTCP + */ +enum { + MPTCP_PM_ATTR_UNSPEC, + + MPTCP_PM_ATTR_ADDR, /* nested address */ + MPTCP_PM_ATTR_RCV_ADD_ADDRS, /* u32 */ + MPTCP_PM_ATTR_SUBFLOWS, /* u32 */ + + __MPTCP_PM_ATTR_MAX +}; + +#define MPTCP_PM_ATTR_MAX (__MPTCP_PM_ATTR_MAX - 1) + +enum { + MPTCP_PM_ADDR_ATTR_UNSPEC, + + MPTCP_PM_ADDR_ATTR_FAMILY, /* u16 */ + MPTCP_PM_ADDR_ATTR_ID, /* u8 */ + MPTCP_PM_ADDR_ATTR_ADDR4, /* struct in_addr */ + MPTCP_PM_ADDR_ATTR_ADDR6, /* struct in6_addr */ + MPTCP_PM_ADDR_ATTR_PORT, /* u16 */ + MPTCP_PM_ADDR_ATTR_FLAGS, /* u32 */ + MPTCP_PM_ADDR_ATTR_IF_IDX, /* s32 */ + + __MPTCP_PM_ADDR_ATTR_MAX +}; + +#define MPTCP_PM_ADDR_ATTR_MAX (__MPTCP_PM_ADDR_ATTR_MAX - 1) + +#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) +#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) +#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) +#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) +#define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) + +enum { + MPTCP_PM_CMD_UNSPEC, + + MPTCP_PM_CMD_ADD_ADDR, + MPTCP_PM_CMD_DEL_ADDR, + MPTCP_PM_CMD_GET_ADDR, + MPTCP_PM_CMD_FLUSH_ADDRS, + MPTCP_PM_CMD_SET_LIMITS, + MPTCP_PM_CMD_GET_LIMITS, + MPTCP_PM_CMD_SET_FLAGS, + + __MPTCP_PM_CMD_AFTER_LAST +}; + +#define MPTCP_INFO_FLAG_FALLBACK _BITUL(0) +#define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED _BITUL(1) + +struct mptcp_info { + __u8 mptcpi_subflows; + __u8 mptcpi_add_addr_signal; + __u8 mptcpi_add_addr_accepted; + __u8 mptcpi_subflows_max; + __u8 mptcpi_add_addr_signal_max; + __u8 mptcpi_add_addr_accepted_max; + __u32 mptcpi_flags; + __u32 mptcpi_token; + __u64 mptcpi_write_seq; + __u64 mptcpi_snd_una; + __u64 mptcpi_rcv_nxt; + __u8 mptcpi_local_addr_used; + __u8 mptcpi_local_addr_max; + __u8 mptcpi_csum_enabled; +}; + +/* + * MPTCP_EVENT_CREATED: token, family, saddr4 | saddr6, daddr4 | daddr6, + * sport, dport + * A new MPTCP connection has been created. It is the good time to allocate + * memory and send ADD_ADDR if needed. Depending on the traffic-patterns + * it can take a long time until the MPTCP_EVENT_ESTABLISHED is sent. + * + * MPTCP_EVENT_ESTABLISHED: token, family, saddr4 | saddr6, daddr4 | daddr6, + * sport, dport + * A MPTCP connection is established (can start new subflows). + * + * MPTCP_EVENT_CLOSED: token + * A MPTCP connection has stopped. + * + * MPTCP_EVENT_ANNOUNCED: token, rem_id, family, daddr4 | daddr6 [, dport] + * A new address has been announced by the peer. + * + * MPTCP_EVENT_REMOVED: token, rem_id + * An address has been lost by the peer. + * + * MPTCP_EVENT_SUB_ESTABLISHED: token, family, loc_id, rem_id, + * saddr4 | saddr6, daddr4 | daddr6, sport, + * dport, backup, if_idx [, error] + * A new subflow has been established. 'error' should not be set. + * + * MPTCP_EVENT_SUB_CLOSED: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] + * A subflow has been closed. An error (copy of sk_err) could be set if an + * error has been detected for this subflow. + * + * MPTCP_EVENT_SUB_PRIORITY: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] + * The priority of a subflow has changed. 'error' should not be set. + */ +enum mptcp_event_type { + MPTCP_EVENT_UNSPEC = 0, + MPTCP_EVENT_CREATED = 1, + MPTCP_EVENT_ESTABLISHED = 2, + MPTCP_EVENT_CLOSED = 3, + + MPTCP_EVENT_ANNOUNCED = 6, + MPTCP_EVENT_REMOVED = 7, + + MPTCP_EVENT_SUB_ESTABLISHED = 10, + MPTCP_EVENT_SUB_CLOSED = 11, + + MPTCP_EVENT_SUB_PRIORITY = 13, +}; + +enum mptcp_event_attr { + MPTCP_ATTR_UNSPEC = 0, + + MPTCP_ATTR_TOKEN, /* u32 */ + MPTCP_ATTR_FAMILY, /* u16 */ + MPTCP_ATTR_LOC_ID, /* u8 */ + MPTCP_ATTR_REM_ID, /* u8 */ + MPTCP_ATTR_SADDR4, /* be32 */ + MPTCP_ATTR_SADDR6, /* struct in6_addr */ + MPTCP_ATTR_DADDR4, /* be32 */ + MPTCP_ATTR_DADDR6, /* struct in6_addr */ + MPTCP_ATTR_SPORT, /* be16 */ + MPTCP_ATTR_DPORT, /* be16 */ + MPTCP_ATTR_BACKUP, /* u8 */ + MPTCP_ATTR_ERROR, /* u8 */ + MPTCP_ATTR_FLAGS, /* u16 */ + MPTCP_ATTR_TIMEOUT, /* u32 */ + MPTCP_ATTR_IF_IDX, /* s32 */ + MPTCP_ATTR_RESET_REASON,/* u32 */ + MPTCP_ATTR_RESET_FLAGS, /* u32 */ + + __MPTCP_ATTR_AFTER_LAST +}; + +#define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) + +/* MPTCP Reset reason codes, rfc8684 */ +#define MPTCP_RST_EUNSPEC 0 +#define MPTCP_RST_EMPTCP 1 +#define MPTCP_RST_ERESOURCE 2 +#define MPTCP_RST_EPROHIBIT 3 +#define MPTCP_RST_EWQ2BIG 4 +#define MPTCP_RST_EBADPERF 5 +#define MPTCP_RST_EMIDDLEBOX 6 + +struct mptcp_subflow_data { + __u32 size_subflow_data; /* size of this structure in userspace */ + __u32 num_subflows; /* must be 0, set by kernel */ + __u32 size_kernel; /* must be 0, set by kernel */ + __u32 size_user; /* size of one element in data[] */ +} __attribute__((aligned(8))); + +struct mptcp_subflow_addrs { + union { + __kernel_sa_family_t sa_family; + struct sockaddr sa_local; + struct sockaddr_in sin_local; + struct sockaddr_in6 sin6_local; + struct __kernel_sockaddr_storage ss_local; + }; + union { + struct sockaddr sa_remote; + struct sockaddr_in sin_remote; + struct sockaddr_in6 sin6_remote; + struct __kernel_sockaddr_storage ss_remote; + }; +}; + +/* MPTCP socket options */ +#define MPTCP_INFO 1 +#define MPTCP_TCPINFO 2 +#define MPTCP_SUBFLOW_ADDRS 3 + +#endif /* _MPTCP_H */ |