diff options
author | Thomas Haller <thaller@redhat.com> | 2022-07-13 16:24:05 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-07-20 10:25:47 +0200 |
commit | 1a0c8772b0d9bfce14e8f1bd8d290d00d824dbb5 (patch) | |
tree | 54f0c9180ffc1865624fc1ad7f474f18585d1c73 | |
parent | be4b775585a7cddf0a35edacbe04be591dfde4e9 (diff) | |
download | NetworkManager-1a0c8772b0d9bfce14e8f1bd8d290d00d824dbb5.tar.gz |
platform: add NMPlatformMptcpAddr object
An NMPObject is hashable, can be compared and printed. That is useful.
Make an NMPObject for MPTCP addresses. It will hold the content of
MPTCP_PM_ATTR_ADDR netlink attribute. But like other NMPObject types it
will also be used to represent the data as NetworkManager tracks it.
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 9 | ||||
-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 | 54 | ||||
-rw-r--r-- | src/libnm-platform/nmp-object.h | 11 |
6 files changed, 195 insertions, 4 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 3c873c9ea7..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. */ 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 d281cc7be0..eb5306a66d 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -381,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); @@ -1551,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) { @@ -1636,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) { @@ -1744,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) { @@ -2089,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); @@ -2123,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))); @@ -3463,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) |