summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-07-20 10:40:16 +0200
committerThomas Haller <thaller@redhat.com>2022-07-20 10:40:16 +0200
commit571f3c57bdf97200726f1b0326406cc6dc73040a (patch)
tree54f0c9180ffc1865624fc1ad7f474f18585d1c73
parent93372e81001baa2278cee1c83115b55f077033a6 (diff)
parent1a0c8772b0d9bfce14e8f1bd8d290d00d824dbb5 (diff)
downloadNetworkManager-571f3c57bdf97200726f1b0326406cc6dc73040a.tar.gz
platform: merge branch 'th/platform-genl-4'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1304
-rw-r--r--Makefile.am3
-rw-r--r--src/libnm-glib-aux/nm-hash-utils.h2
-rw-r--r--src/libnm-platform/nm-linux-platform.c21
-rw-r--r--src/libnm-platform/nm-netlink.c1
-rw-r--r--src/libnm-platform/nm-netlink.h1
-rw-r--r--src/libnm-platform/nm-platform.c87
-rw-r--r--src/libnm-platform/nm-platform.h36
-rw-r--r--src/libnm-platform/nmp-base.h2
-rw-r--r--src/libnm-platform/nmp-object.c147
-rw-r--r--src/libnm-platform/nmp-object.h11
-rw-r--r--src/libnm-std-aux/nm-std-aux.h13
-rw-r--r--src/linux-headers/mptcp.h232
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 */