2 * Copyright (c) 2017-2021 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
20 #include <sys/types.h>
21 #include <sys/socket.h>
24 #include <arpa/inet.h>
25 #include <hs_apps/vcl/vcl_test.h>
31 vcl_test_session_t *sessions;
32 vcl_test_session_t *qsessions;
39 pthread_t thread_handle;
41 } vcl_test_client_worker_t;
45 vcl_test_client_worker_t *workers;
46 vppcom_endpt_t server_endpt;
48 vcl_test_session_t ctrl_session;
49 vcl_test_session_t *sessions;
54 volatile int active_workers;
55 volatile int test_running;
56 struct sockaddr_storage server_addr;
57 } vcl_test_client_main_t;
59 vcl_test_client_main_t vcl_client_main;
61 #define vtc_min(a, b) (a < b ? a : b)
62 #define vtc_max(a, b) (a > b ? a : b)
64 vcl_test_main_t vcl_test_main;
67 vtc_cfg_sync (vcl_test_session_t * ts)
69 vcl_test_cfg_t *rx_cfg = (vcl_test_cfg_t *) ts->rxbuf;
70 int rx_bytes, tx_bytes;
72 vt_atomic_add (&ts->cfg.seq_num, 1);
75 vtinf ("(fd %d): Sending config to server.", ts->fd);
76 vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
78 tx_bytes = ts->write (ts, &ts->cfg, sizeof (ts->cfg));
81 vtwrn ("(fd %d): write test cfg failed (%d)!", ts->fd, tx_bytes);
85 rx_bytes = ts->read (ts, ts->rxbuf, sizeof (vcl_test_cfg_t));
89 if (rx_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC)
91 vtwrn ("(fd %d): Bad server reply cfg -- aborting!", ts->fd);
94 if ((rx_bytes != sizeof (vcl_test_cfg_t))
95 || !vcl_test_cfg_verify (rx_cfg, &ts->cfg))
97 vtwrn ("(fd %d): Invalid config received from server!", ts->fd);
98 if (rx_bytes != sizeof (vcl_test_cfg_t))
100 vtinf ("\tRx bytes %d != cfg size %lu", rx_bytes,
101 sizeof (vcl_test_cfg_t));
105 vcl_test_cfg_dump (rx_cfg, 1 /* is_client */ );
106 vtinf ("(fd %d): Valid config sent to server.", ts->fd);
107 vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
113 vtinf ("(fd %d): Got config back from server.", ts->fd);
114 vcl_test_cfg_dump (rx_cfg, 1 /* is_client */ );
121 vtc_connect_test_sessions (vcl_test_client_worker_t * wrk)
123 vcl_test_client_main_t *vcm = &vcl_client_main;
124 vcl_test_main_t *vt = &vcl_test_main;
125 const vcl_test_proto_vft_t *tp;
126 vcl_test_session_t *ts;
127 uint32_t n_test_sessions;
130 n_test_sessions = wrk->cfg.num_test_sessions;
131 if (n_test_sessions < 1)
137 if (wrk->n_sessions >= n_test_sessions)
141 wrk->sessions = realloc (wrk->sessions,
142 n_test_sessions * sizeof (vcl_test_session_t));
144 wrk->sessions = calloc (n_test_sessions, sizeof (vcl_test_session_t));
148 vterr ("failed to alloc sessions", -errno);
152 tp = vt->protos[vcm->proto];
154 for (i = 0; i < n_test_sessions; i++)
156 ts = &wrk->sessions[i];
157 ts->session_index = i;
158 rv = tp->open (&wrk->sessions[i], &vcm->server_endpt);
162 wrk->n_sessions = n_test_sessions;
165 vtinf ("All test sessions (%d) connected!", n_test_sessions);
170 vtc_worker_test_setup (vcl_test_client_worker_t * wrk)
172 vcl_test_client_main_t *vcm = &vcl_client_main;
173 vcl_test_session_t *ctrl = &vcm->ctrl_session;
174 vcl_test_cfg_t *cfg = &wrk->cfg;
175 vcl_test_session_t *ts;
179 FD_ZERO (&wrk->wr_fdset);
180 FD_ZERO (&wrk->rd_fdset);
182 for (i = 0; i < cfg->num_test_sessions; i++)
184 ts = &wrk->sessions[i];
186 vcl_test_session_buf_alloc (ts);
190 case VCL_TEST_TYPE_ECHO:
191 memcpy (ts->txbuf, ctrl->txbuf, cfg->total_bytes);
193 case VCL_TEST_TYPE_UNI:
194 case VCL_TEST_TYPE_BI:
195 for (j = 0; j < ts->txbuf_size; j++)
196 ts->txbuf[j] = j & 0xff;
200 FD_SET (vppcom_session_index (ts->fd), &wrk->wr_fdset);
201 FD_SET (vppcom_session_index (ts->fd), &wrk->rd_fdset);
202 sidx = vppcom_session_index (ts->fd);
203 wrk->max_fd_index = vtc_max (sidx, wrk->max_fd_index);
205 wrk->max_fd_index += 1;
211 vtc_worker_init (vcl_test_client_worker_t * wrk)
213 vcl_test_client_main_t *vcm = &vcl_client_main;
214 vcl_test_cfg_t *cfg = &wrk->cfg;
215 vcl_test_session_t *ts;
219 __wrk_index = wrk->wrk_index;
221 vtinf ("Initializing worker %u ...", wrk->wrk_index);
225 if (vppcom_worker_register ())
227 vtwrn ("failed to register worker");
230 vt_atomic_add (&vcm->active_workers, 1);
232 rv = vtc_connect_test_sessions (wrk);
235 vterr ("vtc_connect_test_sessions ()", rv);
239 if (vtc_worker_test_setup (wrk))
242 for (n = 0; n < cfg->num_test_sessions; n++)
244 ts = &wrk->sessions[n];
245 memset (&ts->stats, 0, sizeof (ts->stats));
251 static int stats_lock = 0;
254 vtc_accumulate_stats (vcl_test_client_worker_t * wrk,
255 vcl_test_session_t * ctrl)
257 vcl_test_session_t *ts;
261 while (__sync_lock_test_and_set (&stats_lock, 1))
264 if (ctrl->cfg.test == VCL_TEST_TYPE_BI
265 || ctrl->cfg.test == VCL_TEST_TYPE_ECHO)
268 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
270 ts = &wrk->sessions[i];
271 ts->stats.start = ctrl->stats.start;
273 if (ctrl->cfg.verbose > 1)
275 snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", ts->fd);
276 vcl_test_stats_dump (buf, &ts->stats, show_rx, 1 /* show tx */ ,
280 vcl_test_stats_accumulate (&ctrl->stats, &ts->stats);
281 if (vcl_comp_tspec (&ctrl->stats.stop, &ts->stats.stop) < 0)
282 ctrl->stats.stop = ts->stats.stop;
285 __sync_lock_release (&stats_lock);
289 vtc_worker_sessions_exit (vcl_test_client_worker_t * wrk)
291 vcl_test_session_t *ts;
294 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
296 ts = &wrk->sessions[i];
297 vppcom_session_close (ts->fd);
304 vtc_worker_loop (void *arg)
306 vcl_test_client_main_t *vcm = &vcl_client_main;
307 vcl_test_session_t *ctrl = &vcm->ctrl_session;
308 vcl_test_client_worker_t *wrk = arg;
309 uint32_t n_active_sessions;
310 fd_set _wfdset, *wfdset = &_wfdset;
311 fd_set _rfdset, *rfdset = &_rfdset;
312 vcl_test_session_t *ts;
313 int i, rv, check_rx = 0;
315 rv = vtc_worker_init (wrk);
318 vterr ("vtc_worker_init()", rv);
322 vtinf ("Starting test ...");
324 if (wrk->wrk_index == 0)
325 clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
327 check_rx = wrk->cfg.test != VCL_TEST_TYPE_UNI;
328 n_active_sessions = wrk->cfg.num_test_sessions;
329 while (n_active_sessions && vcm->test_running)
331 _wfdset = wrk->wr_fdset;
332 _rfdset = wrk->rd_fdset;
334 rv = vppcom_select (wrk->max_fd_index, (unsigned long *) rfdset,
335 (unsigned long *) wfdset, NULL, 0);
338 vterr ("vppcom_select()", rv);
344 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
346 ts = &wrk->sessions[i];
347 if (!((ts->stats.stop.tv_sec == 0) &&
348 (ts->stats.stop.tv_nsec == 0)))
351 if (FD_ISSET (vppcom_session_index (ts->fd), rfdset)
352 && ts->stats.rx_bytes < ts->cfg.total_bytes)
354 rv = ts->read (ts, ts->rxbuf, ts->rxbuf_size);
359 if (FD_ISSET (vppcom_session_index (ts->fd), wfdset)
360 && ts->stats.tx_bytes < ts->cfg.total_bytes)
362 rv = ts->write (ts, ts->txbuf, ts->cfg.txbuf_size);
365 vtwrn ("vppcom_test_write (%d) failed -- aborting test",
370 if ((!check_rx && ts->stats.tx_bytes >= ts->cfg.total_bytes)
371 || (check_rx && ts->stats.rx_bytes >= ts->cfg.total_bytes))
373 clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
379 vtinf ("Worker %d done ...", wrk->wrk_index);
380 vtc_accumulate_stats (wrk, ctrl);
381 sleep (VCL_TEST_DELAY_DISCONNECT);
382 vtc_worker_sessions_exit (wrk);
384 vt_atomic_add (&vcm->active_workers, -1);
389 vtc_print_stats (vcl_test_session_t * ctrl)
391 int is_echo = ctrl->cfg.test == VCL_TEST_TYPE_ECHO;
395 if (ctrl->cfg.test == VCL_TEST_TYPE_BI
396 || ctrl->cfg.test == VCL_TEST_TYPE_ECHO)
399 vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
400 show_rx, 1 /* show tx */ ,
402 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
404 if (ctrl->cfg.verbose)
406 vtinf (" ctrl session info\n"
407 VCL_TEST_SEPARATOR_STRING
410 " rxbuf size: %u (0x%08x)\n"
412 " txbuf size: %u (0x%08x)\n"
413 VCL_TEST_SEPARATOR_STRING,
414 ctrl->fd, (uint32_t) ctrl->fd,
415 ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
416 ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
420 snprintf (buf, sizeof (buf), "Echo");
422 snprintf (buf, sizeof (buf), "%s-directional Stream",
423 ctrl->cfg.test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
427 vtc_echo_client (vcl_test_client_main_t * vcm)
429 vcl_test_session_t *ctrl = &vcm->ctrl_session;
430 vcl_test_cfg_t *cfg = &ctrl->cfg;
433 cfg->total_bytes = strlen (ctrl->txbuf) + 1;
434 memset (&ctrl->stats, 0, sizeof (ctrl->stats));
436 rv = ctrl->write (ctrl, ctrl->txbuf, cfg->total_bytes);
439 vtwrn ("vppcom_test_write (%d) failed ", ctrl->fd);
443 (void) ctrl->read (ctrl, ctrl->rxbuf, ctrl->rxbuf_size);
447 vtc_stream_client (vcl_test_client_main_t * vcm)
449 vcl_test_session_t *ctrl = &vcm->ctrl_session;
450 vcl_test_cfg_t *cfg = &ctrl->cfg;
451 vcl_test_client_worker_t *wrk;
452 uint32_t i, n_conn, n_conn_per_wrk;
454 vtinf ("%s-directional Stream Test Starting!",
455 ctrl->cfg.test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
457 cfg->total_bytes = cfg->num_writes * cfg->txbuf_size;
458 cfg->ctrl_handle = ctrl->fd;
460 n_conn = cfg->num_test_sessions;
461 n_conn_per_wrk = n_conn / vcm->n_workers;
462 for (i = 0; i < vcm->n_workers; i++)
464 wrk = &vcm->workers[i];
466 wrk->cfg = ctrl->cfg;
467 wrk->cfg.num_test_sessions = vtc_min (n_conn_per_wrk, n_conn);
468 n_conn -= wrk->cfg.num_test_sessions;
471 vcm->test_running = 1;
472 ctrl->cfg.cmd = VCL_TEST_CMD_START;
473 if (vtc_cfg_sync (ctrl))
475 vtwrn ("test cfg sync failed -- aborting!");
479 for (i = 1; i < vcm->n_workers; i++)
481 wrk = &vcm->workers[i];
482 pthread_create (&wrk->thread_handle, NULL, vtc_worker_loop,
485 vtc_worker_loop (&vcm->workers[0]);
487 while (vcm->active_workers > 0)
490 vtinf ("Sending config on ctrl session (fd %d) for stats...", ctrl->fd);
491 ctrl->cfg.cmd = VCL_TEST_CMD_STOP;
492 if (vtc_cfg_sync (ctrl))
494 vtwrn ("test cfg sync failed -- aborting!");
498 vtc_print_stats (ctrl);
500 ctrl->cfg.cmd = VCL_TEST_CMD_SYNC;
501 ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
502 ctrl->cfg.total_bytes = 0;
503 if (vtc_cfg_sync (ctrl))
504 vtwrn ("post-test cfg sync failed!");
508 cfg_txbuf_size_set (void)
510 vcl_test_client_main_t *vcm = &vcl_client_main;
511 vcl_test_session_t *ctrl = &vcm->ctrl_session;
512 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
513 uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
515 if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
517 ctrl->cfg.txbuf_size = txbuf_size;
518 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
519 vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
520 (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
521 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
524 vtwrn ("Invalid txbuf size (%lu) < minimum buf size (%u)!",
525 txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
529 cfg_num_writes_set (void)
531 vcl_test_client_main_t *vcm = &vcl_client_main;
532 vcl_test_session_t *ctrl = &vcm->ctrl_session;
533 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
534 uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
538 ctrl->cfg.num_writes = num_writes;
539 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
540 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
544 vtwrn ("invalid num writes: %u", num_writes);
549 cfg_num_test_sessions_set (void)
551 vcl_test_client_main_t *vcm = &vcl_client_main;
552 vcl_test_session_t *ctrl = &vcm->ctrl_session;
553 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
554 uint32_t num_test_sessions = strtoul ((const char *) p, NULL, 10);
556 if ((num_test_sessions > 0) &&
557 (num_test_sessions <= VCL_TEST_CFG_MAX_TEST_SESS))
559 ctrl->cfg.num_test_sessions = num_test_sessions;
560 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
564 vtwrn ("invalid num test sessions: %u, (%d max)",
565 num_test_sessions, VCL_TEST_CFG_MAX_TEST_SESS);
570 cfg_rxbuf_size_set (void)
572 vcl_test_client_main_t *vcm = &vcl_client_main;
573 vcl_test_session_t *ctrl = &vcm->ctrl_session;
574 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
575 uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
577 if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
579 ctrl->cfg.rxbuf_size = rxbuf_size;
580 vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
581 (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
582 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
585 vtwrn ("Invalid rxbuf size (%lu) < minimum buf size (%u)!",
586 rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
590 cfg_verbose_toggle (void)
592 vcl_test_client_main_t *vcm = &vcl_client_main;
593 vcl_test_session_t *ctrl = &vcm->ctrl_session;
595 ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
596 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
603 vcl_test_client_main_t *vcm = &vcl_client_main;
604 vcl_test_session_t *ctrl = &vcm->ctrl_session;
605 vcl_test_t rv = VCL_TEST_TYPE_NONE;
607 if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
608 strlen (VCL_TEST_TOKEN_EXIT)))
609 rv = VCL_TEST_TYPE_EXIT;
611 else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
612 strlen (VCL_TEST_TOKEN_HELP)))
615 else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
616 strlen (VCL_TEST_TOKEN_SHOW_CFG)))
619 else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
620 strlen (VCL_TEST_TOKEN_VERBOSE)))
621 cfg_verbose_toggle ();
623 else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
624 strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
625 cfg_txbuf_size_set ();
627 else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
628 strlen (VCL_TEST_TOKEN_NUM_TEST_SESS)))
629 cfg_num_test_sessions_set ();
631 else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
632 strlen (VCL_TEST_TOKEN_NUM_WRITES)))
633 cfg_num_writes_set ();
635 else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
636 strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
637 cfg_rxbuf_size_set ();
639 else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
640 strlen (VCL_TEST_TOKEN_RUN_UNI)))
641 rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
643 else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
644 strlen (VCL_TEST_TOKEN_RUN_BI)))
645 rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
648 rv = VCL_TEST_TYPE_ECHO;
654 print_usage_and_exit (void)
657 "vcl_test_client [OPTIONS] <ipaddr> <port>\n"
659 " -h Print this message and exit.\n"
661 " -c Print test config before test.\n"
662 " -w <dir> Write test results to <dir>.\n"
663 " -X Exit after running test.\n"
664 " -p <proto> Use <proto> transport layer\n"
665 " -D Use UDP transport layer\n"
666 " -L Use TLS transport layer\n"
667 " -E Run Echo test.\n"
668 " -N <num-writes> Test Cfg: number of writes.\n"
669 " -R <rxbuf-size> Test Cfg: rx buffer size.\n"
670 " -T <txbuf-size> Test Cfg: tx buffer size.\n"
671 " -U Run Uni-directional test.\n"
672 " -B Run Bi-directional test.\n"
673 " -V Verbose mode.\n"
674 " -I <N> Use N sessions.\n"
675 " -s <N> Use N sessions.\n"
676 " -q <n> QUIC : use N Ssessions on top of n Qsessions\n");
681 vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv)
683 vcl_test_session_t *ctrl = &vcm->ctrl_session;
687 while ((c = getopt (argc, argv, "chnp:w:XE:I:N:R:T:UBV6DLs:q:")) != -1)
694 case 'I': /* deprecated */
696 if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
697 if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
699 vtwrn ("Invalid value for option -%c!", c);
700 print_usage_and_exit ();
702 if (!ctrl->cfg.num_test_sessions ||
703 (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS))
705 vtwrn ("Invalid number of sessions (%d) specified for option -%c!"
706 "\n Valid range is 1 - %d",
707 ctrl->cfg.num_test_sessions, c,
708 VCL_TEST_CFG_MAX_TEST_SESS);
709 print_usage_and_exit ();
714 if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions_perq) != 1)
715 if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions_perq) != 1)
717 vtwrn ("Invalid value for option -%c!", c);
718 print_usage_and_exit ();
720 if (!ctrl->cfg.num_test_sessions_perq ||
721 (ctrl->cfg.num_test_sessions_perq > VCL_TEST_CFG_MAX_TEST_SESS))
723 vtwrn ("Invalid number of Stream sessions (%d) per Qsession"
724 "for option -%c!\nValid range is 1 - %d",
725 ctrl->cfg.num_test_sessions_perq, c,
726 VCL_TEST_CFG_MAX_TEST_SESS);
727 print_usage_and_exit ();
732 if (sscanf (optarg, "%d", &v) != 1)
734 vtwrn ("Invalid value for option -%c!", c);
735 print_usage_and_exit ();
742 vcm->post_test = VCL_TEST_TYPE_EXIT;
746 if (strlen (optarg) > ctrl->txbuf_size)
748 vtwrn ("Option -%c value larger than txbuf size (%d)!",
749 optopt, ctrl->txbuf_size);
750 print_usage_and_exit ();
752 strncpy (ctrl->txbuf, optarg, ctrl->txbuf_size);
753 ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
757 if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
758 if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
760 vtwrn ("Invalid value for option -%c!", c);
761 print_usage_and_exit ();
763 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
767 if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
768 if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
770 vtwrn ("Invalid value for option -%c!", c);
771 print_usage_and_exit ();
773 if (ctrl->cfg.rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
775 ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
776 vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
777 (uint8_t **) & ctrl->rxbuf,
782 vtwrn ("rxbuf size (%lu) less than minumum (%u)",
783 ctrl->cfg.rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
784 print_usage_and_exit ();
790 if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
791 if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
793 vtwrn ("Invalid value for option -%c!", c);
794 print_usage_and_exit ();
796 if (ctrl->cfg.txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
798 ctrl->txbuf_size = ctrl->cfg.txbuf_size;
799 vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
800 (uint8_t **) & ctrl->txbuf,
802 ctrl->cfg.total_bytes =
803 ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
807 vtwrn ("txbuf size (%lu) less than minumum (%u)!",
808 ctrl->cfg.txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
809 print_usage_and_exit ();
814 ctrl->cfg.test = VCL_TEST_TYPE_UNI;
818 ctrl->cfg.test = VCL_TEST_TYPE_BI;
822 ctrl->cfg.verbose = 1;
826 ctrl->cfg.address_ip6 = 1;
830 if (vppcom_unformat_proto (&vcm->proto, optarg))
831 vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
834 case 'D': /* deprecated */
835 vcm->proto = VPPCOM_PROTO_UDP;
838 case 'L': /* deprecated */
839 vcm->proto = VPPCOM_PROTO_TLS;
846 case 'I': /* deprecated */
853 vtwrn ("Option -%c requires an argument.", optopt);
857 if (isprint (optopt))
858 vtwrn ("Unknown option `-%c'.", optopt);
860 vtwrn ("Unknown option character `\\x%x'.", optopt);
865 print_usage_and_exit ();
868 if (argc < (optind + 2))
870 vtwrn ("Insufficient number of arguments!");
871 print_usage_and_exit ();
874 ctrl->cfg.num_test_qsessions = vcm->proto != VPPCOM_PROTO_QUIC ? 0 :
875 (ctrl->cfg.num_test_sessions + ctrl->cfg.num_test_sessions_perq - 1) /
876 ctrl->cfg.num_test_sessions_perq;
878 memset (&vcm->server_addr, 0, sizeof (vcm->server_addr));
879 if (ctrl->cfg.address_ip6)
881 struct sockaddr_in6 *sddr6 = (struct sockaddr_in6 *) &vcm->server_addr;
882 sddr6->sin6_family = AF_INET6;
883 inet_pton (AF_INET6, argv[optind++], &(sddr6->sin6_addr));
884 sddr6->sin6_port = htons (atoi (argv[optind]));
886 vcm->server_endpt.is_ip4 = 0;
887 vcm->server_endpt.ip = (uint8_t *) & sddr6->sin6_addr;
888 vcm->server_endpt.port = (uint16_t) sddr6->sin6_port;
892 struct sockaddr_in *saddr4 = (struct sockaddr_in *) &vcm->server_addr;
893 saddr4->sin_family = AF_INET;
894 inet_pton (AF_INET, argv[optind++], &(saddr4->sin_addr));
895 saddr4->sin_port = htons (atoi (argv[optind]));
897 vcm->server_endpt.is_ip4 = 1;
898 vcm->server_endpt.ip = (uint8_t *) & saddr4->sin_addr;
899 vcm->server_endpt.port = (uint16_t) saddr4->sin_port;
904 vtc_read_user_input (vcl_test_session_t * ctrl)
906 printf ("\nType some characters and hit <return>\n"
907 "('" VCL_TEST_TOKEN_HELP "' for help): ");
909 if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
911 if (strlen (ctrl->txbuf) == 1)
913 printf ("\nNothing to send! Please try again...\n");
916 ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline.
918 /* Parse input for keywords */
919 ctrl->cfg.test = parse_input ();
924 vtc_ctrl_session_exit (void)
926 vcl_test_client_main_t *vcm = &vcl_client_main;
927 vcl_test_session_t *ctrl = &vcm->ctrl_session;
928 int verbose = ctrl->cfg.verbose;
930 ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
931 vtinf ("(fd %d): Sending exit cfg to server...", ctrl->fd);
933 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
934 (void) vcl_test_write (ctrl, (uint8_t *) &ctrl->cfg, sizeof (ctrl->cfg));
939 vtc_ctrl_session_init (vcl_test_client_main_t *vcm, vcl_test_session_t *ctrl)
943 ctrl->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
946 vterr ("vppcom_session_create()", ctrl->fd);
950 vtinf ("Connecting to server...");
951 rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt);
954 vterr ("vppcom_session_connect()", rv);
957 vtinf ("Control session (fd %d) connected.", ctrl->fd);
959 ctrl->read = vcl_test_read;
960 ctrl->write = vcl_test_write;
962 ctrl->cfg.cmd = VCL_TEST_CMD_SYNC;
963 rv = vtc_cfg_sync (ctrl);
966 vterr ("vtc_cfg_sync()", rv);
970 ctrl->cfg.ctrl_handle = ((vcl_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
971 memset (&ctrl->stats, 0, sizeof (ctrl->stats));
977 vt_sigs_handler (int signum, siginfo_t *si, void *uc)
979 vcl_test_client_main_t *vcm = &vcl_client_main;
980 vcl_test_session_t *ctrl = &vcm->ctrl_session;
982 vcm->test_running = 0;
983 clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
987 vt_incercept_sigs (void)
991 memset (&sa, 0, sizeof (sa));
992 sa.sa_sigaction = vt_sigs_handler;
993 sa.sa_flags = SA_SIGINFO;
994 if (sigaction (SIGINT, &sa, 0))
996 vtwrn ("couldn't intercept sigint");
1002 main (int argc, char **argv)
1004 vcl_test_client_main_t *vcm = &vcl_client_main;
1005 vcl_test_session_t *ctrl = &vcm->ctrl_session;
1006 vcl_test_main_t *vt = &vcl_test_main;
1010 vcl_test_cfg_init (&ctrl->cfg);
1011 vcl_test_session_buf_alloc (ctrl);
1012 vtc_process_opts (vcm, argc, argv);
1013 vt_incercept_sigs ();
1015 vcm->workers = calloc (vcm->n_workers, sizeof (vcl_test_client_worker_t));
1016 vt->wrk = calloc (vcm->n_workers, sizeof (vcl_test_wrk_t));
1018 rv = vppcom_app_create ("vcl_test_client");
1020 vtfail ("vppcom_app_create()", rv);
1022 /* Protos like tls/dtls/quic need init */
1023 if (vt->protos[vcm->proto]->init)
1024 vt->protos[vcm->proto]->init (&ctrl->cfg);
1026 if ((rv = vtc_ctrl_session_init (vcm, ctrl)))
1027 vtfail ("vppcom_session_create() ctrl session", rv);
1029 /* Update ctrl port to data port */
1030 vcm->server_endpt.port += 1;
1032 while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
1036 vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1040 switch (ctrl->cfg.test)
1042 case VCL_TEST_TYPE_ECHO:
1043 vtc_echo_client (vcm);
1046 case VCL_TEST_TYPE_UNI:
1047 case VCL_TEST_TYPE_BI:
1048 vtc_stream_client (vcm);
1051 case VCL_TEST_TYPE_EXIT:
1054 case VCL_TEST_TYPE_NONE:
1058 switch (vcm->post_test)
1060 case VCL_TEST_TYPE_EXIT:
1061 switch (ctrl->cfg.test)
1063 case VCL_TEST_TYPE_EXIT:
1064 case VCL_TEST_TYPE_UNI:
1065 case VCL_TEST_TYPE_BI:
1066 case VCL_TEST_TYPE_ECHO:
1067 ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1070 case VCL_TEST_TYPE_NONE:
1076 case VCL_TEST_TYPE_NONE:
1077 case VCL_TEST_TYPE_ECHO:
1078 case VCL_TEST_TYPE_UNI:
1079 case VCL_TEST_TYPE_BI:
1084 memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1085 memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1087 vtc_read_user_input (ctrl);
1090 vtc_ctrl_session_exit ();
1091 vppcom_app_destroy ();
1092 free (vcm->workers);
1097 * fd.io coding-style-patch-verification: ON
1100 * eval: (c-set-style "gnu")