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>
29 typedef struct vtc_worker_ vcl_test_client_worker_t;
30 typedef int (vtc_worker_run_fn) (vcl_test_client_worker_t *wrk);
34 vcl_test_session_t *sessions;
35 vcl_test_session_t *qsessions;
49 struct epoll_event ep_evts[VCL_TEST_CFG_MAX_EPOLL_EVENTS];
50 vcl_test_session_t *next_to_send;
53 pthread_t thread_handle;
54 vtc_worker_run_fn *wrk_run_fn;
60 vcl_test_client_worker_t *workers;
61 vcl_test_session_t ctrl_session;
62 vppcom_endpt_t server_endpt;
67 uint8_t incremental_stats;
69 volatile int active_workers;
70 volatile int test_running;
76 } vcl_test_client_main_t;
78 vcl_test_client_main_t vcl_client_main;
80 #define vtc_min(a, b) (a < b ? a : b)
81 #define vtc_max(a, b) (a > b ? a : b)
83 vcl_test_main_t vcl_test_main;
86 vtc_cfg_sync (vcl_test_session_t * ts)
88 hs_test_cfg_t *rx_cfg = (hs_test_cfg_t *) ts->rxbuf;
89 int rx_bytes, tx_bytes;
91 vt_atomic_add (&ts->cfg.seq_num, 1);
94 vtinf ("(fd %d): Sending config to server.", ts->fd);
95 hs_test_cfg_dump (&ts->cfg, 1 /* is_client */);
97 tx_bytes = ts->write (ts, &ts->cfg, sizeof (ts->cfg));
100 vtwrn ("(fd %d): write test cfg failed (%d)!", ts->fd, tx_bytes);
104 rx_bytes = ts->read (ts, ts->rxbuf, sizeof (hs_test_cfg_t));
108 if (rx_cfg->magic != HS_TEST_CFG_CTRL_MAGIC)
110 vtwrn ("(fd %d): Bad server reply cfg -- aborting!", ts->fd);
113 if ((rx_bytes != sizeof (hs_test_cfg_t)) ||
114 !hs_test_cfg_verify (rx_cfg, &ts->cfg))
116 vtwrn ("(fd %d): Invalid config received from server!", ts->fd);
117 if (rx_bytes != sizeof (hs_test_cfg_t))
119 vtinf ("\tRx bytes %d != cfg size %lu", rx_bytes,
120 sizeof (hs_test_cfg_t));
124 hs_test_cfg_dump (rx_cfg, 1 /* is_client */);
125 vtinf ("(fd %d): Valid config sent to server.", ts->fd);
126 hs_test_cfg_dump (&ts->cfg, 1 /* is_client */);
132 vtinf ("(fd %d): Got config back from server.", ts->fd);
133 hs_test_cfg_dump (rx_cfg, 1 /* is_client */);
140 vtc_worker_alloc_sessions (vcl_test_client_worker_t *wrk)
142 vcl_test_session_t *ts;
143 uint32_t n_test_sessions;
147 n_test_sessions = wrk->cfg.num_test_sessions;
148 if (n_test_sessions < 1)
154 if (wrk->n_sessions >= n_test_sessions)
158 wrk->sessions = realloc (wrk->sessions,
159 n_test_sessions * sizeof (vcl_test_session_t));
161 wrk->sessions = calloc (n_test_sessions, sizeof (vcl_test_session_t));
165 vterr ("failed to alloc sessions", -errno);
169 clock_gettime (CLOCK_REALTIME, &now);
171 for (i = 0; i < n_test_sessions; i++)
173 ts = &wrk->sessions[i];
174 memset (ts, 0, sizeof (*ts));
175 ts->session_index = i;
176 ts->old_stats.stop = now;
178 vcl_test_session_buf_alloc (ts);
180 switch (ts->cfg.test)
182 case HS_TEST_TYPE_UNI:
183 case HS_TEST_TYPE_BI:
184 for (j = 0; j < ts->txbuf_size; j++)
185 ts->txbuf[j] = j & 0xff;
191 wrk->n_sessions = n_test_sessions;
195 vtinf ("All test sessions (%d) initialized!", n_test_sessions);
201 vtc_worker_init (vcl_test_client_worker_t * wrk)
203 vcl_test_client_main_t *vcm = &vcl_client_main;
206 __wrk_index = wrk->wrk_index;
208 vtinf ("Initializing worker %u ...", wrk->wrk_index);
212 if (vppcom_worker_register ())
214 vtwrn ("failed to register worker");
217 vt_atomic_add (&vcm->active_workers, 1);
219 rv = vtc_worker_alloc_sessions (wrk);
222 vterr ("vtc_worker_alloc_sessions ()", rv);
229 static int stats_lock = 0;
232 vtc_accumulate_stats (vcl_test_client_worker_t * wrk,
233 vcl_test_session_t * ctrl)
235 vcl_test_session_t *ts;
239 while (__sync_lock_test_and_set (&stats_lock, 1))
242 if (ctrl->cfg.test == HS_TEST_TYPE_BI || ctrl->cfg.test == HS_TEST_TYPE_ECHO)
245 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
247 ts = &wrk->sessions[i];
248 ts->stats.start = ctrl->stats.start;
250 if (ctrl->cfg.verbose > 1)
252 snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", ts->fd);
253 vcl_test_stats_dump (buf, &ts->stats, show_rx, 1 /* show tx */ ,
257 vcl_test_stats_accumulate (&ctrl->stats, &ts->stats);
258 if (vcl_comp_tspec (&ctrl->stats.stop, &ts->stats.stop) < 0)
259 ctrl->stats.stop = ts->stats.stop;
262 __sync_lock_release (&stats_lock);
266 vtc_worker_sessions_exit (vcl_test_client_worker_t * wrk)
268 vcl_test_session_t *ts;
271 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
273 ts = &wrk->sessions[i];
274 vppcom_session_close (ts->fd);
275 vcl_test_session_buf_free (ts);
282 vtc_inc_stats_check (vcl_test_session_t *ts)
284 /* Avoid checking time too often because of syscall cost */
285 if (ts->stats.tx_bytes - ts->old_stats.tx_bytes < 1 << 20)
288 clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
289 if (vcl_test_time_diff (&ts->old_stats.stop, &ts->stats.stop) > 1)
291 vcl_test_stats_dump_inc (ts, 0 /* is_rx */);
292 ts->old_stats = ts->stats;
297 vtc_worker_start_transfer (vcl_test_client_worker_t *wrk)
299 vtinf ("Worker %u starting transfer ...", wrk->wrk_index);
301 if (wrk->wrk_index == 0)
303 vcl_test_client_main_t *vcm = &vcl_client_main;
304 vcl_test_session_t *ctrl = &vcm->ctrl_session;
306 clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
311 vtc_session_check_is_done (vcl_test_session_t *ts, uint8_t check_rx)
313 if ((!check_rx && ts->stats.tx_bytes >= ts->cfg.total_bytes) ||
314 (check_rx && ts->stats.rx_bytes >= ts->cfg.total_bytes))
316 clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
324 vtc_worker_connect_sessions_select (vcl_test_client_worker_t *wrk)
326 vcl_test_client_main_t *vcm = &vcl_client_main;
327 vcl_test_main_t *vt = &vcl_test_main;
328 const vcl_test_proto_vft_t *tp;
329 vcl_test_session_t *ts;
333 tp = vt->protos[vcm->proto];
335 FD_ZERO (&wrk->wr_fdset);
336 FD_ZERO (&wrk->rd_fdset);
338 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
340 ts = &wrk->sessions[i];
342 rv = tp->open (&wrk->sessions[i], &vcm->server_endpt);
346 FD_SET (vppcom_session_index (ts->fd), &wrk->wr_fdset);
347 FD_SET (vppcom_session_index (ts->fd), &wrk->rd_fdset);
348 sidx = vppcom_session_index (ts->fd);
349 wrk->max_fd_index = vtc_max (sidx, wrk->max_fd_index);
351 wrk->max_fd_index += 1;
353 vtinf ("All test sessions (%d) connected!", wrk->cfg.num_test_sessions);
359 vtc_worker_run_select (vcl_test_client_worker_t *wrk)
361 vcl_test_client_main_t *vcm = &vcl_client_main;
362 fd_set _wfdset, *wfdset = &_wfdset;
363 fd_set _rfdset, *rfdset = &_rfdset;
364 uint32_t n_active_sessions;
365 vcl_test_session_t *ts;
366 int i, rv, check_rx = 0;
368 rv = vtc_worker_connect_sessions_select (wrk);
371 vterr ("vtc_worker_connect_sessions()", rv);
375 check_rx = wrk->cfg.test != HS_TEST_TYPE_UNI;
376 n_active_sessions = wrk->cfg.num_test_sessions;
378 vtc_worker_start_transfer (wrk);
380 while (n_active_sessions && vcm->test_running)
382 _wfdset = wrk->wr_fdset;
383 _rfdset = wrk->rd_fdset;
385 rv = vppcom_select (wrk->max_fd_index, (unsigned long *) rfdset,
386 (unsigned long *) wfdset, NULL, 0);
389 vterr ("vppcom_select()", rv);
395 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
397 ts = &wrk->sessions[i];
401 if (FD_ISSET (vppcom_session_index (ts->fd), rfdset) &&
402 ts->stats.rx_bytes < ts->cfg.total_bytes)
404 rv = ts->read (ts, ts->rxbuf, ts->rxbuf_size);
409 if (FD_ISSET (vppcom_session_index (ts->fd), wfdset) &&
410 ts->stats.tx_bytes < ts->cfg.total_bytes)
412 rv = ts->write (ts, ts->txbuf, ts->cfg.txbuf_size);
415 vtwrn ("vppcom_test_write (%d) failed -- aborting test",
419 if (vcm->incremental_stats)
420 vtc_inc_stats_check (ts);
422 if ((!check_rx && ts->stats.tx_bytes >= ts->cfg.total_bytes) ||
423 (check_rx && ts->stats.rx_bytes >= ts->cfg.total_bytes))
425 clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
436 vtc_worker_epoll_send_add (vcl_test_client_worker_t *wrk,
437 vcl_test_session_t *ts)
439 if (!wrk->next_to_send)
441 wrk->next_to_send = ts;
445 ts->next = wrk->next_to_send;
446 wrk->next_to_send = ts->next;
451 vtc_worker_epoll_send_del (vcl_test_client_worker_t *wrk,
452 vcl_test_session_t *ts, vcl_test_session_t *prev)
456 wrk->next_to_send = ts->next;
460 prev->next = ts->next;
465 vtc_worker_connect_sessions_epoll (vcl_test_client_worker_t *wrk)
467 vcl_test_client_main_t *vcm = &vcl_client_main;
468 vcl_test_main_t *vt = &vcl_test_main;
469 const vcl_test_proto_vft_t *tp;
470 struct timespec start, end;
471 uint32_t n_connected = 0;
472 vcl_test_session_t *ts;
473 struct epoll_event ev;
474 int i, ci = 0, rv, n_ev;
477 tp = vt->protos[vcm->proto];
478 wrk->epoll_sh = vppcom_epoll_create ();
480 ev.events = EPOLLET | EPOLLOUT;
482 clock_gettime (CLOCK_REALTIME, &start);
484 while (n_connected < wrk->cfg.num_test_sessions)
487 * Try to connect more sessions if under pending threshold
489 while ((ci - n_connected) < 16 && ci < wrk->cfg.num_test_sessions)
491 ts = &wrk->sessions[ci];
492 ts->noblk_connect = 1;
493 rv = tp->open (&wrk->sessions[ci], &vcm->server_endpt);
496 vtwrn ("open: %d", rv);
501 rv = vppcom_epoll_ctl (wrk->epoll_sh, EPOLL_CTL_ADD, ts->fd, &ev);
504 vtwrn ("vppcom_epoll_ctl: %d", rv);
511 * Handle connected events
514 vppcom_epoll_wait (wrk->epoll_sh, wrk->ep_evts,
515 VCL_TEST_CFG_MAX_EPOLL_EVENTS, 0 /* timeout */);
518 vterr ("vppcom_epoll_wait() returned", n_ev);
526 for (i = 0; i < n_ev; i++)
528 ts = &wrk->sessions[wrk->ep_evts[i].data.u32];
529 if (!(wrk->ep_evts[i].events & EPOLLOUT))
531 vtwrn ("connect failed");
536 vtwrn ("connection already open?");
544 clock_gettime (CLOCK_REALTIME, &end);
546 diff = vcl_test_time_diff (&start, &end);
547 vtinf ("Connected (%u) connected in %.2f seconds (%u CPS)!",
548 wrk->cfg.num_test_sessions, diff,
549 (uint32_t) ((double) wrk->cfg.num_test_sessions / diff));
551 ev.events = EPOLLET | EPOLLIN | EPOLLOUT;
553 for (i = 0; i < wrk->cfg.num_test_sessions; i++)
555 ts = &wrk->sessions[i];
557 /* No data to be sent */
558 if (ts->cfg.total_bytes == 0)
561 clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
567 rv = vppcom_epoll_ctl (wrk->epoll_sh, EPOLL_CTL_MOD, ts->fd, &ev);
570 vtwrn ("vppcom_epoll_ctl: %d", rv);
573 vtc_worker_epoll_send_add (wrk, ts);
580 vtc_worker_run_epoll (vcl_test_client_worker_t *wrk)
582 vcl_test_client_main_t *vcm = &vcl_client_main;
583 uint32_t n_active_sessions, max_writes = 16, n_writes = 0;
584 vcl_test_session_t *ts, *prev = 0;
585 int i, rv, check_rx = 0, n_ev;
587 rv = vtc_worker_connect_sessions_epoll (wrk);
590 vterr ("vtc_worker_connect_sessions()", rv);
594 n_active_sessions = rv;
595 check_rx = wrk->cfg.test != HS_TEST_TYPE_UNI;
597 vtc_worker_start_transfer (wrk);
598 ts = wrk->next_to_send;
600 while (n_active_sessions && vcm->test_running)
607 ts = wrk->next_to_send;
612 rv = ts->write (ts, ts->txbuf, ts->cfg.txbuf_size);
615 if (vcm->incremental_stats)
616 vtc_inc_stats_check (ts);
617 if (vtc_session_check_is_done (ts, check_rx))
618 n_active_sessions -= 1;
622 vtc_worker_epoll_send_del (wrk, ts, prev);
626 vtwrn ("vppcom_test_write (%d) failed -- aborting test", ts->fd);
633 if (rv > 0 && n_writes < max_writes)
643 vppcom_epoll_wait (wrk->epoll_sh, wrk->ep_evts,
644 VCL_TEST_CFG_MAX_EPOLL_EVENTS, 0 /* timeout */);
647 vterr ("vppcom_epoll_wait()", n_ev);
655 for (i = 0; i < n_ev; i++)
657 ts = &wrk->sessions[wrk->ep_evts[i].data.u32];
662 if (wrk->ep_evts[i].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP))
664 vtinf ("%u finished before reading all data?", ts->fd);
667 if ((wrk->ep_evts[i].events & EPOLLIN) &&
668 ts->stats.rx_bytes < ts->cfg.total_bytes)
670 rv = ts->read (ts, ts->rxbuf, ts->rxbuf_size);
673 if (vtc_session_check_is_done (ts, check_rx))
674 n_active_sessions -= 1;
676 if ((wrk->ep_evts[i].events & EPOLLOUT) &&
677 ts->stats.tx_bytes < ts->cfg.total_bytes)
679 vtc_worker_epoll_send_add (wrk, ts);
690 vtc_worker_run (vcl_test_client_worker_t *wrk)
694 vtinf ("Worker %u starting test ...", wrk->wrk_index);
696 rv = wrk->wrk_run_fn (wrk);
698 vtinf ("Worker %d done ...", wrk->wrk_index);
704 vtc_worker_loop (void *arg)
706 vcl_test_client_main_t *vcm = &vcl_client_main;
707 vcl_test_session_t *ctrl = &vcm->ctrl_session;
708 vcl_test_client_worker_t *wrk = arg;
710 if (vtc_worker_init (wrk))
713 if (vtc_worker_run (wrk))
716 vtc_accumulate_stats (wrk, ctrl);
717 sleep (VCL_TEST_DELAY_DISCONNECT);
718 vtc_worker_sessions_exit (wrk);
723 vt_atomic_add (&vcm->active_workers, -1);
729 vtc_print_stats (vcl_test_session_t * ctrl)
731 int is_echo = ctrl->cfg.test == HS_TEST_TYPE_ECHO;
735 if (ctrl->cfg.test == HS_TEST_TYPE_BI || ctrl->cfg.test == HS_TEST_TYPE_ECHO)
738 vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
739 show_rx, 1 /* show tx */ ,
741 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
743 if (ctrl->cfg.verbose)
745 vtinf (" ctrl session info\n" HS_TEST_SEPARATOR_STRING
748 " rxbuf size: %u (0x%08x)\n"
750 " txbuf size: %u (0x%08x)\n" HS_TEST_SEPARATOR_STRING,
751 ctrl->fd, (uint32_t) ctrl->fd, ctrl->rxbuf, ctrl->rxbuf_size,
752 ctrl->rxbuf_size, ctrl->txbuf, ctrl->txbuf_size,
757 snprintf (buf, sizeof (buf), "Echo");
759 snprintf (buf, sizeof (buf), "%s-directional Stream",
760 ctrl->cfg.test == HS_TEST_TYPE_BI ? "Bi" : "Uni");
764 vtc_echo_client (vcl_test_client_main_t * vcm)
766 vcl_test_session_t *ctrl = &vcm->ctrl_session;
767 hs_test_cfg_t *cfg = &ctrl->cfg;
770 cfg->total_bytes = strlen (ctrl->txbuf) + 1;
771 memset (&ctrl->stats, 0, sizeof (ctrl->stats));
773 rv = ctrl->write (ctrl, ctrl->txbuf, cfg->total_bytes);
776 vtwrn ("vppcom_test_write (%d) failed ", ctrl->fd);
780 (void) ctrl->read (ctrl, ctrl->rxbuf, ctrl->rxbuf_size);
784 vtc_stream_client (vcl_test_client_main_t * vcm)
786 vcl_test_session_t *ctrl = &vcm->ctrl_session;
787 hs_test_cfg_t *cfg = &ctrl->cfg;
788 vcl_test_client_worker_t *wrk;
789 uint32_t i, n_conn, n_conn_per_wrk;
791 vtinf ("%s-directional Stream Test Starting!",
792 ctrl->cfg.test == HS_TEST_TYPE_BI ? "Bi" : "Uni");
794 memset (&ctrl->stats, 0, sizeof (vcl_test_stats_t));
795 cfg->total_bytes = cfg->num_writes * cfg->txbuf_size;
796 cfg->ctrl_handle = ctrl->fd;
798 n_conn = cfg->num_test_sessions;
799 n_conn_per_wrk = n_conn / vcm->n_workers;
800 for (i = 0; i < vcm->n_workers; i++)
802 wrk = &vcm->workers[i];
804 wrk->cfg = ctrl->cfg;
805 wrk->cfg.num_test_sessions = vtc_min (n_conn_per_wrk, n_conn);
806 n_conn -= wrk->cfg.num_test_sessions;
809 vcm->test_running = 1;
810 ctrl->cfg.cmd = HS_TEST_CMD_START;
811 if (vtc_cfg_sync (ctrl))
813 vtwrn ("test cfg sync failed -- aborting!");
817 for (i = 1; i < vcm->n_workers; i++)
819 wrk = &vcm->workers[i];
820 if (pthread_create (&wrk->thread_handle, NULL, vtc_worker_loop,
823 vtwrn ("pthread_create failed -- aborting!");
827 vtc_worker_loop (&vcm->workers[0]);
829 while (vcm->active_workers > 0)
832 vtinf ("Sending config on ctrl session (fd %d) for stats...", ctrl->fd);
833 ctrl->cfg.cmd = HS_TEST_CMD_STOP;
834 if (vtc_cfg_sync (ctrl))
836 vtwrn ("test cfg sync failed -- aborting!");
840 vtc_print_stats (ctrl);
842 ctrl->cfg.cmd = HS_TEST_CMD_SYNC;
843 ctrl->cfg.test = HS_TEST_TYPE_ECHO;
844 ctrl->cfg.total_bytes = 0;
845 if (vtc_cfg_sync (ctrl))
846 vtwrn ("post-test cfg sync failed!");
850 cfg_txbuf_size_set (void)
852 vcl_test_client_main_t *vcm = &vcl_client_main;
853 vcl_test_session_t *ctrl = &vcm->ctrl_session;
854 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
855 uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
857 if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
859 ctrl->cfg.txbuf_size = txbuf_size;
860 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
861 vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
862 (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
863 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
866 vtwrn ("Invalid txbuf size (%lu) < minimum buf size (%u)!",
867 txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
871 cfg_num_writes_set (void)
873 vcl_test_client_main_t *vcm = &vcl_client_main;
874 vcl_test_session_t *ctrl = &vcm->ctrl_session;
875 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
876 uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
880 ctrl->cfg.num_writes = num_writes;
881 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
882 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
886 vtwrn ("invalid num writes: %u", num_writes);
891 cfg_num_test_sessions_set (void)
893 vcl_test_client_main_t *vcm = &vcl_client_main;
894 vcl_test_session_t *ctrl = &vcm->ctrl_session;
895 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
896 uint32_t num_test_sessions = strtoul ((const char *) p, NULL, 10);
898 if ((num_test_sessions > 0) &&
899 (num_test_sessions <= VCL_TEST_CFG_MAX_TEST_SESS))
901 ctrl->cfg.num_test_sessions = num_test_sessions;
902 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
906 vtwrn ("invalid num test sessions: %u, (%d max)",
907 num_test_sessions, VCL_TEST_CFG_MAX_TEST_SESS);
912 cfg_rxbuf_size_set (void)
914 vcl_test_client_main_t *vcm = &vcl_client_main;
915 vcl_test_session_t *ctrl = &vcm->ctrl_session;
916 char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
917 uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
919 if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
921 ctrl->cfg.rxbuf_size = rxbuf_size;
922 vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
923 (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
924 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
927 vtwrn ("Invalid rxbuf size (%lu) < minimum buf size (%u)!",
928 rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
932 cfg_verbose_toggle (void)
934 vcl_test_client_main_t *vcm = &vcl_client_main;
935 vcl_test_session_t *ctrl = &vcm->ctrl_session;
937 ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
938 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
944 vcl_test_client_main_t *vcm = &vcl_client_main;
945 vcl_test_session_t *ctrl = &vcm->ctrl_session;
946 hs_test_t rv = HS_TEST_TYPE_NONE;
948 if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
949 strlen (VCL_TEST_TOKEN_EXIT)))
950 rv = HS_TEST_TYPE_EXIT;
952 else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
953 strlen (VCL_TEST_TOKEN_HELP)))
956 else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
957 strlen (VCL_TEST_TOKEN_SHOW_CFG)))
960 else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
961 strlen (VCL_TEST_TOKEN_VERBOSE)))
962 cfg_verbose_toggle ();
964 else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
965 strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
966 cfg_txbuf_size_set ();
968 else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
969 strlen (VCL_TEST_TOKEN_NUM_TEST_SESS)))
970 cfg_num_test_sessions_set ();
972 else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
973 strlen (VCL_TEST_TOKEN_NUM_WRITES)))
974 cfg_num_writes_set ();
976 else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
977 strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
978 cfg_rxbuf_size_set ();
980 else if (!strncmp (HS_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
981 strlen (HS_TEST_TOKEN_RUN_UNI)))
982 rv = ctrl->cfg.test = HS_TEST_TYPE_UNI;
984 else if (!strncmp (HS_TEST_TOKEN_RUN_BI, ctrl->txbuf,
985 strlen (HS_TEST_TOKEN_RUN_BI)))
986 rv = ctrl->cfg.test = HS_TEST_TYPE_BI;
989 rv = HS_TEST_TYPE_ECHO;
995 print_usage_and_exit (void)
999 "vcl_test_client [OPTIONS] <ipaddr> <port>\n"
1001 " -h Print this message and exit.\n"
1003 " -c Print test config before test.\n"
1004 " -w <dir> Write test results to <dir>.\n"
1005 " -X Exit after running test.\n"
1006 " -p <proto> Use <proto> transport layer\n"
1007 " -D Use UDP transport layer\n"
1008 " -L Use TLS transport layer\n"
1009 " -E Run Echo test.\n"
1010 " -N <num-writes> Test Cfg: number of writes.\n"
1011 " -R <rxbuf-size> Test Cfg: rx buffer size.\n"
1012 " -T <txbuf-size> Test Cfg: tx buffer size.\n"
1013 " -U Run Uni-directional test.\n"
1014 " -B Run Bi-directional test.\n"
1015 " -b <bytes> Total number of bytes transferred\n"
1016 " -V Verbose mode.\n"
1017 " -I <N> Use N sessions.\n"
1018 " -s <N> Use N sessions.\n"
1019 " -S Print incremental stats per session.\n"
1020 " -q <n> QUIC : use N Ssessions on top of n Qsessions\n");
1025 vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv)
1027 vcl_test_session_t *ctrl = &vcm->ctrl_session;
1031 while ((c = getopt (argc, argv, "chnp:w:xXE:I:N:R:T:b:UBV6DLs:q:S")) != -1)
1038 case 'I': /* deprecated */
1040 if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
1041 if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
1043 vtwrn ("Invalid value for option -%c!", c);
1044 print_usage_and_exit ();
1046 if (!ctrl->cfg.num_test_sessions ||
1047 (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS))
1049 vtwrn ("Invalid number of sessions (%d) specified for option -%c!"
1050 "\n Valid range is 1 - %d",
1051 ctrl->cfg.num_test_sessions, c,
1052 VCL_TEST_CFG_MAX_TEST_SESS);
1053 print_usage_and_exit ();
1058 if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions_perq) != 1)
1059 if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions_perq) != 1)
1061 vtwrn ("Invalid value for option -%c!", c);
1062 print_usage_and_exit ();
1064 if (!ctrl->cfg.num_test_sessions_perq ||
1065 (ctrl->cfg.num_test_sessions_perq > VCL_TEST_CFG_MAX_TEST_SESS))
1067 vtwrn ("Invalid number of Stream sessions (%d) per Qsession"
1068 "for option -%c!\nValid range is 1 - %d",
1069 ctrl->cfg.num_test_sessions_perq, c,
1070 VCL_TEST_CFG_MAX_TEST_SESS);
1071 print_usage_and_exit ();
1076 if (sscanf (optarg, "%d", &v) != 1)
1078 vtwrn ("Invalid value for option -%c!", c);
1079 print_usage_and_exit ();
1086 vcm->post_test = HS_TEST_TYPE_EXIT;
1090 vcm->post_test = HS_TEST_TYPE_NONE;
1094 if (strlen (optarg) > ctrl->txbuf_size)
1096 vtwrn ("Option -%c value larger than txbuf size (%d)!",
1097 optopt, ctrl->txbuf_size);
1098 print_usage_and_exit ();
1100 strncpy (ctrl->txbuf, optarg, ctrl->txbuf_size);
1101 ctrl->cfg.test = HS_TEST_TYPE_ECHO;
1105 if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
1106 if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
1108 vtwrn ("Invalid value for option -%c!", c);
1109 print_usage_and_exit ();
1111 ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
1115 if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
1116 if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
1118 vtwrn ("Invalid value for option -%c!", c);
1119 print_usage_and_exit ();
1121 if (ctrl->cfg.rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
1123 ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
1124 vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
1125 (uint8_t **) & ctrl->rxbuf,
1130 vtwrn ("rxbuf size (%lu) less than minumum (%u)",
1131 ctrl->cfg.rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
1132 print_usage_and_exit ();
1138 if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
1139 if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
1141 vtwrn ("Invalid value for option -%c!", c);
1142 print_usage_and_exit ();
1144 if (ctrl->cfg.txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
1146 ctrl->txbuf_size = ctrl->cfg.txbuf_size;
1147 vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
1148 (uint8_t **) & ctrl->txbuf,
1150 ctrl->cfg.total_bytes =
1151 ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
1155 vtwrn ("txbuf size (%lu) less than minumum (%u)!",
1156 ctrl->cfg.txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
1157 print_usage_and_exit ();
1161 if (sscanf (optarg, "0x%lu", &ctrl->cfg.total_bytes) != 1)
1162 if (sscanf (optarg, "%ld", &ctrl->cfg.total_bytes) != 1)
1164 vtwrn ("Invalid value for option -%c!", c);
1165 print_usage_and_exit ();
1167 if (ctrl->cfg.total_bytes % ctrl->cfg.txbuf_size)
1169 vtwrn ("total bytes must be mutliple of txbuf size(0x%lu)!",
1170 ctrl->cfg.txbuf_size);
1171 print_usage_and_exit ();
1173 ctrl->cfg.num_writes = ctrl->cfg.total_bytes / ctrl->cfg.txbuf_size;
1177 ctrl->cfg.test = HS_TEST_TYPE_UNI;
1181 ctrl->cfg.test = HS_TEST_TYPE_BI;
1185 ctrl->cfg.verbose = 1;
1189 ctrl->cfg.address_ip6 = 1;
1193 if (vppcom_unformat_proto (&vcm->proto, optarg))
1194 vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
1197 case 'D': /* deprecated */
1198 vcm->proto = VPPCOM_PROTO_UDP;
1201 case 'L': /* deprecated */
1202 vcm->proto = VPPCOM_PROTO_TLS;
1206 vcm->incremental_stats = 1;
1213 case 'I': /* deprecated */
1220 vtwrn ("Option -%c requires an argument.", optopt);
1224 if (isprint (optopt))
1225 vtwrn ("Unknown option `-%c'.", optopt);
1227 vtwrn ("Unknown option character `\\x%x'.", optopt);
1232 print_usage_and_exit ();
1235 if (argc > (optind + 2))
1237 vtwrn ("Invalid number of arguments!");
1238 print_usage_and_exit ();
1241 ctrl->cfg.num_test_qsessions = vcm->proto != VPPCOM_PROTO_QUIC ? 0 :
1242 (ctrl->cfg.num_test_sessions + ctrl->cfg.num_test_sessions_perq - 1) /
1243 ctrl->cfg.num_test_sessions_perq;
1245 memset (&vcm->server_addr, 0, sizeof (vcm->server_addr));
1246 if (ctrl->cfg.address_ip6)
1248 struct in6_addr *in6 = &vcm->server_addr.v6;
1249 inet_pton (AF_INET6, argv[optind++], in6);
1251 vcm->server_endpt.is_ip4 = 0;
1252 vcm->server_endpt.ip = (uint8_t *) in6;
1256 struct in_addr *in4 = &vcm->server_addr.v4;
1257 inet_pton (AF_INET, argv[optind++], in4);
1259 vcm->server_endpt.is_ip4 = 1;
1260 vcm->server_endpt.ip = (uint8_t *) in4;
1263 if (argc == optind + 1)
1264 vcm->server_endpt.port = htons (atoi (argv[optind]));
1266 vcm->server_endpt.port = htons (VCL_TEST_SERVER_PORT);
1270 vtc_read_user_input (vcl_test_session_t * ctrl)
1272 printf ("\nType some characters and hit <return>\n"
1273 "('" VCL_TEST_TOKEN_HELP "' for help): ");
1275 if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
1277 if (strlen (ctrl->txbuf) == 1)
1279 printf ("\nNothing to send! Please try again...\n");
1282 ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline.
1284 /* Parse input for keywords */
1285 ctrl->cfg.test = parse_input ();
1290 vtc_ctrl_session_exit (void)
1292 vcl_test_client_main_t *vcm = &vcl_client_main;
1293 vcl_test_session_t *ctrl = &vcm->ctrl_session;
1294 int verbose = ctrl->cfg.verbose;
1296 /* Only clients exits, server can accept new connections */
1297 if (vcm->post_test == HS_TEST_TYPE_EXIT_CLIENT)
1300 ctrl->cfg.test = HS_TEST_TYPE_EXIT;
1301 vtinf ("(fd %d): Sending exit cfg to server...", ctrl->fd);
1303 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
1304 (void) vcl_test_write (ctrl, (uint8_t *) &ctrl->cfg, sizeof (ctrl->cfg));
1309 vtc_ctrl_session_init (vcl_test_client_main_t *vcm, vcl_test_session_t *ctrl)
1313 ctrl->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
1316 vterr ("vppcom_session_create()", ctrl->fd);
1320 vtinf ("Connecting to server...");
1321 rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt);
1324 vterr ("vppcom_session_connect()", rv);
1327 vtinf ("Control session (fd %d) connected.", ctrl->fd);
1329 ctrl->read = vcl_test_read;
1330 ctrl->write = vcl_test_write;
1332 ctrl->cfg.cmd = HS_TEST_CMD_SYNC;
1333 rv = vtc_cfg_sync (ctrl);
1336 vterr ("vtc_cfg_sync()", rv);
1340 ctrl->cfg.ctrl_handle = ((hs_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
1341 memset (&ctrl->stats, 0, sizeof (ctrl->stats));
1347 vt_sigs_handler (int signum, siginfo_t *si, void *uc)
1349 vcl_test_client_main_t *vcm = &vcl_client_main;
1350 vcl_test_session_t *ctrl = &vcm->ctrl_session;
1352 vcm->test_running = 0;
1353 clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
1357 vt_incercept_sigs (void)
1359 struct sigaction sa;
1361 memset (&sa, 0, sizeof (sa));
1362 sa.sa_sigaction = vt_sigs_handler;
1363 sa.sa_flags = SA_SIGINFO;
1364 if (sigaction (SIGINT, &sa, 0))
1366 vtwrn ("couldn't intercept sigint");
1372 vtc_alloc_workers (vcl_test_client_main_t *vcm)
1374 vcl_test_main_t *vt = &vcl_test_main;
1375 vtc_worker_run_fn *run_fn;
1377 vcm->workers = calloc (vcm->n_workers, sizeof (vcl_test_client_worker_t));
1378 vt->wrk = calloc (vcm->n_workers, sizeof (vcl_test_wrk_t));
1380 if (vcm->ctrl_session.cfg.num_test_sessions > VCL_TEST_CFG_MAX_SELECT_SESS)
1381 run_fn = vtc_worker_run_epoll;
1383 run_fn = vtc_worker_run_select;
1385 for (int i = 0; i < vcm->n_workers; i++)
1386 vcm->workers[i].wrk_run_fn = run_fn;
1390 main (int argc, char **argv)
1392 vcl_test_client_main_t *vcm = &vcl_client_main;
1393 vcl_test_session_t *ctrl = &vcm->ctrl_session;
1394 vcl_test_main_t *vt = &vcl_test_main;
1398 vcm->post_test = HS_TEST_TYPE_EXIT_CLIENT;
1400 hs_test_cfg_init (&ctrl->cfg);
1401 vt_incercept_sigs ();
1402 vcl_test_session_buf_alloc (ctrl);
1403 vtc_process_opts (vcm, argc, argv);
1405 vtc_alloc_workers (vcm);
1407 rv = vppcom_app_create ("vcl_test_client");
1409 vtfail ("vppcom_app_create()", rv);
1411 /* Protos like tls/dtls/quic need init */
1412 if (vt->protos[vcm->proto]->init)
1414 rv = vt->protos[vcm->proto]->init (&ctrl->cfg);
1416 vtfail ("client init failed", rv);
1419 if ((rv = vtc_ctrl_session_init (vcm, ctrl)))
1420 vtfail ("vppcom_session_create() ctrl session", rv);
1422 /* Update ctrl port to data port */
1423 vcm->server_endpt.port = hs_make_data_port (vcm->server_endpt.port);
1425 while (ctrl->cfg.test != HS_TEST_TYPE_EXIT)
1429 hs_test_cfg_dump (&ctrl->cfg, 1 /* is_client */);
1433 switch (ctrl->cfg.test)
1435 case HS_TEST_TYPE_ECHO:
1436 vtc_echo_client (vcm);
1439 case HS_TEST_TYPE_UNI:
1440 case HS_TEST_TYPE_BI:
1441 vtc_stream_client (vcm);
1444 case HS_TEST_TYPE_EXIT:
1447 case HS_TEST_TYPE_NONE:
1451 switch (vcm->post_test)
1453 case HS_TEST_TYPE_EXIT:
1454 case HS_TEST_TYPE_EXIT_CLIENT:
1455 switch (ctrl->cfg.test)
1457 case HS_TEST_TYPE_EXIT:
1458 case HS_TEST_TYPE_UNI:
1459 case HS_TEST_TYPE_BI:
1460 case HS_TEST_TYPE_ECHO:
1461 ctrl->cfg.test = HS_TEST_TYPE_EXIT;
1464 case HS_TEST_TYPE_NONE:
1470 case HS_TEST_TYPE_NONE:
1471 case HS_TEST_TYPE_ECHO:
1472 case HS_TEST_TYPE_UNI:
1473 case HS_TEST_TYPE_BI:
1478 memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1479 memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1481 vtc_read_user_input (ctrl);
1484 vtc_ctrl_session_exit ();
1485 vppcom_app_destroy ();
1486 free (vcm->workers);
1491 * fd.io coding-style-patch-verification: ON
1494 * eval: (c-set-style "gnu")