From: Paolo Abeni Date: Fri, 10 Jul 2020 13:52:35 +0000 (+0200) Subject: ss: mptcp: add msk diag interface support X-Git-Url: https://git.proxmox.com/?p=mirror_iproute2.git;a=commitdiff_plain;h=9c3be2c0eee01be7832b7900a8be798a19c659a5 ss: mptcp: add msk diag interface support This implement support for MPTCP sockets type, comprising extended socket info. Note that we need to add an extended attribute carrying the actual protocol number to the diag request. Signed-off-by: Paolo Abeni Signed-off-by: David Ahern --- diff --git a/misc/ss.c b/misc/ss.c index f3d01812..f0dd129e 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -63,6 +63,10 @@ #define AF_VSOCK PF_VSOCK #endif +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + #define BUF_CHUNK (1024 * 1024) /* Buffer chunk allocation size */ #define BUF_CHUNKS_MAX 5 /* Maximum number of allocated buffer chunks */ #define LEN_ALIGN(x) (((x) + 1) & ~1) @@ -189,6 +193,7 @@ static const char *dg_proto; enum { TCP_DB, + MPTCP_DB, DCCP_DB, UDP_DB, RAW_DB, @@ -209,7 +214,7 @@ enum { #define PACKET_DBM ((1<mptcpi_subflows) + out(" subflows:%d", s->mptcpi_subflows); + if (s->mptcpi_add_addr_signal) + out(" add_addr_signal:%d", s->mptcpi_add_addr_signal); + if (s->mptcpi_add_addr_signal) + out(" add_addr_accepted:%d", s->mptcpi_add_addr_accepted); + if (s->mptcpi_subflows_max) + out(" subflows_max:%d", s->mptcpi_subflows_max); + if (s->mptcpi_add_addr_signal_max) + out(" add_addr_signal_max:%d", s->mptcpi_add_addr_signal_max); + if (s->mptcpi_add_addr_accepted_max) + out(" add_addr_accepted_max:%d", s->mptcpi_add_addr_accepted_max); + if (s->mptcpi_flags & MPTCP_INFO_FLAG_FALLBACK) + out(" fallback"); + if (s->mptcpi_flags & MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED) + out(" remote_key"); + if (s->mptcpi_token) + out(" token:%x", s->mptcpi_token); + if (s->mptcpi_write_seq) + out(" write_seq:%llx", s->mptcpi_write_seq); + if (s->mptcpi_snd_una) + out(" snd_una:%llx", s->mptcpi_snd_una); + if (s->mptcpi_rcv_nxt) + out(" rcv_nxt:%llx", s->mptcpi_rcv_nxt); +} + +static void mptcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, + struct rtattr *tb[]) +{ + print_skmeminfo(tb, INET_DIAG_SKMEMINFO); + + if (tb[INET_DIAG_INFO]) { + struct mptcp_info *info; + int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]); + + /* workaround for older kernels with less fields */ + if (len < sizeof(*info)) { + info = alloca(sizeof(*info)); + memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len); + memset((char *)info + len, 0, sizeof(*info) - len); + } else + info = RTA_DATA(tb[INET_DIAG_INFO]); + + mptcp_stats_print(info); + } +} + static const char *format_host_sa(struct sockaddr_storage *sa) { union { @@ -3277,6 +3338,8 @@ static int inet_show_sock(struct nlmsghdr *nlh, out("\n\t"); if (s->type == IPPROTO_SCTP) sctp_show_info(nlh, r, tb); + else if (s->type == IPPROTO_MPTCP) + mptcp_show_info(nlh, r, tb); else tcp_show_info(nlh, r, tb); } @@ -3365,9 +3428,11 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) DIAG_REQUEST(req, struct inet_diag_req_v2 r); char *bc = NULL; int bclen; + __u32 proto; struct msghdr msg; - struct rtattr rta; - struct iovec iov[3]; + struct rtattr rta_bc; + struct rtattr rta_proto; + struct iovec iov[5]; int iovlen = 1; if (family == PF_UNSPEC) @@ -3400,15 +3465,26 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) if (f->f) { bclen = ssfilter_bytecompile(f->f, &bc); if (bclen) { - rta.rta_type = INET_DIAG_REQ_BYTECODE; - rta.rta_len = RTA_LENGTH(bclen); - iov[1] = (struct iovec){ &rta, sizeof(rta) }; + rta_bc.rta_type = INET_DIAG_REQ_BYTECODE; + rta_bc.rta_len = RTA_LENGTH(bclen); + iov[1] = (struct iovec){ &rta_bc, sizeof(rta_bc) }; iov[2] = (struct iovec){ bc, bclen }; req.nlh.nlmsg_len += RTA_LENGTH(bclen); iovlen = 3; } } + /* put extended protocol attribute, if required */ + if (protocol > 255) { + rta_proto.rta_type = INET_DIAG_REQ_PROTOCOL; + rta_proto.rta_len = RTA_LENGTH(sizeof(proto)); + proto = protocol; + iov[iovlen] = (struct iovec){ &rta_proto, sizeof(rta_proto) }; + iov[iovlen + 1] = (struct iovec){ &proto, sizeof(proto) }; + req.nlh.nlmsg_len += RTA_LENGTH(sizeof(proto)); + iovlen += 2; + } + msg = (struct msghdr) { .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), @@ -3668,6 +3744,18 @@ outerr: } while (0); } +static int mptcp_show(struct filter *f) +{ + if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6)) + return 0; + + if (!getenv("PROC_NET_MPTCP") && !getenv("PROC_ROOT") + && inet_show_netlink(f, NULL, IPPROTO_MPTCP) == 0) + return 0; + + return 0; +} + static int dccp_show(struct filter *f) { if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6)) @@ -5108,6 +5196,7 @@ static void _usage(FILE *dest) " -6, --ipv6 display only IP version 6 sockets\n" " -0, --packet display PACKET sockets\n" " -t, --tcp display only TCP sockets\n" +" -M, --mptcp display only MPTCP sockets\n" " -S, --sctp display only SCTP sockets\n" " -u, --udp display only UDP sockets\n" " -d, --dccp display only DCCP sockets\n" @@ -5123,7 +5212,7 @@ static void _usage(FILE *dest) " -O, --oneline socket's data printed on a single line\n" "\n" " -A, --query=QUERY, --socket=QUERY\n" -" QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink|vsock_stream|vsock_dgram|tipc}[,QUERY]\n" +" QUERY := {all|inet|tcp|mptcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink|vsock_stream|vsock_dgram|tipc}[,QUERY]\n" "\n" " -D, --diag=FILE Dump raw information about TCP sockets to FILE\n" " -F, --filter=FILE read filter information from FILE\n" @@ -5250,6 +5339,7 @@ static const struct option long_opts[] = { { "kill", 0, 0, 'K' }, { "no-header", 0, 0, 'H' }, { "xdp", 0, 0, OPT_XDPSOCK}, + { "mptcp", 0, 0, 'M' }, { "oneline", 0, 0, 'O' }, { 0 } @@ -5266,7 +5356,7 @@ int main(int argc, char *argv[]) int state_filter = 0; while ((ch = getopt_long(argc, argv, - "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHSO", + "dhaletuwxnro460spbEf:mMiA:D:F:vVzZN:KHSO", long_opts, NULL)) != EOF) { switch (ch) { case 'n': @@ -5341,6 +5431,9 @@ int main(int argc, char *argv[]) case OPT_XDPSOCK: filter_af_set(¤t_filter, AF_XDP); break; + case 'M': + filter_db_set(¤t_filter, MPTCP_DB, true); + break; case 'f': if (strcmp(optarg, "inet") == 0) filter_af_set(¤t_filter, AF_INET); @@ -5566,6 +5659,8 @@ int main(int argc, char *argv[]) tipc_show(¤t_filter); if (current_filter.dbs & (1<