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.
This commit is contained in:
Thomas Haller 2022-07-13 16:24:05 +02:00
parent be4b775585
commit 1a0c8772b0
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
6 changed files with 195 additions and 4 deletions

View file

@ -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. */

View file

@ -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)
{

View file

@ -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);

View file

@ -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;

View file

@ -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,
},
};

View file

@ -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)