Skip to content

Commit 03ca56b

Browse files
Gang Yanintel-lab-lkp
Gang Yan
authored andcommitted
selftests: mptcp: add helpers to get subflow_info
This patch adds 'get_subflow_info' in 'mptcp_diag', which can check whether a TCP connection is an MPTCP subflow based on the "INET_ULP_INFO_MPTCP" with tcp_diag method. The helper 'print_subflow_info' in 'mptcp_diag' can print the subflow_filed of an MPTCP subflow for further checking the 'subflow_info' through inet_diag method. The example of the whole output should be: ''' 127.0.0.1:10000 -> 127.0.0.1:38984 It's a mptcp subflow, the subflow info: flags:Mec token:0000(id:0)/4278e77e(id:0) seq:9288466187236176036 \ sfseq:1 ssnoff:2317083055 maplen:215 ''' Co-developed-by: Geliang Tang <[email protected]> Signed-off-by: Geliang Tang <[email protected]> Signed-off-by: Gang Yan <[email protected]>
1 parent f5f66d2 commit 03ca56b

File tree

1 file changed

+157
-2
lines changed

1 file changed

+157
-2
lines changed

tools/testing/selftests/net/mptcp/mptcp_diag.c

+157-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <sys/socket.h>
99
#include <netinet/in.h>
1010
#include <linux/tcp.h>
11+
#include <arpa/inet.h>
1112

1213
#include <unistd.h>
1314
#include <stdlib.h>
@@ -19,8 +20,13 @@
1920
#define IPPROTO_MPTCP 262
2021
#endif
2122

23+
#define parse_rtattr_nested(tb, max, rta) \
24+
(parse_rtattr_flags((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta), \
25+
NLA_F_NESTED))
26+
2227
struct params {
2328
__u32 target_token;
29+
char subflow_addrs[1024];
2430
};
2531

2632
struct mptcp_info {
@@ -50,6 +56,37 @@ struct mptcp_info {
5056
__u32 mptcpi_last_ack_recv;
5157
};
5258

59+
enum {
60+
MPTCP_SUBFLOW_ATTR_UNSPEC,
61+
MPTCP_SUBFLOW_ATTR_TOKEN_REM,
62+
MPTCP_SUBFLOW_ATTR_TOKEN_LOC,
63+
MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ,
64+
MPTCP_SUBFLOW_ATTR_MAP_SEQ,
65+
MPTCP_SUBFLOW_ATTR_MAP_SFSEQ,
66+
MPTCP_SUBFLOW_ATTR_SSN_OFFSET,
67+
MPTCP_SUBFLOW_ATTR_MAP_DATALEN,
68+
MPTCP_SUBFLOW_ATTR_FLAGS,
69+
MPTCP_SUBFLOW_ATTR_ID_REM,
70+
MPTCP_SUBFLOW_ATTR_ID_LOC,
71+
MPTCP_SUBFLOW_ATTR_PAD,
72+
73+
__MPTCP_SUBFLOW_ATTR_MAX
74+
};
75+
76+
#define MPTCP_SUBFLOW_ATTR_MAX (__MPTCP_SUBFLOW_ATTR_MAX - 1)
77+
78+
#define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0)
79+
#define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1)
80+
#define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2)
81+
#define MPTCP_SUBFLOW_FLAG_JOIN_LOC _BITUL(3)
82+
#define MPTCP_SUBFLOW_FLAG_BKUP_REM _BITUL(4)
83+
#define MPTCP_SUBFLOW_FLAG_BKUP_LOC _BITUL(5)
84+
#define MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED _BITUL(6)
85+
#define MPTCP_SUBFLOW_FLAG_CONNECTED _BITUL(7)
86+
#define MPTCP_SUBFLOW_FLAG_MAPVALID _BITUL(8)
87+
88+
#define rta_getattr(type, value) (*(type *)RTA_DATA(value))
89+
5390
static void die_perror(const char *msg)
5491
{
5592
perror(msg);
@@ -58,7 +95,9 @@ static void die_perror(const char *msg)
5895

5996
static void die_usage(int r)
6097
{
61-
fprintf(stderr, "Usage: mptcp_diag -t\n");
98+
fprintf(stderr, "Usage:\n"
99+
"mptcp_diag -t <token>\n"
100+
"mptcp_diag -s \"<saddr>:<sport> <daddr>:<dport>\"\n");
62101
exit(r);
63102
}
64103

@@ -159,6 +198,66 @@ static void print_info_msg(struct mptcp_info *info)
159198
printf("bytes_acked: %llu\n", info->mptcpi_bytes_acked);
160199
}
161200

201+
/*
202+
* 'print_subflow_info' is from 'mptcp_subflow_info'
203+
* which is a function in 'misc/ss.c' of iproute2.
204+
*/
205+
static void print_subflow_info(struct rtattr *tb[])
206+
{
207+
u_int32_t flags = 0;
208+
209+
printf("It's a mptcp subflow, the subflow info:\n");
210+
if (tb[MPTCP_SUBFLOW_ATTR_FLAGS]) {
211+
char caps[32 + 1] = { 0 }, *cap = &caps[0];
212+
213+
flags = rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_FLAGS]);
214+
215+
if (flags & MPTCP_SUBFLOW_FLAG_MCAP_REM)
216+
*cap++ = 'M';
217+
if (flags & MPTCP_SUBFLOW_FLAG_MCAP_LOC)
218+
*cap++ = 'm';
219+
if (flags & MPTCP_SUBFLOW_FLAG_JOIN_REM)
220+
*cap++ = 'J';
221+
if (flags & MPTCP_SUBFLOW_FLAG_JOIN_LOC)
222+
*cap++ = 'j';
223+
if (flags & MPTCP_SUBFLOW_FLAG_BKUP_REM)
224+
*cap++ = 'B';
225+
if (flags & MPTCP_SUBFLOW_FLAG_BKUP_LOC)
226+
*cap++ = 'b';
227+
if (flags & MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED)
228+
*cap++ = 'e';
229+
if (flags & MPTCP_SUBFLOW_FLAG_CONNECTED)
230+
*cap++ = 'c';
231+
if (flags & MPTCP_SUBFLOW_FLAG_MAPVALID)
232+
*cap++ = 'v';
233+
234+
if (flags)
235+
printf(" flags:%s", caps);
236+
}
237+
if (tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM] &&
238+
tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC] &&
239+
tb[MPTCP_SUBFLOW_ATTR_ID_REM] &&
240+
tb[MPTCP_SUBFLOW_ATTR_ID_LOC])
241+
printf(" token:%04x(id:%u)/%04x(id:%u)",
242+
rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM]),
243+
rta_getattr(__u8, tb[MPTCP_SUBFLOW_ATTR_ID_REM]),
244+
rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC]),
245+
rta_getattr(__u8, tb[MPTCP_SUBFLOW_ATTR_ID_LOC]));
246+
if (tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ])
247+
printf(" seq:%llu",
248+
rta_getattr(__u64, tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ]));
249+
if (tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ])
250+
printf(" sfseq:%u",
251+
rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ]));
252+
if (tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET])
253+
printf(" ssnoff:%u",
254+
rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET]));
255+
if (tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN])
256+
printf(" maplen:%u",
257+
rta_getattr(__u32, tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN]));
258+
printf("\n");
259+
}
260+
162261
static void parse_nlmsg(struct nlmsghdr *nlh, __u32 proto)
163262
{
164263
struct inet_diag_msg *r = NLMSG_DATA(nlh);
@@ -182,6 +281,22 @@ static void parse_nlmsg(struct nlmsghdr *nlh, __u32 proto)
182281
}
183282
print_info_msg(info);
184283
}
284+
if (proto == IPPROTO_TCP && tb[INET_DIAG_ULP_INFO]) {
285+
struct rtattr *ulpinfo[INET_ULP_INFO_MAX + 1] = { 0 };
286+
287+
parse_rtattr_nested(ulpinfo, INET_ULP_INFO_MAX,
288+
tb[INET_DIAG_ULP_INFO]);
289+
290+
if (ulpinfo[INET_ULP_INFO_MPTCP]) {
291+
struct rtattr *sfinfo[MPTCP_SUBFLOW_ATTR_MAX + 1] = { 0 };
292+
293+
parse_rtattr_nested(sfinfo, MPTCP_SUBFLOW_ATTR_MAX,
294+
ulpinfo[INET_ULP_INFO_MPTCP]);
295+
print_subflow_info(sfinfo);
296+
} else {
297+
printf("It's a normal TCP!\n");
298+
}
299+
}
185300
}
186301

