summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-07-14 22:19:47 +0200
committerThomas Haller <thaller@redhat.com>2022-08-09 08:02:50 +0200
commitce635c4339125a30cb470fee222e73c2125ecfd7 (patch)
tree9894cdea1210eef6168d302b3cf941f7cafd544f
parentec64559caab3057d32a38e1ec7ed813764be10b4 (diff)
downloadNetworkManager-ce635c4339125a30cb470fee222e73c2125ecfd7.tar.gz
platform: add dump/update function for MPTCP addresses
Since the generic netlink API does (currently) not support notifications about changes of the MPTCP addresses, we won't get notifications when they change, and it seems wrong to put such things in the NMPlatform cache. We can just get the list of endpoints by polling, so add a function nm_platform_mptcp_addrs_dump() for that. Also, add nm_platform_mptcp_addr_update() which can add/remove/update MPTCP addresses.
-rw-r--r--src/core/platform/tests/monitor.c15
-rw-r--r--src/libnm-platform/nm-linux-platform.c300
-rw-r--r--src/libnm-platform/nm-platform.c59
-rw-r--r--src/libnm-platform/nm-platform.h9
-rw-r--r--src/libnm-platform/nmp-object.c2
5 files changed, 366 insertions, 19 deletions
diff --git a/src/core/platform/tests/monitor.c b/src/core/platform/tests/monitor.c
index 1a71e6335d..8d0e01074a 100644
--- a/src/core/platform/tests/monitor.c
+++ b/src/core/platform/tests/monitor.c
@@ -9,6 +9,7 @@
#include <syslog.h>
#include "libnm-platform/nm-linux-platform.h"
+#include "libnm-platform/nmp-object.h"
#include "nm-test-utils-core.h"
@@ -50,6 +51,18 @@ read_argv(int *argc, char ***argv)
return TRUE;
}
+/*****************************************************************************/
+
+static void
+mptcp_addr_dump(NMPlatform *platform)
+{
+ gs_unref_ptrarray GPtrArray *addrs = NULL;
+
+ addrs = nm_platform_mptcp_addrs_dump(platform);
+}
+
+/*****************************************************************************/
+
int
main(int argc, char **argv)
{
@@ -69,6 +82,8 @@ main(int argc, char **argv)
nm_linux_platform_setup();
+ mptcp_addr_dump(NM_PLATFORM_GET);
+
if (global_opt.persist)
g_main_loop_run(loop);
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index fc3ca60aeb..cd685fe20e 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -9334,6 +9334,9 @@ object_delete(NMPlatform *platform, const NMPObject *obj)
case NMP_OBJECT_TYPE_TFILTER:
nlmsg = _nl_msg_new_tfilter(RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER(obj));
break;
+ case NMP_OBJECT_TYPE_MPTCP_ADDR:
+ return (nm_platform_mptcp_addr_update(platform, FALSE, NMP_OBJECT_CAST_MPTCP_ADDR(obj))
+ >= 0);
default:
break;
}
@@ -10101,6 +10104,301 @@ out:
/*****************************************************************************/
+static const NMPObject *
+_mptcp_addrs_dump_parse_addr(struct nlattr *attr)
+{
+ static const struct nla_policy policy[] = {
+ [MPTCP_PM_ADDR_ATTR_FAMILY] = {.type = NLA_U16},
+ [MPTCP_PM_ADDR_ATTR_ID] = {.type = NLA_U8},
+ [MPTCP_PM_ADDR_ATTR_ADDR4] = {.minlen = sizeof(in_addr_t)},
+ [MPTCP_PM_ADDR_ATTR_ADDR6] = {.minlen = sizeof(struct in6_addr)},
+ [MPTCP_PM_ADDR_ATTR_PORT] = {.type = NLA_U16},
+ [MPTCP_PM_ADDR_ATTR_FLAGS] = {.type = NLA_U32},
+ [MPTCP_PM_ADDR_ATTR_IF_IDX] = {.type = NLA_S32},
+ };
+ struct nlattr *tb[G_N_ELEMENTS(policy)];
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPlatformMptcpAddr *mptcp_addr;
+ int addr_family;
+ int addr_attr;
+
+ if (nla_parse_nested_arr(tb, attr, policy) < 0)
+ return NULL;
+
+ if (!tb[MPTCP_PM_ADDR_ATTR_ID])
+ return NULL;
+
+ obj = nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, NULL);
+ mptcp_addr = &obj->mptcp_addr;
+
+ mptcp_addr->id = nla_get_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
+
+ if (!tb[MPTCP_PM_ADDR_ATTR_FAMILY]) {
+ /* If we don't have the family. Only create a stub object containing
+ * the ID. */
+ goto out;
+ }
+
+ addr_family = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
+
+ if (addr_family == AF_INET)
+ addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4;
+ else if (addr_family == AF_INET6)
+ addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6;
+ else
+ goto out;
+
+ if (!tb[addr_attr])
+ goto out;
+
+ mptcp_addr->addr_family = addr_family;
+ memcpy(&mptcp_addr->addr, nla_data(tb[addr_attr]), nm_utils_addr_family_to_size(addr_family));
+
+ if (tb[MPTCP_PM_ADDR_ATTR_PORT])
+ mptcp_addr->port = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]);
+
+ if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX])
+ mptcp_addr->ifindex = nla_get_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
+
+ if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
+ mptcp_addr->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
+
+out:
+
+ return g_steal_pointer(&obj);
+}
+
+typedef struct {
+ GPtrArray *addrs;
+} FetchMptcpAddrParseData;
+
+static int
+_mptcp_addrs_dump_parse_cb(const struct nl_msg *msg, void *arg)
+{
+ static const struct nla_policy policy[] = {
+ [MPTCP_PM_ATTR_ADDR] = {.type = NLA_NESTED},
+ };
+ struct nlattr *tb[G_N_ELEMENTS(policy)];
+ FetchMptcpAddrParseData *parse_data = arg;
+
+ if (genlmsg_parse_arr(nlmsg_hdr(msg), 0, tb, policy) < 0)
+ return NL_SKIP;
+
+ if (tb[MPTCP_PM_ATTR_ADDR]) {
+ const NMPObject *obj;
+
+ obj = _mptcp_addrs_dump_parse_addr(tb[MPTCP_PM_ATTR_ADDR]);
+ if (obj)
+ g_ptr_array_add(parse_data->addrs, (gpointer) obj);
+ }
+
+ return NL_OK;
+}
+
+#define EXTACK_MSG_BUFSIZE 200
+
+static int
+_mptcp_addr_update_err_cb(const struct sockaddr_nl *nla, const struct nlmsgerr *nlerr, void *arg)
+{
+ char *out_extack_msg = arg;
+ const char *extack_msg;
+ int errsv;
+
+ errsv = nlmsg_parse_error(nlmsg_undata(nlerr), &extack_msg);
+ if (extack_msg)
+ g_strlcpy(out_extack_msg, extack_msg, EXTACK_MSG_BUFSIZE);
+ return errsv;
+}
+
+static int
+mptcp_addr_update(NMPlatform *platform, NMOptionBool add, const NMPlatformMptcpAddr *addr)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *nla_nest;
+ char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
+ guint16 genl_family_id;
+ guint8 cmd_num;
+ const char *cmd_str;
+ int nle;
+ char extack_msg[EXTACK_MSG_BUFSIZE];
+ const struct nl_cb cb = {
+ .err_cb = _mptcp_addr_update_err_cb,
+ .err_arg = extack_msg,
+ };
+
+ extack_msg[0] = '\0';
+
+ if (add == NM_OPTION_BOOL_DEFAULT) {
+ cmd_num = MPTCP_PM_CMD_SET_FLAGS;
+ cmd_str = "update";
+ } else if (add) {
+ cmd_num = MPTCP_PM_CMD_ADD_ADDR;
+ cmd_str = "add";
+ } else {
+ cmd_num = MPTCP_PM_CMD_DEL_ADDR;
+ cmd_str = "delete";
+ }
+
+ nm_assert_addr_family_or_unspec(addr->addr_family);
+ nm_assert(cmd_num != MPTCP_PM_CMD_ADD_ADDR
+ || (addr->port == 0 && addr->addr_family != AF_UNSPEC));
+ nm_assert(cmd_num != MPTCP_PM_CMD_SET_FLAGS || (addr->id != 0 && addr->port == 0));
+ nm_assert(cmd_num != MPTCP_PM_CMD_DEL_ADDR || addr->id != 0);
+
+ genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM);
+ if (genl_family_id == 0) {
+ _LOGT("mptcp: %s address %s fails because %s generic netlink family is unknown",
+ cmd_str,
+ nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
+ nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name);
+ return -ENOSYS;
+ }
+
+ _LOGT("mptcp: %s address %s",
+ cmd_str,
+ nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)));
+
+ nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN) + 200);
+
+ if (!genlmsg_put(nlmsg,
+ NL_AUTO_PORT,
+ NL_AUTO_SEQ,
+ genl_family_id,
+ 0,
+ NLM_F_REQUEST,
+ cmd_num,
+ MPTCP_PM_VER))
+ goto nla_put_failure;
+
+ nla_nest = nla_nest_start(nlmsg, MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
+ if (!nla_nest)
+ goto nla_put_failure;
+
+ if (addr->id != 0)
+ NLA_PUT_U8(nlmsg, MPTCP_PM_ADDR_ATTR_ID, addr->id);
+ if (addr->flags != 0)
+ NLA_PUT_U32(nlmsg, MPTCP_PM_ADDR_ATTR_FLAGS, addr->flags);
+ if (addr->ifindex != 0)
+ NLA_PUT_S32(nlmsg, MPTCP_PM_ADDR_ATTR_IF_IDX, addr->ifindex);
+ if (addr->port != 0)
+ NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_PORT, addr->port);
+ if (addr->addr_family != AF_UNSPEC) {
+ int addr_attr;
+
+ NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_FAMILY, addr->addr_family);
+ if (addr->addr_family == AF_INET)
+ addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4;
+ else if (addr->addr_family == AF_INET6)
+ addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6;
+ else
+ g_return_val_if_reached(-NME_BUG);
+ NLA_PUT(nlmsg, addr_attr, nm_utils_addr_family_to_size(addr->addr_family), &addr->addr);
+ }
+
+ NLA_NEST_END(nlmsg, nla_nest);
+
+ nle = nl_send_auto(priv->sk_genl_sync, nlmsg);
+ if (nle < 0) {
+ _LOGT("mptcp: %s address %s: failed sending request: %s (%d)",
+ cmd_str,
+ nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
+ nm_strerror(nle),
+ nle);
+ return nle;
+ }
+
+ do {
+ nle = nl_recvmsgs(priv->sk_genl_sync, &cb);
+ } while (nle == -EAGAIN);
+
+ if (nle < 0) {
+ _LOGT("mptcp: %s address %s: failed: %s (%d)%s%s%s",
+ cmd_str,
+ nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
+ nm_strerror(nle),
+ nle,
+ NM_PRINT_FMT_QUOTED(extack_msg[0] != '\0', " \"", extack_msg, "\"", ""));
+ return nle;
+ }
+
+ _LOGT("mptcp: %s address %s: success",
+ cmd_str,
+ nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)));
+
+ return 0;
+
+nla_put_failure:
+ g_return_val_if_reached(-NME_BUG);
+}
+
+static GPtrArray *
+mptcp_addrs_dump(NMPlatform *platform)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+ gs_unref_ptrarray GPtrArray *addrs = NULL;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ FetchMptcpAddrParseData parse_data;
+ guint16 genl_family_id;
+ int r;
+ guint i;
+
+ genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM);
+ if (genl_family_id == 0) {
+ _LOGT("mptcp: dump addresses fails because %s generic netlink family is unknown",
+ nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name);
+ return NULL;
+ }
+
+ nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN));
+
+ if (!genlmsg_put(nlmsg,
+ NL_AUTO_PORT,
+ NL_AUTO_SEQ,
+ genl_family_id,
+ 0,
+ NLM_F_REQUEST | NLM_F_DUMP,
+ MPTCP_PM_CMD_GET_ADDR,
+ MPTCP_PM_VER))
+ g_return_val_if_reached(NULL);
+
+ r = nl_send_auto(priv->sk_genl_sync, nlmsg);
+ if (r < 0) {
+ _LOGT("mptcp: dump addresses failed to send dump request: %s", nm_strerror(r));
+ return NULL;
+ }
+
+ addrs = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
+
+ parse_data = (FetchMptcpAddrParseData){
+ .addrs = addrs,
+ };
+
+ nl_recvmsgs(priv->sk_genl_sync,
+ &((const struct nl_cb){
+ .valid_cb = _mptcp_addrs_dump_parse_cb,
+ .valid_arg = (gpointer) &parse_data,
+ }));
+
+ if (_LOGT_ENABLED()) {
+ _LOGT("mptcp: %u addresses dumped", addrs->len);
+ for (i = 0; i < addrs->len; i++) {
+ char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
+
+ _LOGT("mptcp: address[%04d]: %s",
+ i,
+ nmp_object_to_string(addrs->pdata[i],
+ NMP_OBJECT_TO_STRING_PUBLIC,
+ sbuf,
+ sizeof(sbuf)));
+ }
+ }
+
+ return g_steal_pointer(&addrs);
+}
+
+/*****************************************************************************/
+
static void
cache_update_link_udev(NMPlatform *platform, int ifindex, struct udev_device *udevice)
{
@@ -10589,4 +10887,6 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass)
platform_class->process_events = process_events;
platform_class->genl_get_family_id = genl_get_family_id;
+ platform_class->mptcp_addr_update = mptcp_addr_update;
+ platform_class->mptcp_addrs_dump = mptcp_addrs_dump;
}
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index e6cba638b4..ab9664d2ee 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -7,6 +7,8 @@
#include "nm-platform.h"
+#include "libnm-std-aux/nm-linux-compat.h"
+
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
@@ -402,7 +404,7 @@ const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM] = {
},
[NMP_GENL_FAMILY_TYPE_MPTCP_PM] =
{
- .name = "mptcp_pm",
+ .name = MPTCP_PM_NAME,
},
[NMP_GENL_FAMILY_TYPE_NL80211] =
{
@@ -5320,23 +5322,26 @@ nm_platform_object_delete(NMPlatform *self, const NMPObject *obj)
_CHECK_SELF(self, klass, FALSE);
- switch (NMP_OBJECT_GET_TYPE(obj)) {
- case NMP_OBJECT_TYPE_ROUTING_RULE:
- _LOGD("%s: delete %s",
- NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
- nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
- break;
- case NMP_OBJECT_TYPE_IP4_ROUTE:
- case NMP_OBJECT_TYPE_IP6_ROUTE:
- case NMP_OBJECT_TYPE_QDISC:
- case NMP_OBJECT_TYPE_TFILTER:
- ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex;
- _LOG3D("%s: delete %s",
- NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
- nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
- break;
- default:
- g_return_val_if_reached(FALSE);
+ if (_LOGD_ENABLED()) {
+ switch (NMP_OBJECT_GET_TYPE(obj)) {
+ case NMP_OBJECT_TYPE_ROUTING_RULE:
+ case NMP_OBJECT_TYPE_MPTCP_ADDR:
+ _LOGD("%s: delete %s",
+ NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
+ nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ case NMP_OBJECT_TYPE_QDISC:
+ case NMP_OBJECT_TYPE_TFILTER:
+ ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex;
+ _LOG3D("%s: delete %s",
+ NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
+ nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
+ break;
+ default:
+ g_return_val_if_reached(FALSE);
+ }
}
return klass->object_delete(self, obj);
@@ -9393,6 +9398,24 @@ nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type)
/*****************************************************************************/
+int
+nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr)
+{
+ _CHECK_SELF(self, klass, -NME_BUG);
+
+ return klass->mptcp_addr_update(self, add, addr);
+}
+
+GPtrArray *
+nm_platform_mptcp_addrs_dump(NMPlatform *self)
+{
+ _CHECK_SELF(self, klass, NULL);
+
+ return klass->mptcp_addrs_dump(self);
+}
+
+/*****************************************************************************/
+
GHashTable *
nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex)
{
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index a4aebee573..90ffbed02e 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -1394,6 +1394,10 @@ typedef struct {
guint16 (*genl_get_family_id)(NMPlatform *platform, NMPGenlFamilyType family_type);
+ int (*mptcp_addr_update)(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr);
+
+ GPtrArray *(*mptcp_addrs_dump)(NMPlatform *self);
+
} NMPlatformClass;
/* NMPlatform signals
@@ -2668,4 +2672,9 @@ gboolean nm_platform_ip_address_match(int addr_family,
guint16 nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type);
+int
+nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr);
+
+GPtrArray *nm_platform_mptcp_addrs_dump(NMPlatform *self);
+
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 67f508ef14..d06aa9cdf3 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -1785,7 +1785,7 @@ _vt_cmd_obj_is_alive_tfilter(const NMPObject *obj)
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);
+ return NM_IN_SET(obj->mptcp_addr.addr_family, AF_INET, AF_INET6, AF_UNSPEC);
}
gboolean