1 // SPDX-License-Identifier: GPL-2.0
20 #include <sys/socket.h>
21 #include <sys/types.h>
25 #include <netinet/in.h>
27 #include <linux/tcp.h>
29 static int pf = AF_INET;
32 #define IPPROTO_MPTCP 262
41 __u8 mptcpi_add_addr_signal;
42 __u8 mptcpi_add_addr_accepted;
43 __u8 mptcpi_subflows_max;
44 __u8 mptcpi_add_addr_signal_max;
45 __u8 mptcpi_add_addr_accepted_max;
48 __u64 mptcpi_write_seq;
51 __u8 mptcpi_local_addr_used;
52 __u8 mptcpi_local_addr_max;
53 __u8 mptcpi_csum_enabled;
56 struct mptcp_subflow_data {
57 __u32 size_subflow_data; /* size of this structure in userspace */
58 __u32 num_subflows; /* must be 0, set by kernel */
59 __u32 size_kernel; /* must be 0, set by kernel */
60 __u32 size_user; /* size of one element in data[] */
61 } __attribute__((aligned(8)));
63 struct mptcp_subflow_addrs {
65 __kernel_sa_family_t sa_family;
66 struct sockaddr sa_local;
67 struct sockaddr_in sin_local;
68 struct sockaddr_in6 sin6_local;
69 struct __kernel_sockaddr_storage ss_local;
72 struct sockaddr sa_remote;
73 struct sockaddr_in sin_remote;
74 struct sockaddr_in6 sin6_remote;
75 struct __kernel_sockaddr_storage ss_remote;
80 #define MPTCP_TCPINFO 2
81 #define MPTCP_SUBFLOW_ADDRS 3
86 uint64_t mptcpi_rcv_delta;
87 uint64_t tcpi_rcv_delta;
90 static void die_perror(const char *msg)
96 static void die_usage(int r)
98 fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
102 static void xerror(const char *fmt, ...)
107 vfprintf(stderr, fmt, ap);
113 static const char *getxinfo_strerr(int err)
115 if (err == EAI_SYSTEM)
116 return strerror(errno);
118 return gai_strerror(err);
121 static void xgetaddrinfo(const char *node, const char *service,
122 const struct addrinfo *hints,
123 struct addrinfo **res)
125 int err = getaddrinfo(node, service, hints, res);
128 const char *errstr = getxinfo_strerr(err);
130 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
131 node ? node : "", service ? service : "", errstr);
136 static int sock_listen_mptcp(const char * const listenaddr,
137 const char * const port)
140 struct addrinfo hints = {
141 .ai_protocol = IPPROTO_TCP,
142 .ai_socktype = SOCK_STREAM,
143 .ai_flags = AI_PASSIVE | AI_NUMERICHOST
146 hints.ai_family = pf;
148 struct addrinfo *a, *addr;
151 xgetaddrinfo(listenaddr, port, &hints, &addr);
152 hints.ai_family = pf;
154 for (a = addr; a; a = a->ai_next) {
155 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
159 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
161 perror("setsockopt");
163 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
174 xerror("could not create listen socket");
176 if (listen(sock, 20))
177 die_perror("listen");
182 static int sock_connect_mptcp(const char * const remoteaddr,
183 const char * const port, int proto)
185 struct addrinfo hints = {
186 .ai_protocol = IPPROTO_TCP,
187 .ai_socktype = SOCK_STREAM,
189 struct addrinfo *a, *addr;
192 hints.ai_family = pf;
194 xgetaddrinfo(remoteaddr, port, &hints, &addr);
195 for (a = addr; a; a = a->ai_next) {
196 sock = socket(a->ai_family, a->ai_socktype, proto);
200 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
203 die_perror("connect");
207 xerror("could not create connect socket");
213 static void parse_opts(int argc, char **argv)
217 while ((c = getopt(argc, argv, "h6")) != -1) {
232 static void do_getsockopt_bogus_sf_data(int fd, int optname)
234 struct mptcp_subflow_data good_data;
236 struct mptcp_subflow_data d;
239 socklen_t olen, _olen;
242 memset(&bd, 0, sizeof(bd));
243 memset(&good_data, 0, sizeof(good_data));
245 olen = sizeof(good_data);
246 good_data.size_subflow_data = olen;
248 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
249 assert(ret < 0); /* 0 size_subflow_data */
250 assert(olen == sizeof(good_data));
254 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
256 assert(olen == sizeof(good_data));
257 assert(bd.d.num_subflows == 1);
258 assert(bd.d.size_kernel > 0);
259 assert(bd.d.size_user == 0);
262 _olen = rand() % olen;
264 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
265 assert(ret < 0); /* bogus olen */
266 assert(olen == _olen); /* must be unchanged */
269 olen = sizeof(good_data);
270 bd.d.size_kernel = 1;
271 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
272 assert(ret < 0); /* size_kernel not 0 */
275 olen = sizeof(good_data);
276 bd.d.num_subflows = 1;
277 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
278 assert(ret < 0); /* num_subflows not 0 */
280 /* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */
283 bd.d.size_subflow_data = sizeof(bd);
285 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
288 /* olen must be truncated to real data size filled by kernel: */
289 assert(olen == sizeof(good_data));
291 assert(bd.d.size_subflow_data == sizeof(bd));
294 bd.d.size_subflow_data += 1;
296 olen = bd.d.size_subflow_data + 1;
299 ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen);
302 /* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */
303 assert(olen == _olen);
305 assert(bd.d.size_subflow_data == sizeof(good_data) + 1);
306 assert(bd.buf[0] == 0);
309 static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
316 ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
319 die_perror("getsockopt MPTCP_INFO");
321 assert(olen == sizeof(i));
323 if (s->mi.mptcpi_write_seq == 0)
326 assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq);
328 s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt;
331 static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w)
334 struct mptcp_subflow_data d;
335 struct tcp_info ti[2];
341 memset(&ti, 0, sizeof(ti));
343 ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
344 ti.d.size_user = sizeof(struct tcp_info);
347 ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
349 xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
351 assert(olen <= sizeof(ti));
352 assert(ti.d.size_user == ti.d.size_kernel);
353 assert(ti.d.size_user == sizeof(struct tcp_info));
354 assert(ti.d.num_subflows == 1);
356 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
357 olen -= sizeof(struct mptcp_subflow_data);
358 assert(olen == sizeof(struct tcp_info));
360 if (ti.ti[0].tcpi_bytes_sent == w &&
361 ti.ti[0].tcpi_bytes_received == r)
364 if (r == 0 && ti.ti[0].tcpi_bytes_sent == w &&
365 ti.ti[0].tcpi_bytes_received) {
366 s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received;
370 /* wait and repeat, might be that tx is still ongoing */
372 } while (tries-- > 0);
374 xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu",
375 ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r);
378 do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
381 static void do_getsockopt_subflow_addrs(int fd)
383 struct sockaddr_storage remote, local;
384 socklen_t olen, rlen, llen;
387 struct mptcp_subflow_data d;
388 struct mptcp_subflow_addrs addr[2];
391 memset(&addrs, 0, sizeof(addrs));
392 memset(&local, 0, sizeof(local));
393 memset(&remote, 0, sizeof(remote));
395 addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
396 addrs.d.size_user = sizeof(struct mptcp_subflow_addrs);
397 olen = sizeof(addrs);
399 ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
401 die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
403 assert(olen <= sizeof(addrs));
404 assert(addrs.d.size_user == addrs.d.size_kernel);
405 assert(addrs.d.size_user == sizeof(struct mptcp_subflow_addrs));
406 assert(addrs.d.num_subflows == 1);
408 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
409 olen -= sizeof(struct mptcp_subflow_data);
410 assert(olen == sizeof(struct mptcp_subflow_addrs));
412 llen = sizeof(local);
413 ret = getsockname(fd, (struct sockaddr *)&local, &llen);
415 die_perror("getsockname");
416 rlen = sizeof(remote);
417 ret = getpeername(fd, (struct sockaddr *)&remote, &rlen);
419 die_perror("getpeername");
422 assert(rlen == llen);
424 assert(remote.ss_family == local.ss_family);
426 assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
427 assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
429 memset(&addrs, 0, sizeof(addrs));
431 addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
432 addrs.d.size_user = sizeof(sa_family_t);
433 olen = sizeof(addrs.d) + sizeof(sa_family_t);
435 ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
437 assert(olen == sizeof(addrs.d) + sizeof(sa_family_t));
439 assert(addrs.addr[0].sa_family == pf);
440 assert(addrs.addr[0].sa_family == local.ss_family);
442 assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0);
443 assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0);
445 do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
448 static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
450 do_getsockopt_mptcp_info(s, fd, w);
452 do_getsockopt_tcp_info(s, fd, r, w);
454 do_getsockopt_subflow_addrs(fd);
457 static void connect_one_server(int fd, int pipefd)
459 char buf[4096], buf2[4096];
460 size_t len, i, total;
465 memset(&s, 0, sizeof(s));
467 len = rand() % (sizeof(buf) - 1);
472 for (i = 0; i < len ; i++) {
473 buf[i] = rand() % 26;
479 do_getsockopts(&s, fd, 0, 0);
481 /* un-block server */
482 ret = read(pipefd, buf2, 4);
486 assert(strncmp(buf2, "xmit", 4) == 0);
488 ret = write(fd, buf, len);
492 if (ret != (ssize_t)len)
493 xerror("short write");
497 ret = read(fd, buf2 + total, sizeof(buf2) - total);
506 } while (total < len);
509 xerror("total %lu, len %lu eof %d\n", total, len, eof);
511 if (memcmp(buf, buf2, len))
512 xerror("data corruption");
514 if (s.tcpi_rcv_delta)
515 assert(s.tcpi_rcv_delta <= total);
517 do_getsockopts(&s, fd, ret, ret);
520 total += 1; /* sequence advances due to FIN */
522 assert(s.mptcpi_rcv_delta == (uint64_t)total);
526 static void process_one_client(int fd, int pipefd)
528 ssize_t ret, ret2, ret3;
532 memset(&s, 0, sizeof(s));
533 do_getsockopts(&s, fd, 0, 0);
535 ret = write(pipefd, "xmit", 4);
538 ret = read(fd, buf, sizeof(buf));
542 assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
544 if (s.tcpi_rcv_delta)
545 assert(s.tcpi_rcv_delta == (uint64_t)ret);
547 ret2 = write(fd, buf, ret);
551 /* wait for hangup */
552 ret3 = read(fd, buf, 1);
554 xerror("expected EOF, got %lu", ret3);
556 do_getsockopts(&s, fd, ret, ret2);
557 if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
558 xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
562 static int xaccept(int s)
564 int fd = accept(s, NULL, 0);
567 die_perror("accept");
572 static int server(int pipefd)
578 fd = sock_listen_mptcp("127.0.0.1", "15432");
581 fd = sock_listen_mptcp("::1", "15432");
584 xerror("Unknown pf %d\n", pf);
588 r = write(pipefd, "conn", 4);
594 process_one_client(r, pipefd);
599 static void test_ip_tos_sockopt(int fd)
601 uint8_t tos_in, tos_out;
605 tos_in = rand() & 0xfc;
606 r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out));
608 die_perror("setsockopt IP_TOS");
612 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
614 die_perror("getsockopt IP_TOS");
616 if (tos_in != tos_out)
617 xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s);
620 xerror("tos should be 1 byte");
623 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
625 die_perror("getsockopt IP_TOS 0");
627 xerror("expect socklen_t == 0");
630 r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
631 if (r != -1 && errno != EINVAL)
632 die_perror("getsockopt IP_TOS did not indicate -EINVAL");
634 xerror("expect socklen_t == -1");
637 static int client(int pipefd)
645 fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
648 fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
651 xerror("Unknown pf %d\n", pf);
654 test_ip_tos_sockopt(fd);
656 connect_one_server(fd, pipefd);
661 static pid_t xfork(void)
671 static int rcheck(int wstatus, const char *what)
673 if (WIFEXITED(wstatus)) {
674 if (WEXITSTATUS(wstatus) == 0)
676 fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
677 return WEXITSTATUS(wstatus);
678 } else if (WIFSIGNALED(wstatus)) {
679 xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
680 } else if (WIFSTOPPED(wstatus)) {
681 xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
687 static void init_rng(void)
689 int fd = open("/dev/urandom", O_RDONLY);
696 ret = read(fd, &foo, sizeof(foo));
697 assert(ret == sizeof(foo));
706 int main(int argc, char *argv[])
712 parse_opts(argc, argv);
722 return server(pipefds[1]);
726 /* wait until server bound a socket */
727 e1 = read(pipefds[0], &e1, 4);
732 return client(pipefds[0]);
736 ret = waitpid(s, &wstatus, 0);
738 die_perror("waitpid");
739 e1 = rcheck(wstatus, "server");
740 ret = waitpid(c, &wstatus, 0);
742 die_perror("waitpid");
743 e2 = rcheck(wstatus, "client");