187302
static void recv_nlmsg(int fd, __u32 proto)
@@ -244,21 +359,58 @@ static void get_mptcpinfo(__u32 token)
244359
close(fd);
245360
}
246361

362+
static void get_subflow_info(char *subflow_addrs)
363+
{
364+
struct inet_diag_req_v2 r = {
365+
.sdiag_family = AF_INET,
366+
.sdiag_protocol = IPPROTO_TCP,
367+
.id.idiag_cookie[0] = INET_DIAG_NOCOOKIE,
368+
.id.idiag_cookie[1] = INET_DIAG_NOCOOKIE,
369+
};
370+
char saddr[64], daddr[64];
371+
int sport, dport;
372+
int ret;
373+
int fd;
374+
375+
ret = sscanf(subflow_addrs, "%[^:]:%d %[^:]:%d", saddr, &sport, daddr, &dport);
376+
if (ret != 4)
377+
die_perror("IP PORT Pairs has style problems!");
378+
379+
printf("%s:%d -> %s:%d\n", saddr, sport, daddr, dport);
380+
381+
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
382+
if (fd < 0)
383+
die_perror("Netlink socket");
384+
385+
r.id.idiag_sport = htons(sport);
386+
r.id.idiag_dport = htons(dport);
387+
388+
inet_pton(AF_INET, saddr, &r.id.idiag_src);
389+
inet_pton(AF_INET, daddr, &r.id.idiag_dst);
390+
r.idiag_ext |= (1 << (INET_DIAG_INFO - 1));
391+
send_query(fd, &r, IPPROTO_TCP);
392+
recv_nlmsg(fd, IPPROTO_TCP);
393+
}
394+
247395
static void parse_opts(int argc, char **argv, struct params *p)
248396
{
249397
int c;
250398

251399
if (argc < 2)
252400
die_usage(1);
253401

254-
while ((c = getopt(argc, argv, "ht:")) != -1) {
402+
while ((c = getopt(argc, argv, "ht:s:")) != -1) {
255403
switch (c) {
256404
case 'h':
257405
die_usage(0);
258406
break;
259407
case 't':
260408
sscanf(optarg, "%x", &p->target_token);
261409
break;
410+
case 's':
411+
snprintf(p->subflow_addrs, strlen(optarg) + 1,
412+
"%s", optarg);
413+
break;
262414
default:
263415
die_usage(1);
264416
break;
@@ -275,6 +427,9 @@ int main(int argc, char *argv[])
275427
if (p.target_token)
276428
get_mptcpinfo(p.target_token);
277429

430+
if (strlen(p.subflow_addrs) != 0)
431+
get_subflow_info(p.subflow_addrs);
432+
278433
return 0;
279434
}
280435

0 commit comments

Comments
 (0)