]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
mptcp: add support for event monitoring
authorFlorian Westphal <fw@strlen.de>
Fri, 16 Apr 2021 13:59:30 +0000 (15:59 +0200)
committerDavid Ahern <dsahern@kernel.org>
Thu, 22 Apr 2021 05:10:25 +0000 (05:10 +0000)
This adds iproute2 support for mptcp event monitoring, e.g. creation,
establishment, address announcements from the peer, subflow establishment
and so on.

While the kernel-generated events are primarily aimed at mptcpd (e.g. for
subflow management), this is also useful for debugging.

This adds print support for the existing events.

Sample output of 'ip mptcp monitor':
[       CREATED] token=83f3a692 remid=0 locid=0 saddr4=10.0.1.2 daddr4=10.0.1.1 sport=58710 dport=10011
[   ESTABLISHED] token=83f3a692 remid=0 locid=0 saddr4=10.0.1.2 daddr4=10.0.1.1 sport=58710 dport=10011
[SF_ESTABLISHED] token=83f3a692 remid=0 locid=1 saddr4=10.0.2.2 daddr4=10.0.1.1 sport=40195 dport=10011 backup=0
[        CLOSED] token=83f3a692

Signed-off-by: Florian Westphal <fw@strlen.de>
include/libgenl.h
ip/ipmptcp.c
lib/libgenl.c
man/man8/ip-mptcp.8

index 656493a2c3c41fb43bf1996c1a9f30338eccdead..97281cc1103f747087c81e4c295afe057e2c7266 100644 (file)
@@ -21,6 +21,7 @@ struct {                                                              \
        },                                                              \
 }
 
+int genl_add_mcast_grp(struct rtnl_handle *grth, __u16 genl_family, const char *group);
 int genl_resolve_family(struct rtnl_handle *grth, const char *family);
 int genl_init_handle(struct rtnl_handle *grth, const char *family,
                     int *genl_family);
index 5f659b598c900e8279df7b07e44a1a1a4bd6eae6..5f490f0026d9664ada7e376a59a3b0f70891b7b9 100644 (file)
@@ -23,6 +23,7 @@ static void usage(void)
                "       ip mptcp endpoint flush\n"
                "       ip mptcp limits set [ subflows NR ] [ add_addr_accepted NR ]\n"
                "       ip mptcp limits show\n"
+               "       ip mptcp monitor\n"
                "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
                "FLAG  := [ signal | subflow | backup ]\n");
 
@@ -397,6 +398,110 @@ static int mptcp_limit_get_set(int argc, char **argv, int cmd)
        return 0;
 }
 
+static const char * const event_to_str[] = {
+       [MPTCP_EVENT_CREATED] = "CREATED",
+       [MPTCP_EVENT_ESTABLISHED] = "ESTABLISHED",
+       [MPTCP_EVENT_CLOSED] = "CLOSED",
+       [MPTCP_EVENT_ANNOUNCED] = "ANNOUNCED",
+       [MPTCP_EVENT_REMOVED] = "REMOVED",
+       [MPTCP_EVENT_SUB_ESTABLISHED] = "SF_ESTABLISHED",
+       [MPTCP_EVENT_SUB_CLOSED] = "SF_CLOSED",
+       [MPTCP_EVENT_SUB_PRIORITY] = "SF_PRIO",
+};
+
+static void print_addr(const char *key, int af, struct rtattr *value)
+{
+       void *data = RTA_DATA(value);
+       char str[INET6_ADDRSTRLEN];
+
+       if (inet_ntop(af, data, str, sizeof(str)))
+               printf(" %s=%s", key, str);
+}
+
+static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl,
+                            struct nlmsghdr *n, void *arg)
+{
+       const struct genlmsghdr *ghdr = NLMSG_DATA(n);
+       struct rtattr *tb[MPTCP_ATTR_MAX + 1];
+       int len = n->nlmsg_len;
+
+       len -= NLMSG_LENGTH(GENL_HDRLEN);
+       if (len < 0)
+               return -1;
+
+       if (n->nlmsg_type != genl_family)
+               return 0;
+
+       if (timestamp)
+               print_timestamp(stdout);
+
+       if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) {
+               printf("[UNKNOWN %u]\n", ghdr->cmd);
+               goto out;
+       }
+
+       if (event_to_str[ghdr->cmd] == NULL) {
+               printf("[UNKNOWN %u]\n", ghdr->cmd);
+               goto out;
+       }
+
+       printf("[%14s]", event_to_str[ghdr->cmd]);
+
+       parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
+
+       printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN]));
+
+       if (tb[MPTCP_ATTR_REM_ID])
+               printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID]));
+       if (tb[MPTCP_ATTR_LOC_ID])
+               printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID]));
+
+       if (tb[MPTCP_ATTR_SADDR4])
+               print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]);
+       if (tb[MPTCP_ATTR_DADDR4])
+               print_addr("daddr4", AF_INET, tb[MPTCP_ATTR_DADDR4]);
+       if (tb[MPTCP_ATTR_SADDR6])
+               print_addr("saddr6", AF_INET6, tb[MPTCP_ATTR_SADDR6]);
+       if (tb[MPTCP_ATTR_DADDR6])
+               print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]);
+       if (tb[MPTCP_ATTR_SPORT])
+               printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT]));
+       if (tb[MPTCP_ATTR_DPORT])
+               printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT]));
+       if (tb[MPTCP_ATTR_BACKUP])
+               printf(" backup=%d", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP]));
+       if (tb[MPTCP_ATTR_ERROR])
+               printf(" error=%d", rta_getattr_u8(tb[MPTCP_ATTR_ERROR]));
+       if (tb[MPTCP_ATTR_FLAGS])
+               printf(" flags=%x", rta_getattr_u16(tb[MPTCP_ATTR_FLAGS]));
+       if (tb[MPTCP_ATTR_TIMEOUT])
+               printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT]));
+       if (tb[MPTCP_ATTR_IF_IDX])
+               printf(" ifindex=%d", rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX]));
+       if (tb[MPTCP_ATTR_RESET_REASON])
+               printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON]));
+       if (tb[MPTCP_ATTR_RESET_FLAGS])
+               printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS]));
+
+       puts("");
+out:
+       fflush(stdout);
+       return 0;
+}
+
+static int mptcp_monitor(void)
+{
+       if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) {
+               perror("can't subscribe to mptcp events");
+               return 1;
+       }
+
+       if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0)
+               return 2;
+
+       return 0;
+}
+
 int do_mptcp(int argc, char **argv)
 {
        if (argc == 0)
@@ -441,6 +546,14 @@ int do_mptcp(int argc, char **argv)
                                                   MPTCP_PM_CMD_GET_LIMITS);
        }
 
