blob: 61262d2f28f7848317306d4c128084fcd753ffaf [file] [log] [blame]
Alexey Kodaneva8c23232014-04-15 14:45:26 +04001/*
2 * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
19 *
20 */
21
22#include <pthread.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <netdb.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <poll.h>
29#include <time.h>
30#include <string.h>
31#include <unistd.h>
32#include <errno.h>
33
34#include "test.h"
Cyril Hrubisf85e3b32014-04-15 13:30:02 +020035#include "lapi/posix_clocks.h"
Alexey Kodaneva8c23232014-04-15 14:45:26 +040036#include "safe_macros.h"
37
38char *TCID = "tcp_fastopen";
39
40static const int max_msg_len = 1500;
41
42/* TCP server requiers */
43#ifndef TCP_FASTOPEN
44#define TCP_FASTOPEN 23
45#endif
46
47/* TCP client requiers */
48#ifndef MSG_FASTOPEN
49#define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */
50#endif
51
52enum {
53 TCP_SERVER = 0,
54 TCP_CLIENT,
55};
56static int tcp_mode;
57
58enum {
59 TFO_ENABLED = 0,
60 TFO_DISABLED,
61};
62static int tfo_support;
63static int fastopen_api;
64
65static const char tfo_cfg[] = "/proc/sys/net/ipv4/tcp_fastopen";
66static const char tcp_tw_reuse[] = "/proc/sys/net/ipv4/tcp_tw_reuse";
67static int tw_reuse_changed;
68static int tfo_cfg_value;
69static int tfo_bit_num;
70static int tfo_cfg_changed;
71static int tfo_queue_size = 100;
72static int max_queue_len = 100;
73static const int client_byte = 0x43;
74static const int server_byte = 0x53;
75static const int start_byte = 0x24;
76static const int start_fin_byte = 0x25;
77static const int end_byte = 0x0a;
78static int client_msg_size = 32;
79static int server_msg_size = 128;
80static char *client_msg;
81static char *server_msg;
82
83/*
84 * The number of requests from client after
85 * which server has to close the connection.
86 */
87static int server_max_requests = 3;
88static int client_max_requests = 10;
89static int clients_num = 2;
90static char *tcp_port = "61000";
91static char *server_addr = "localhost";
92/* server socket */
93static int sfd;
94
95/* how long a client must wait for the server's reply, microsec */
96static long wait_timeout = 10000000;
97
98/* in the end test will save time result in this file */
99static char *rpath = "./tfo_result";
100
101static int force_run;
102static int verbose;
103
104static char *narg, *Narg, *qarg, *rarg, *Rarg, *aarg, *Targ;
105
106static const option_t options[] = {
107 /* server params */
108 {"R:", NULL, &Rarg},
109 {"q:", NULL, &qarg},
110
111 /* client params */
112 {"H:", NULL, &server_addr},
113 {"a:", NULL, &aarg},
114 {"n:", NULL, &narg},
115 {"N:", NULL, &Narg},
116 {"T:", NULL, &Targ},
117 {"r:", NULL, &rarg},
118 {"d:", NULL, &rpath},
119
120 /* common */
121 {"g:", NULL, &tcp_port},
122 {"F", &force_run, NULL},
123 {"l", &tcp_mode, NULL},
124 {"o", &fastopen_api, NULL},
125 {"O", &tfo_support, NULL},
126 {"v", &verbose, NULL},
127 {NULL, NULL, NULL}
128};
129
130static void help(void)
131{
132 printf("\n -F Force to run\n");
133 printf(" -v Verbose\n");
134 printf(" -o Use old TCP API, default is new TCP API\n");
135 printf(" -O TFO support is off, default is on\n");
136 printf(" -l Become TCP Client, default is TCP server\n");
137 printf(" -g x x - server port, default is %s\n", tcp_port);
138
139 printf("\n Client:\n");
140 printf(" -H x x - server name or ip address, default is '%s'\n",
141 server_addr);
142 printf(" -a x x - num of clients running in parallel\n");
143 printf(" -r x x - num of client requests\n");
144 printf(" -n x Client message size, max msg size is '%d'\n",
145 max_msg_len);
146 printf(" -N x Server message size, max msg size is '%d'\n",
147 max_msg_len);
148 printf(" -T x Reply timeout, default is '%ld' (microsec)\n",
149 wait_timeout);
150 printf(" -d x x is a path to the file where results are saved\n");
151
152 printf("\n Server:\n");
153 printf(" -R x x - num of requests, after which conn. closed\n");
154 printf(" -q x x - server's limit on the queue of TFO requests\n");
155}
156
157/* common structure for TCP server and TCP client */
158struct tcp_func {
159 void (*init)(void);
160 void (*run)(void);
161 void (*cleanup)(void);
162};
163static struct tcp_func tcp;
164
165#define MAX_THREADS 10000
166static pthread_attr_t attr;
167static pthread_t *thread_ids;
168
169static struct addrinfo *remote_addrinfo;
170static struct addrinfo *local_addrinfo;
171static const struct linger clo = { 1, 3 };
172
173static void do_cleanup(void)
174{
175 free(client_msg);
176 free(server_msg);
177
178 tcp.cleanup();
179
180 if (tfo_cfg_changed) {
181 SAFE_FILE_SCANF(NULL, tfo_cfg, "%d", &tfo_cfg_value);
182 tfo_cfg_value &= ~tfo_bit_num;
183 tfo_cfg_value |= !tfo_support << (tfo_bit_num - 1);
184 tst_resm(TINFO, "unset '%s' back to '%d'",
185 tfo_cfg, tfo_cfg_value);
186 SAFE_FILE_PRINTF(NULL, tfo_cfg, "%d", tfo_cfg_value);
187 }
188
189 if (tw_reuse_changed) {
190 SAFE_FILE_PRINTF(NULL, tcp_tw_reuse, "0");
191 tst_resm(TINFO, "unset '%s' back to '0'", tcp_tw_reuse);
192 }
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400193}
194TST_DECLARE_ONCE_FN(cleanup, do_cleanup)
195
196static int sock_recv_poll(int fd, char *buf, int buf_size, int offset)
197{
198 struct pollfd pfd;
199 pfd.fd = fd;
200 pfd.events = POLLIN;
201 int len = -1;
202 while (1) {
203 errno = 0;
204 int ret = poll(&pfd, 1, wait_timeout / 1000);
205 if (ret == -1) {
206 if (errno == EINTR)
207 continue;
208 break;
209 }
210
211 if (ret == 0) {
212 errno = ETIME;
213 break;
214 }
215
216 if (ret != 1 || !(pfd.revents & POLLIN))
217 break;
218
219 errno = 0;
220 len = recv(fd, buf + offset,
221 buf_size - offset, MSG_DONTWAIT);
222
223 if (len == -1 && errno == EINTR)
224 continue;
225 else
226 break;
227 }
228
229 return len;
230}
231
232static int client_recv(int *fd, char *buf)
233{
234 int len, offset = 0;
235
236 while (1) {
237 errno = 0;
238 len = sock_recv_poll(*fd, buf, server_msg_size, offset);
239
240 /* socket closed or msg is not valid */
241 if (len < 1 || (offset + len) > server_msg_size ||
242 (buf[0] != start_byte && buf[0] != start_fin_byte)) {
243 if (!errno)
244 errno = ENOMSG;
245 break;
246 }
247 offset += len;
248 if (buf[offset - 1] != end_byte)
249 continue;
250
251 if (verbose) {
252 tst_resm_hexd(TINFO, buf, offset,
253 "msg recv from sock %d:", *fd);
254 }
255
256 /* recv last msg, close socket */
257 if (buf[0] == start_fin_byte)
258 break;
259 return 0;
260 }
261
262 shutdown(*fd, SHUT_WR);
263 SAFE_CLOSE(cleanup, *fd);
264 *fd = -1;
265 return (errno) ? -1 : 0;
266}
267
268static int client_connect_send(const char *msg, int size)
269{
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400270 int cfd = socket(remote_addrinfo->ai_family, SOCK_STREAM, 0);
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400271 const int flag = 1;
272 setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
273
274 if (cfd == -1)
275 return cfd;
276
277 if (fastopen_api == TFO_ENABLED) {
278 /* Replaces connect() + send()/write() */
279 if (sendto(cfd, msg, size, MSG_FASTOPEN | MSG_NOSIGNAL,
280 remote_addrinfo->ai_addr,
281 remote_addrinfo->ai_addrlen) != size) {
282 SAFE_CLOSE(cleanup, cfd);
283 return -1;
284 }
285 } else {
286 /* old TCP API */
287 if (connect(cfd, remote_addrinfo->ai_addr,
288 remote_addrinfo->ai_addrlen)) {
289 SAFE_CLOSE(cleanup, cfd);
290 return -1;
291 }
292
293 if (send(cfd, msg, size, MSG_NOSIGNAL) != client_msg_size) {
294 SAFE_CLOSE(cleanup, cfd);
295 return -1;
296 }
297 }
298
299 return cfd;
300}
301
302void *client_fn(LTP_ATTRIBUTE_UNUSED void *arg)
303{
304 char buf[server_msg_size];
305 int cfd, i;
306 intptr_t err = 0;
307
308 /* connect & send requests */
309 cfd = client_connect_send(client_msg, client_msg_size);
310 if (cfd == -1) {
311 err = errno;
312 goto out;
313 }
314
315 if (client_recv(&cfd, buf)) {
316 err = errno;
317 goto out;
318 }
319
320 for (i = 1; i < client_max_requests; ++i) {
321
322 /* check connection, it can be closed */
323 int ret = 0;
324 if (cfd != -1)
325 ret = recv(cfd, buf, 1, MSG_DONTWAIT);
326
327 if (ret == 0) {
328 /* try to reconnect and send */
329 if (cfd != -1)
330 SAFE_CLOSE(cleanup, cfd);
331
332 cfd = client_connect_send(client_msg, client_msg_size);
333 if (cfd == -1) {
334 err = errno;
335 goto out;
336 }
337
338 if (client_recv(&cfd, buf)) {
339 err = errno;
340 break;
341 }
342
343 continue;
344
345 } else if (ret > 0) {
346 err = EMSGSIZE;
347 break;
348 }
349
350 if (verbose) {
351 tst_resm_hexd(TINFO, client_msg, client_msg_size,
352 "try to send msg[%d]", i);
353 }
354
355 if (send(cfd, client_msg, client_msg_size,
356 MSG_NOSIGNAL) != client_msg_size) {
357 err = ECOMM;
358 break;
359 }
360 if (client_recv(&cfd, buf)) {
361 err = errno;
362 break;
363 }
364 }
365
366 if (cfd != -1)
367 SAFE_CLOSE(cleanup, cfd);
368
369out:
370 return (void *) err;
371}
372
373union net_size_field {
374 char bytes[2];
375 uint16_t value;
376};
377
378static void make_client_request(void)
379{
380 client_msg[0] = start_byte;
381
382 /* set size for reply */
383 union net_size_field net_size;
384 net_size.value = htons(server_msg_size);
385 client_msg[1] = net_size.bytes[0];
386 client_msg[2] = net_size.bytes[1];
387
388 client_msg[client_msg_size - 1] = end_byte;
389}
390
391static int parse_client_request(const char *msg)
392{
393 union net_size_field net_size;
394 net_size.bytes[0] = msg[1];
395 net_size.bytes[1] = msg[2];
396 int size = ntohs(net_size.value);
397 if (size < 2 || size > max_msg_len)
398 return -1;
399
400 return size;
401}
402
403static struct timespec tv_client_start;
404static struct timespec tv_client_end;
405
406static void client_init(void)
407{
408 if (clients_num >= MAX_THREADS) {
409 tst_brkm(TBROK, cleanup,
410 "Unexpected num of clients '%d'",
411 clients_num);
412 }
413
414 thread_ids = SAFE_MALLOC(NULL, sizeof(pthread_t) * clients_num);
415
416 client_msg = SAFE_MALLOC(NULL, client_msg_size);
417 memset(client_msg, client_byte, client_msg_size);
418
419 make_client_request();
420
421 struct addrinfo hints;
422 memset(&hints, 0, sizeof(struct addrinfo));
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400423 hints.ai_socktype = SOCK_STREAM;
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400424 int err = getaddrinfo(server_addr, tcp_port, &hints, &remote_addrinfo);
425 if (err) {
426 tst_brkm(TBROK, cleanup, "getaddrinfo of '%s' failed, %s",
427 server_addr, gai_strerror(err));
428 }
429
430 tst_resm(TINFO, "TCP Fast Open over IPv%s",
431 (remote_addrinfo->ai_family == AF_INET6) ? "6" : "4");
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400432
433 clock_gettime(CLOCK_MONOTONIC_RAW, &tv_client_start);
434 int i;
435 for (i = 0; i < clients_num; ++i) {
436 if (pthread_create(&thread_ids[i], 0, client_fn, NULL) != 0) {
437 tst_brkm(TBROK | TERRNO, cleanup,
438 "pthread_create failed at %s:%d",
439 __FILE__, __LINE__);
440 }
441 }
442}
443
444static void client_run(void)
445{
446 void *res = NULL;
447 long clnt_time = 0;
448 int i;
449 for (i = 0; i < clients_num; ++i) {
450 pthread_join(thread_ids[i], &res);
451 if (res) {
452 tst_brkm(TBROK, cleanup, "client[%d] failed: %s",
453 i, strerror((intptr_t)res));
454 }
455 }
456
457 clock_gettime(CLOCK_MONOTONIC_RAW, &tv_client_end);
458 clnt_time = (tv_client_end.tv_sec - tv_client_start.tv_sec) * 1000 +
459 (tv_client_end.tv_nsec - tv_client_start.tv_nsec) / 1000000;
460
461 tst_resm(TINFO, "total time '%ld' ms", clnt_time);
462
463 /* ask server to terminate */
464 client_msg[0] = start_fin_byte;
465 int cfd = client_connect_send(client_msg, client_msg_size);
466 if (cfd != -1) {
467 shutdown(cfd, SHUT_WR);
468 SAFE_CLOSE(NULL, cfd);
469 }
470 /* the script tcp_fastopen_run.sh will remove it */
471 SAFE_FILE_PRINTF(cleanup, rpath, "%ld", clnt_time);
472}
473
474static void client_cleanup(void)
475{
476 free(thread_ids);
477
478 if (remote_addrinfo)
479 freeaddrinfo(remote_addrinfo);
480}
481
482static char *make_server_reply(int size)
483{
484 char *send_msg = SAFE_MALLOC(NULL, size);
485 memset(send_msg, server_byte, size - 1);
486 send_msg[0] = start_byte;
487 send_msg[size - 1] = end_byte;
488 return send_msg;
489}
490
491void *server_fn(void *cfd)
492{
493 int client_fd = (intptr_t) cfd;
494 int num_requests = 0, offset = 0;
495
496 /* Reply will be constructed from first client request */
497 char *send_msg = NULL;
498 int send_msg_size = 0;
499
500 char recv_msg[max_msg_len];
501
502 setsockopt(client_fd, SOL_SOCKET, SO_LINGER, &clo, sizeof(clo));
503 ssize_t recv_len;
504
505 while (1) {
506 recv_len = sock_recv_poll(client_fd, recv_msg,
507 max_msg_len, offset);
508
509 if (recv_len == 0)
510 break;
511
512 if (recv_len < 0 || (offset + recv_len) > max_msg_len ||
513 (recv_msg[0] != start_byte &&
514 recv_msg[0] != start_fin_byte)) {
515 tst_resm(TFAIL, "recv failed, sock '%d'", client_fd);
516 goto out;
517 }
518
519 offset += recv_len;
520
521 if (recv_msg[offset - 1] != end_byte) {
522 /* msg is not complete, continue recv */
523 continue;
524 }
525
526 /* client asks to terminate */
527 if (recv_msg[0] == start_fin_byte)
528 goto out;
529
530 if (verbose) {
531 tst_resm_hexd(TINFO, recv_msg, offset,
532 "msg recv from sock %d:", client_fd);
533 }
534
535 /* if we send reply for the first time, construct it here */
536 if (!send_msg) {
537 send_msg_size = parse_client_request(recv_msg);
538 if (send_msg_size < 0) {
539 tst_resm(TFAIL, "wrong msg size '%d'",
540 send_msg_size);
541 goto out;
542 }
543 send_msg = make_server_reply(send_msg_size);
544 }
545
546 /*
547 * It will tell client that server is going
548 * to close this connection.
549 */
550 if (++num_requests >= server_max_requests)
551 send_msg[0] = start_fin_byte;
552
553 if (send(client_fd, send_msg, send_msg_size,
554 MSG_NOSIGNAL) == -1) {
555 tst_resm(TFAIL | TERRNO, "send failed");
556 goto out;
557 }
558
559 offset = 0;
560
561 if (num_requests >= server_max_requests) {
562 /* max reqs, close socket */
563 shutdown(client_fd, SHUT_WR);
564 break;
565 }
566 }
567
568 free(send_msg);
569 SAFE_CLOSE(cleanup, client_fd);
570 return NULL;
571
572out:
573 free(send_msg);
574 SAFE_CLOSE(cleanup, client_fd);
575 cleanup();
576 tst_exit();
577}
578
579static void server_thread_add(intptr_t client_fd)
580{
581 pthread_t id;
582 if (pthread_create(&id, &attr, server_fn, (void *) client_fd)) {
583 tst_brkm(TBROK | TERRNO, cleanup,
584 "pthread_create failed at %s:%d", __FILE__, __LINE__);
585 }
586}
587
588static void server_init(void)
589{
590 struct addrinfo hints;
591 memset(&hints, 0, sizeof(struct addrinfo));
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400592 hints.ai_family = AF_INET6;
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400593 hints.ai_socktype = SOCK_STREAM;
594 hints.ai_flags = AI_PASSIVE;
595 if (getaddrinfo(NULL, tcp_port, &hints, &local_addrinfo) != 0)
596 tst_brkm(TBROK | TERRNO, cleanup, "getaddrinfo failed");
597
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400598 /* IPv6 socket is also able to access IPv4 protocol stack */
599 sfd = socket(AF_INET6, SOCK_STREAM, 0);
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400600 if (sfd == -1)
601 tst_brkm(TBROK, cleanup, "Failed to create a socket");
602
603 tst_resm(TINFO, "assigning a name to the server socket...");
604 if (!local_addrinfo)
605 tst_brkm(TBROK, cleanup, "failed to get the address");
606
607 while (bind(sfd, local_addrinfo->ai_addr,
608 local_addrinfo->ai_addrlen) == -1) {
609 usleep(100000);
610 }
611 tst_resm(TINFO, "the name assigned");
612
613 freeaddrinfo(local_addrinfo);
614
615 const int flag = 1;
616 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
617
618 if (fastopen_api == TFO_ENABLED) {
619 if (setsockopt(sfd, IPPROTO_TCP, TCP_FASTOPEN, &tfo_queue_size,
620 sizeof(tfo_queue_size)) == -1)
621 tst_brkm(TBROK, cleanup, "Can't set TFO sock. options");
622 }
623
624 listen(sfd, max_queue_len);
625 tst_resm(TINFO, "Listen on the socket '%d', port '%s'", sfd, tcp_port);
626}
627
628static void server_cleanup(void)
629{
630 SAFE_CLOSE(NULL, sfd);
631}
632
633static void server_run(void)
634{
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400635 /* IPv4 source address will be mapped to IPv6 address */
636 struct sockaddr_in6 addr6;
637 socklen_t addr_size = sizeof(addr6);
638
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400639 pthread_attr_init(&attr);
640
641 /*
642 * detaching threads allow to reclaim thread's resources
643 * once a thread finishes its work.
644 */
645 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
646 tst_brkm(TBROK | TERRNO, cleanup, "setdetachstate failed");
647
648 while (1) {
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400649 int client_fd = accept(sfd, (struct sockaddr *)&addr6,
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400650 &addr_size);
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400651
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400652 if (client_fd == -1)
653 tst_brkm(TBROK, cleanup, "Can't create client socket");
654
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400655 if (verbose) {
656 char addr_buf[INET6_ADDRSTRLEN];
657 tst_resm(TINFO, "conn: port '%d', addr '%s'",
658 addr6.sin6_port, inet_ntop(AF_INET6,
659 &addr6.sin6_addr, addr_buf, INET6_ADDRSTRLEN));
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400660 }
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400661
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400662 server_thread_add(client_fd);
663 }
664}
665
666static void check_opt(const char *name, char *arg, int *val, int lim)
667{
668 if (arg) {
669 if (sscanf(arg, "%i", val) != 1)
670 tst_brkm(TBROK, NULL, "-%s option arg is not a number",
671 name);
672 if (clients_num < lim)
673 tst_brkm(TBROK, NULL, "-%s option arg is less than %d",
674 name, lim);
675 }
676}
677
678static void check_opt_l(const char *name, char *arg, long *val, long lim)
679{
680 if (arg) {
681 if (sscanf(arg, "%ld", val) != 1)
682 tst_brkm(TBROK, NULL, "-%s option arg is not a number",
683 name);
684 if (clients_num < lim)
685 tst_brkm(TBROK, NULL, "-%s option arg is less than %ld",
686 name, lim);
687 }
688}
689
690static void setup(int argc, char *argv[])
691{
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200692 const char *msg;
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400693 msg = parse_opts(argc, argv, options, help);
694 if (msg != NULL)
695 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
696
697 /* if client_num is not set, use num of processors */
698 clients_num = sysconf(_SC_NPROCESSORS_ONLN);
699
700 check_opt("a", aarg, &clients_num, 1);
701 check_opt("r", rarg, &client_max_requests, 1);
702 check_opt("R", Rarg, &server_max_requests, 1);
703 check_opt("n", narg, &client_msg_size, 1);
704 check_opt("N", Narg, &server_msg_size, 1);
705 check_opt("q", qarg, &tfo_queue_size, 1);
706 check_opt_l("T", Targ, &wait_timeout, 0L);
707
708 if (!force_run)
709 tst_require_root(NULL);
710
711 if (!force_run && tst_kvercmp(3, 7, 0) < 0) {
712 tst_brkm(TCONF, NULL,
713 "Test must be run with kernel 3.7 or newer");
714 }
715
716 /* check tcp fast open knob */
717 if (!force_run && access(tfo_cfg, F_OK) == -1)
718 tst_brkm(TCONF, NULL, "Failed to find '%s'", tfo_cfg);
719
720 if (!force_run) {
721 SAFE_FILE_SCANF(NULL, tfo_cfg, "%d", &tfo_cfg_value);
722 tst_resm(TINFO, "'%s' is %d", tfo_cfg, tfo_cfg_value);
723 }
724
725 tst_sig(FORK, DEF_HANDLER, cleanup);
726
727 tst_resm(TINFO, "TCP %s is using %s TCP API.",
728 (tcp_mode == TCP_SERVER) ? "server" : "client",
729 (fastopen_api == TFO_ENABLED) ? "Fastopen" : "old");
730
731 switch (tcp_mode) {
732 case TCP_SERVER:
733 tst_resm(TINFO, "max requests '%d'",
734 server_max_requests);
735 tcp.init = server_init;
736 tcp.run = server_run;
737 tcp.cleanup = server_cleanup;
738 tfo_bit_num = 2;
739 break;
740 case TCP_CLIENT:
Alexey Kodanevbcf52392014-10-22 14:19:08 +0400741 tst_resm(TINFO, "connection: addr '%s', port '%s'",
742 server_addr, tcp_port);
Alexey Kodaneva8c23232014-04-15 14:45:26 +0400743 tst_resm(TINFO, "client max req: %d", client_max_requests);
744 tst_resm(TINFO, "clients num: %d", clients_num);
745 tst_resm(TINFO, "client msg size: %d", client_msg_size);
746 tst_resm(TINFO, "server msg size: %d", server_msg_size);
747
748 tcp.init = client_init;
749 tcp.run = client_run;
750 tcp.cleanup = client_cleanup;
751 tfo_bit_num = 1;
752 break;
753 }
754
755 tfo_support = TFO_ENABLED == tfo_support;
756 if (((tfo_cfg_value & tfo_bit_num) == tfo_bit_num) != tfo_support) {
757 int value = (tfo_cfg_value & ~tfo_bit_num)
758 | (tfo_support << (tfo_bit_num - 1));
759 tst_resm(TINFO, "set '%s' to '%d'", tfo_cfg, value);
760 SAFE_FILE_PRINTF(cleanup, tfo_cfg, "%d", value);
761 tfo_cfg_changed = 1;
762 }
763
764 int reuse_value = 0;
765 SAFE_FILE_SCANF(cleanup, tcp_tw_reuse, "%d", &reuse_value);
766 if (!reuse_value) {
767 SAFE_FILE_PRINTF(cleanup, tcp_tw_reuse, "1");
768 tw_reuse_changed = 1;
769 tst_resm(TINFO, "set '%s' to '1'", tcp_tw_reuse);
770 }
771
772 tst_resm(TINFO, "TFO support %s",
773 (tfo_support) ? "enabled" : "disabled");
774
775 tcp.init();
776}
777
778int main(int argc, char *argv[])
779{
780 setup(argc, argv);
781
782 tcp.run();
783
784 cleanup();
785
786 tst_exit();
787}