~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/mptcp/mptcp_sockopt.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 #define _GNU_SOURCE
  4 
  5 #include <assert.h>
  6 #include <errno.h>
  7 #include <fcntl.h>
  8 #include <limits.h>
  9 #include <string.h>
 10 #include <stdarg.h>
 11 #include <stdbool.h>
 12 #include <stdint.h>
 13 #include <inttypes.h>
 14 #include <stdio.h>
 15 #include <stdlib.h>
 16 #include <strings.h>
 17 #include <time.h>
 18 #include <unistd.h>
 19 
 20 #include <sys/socket.h>
 21 #include <sys/types.h>
 22 #include <sys/wait.h>
 23 
 24 #include <netdb.h>
 25 #include <netinet/in.h>
 26 
 27 #include <linux/tcp.h>
 28 
 29 static int pf = AF_INET;
 30 
 31 #ifndef IPPROTO_MPTCP
 32 #define IPPROTO_MPTCP 262
 33 #endif
 34 #ifndef SOL_MPTCP
 35 #define SOL_MPTCP 284
 36 #endif
 37 
 38 #ifndef MPTCP_INFO
 39 struct mptcp_info {
 40         __u8    mptcpi_subflows;
 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;
 46         __u32   mptcpi_flags;
 47         __u32   mptcpi_token;
 48         __u64   mptcpi_write_seq;
 49         __u64   mptcpi_snd_una;
 50         __u64   mptcpi_rcv_nxt;
 51         __u8    mptcpi_local_addr_used;
 52         __u8    mptcpi_local_addr_max;
 53         __u8    mptcpi_csum_enabled;
 54         __u32   mptcpi_retransmits;
 55         __u64   mptcpi_bytes_retrans;
 56         __u64   mptcpi_bytes_sent;
 57         __u64   mptcpi_bytes_received;
 58         __u64   mptcpi_bytes_acked;
 59 };
 60 
 61 struct mptcp_subflow_data {
 62         __u32           size_subflow_data;              /* size of this structure in userspace */
 63         __u32           num_subflows;                   /* must be 0, set by kernel */
 64         __u32           size_kernel;                    /* must be 0, set by kernel */
 65         __u32           size_user;                      /* size of one element in data[] */
 66 } __attribute__((aligned(8)));
 67 
 68 struct mptcp_subflow_addrs {
 69         union {
 70                 __kernel_sa_family_t sa_family;
 71                 struct sockaddr sa_local;
 72                 struct sockaddr_in sin_local;
 73                 struct sockaddr_in6 sin6_local;
 74                 struct __kernel_sockaddr_storage ss_local;
 75         };
 76         union {
 77                 struct sockaddr sa_remote;
 78                 struct sockaddr_in sin_remote;
 79                 struct sockaddr_in6 sin6_remote;
 80                 struct __kernel_sockaddr_storage ss_remote;
 81         };
 82 };
 83 
 84 #define MPTCP_INFO              1
 85 #define MPTCP_TCPINFO           2
 86 #define MPTCP_SUBFLOW_ADDRS     3
 87 #endif
 88 
 89 #ifndef MPTCP_FULL_INFO
 90 struct mptcp_subflow_info {
 91         __u32                           id;
 92         struct mptcp_subflow_addrs      addrs;
 93 };
 94 
 95 struct mptcp_full_info {
 96         __u32           size_tcpinfo_kernel;    /* must be 0, set by kernel */
 97         __u32           size_tcpinfo_user;
 98         __u32           size_sfinfo_kernel;     /* must be 0, set by kernel */
 99         __u32           size_sfinfo_user;
100         __u32           num_subflows;           /* must be 0, set by kernel (real subflow count) */
101         __u32           size_arrays_user;       /* max subflows that userspace is interested in;
102                                                  * the buffers at subflow_info/tcp_info
103                                                  * are respectively at least:
104                                                  *  size_arrays * size_sfinfo_user
105                                                  *  size_arrays * size_tcpinfo_user
106                                                  * bytes wide
107                                                  */
108         __aligned_u64           subflow_info;
109         __aligned_u64           tcp_info;
110         struct mptcp_info       mptcp_info;
111 };
112 
113 #define MPTCP_FULL_INFO         4
114 #endif
115 
116 struct so_state {
117         struct mptcp_info mi;
118         struct mptcp_info last_sample;
119         struct tcp_info tcp_info;
120         struct mptcp_subflow_addrs addrs;
121         uint64_t mptcpi_rcv_delta;
122         uint64_t tcpi_rcv_delta;
123         bool pkt_stats_avail;
124 };
125 
126 #ifndef MIN
127 #define MIN(a, b) ((a) < (b) ? (a) : (b))
128 #endif
129 
130 static void die_perror(const char *msg)
131 {
132         perror(msg);
133         exit(1);
134 }
135 
136 static void die_usage(int r)
137 {
138         fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
139         exit(r);
140 }
141 
142 static void xerror(const char *fmt, ...)
143 {
144         va_list ap;
145 
146         va_start(ap, fmt);
147         vfprintf(stderr, fmt, ap);
148         va_end(ap);
149         fputc('\n', stderr);
150         exit(1);
151 }
152 
153 static const char *getxinfo_strerr(int err)
154 {
155         if (err == EAI_SYSTEM)
156                 return strerror(errno);
157 
158         return gai_strerror(err);
159 }
160 
161 static void xgetaddrinfo(const char *node, const char *service,
162                          const struct addrinfo *hints,
163                          struct addrinfo **res)
164 {
165         int err = getaddrinfo(node, service, hints, res);
166 
167         if (err) {
168                 const char *errstr = getxinfo_strerr(err);
169 
170                 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
171                         node ? node : "", service ? service : "", errstr);
172                 exit(1);
173         }
174 }
175 
176 static int sock_listen_mptcp(const char * const listenaddr,
177                              const char * const port)
178 {
179         int sock = -1;
180         struct addrinfo hints = {
181                 .ai_protocol = IPPROTO_TCP,
182                 .ai_socktype = SOCK_STREAM,
183                 .ai_flags = AI_PASSIVE | AI_NUMERICHOST
184         };
185 
186         hints.ai_family = pf;
187 
188         struct addrinfo *a, *addr;
189         int one = 1;
190 
191         xgetaddrinfo(listenaddr, port, &hints, &addr);
192         hints.ai_family = pf;
193 
194         for (a = addr; a; a = a->ai_next) {
195                 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
196                 if (sock < 0)
197                         continue;
198 
199                 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
200                                      sizeof(one)))
201                         perror("setsockopt");
202 
203                 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
204                         break; /* success */
205 
206                 perror("bind");
207                 close(sock);
208                 sock = -1;
209         }
210 
211         freeaddrinfo(addr);
212 
213         if (sock < 0)
214                 xerror("could not create listen socket");
215 
216         if (listen(sock, 20))
217                 die_perror("listen");
218 
219         return sock;
220 }
221 
222 static int sock_connect_mptcp(const char * const remoteaddr,
223                               const char * const port, int proto)
224 {
225         struct addrinfo hints = {
226                 .ai_protocol = IPPROTO_TCP,
227                 .ai_socktype = SOCK_STREAM,
228         };
229         struct addrinfo *a, *addr;
230         int sock = -1;
231 
232         hints.ai_family = pf;
233 
234         xgetaddrinfo(remoteaddr, port, &hints, &addr);
235         for (a = addr; a; a = a->ai_next) {
236                 sock = socket(a->ai_family, a->ai_socktype, proto);
237                 if (sock < 0)
238                         continue;
239 
240                 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
241                         break; /* success */
242 
243                 die_perror("connect");
244         }
245 
246         if (sock < 0)
247                 xerror("could not create connect socket");
248 
249         freeaddrinfo(addr);
250         return sock;
251 }
252 
253 static void parse_opts(int argc, char **argv)
254 {
255         int c;
256 
257         while ((c = getopt(argc, argv, "h6")) != -1) {
258                 switch (c) {
259                 case 'h':
260                         die_usage(0);
261                         break;
262                 case '6':
263                         pf = AF_INET6;
264                         break;
265                 default:
266                         die_usage(1);
267                         break;
268                 }
269         }
270 }
271 
272 static void do_getsockopt_bogus_sf_data(int fd, int optname)
273 {
274         struct mptcp_subflow_data good_data;
275         struct bogus_data {
276                 struct mptcp_subflow_data d;
277                 char buf[2];
278         } bd;
279         socklen_t olen, _olen;
280         int ret;
281 
282         memset(&bd, 0, sizeof(bd));
283         memset(&good_data, 0, sizeof(good_data));
284 
285         olen = sizeof(good_data);
286         good_data.size_subflow_data = olen;
287 
288         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
289         assert(ret < 0); /* 0 size_subflow_data */
290         assert(olen == sizeof(good_data));
291 
292         bd.d = good_data;
293 
294         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
295         assert(ret == 0);
296         assert(olen == sizeof(good_data));
297         assert(bd.d.num_subflows == 1);
298         assert(bd.d.size_kernel > 0);
299         assert(bd.d.size_user == 0);
300 
301         bd.d = good_data;
302         _olen = rand() % olen;
303         olen = _olen;
304         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
305         assert(ret < 0);        /* bogus olen */
306         assert(olen == _olen);  /* must be unchanged */
307 
308         bd.d = good_data;
309         olen = sizeof(good_data);
310         bd.d.size_kernel = 1;
311         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
312         assert(ret < 0); /* size_kernel not 0 */
313 
314         bd.d = good_data;
315         olen = sizeof(good_data);
316         bd.d.num_subflows = 1;
317         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
318         assert(ret < 0); /* num_subflows not 0 */
319 
320         /* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */
321         bd.d = good_data;
322         olen = sizeof(bd);
323         bd.d.size_subflow_data = sizeof(bd);
324 
325         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
326         assert(ret == 0);
327 
328         /* olen must be truncated to real data size filled by kernel: */
329         assert(olen == sizeof(good_data));
330 
331         assert(bd.d.size_subflow_data == sizeof(bd));
332 
333         bd.d = good_data;
334         bd.d.size_subflow_data += 1;
335         bd.d.size_user = 1;
336         olen = bd.d.size_subflow_data + 1;
337         _olen = olen;
338 
339         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen);
340         assert(ret == 0);
341 
342         /* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */
343         assert(olen == _olen);
344 
345         assert(bd.d.size_subflow_data == sizeof(good_data) + 1);
346         assert(bd.buf[0] == 0);
347 }
348 
349 static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
350 {
351         struct mptcp_info i;
352         socklen_t olen;
353         int ret;
354 
355         olen = sizeof(i);
356         ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
357 
358         if (ret < 0)
359                 die_perror("getsockopt MPTCP_INFO");
360 
361         s->pkt_stats_avail = olen >= sizeof(i);
362 
363         s->last_sample = i;
364         if (s->mi.mptcpi_write_seq == 0)
365                 s->mi = i;
366 
367         assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq);
368 
369         s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt;
370 }
371 
372 static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w)
373 {
374         struct my_tcp_info {
375                 struct mptcp_subflow_data d;
376                 struct tcp_info ti[2];
377         } ti;
378         int ret, tries = 5;
379         socklen_t olen;
380 
381         do {
382                 memset(&ti, 0, sizeof(ti));
383 
384                 ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
385                 ti.d.size_user = sizeof(struct tcp_info);
386                 olen = sizeof(ti);
387 
388                 ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
389                 if (ret < 0)
390                         xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
391 
392                 assert(olen <= sizeof(ti));
393                 assert(ti.d.size_kernel > 0);
394                 assert(ti.d.size_user ==
395                        MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
396                 assert(ti.d.num_subflows == 1);
397 
398                 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
399                 olen -= sizeof(struct mptcp_subflow_data);
400                 assert(olen == ti.d.size_user);
401 
402                 s->tcp_info = ti.ti[0];
403 
404                 if (ti.ti[0].tcpi_bytes_sent == w &&
405                     ti.ti[0].tcpi_bytes_received == r)
406                         goto done;
407 
408                 if (r == 0 && ti.ti[0].tcpi_bytes_sent == w &&
409                     ti.ti[0].tcpi_bytes_received) {
410                         s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received;
411                         goto done;
412                 }
413 
414                 /* wait and repeat, might be that tx is still ongoing */
415                 sleep(1);
416         } while (tries-- > 0);
417 
418         xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu",
419                 ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r);
420 
421 done:
422         do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
423 }
424 
425 static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
426 {
427         struct sockaddr_storage remote, local;
428         socklen_t olen, rlen, llen;
429         int ret;
430         struct my_addrs {
431                 struct mptcp_subflow_data d;
432                 struct mptcp_subflow_addrs addr[2];
433         } addrs;
434 
435         memset(&addrs, 0, sizeof(addrs));
436         memset(&local, 0, sizeof(local));
437         memset(&remote, 0, sizeof(remote));
438 
439         addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
440         addrs.d.size_user = sizeof(struct mptcp_subflow_addrs);
441         olen = sizeof(addrs);
442 
443         ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
444         if (ret < 0)
445                 die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
446 
447         assert(olen <= sizeof(addrs));
448         assert(addrs.d.size_kernel > 0);
449         assert(addrs.d.size_user ==
450                MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
451         assert(addrs.d.num_subflows == 1);
452 
453         assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
454         olen -= sizeof(struct mptcp_subflow_data);
455         assert(olen == addrs.d.size_user);
456 
457         llen = sizeof(local);
458         ret = getsockname(fd, (struct sockaddr *)&local, &llen);
459         if (ret < 0)
460                 die_perror("getsockname");
461         rlen = sizeof(remote);
462         ret = getpeername(fd, (struct sockaddr *)&remote, &rlen);
463         if (ret < 0)
464                 die_perror("getpeername");
465 
466         assert(rlen > 0);
467         assert(rlen == llen);
468 
469         assert(remote.ss_family == local.ss_family);
470 
471         assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
472         assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
473         s->addrs = addrs.addr[0];
474 
475         memset(&addrs, 0, sizeof(addrs));
476 
477         addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
478         addrs.d.size_user = sizeof(sa_family_t);
479         olen = sizeof(addrs.d) + sizeof(sa_family_t);
480 
481         ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
482         assert(ret == 0);
483         assert(olen == sizeof(addrs.d) + sizeof(sa_family_t));
484 
485         assert(addrs.addr[0].sa_family == pf);
486         assert(addrs.addr[0].sa_family == local.ss_family);
487 
488         assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0);
489         assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0);
490 
491         do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
492 }
493 
494 static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
495 {
496         size_t data_size = sizeof(struct mptcp_full_info);
497         struct mptcp_subflow_info sfinfo[2];
498         struct tcp_info tcp_info[2];
499         struct mptcp_full_info mfi;
500         socklen_t olen;
501         int ret;
502 
503         memset(&mfi, 0, data_size);
504         memset(tcp_info, 0, sizeof(tcp_info));
505         memset(sfinfo, 0, sizeof(sfinfo));
506 
507         mfi.size_tcpinfo_user = sizeof(struct tcp_info);
508         mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
509         mfi.size_arrays_user = 2;
510         mfi.subflow_info = (unsigned long)&sfinfo[0];
511         mfi.tcp_info = (unsigned long)&tcp_info[0];
512         olen = data_size;
513 
514         ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
515         if (ret < 0) {
516                 if (errno == EOPNOTSUPP) {
517                         perror("MPTCP_FULL_INFO test skipped");
518                         return;
519                 }
520                 xerror("getsockopt MPTCP_FULL_INFO");
521         }
522 
523         assert(olen <= data_size);
524         assert(mfi.size_tcpinfo_kernel > 0);
525         assert(mfi.size_tcpinfo_user ==
526                MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
527         assert(mfi.size_sfinfo_kernel > 0);
528         assert(mfi.size_sfinfo_user ==
529                MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
530         assert(mfi.num_subflows == 1);
531 
532         /* Tolerate future extension to mptcp_info struct and running newer
533          * test on top of older kernel.
534          * Anyway any kernel supporting MPTCP_FULL_INFO must at least include
535          * the following in mptcp_info.
536          */
537         assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
538         assert(mfi.mptcp_info.mptcpi_subflows == 0);
539         assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
540         assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
541 
542         assert(sfinfo[0].id == 1);
543         assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
544         assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
545         assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
546 }
547 
548 static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
549 {
550         do_getsockopt_mptcp_info(s, fd, w);
551 
552         do_getsockopt_tcp_info(s, fd, r, w);
553 
554         do_getsockopt_subflow_addrs(s, fd);
555 
556         if (r)
557                 do_getsockopt_mptcp_full_info(s, fd);
558 }
559 
560 static void connect_one_server(int fd, int pipefd)
561 {
562         char buf[4096], buf2[4096];
563         size_t len, i, total;
564         struct so_state s;
565         bool eof = false;
566         ssize_t ret;
567 
568         memset(&s, 0, sizeof(s));
569 
570         len = rand() % (sizeof(buf) - 1);
571 
572         if (len < 128)
573                 len = 128;
574 
575         for (i = 0; i < len ; i++) {
576                 buf[i] = rand() % 26;
577                 buf[i] += 'A';
578         }
579 
580         buf[i] = '\n';
581 
582         do_getsockopts(&s, fd, 0, 0);
583 
584         /* un-block server */
585         ret = read(pipefd, buf2, 4);
586         assert(ret == 4);
587         close(pipefd);
588 
589         assert(strncmp(buf2, "xmit", 4) == 0);
590 
591         ret = write(fd, buf, len);
592         if (ret < 0)
593                 die_perror("write");
594 
595         if (ret != (ssize_t)len)
596                 xerror("short write");
597 
598         total = 0;
599         do {
600                 ret = read(fd, buf2 + total, sizeof(buf2) - total);
601                 if (ret < 0)
602                         die_perror("read");
603                 if (ret == 0) {
604                         eof = true;
605                         break;
606                 }
607 
608                 total += ret;
609         } while (total < len);
610 
611         if (total != len)
612                 xerror("total %lu, len %lu eof %d\n", total, len, eof);
613 
614         if (memcmp(buf, buf2, len))
615                 xerror("data corruption");
616 
617         if (s.tcpi_rcv_delta)
618                 assert(s.tcpi_rcv_delta <= total);
619 
620         do_getsockopts(&s, fd, ret, ret);
621 
622         if (eof)
623                 total += 1; /* sequence advances due to FIN */
624 
625         assert(s.mptcpi_rcv_delta == (uint64_t)total);
626         close(fd);
627 }
628 
629 static void process_one_client(int fd, int pipefd)
630 {
631         ssize_t ret, ret2, ret3;
632         struct so_state s;
633         char buf[4096];
634 
635         memset(&s, 0, sizeof(s));
636         do_getsockopts(&s, fd, 0, 0);
637 
638         ret = write(pipefd, "xmit", 4);
639         assert(ret == 4);
640 
641         ret = read(fd, buf, sizeof(buf));
642         if (ret < 0)
643                 die_perror("read");
644 
645         assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
646 
647         if (s.tcpi_rcv_delta)
648                 assert(s.tcpi_rcv_delta == (uint64_t)ret);
649 
650         ret2 = write(fd, buf, ret);
651         if (ret2 < 0)
652                 die_perror("write");
653 
654         /* wait for hangup */
655         ret3 = read(fd, buf, 1);
656         if (ret3 != 0)
657                 xerror("expected EOF, got %lu", ret3);
658 
659         do_getsockopts(&s, fd, ret, ret2);
660         if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
661                 xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
662 
663         /* be nice when running on top of older kernel */
664         if (s.pkt_stats_avail) {
665                 if (s.last_sample.mptcpi_bytes_sent != ret2)
666                         xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
667                                s.last_sample.mptcpi_bytes_sent, ret2,
668                                s.last_sample.mptcpi_bytes_sent - ret2);
669                 if (s.last_sample.mptcpi_bytes_received != ret)
670                         xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
671                                s.last_sample.mptcpi_bytes_received, ret,
672                                s.last_sample.mptcpi_bytes_received - ret);
673                 if (s.last_sample.mptcpi_bytes_acked != ret)
674                         xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
675                                s.last_sample.mptcpi_bytes_acked, ret2,
676                                s.last_sample.mptcpi_bytes_acked - ret2);
677         }
678 
679         close(fd);
680 }
681 
682 static int xaccept(int s)
683 {
684         int fd = accept(s, NULL, 0);
685 
686         if (fd < 0)
687                 die_perror("accept");
688 
689         return fd;
690 }
691 
692 static int server(int pipefd)
693 {
694         int fd = -1, r;
695 
696         switch (pf) {
697         case AF_INET:
698                 fd = sock_listen_mptcp("127.0.0.1", "15432");
699                 break;
700         case AF_INET6:
701                 fd = sock_listen_mptcp("::1", "15432");
702                 break;
703         default:
704                 xerror("Unknown pf %d\n", pf);
705                 break;
706         }
707 
708         r = write(pipefd, "conn", 4);
709         assert(r == 4);
710 
711         alarm(15);
712         r = xaccept(fd);
713 
714         process_one_client(r, pipefd);
715 
716         return 0;
717 }
718 
719 static void test_ip_tos_sockopt(int fd)
720 {
721         uint8_t tos_in, tos_out;
722         socklen_t s;
723         int r;
724 
725         tos_in = rand() & 0xfc;
726         r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out));
727         if (r != 0)
728                 die_perror("setsockopt IP_TOS");
729 
730         tos_out = 0;
731         s = sizeof(tos_out);
732         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
733         if (r != 0)
734                 die_perror("getsockopt IP_TOS");
735 
736         if (tos_in != tos_out)
737                 xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s);
738 
739         if (s != 1)
740                 xerror("tos should be 1 byte");
741 
742         s = 0;
743         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
744         if (r != 0)
745                 die_perror("getsockopt IP_TOS 0");
746         if (s != 0)
747                 xerror("expect socklen_t == 0");
748 
749         s = -1;
750         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
751         if (r != -1 && errno != EINVAL)
752                 die_perror("getsockopt IP_TOS did not indicate -EINVAL");
753         if (s != -1)
754                 xerror("expect socklen_t == -1");
755 }
756 
757 static int client(int pipefd)
758 {
759         int fd = -1;
760 
761         alarm(15);
762 
763         switch (pf) {
764         case AF_INET:
765                 fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
766                 break;
767         case AF_INET6:
768                 fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
769                 break;
770         default:
771                 xerror("Unknown pf %d\n", pf);
772         }
773 
774         test_ip_tos_sockopt(fd);
775 
776         connect_one_server(fd, pipefd);
777 
778         return 0;
779 }
780 
781 static pid_t xfork(void)
782 {
783         pid_t p = fork();
784 
785         if (p < 0)
786                 die_perror("fork");
787 
788         return p;
789 }
790 
791 static int rcheck(int wstatus, const char *what)
792 {
793         if (WIFEXITED(wstatus)) {
794                 if (WEXITSTATUS(wstatus) == 0)
795                         return 0;
796                 fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
797                 return WEXITSTATUS(wstatus);
798         } else if (WIFSIGNALED(wstatus)) {
799                 xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
800         } else if (WIFSTOPPED(wstatus)) {
801                 xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
802         }
803 
804         return 111;
805 }
806 
807 static void init_rng(void)
808 {
809         int fd = open("/dev/urandom", O_RDONLY);
810 
811         if (fd >= 0) {
812                 unsigned int foo;
813                 ssize_t ret;
814 
815                 /* can't fail */
816                 ret = read(fd, &foo, sizeof(foo));
817                 assert(ret == sizeof(foo));
818 
819                 close(fd);
820                 srand(foo);
821         } else {
822                 srand(time(NULL));
823         }
824 }
825 
826 int main(int argc, char *argv[])
827 {
828         int e1, e2, wstatus;
829         pid_t s, c, ret;
830         int pipefds[2];
831 
832         parse_opts(argc, argv);
833 
834         init_rng();
835 
836         e1 = pipe(pipefds);
837         if (e1 < 0)
838                 die_perror("pipe");
839 
840         s = xfork();
841         if (s == 0)
842                 return server(pipefds[1]);
843 
844         close(pipefds[1]);
845 
846         /* wait until server bound a socket */
847         e1 = read(pipefds[0], &e1, 4);
848         assert(e1 == 4);
849 
850         c = xfork();
851         if (c == 0)
852                 return client(pipefds[0]);
853 
854         close(pipefds[0]);
855 
856         ret = waitpid(s, &wstatus, 0);
857         if (ret == -1)
858                 die_perror("waitpid");
859         e1 = rcheck(wstatus, "server");
860         ret = waitpid(c, &wstatus, 0);
861         if (ret == -1)
862                 die_perror("waitpid");
863         e2 = rcheck(wstatus, "client");
864 
865         return e1 ? e1 : e2;
866 }
867 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php