+       if (matches(*argv, "monitor") == 0) {
+               NEXT_ARG_FWD();
+               if (argc == 0)
+                       return mptcp_monitor();
+
+               goto unknown;
+       }
+
 unknown:
        fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n",
                *argv);
index f2ce698fc71169a808a40e5d3651b06a2ae7b978..4c51d47af46b09a37577c13b762a0054c2e53606 100644 (file)
@@ -67,6 +67,72 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family)
        return fnum;
 }
 
+static int genl_parse_grps(struct rtattr *attr, const char *name, unsigned int *id)
+{
+       const struct rtattr *pos;
+
+       rtattr_for_each_nested(pos, attr) {
+               struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
+
+               parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, pos);
+
+               if (tb[CTRL_ATTR_MCAST_GRP_NAME] && tb[CTRL_ATTR_MCAST_GRP_ID]) {
+                       if (strcmp(name, rta_getattr_str(tb[CTRL_ATTR_MCAST_GRP_NAME])) == 0) {
+                               *id = rta_getattr_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+                               return 0;
+                       }
+               }
+       }
+
+       return -1;
+}
+
+int genl_add_mcast_grp(struct rtnl_handle *grth, __u16 fnum, const char *group)
+{
+       GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY,
+                    NLM_F_REQUEST);
+       struct rtattr *tb[CTRL_ATTR_MAX + 1];
+       struct nlmsghdr *answer = NULL;
+       struct genlmsghdr *ghdr;
+       struct rtattr *attrs;
+       int len, ret = -1;
+       unsigned int id;
+
+       addattr16(&req.n, sizeof(req), CTRL_ATTR_FAMILY_ID, fnum);
+
+       if (rtnl_talk(grth, &req.n, &answer) < 0) {
+               fprintf(stderr, "Error talking to the kernel\n");
+               return -2;
+       }
+
+       ghdr = NLMSG_DATA(answer);
+       len = answer->nlmsg_len;
+
+       if (answer->nlmsg_type != GENL_ID_CTRL)
+               goto err_free;
+
+       len -= NLMSG_LENGTH(GENL_HDRLEN);
+       if (len < 0)
+               goto err_free;
+
+       attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+       parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+       if (tb[CTRL_ATTR_MCAST_GROUPS] == NULL) {
+               fprintf(stderr, "Missing mcast groups TLV\n");
+               goto err_free;
+       }
+
+       if (genl_parse_grps(tb[CTRL_ATTR_MCAST_GROUPS], group, &id) < 0)
+               goto err_free;
+
+       ret = rtnl_add_nl_group(grth, id);
+
+err_free:
+       free(answer);
+       return ret;
+}
+
 int genl_init_handle(struct rtnl_handle *grth, const char *family,
                     int *genl_family)
 {
index 98cb93b9c595a4ee0d9e56228e8fb178acc0e230..22335b6129ae13795e4c295763ed68d522f829f4 100644 (file)
@@ -67,6 +67,9 @@ ip-mptcp \- MPTCP path manager configuration
 .ti -8
 .BR "ip mptcp limits show"
 
+.ti -8
+.BR "ip mptcp monitor"
+
 .SH DESCRIPTION
 
 MPTCP is a transport protocol built on top of TCP that allows TCP
@@ -145,5 +148,10 @@ each accepted ADD_ADDR option, respecting the
 .IR SUBFLOW_NR
 limit.
 
+.sp
+.PP
+.B monitor
+displays creation and deletion of MPTCP connections as well as addition or removal of remote addresses and subflows.
+
 .SH AUTHOR
 Original Manpage by Paolo Abeni <pabeni@redhat.com>