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>
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+
2227struct params {
2328 __u32 target_token ;
29+ char subflow_addrs [1024 ];
2430};
2531
2632struct 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+
5390static void die_perror (const char * msg )
5491{
5592 perror (msg );
@@ -58,7 +95,9 @@ static void die_perror(const char *msg)
5895
5996static 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+
162261static 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
187302static 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+
247395static 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