FD.io VPP  v19.08.1-401-g8e4ed521a
Vector Packet Processing
vcl_test_client.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <arpa/inet.h>
25 #include <hs_apps/vcl/vcl_test.h>
26 #include <pthread.h>
27 
28 typedef struct
29 {
32  uint32_t n_sessions;
33  uint32_t n_qsessions;
34  uint32_t wrk_index;
35  fd_set wr_fdset;
36  fd_set rd_fdset;
38  pthread_t thread_handle;
41 
42 typedef struct
43 {
45  vppcom_endpt_t server_endpt;
46  uint32_t cfg_seq_num;
50  uint8_t dump_cfg;
52  uint8_t proto;
53  uint32_t n_workers;
54  volatile int active_workers;
55  struct sockaddr_storage server_addr;
57 
58 static __thread int __wrk_index = 0;
59 
61 
62 #define vtc_min(a, b) (a < b ? a : b)
63 #define vtc_max(a, b) (a > b ? a : b)
64 
65 static int
67 {
68  vcl_test_cfg_t *rx_cfg = (vcl_test_cfg_t *) ts->rxbuf;
69  int rx_bytes, tx_bytes;
70 
71  vt_atomic_add (&ts->cfg.seq_num, 1);
72  if (ts->cfg.verbose)
73  {
74  vtinf ("(fd %d): Sending config to server.", ts->fd);
75  vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
76  }
77  tx_bytes = vcl_test_write (ts->fd, (uint8_t *) & ts->cfg,
78  sizeof (ts->cfg), NULL, ts->cfg.verbose);
79  if (tx_bytes < 0)
80  {
81  vtwrn ("(fd %d): write test cfg failed (%d)!", ts->fd, tx_bytes);
82  return tx_bytes;
83  }
84 
85  rx_bytes = vcl_test_read (ts->fd, (uint8_t *) ts->rxbuf,
86  sizeof (vcl_test_cfg_t), NULL);
87  if (rx_bytes < 0)
88  return rx_bytes;
89 
90  if (rx_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC)
91  {
92  vtwrn ("(fd %d): Bad server reply cfg -- aborting!", ts->fd);
93  return -1;
94  }
95  if ((rx_bytes != sizeof (vcl_test_cfg_t))
96  || !vcl_test_cfg_verify (rx_cfg, &ts->cfg))
97  {
98  vtwrn ("(fd %d): Invalid config received from server!", ts->fd);
99  if (rx_bytes != sizeof (vcl_test_cfg_t))
100  {
101  vtinf ("\tRx bytes %d != cfg size %lu", rx_bytes,
102  sizeof (vcl_test_cfg_t));
103  }
104  else
105  {
106  vcl_test_cfg_dump (rx_cfg, 1 /* is_client */ );
107  vtinf ("(fd %d): Valid config sent to server.", ts->fd);
108  vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
109  }
110  return -1;
111  }
112  if (ts->cfg.verbose)
113  {
114  vtinf ("(fd %d): Got config back from server.", ts->fd);
115  vcl_test_cfg_dump (rx_cfg, 1 /* is_client */ );
116  }
117 
118  return 0;
119 }
120 
121 static int
123 {
125  vcl_test_session_t *ts, *tq;
126  uint32_t i, flags, flen;
127  int rv;
128 
129  if (wrk->cfg.num_test_sessions < 1 || wrk->cfg.num_test_sessions_perq < 1)
130  {
131  errno = EINVAL;
132  return -1;
133  }
134 
135  if (wrk->n_sessions >= wrk->cfg.num_test_sessions)
136  goto done;
137 
138  /* Connect Qsessions */
139 
140  if (wrk->n_qsessions)
141  wrk->qsessions =
142  realloc (wrk->qsessions,
143  wrk->cfg.num_test_qsessions * sizeof (vcl_test_session_t));
144  else
145  wrk->qsessions =
146  calloc (wrk->cfg.num_test_qsessions, sizeof (vcl_test_session_t));
147 
148  if (!wrk->qsessions)
149  {
150  vterr ("failed to alloc Qsessions", -errno);
151  return errno;
152  }
153 
154 
155  for (i = 0; i < wrk->cfg.num_test_qsessions; i++)
156  {
157  tq = &wrk->qsessions[i];
158  tq->fd = vppcom_session_create (vcm->proto, 0 /* is_nonblocking */ );
159  tq->session_index = i;
160  if (tq->fd < 0)
161  {
162  vterr ("vppcom_session_create()", tq->fd);
163  return tq->fd;
164  }
165 
166  /* Connect is blocking */
167  rv = vppcom_session_connect (tq->fd, &vcm->server_endpt);
168  if (rv < 0)
169  {
170  vterr ("vppcom_session_connect()", rv);
171  return rv;
172  }
173  flags = O_NONBLOCK;
174  flen = sizeof (flags);
175  vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
176  vtinf ("Test Qsession %d (fd %d) connected.", i, tq->fd);
177  }
178  wrk->n_qsessions = wrk->cfg.num_test_qsessions;
179 
180  /* Connect Stream sessions */
181 
182  if (wrk->n_sessions)
183  wrk->sessions =
184  realloc (wrk->sessions,
185  wrk->cfg.num_test_sessions * sizeof (vcl_test_session_t));
186  else
187  wrk->sessions =
188  calloc (wrk->cfg.num_test_sessions, sizeof (vcl_test_session_t));
189 
190  if (!wrk->sessions)
191  {
192  vterr ("failed to alloc sessions", -errno);
193  return errno;
194  }
195 
196  for (i = 0; i < wrk->cfg.num_test_sessions; i++)
197  {
198  tq = &wrk->qsessions[i / wrk->cfg.num_test_sessions_perq];
199  ts = &wrk->sessions[i];
200  ts->fd = vppcom_session_create (vcm->proto, 1 /* is_nonblocking */ );
201  ts->session_index = i;
202  if (ts->fd < 0)
203  {
204  vterr ("vppcom_session_create()", ts->fd);
205  return ts->fd;
206  }
207 
208  rv = vppcom_session_stream_connect (ts->fd, tq->fd);
209  if (rv < 0)
210  {
211  vterr ("vppcom_session_stream_connect()", rv);
212  return rv;
213  }
214 
215  vtinf ("Test session %d (fd %d) connected.", i, ts->fd);
216  }
217  wrk->n_sessions = wrk->cfg.num_test_sessions;
218 
219 done:
220  vtinf ("All test sessions (%d) connected!", wrk->cfg.num_test_sessions);
221  return 0;
222 }
223 
224 static int
226 {
228  vcl_test_session_t *ts;
229  uint32_t n_test_sessions;
230  uint32_t flags, flen;
231  int i, rv;
232 
233  if (vcm->proto == VPPCOM_PROTO_QUIC)
234  return vtc_quic_connect_test_sessions (wrk);
235 
236  n_test_sessions = wrk->cfg.num_test_sessions;
237  if (n_test_sessions < 1)
238  {
239  errno = EINVAL;
240  return -1;
241  }
242 
243  if (wrk->n_sessions >= n_test_sessions)
244  goto done;
245 
246  if (wrk->n_sessions)
247  wrk->sessions = realloc (wrk->sessions,
248  n_test_sessions * sizeof (vcl_test_session_t));
249  else
250  wrk->sessions = calloc (n_test_sessions, sizeof (vcl_test_session_t));
251 
252  if (!wrk->sessions)
253  {
254  vterr ("failed to alloc sessions", -errno);
255  return errno;
256  }
257 
258  for (i = 0; i < n_test_sessions; i++)
259  {
260  ts = &wrk->sessions[i];
261  ts->fd = vppcom_session_create (vcm->proto, 0 /* is_nonblocking */ );
262  if (ts->fd < 0)
263  {
264  vterr ("vppcom_session_create()", ts->fd);
265  return ts->fd;
266  }
267 
268  /* Connect is blocking */
269  rv = vppcom_session_connect (ts->fd, &vcm->server_endpt);
270  if (rv < 0)
271  {
272  vterr ("vppcom_session_connect()", rv);
273  return rv;
274  }
275  flags = O_NONBLOCK;
276  flen = sizeof (flags);
277  vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
278  vtinf ("Test session %d (fd %d) connected.", i, ts->fd);
279  }
280  wrk->n_sessions = n_test_sessions;
281 
282 done:
283  vtinf ("All test sessions (%d) connected!", n_test_sessions);
284  return 0;
285 }
286 
287 static int
289 {
291  vcl_test_session_t *ctrl = &vcm->ctrl_session;
292  vcl_test_cfg_t *cfg = &wrk->cfg;
293  vcl_test_session_t *ts;
294  uint32_t sidx;
295  int i, j;
296 
297  FD_ZERO (&wrk->wr_fdset);
298  FD_ZERO (&wrk->rd_fdset);
299 
300  for (i = 0; i < cfg->num_test_sessions; i++)
301  {
302  ts = &wrk->sessions[i];
303  ts->cfg = wrk->cfg;
305 
306  switch (cfg->test)
307  {
308  case VCL_TEST_TYPE_ECHO:
309  memcpy (ts->txbuf, ctrl->txbuf, cfg->total_bytes);
310  break;
311  case VCL_TEST_TYPE_UNI:
312  case VCL_TEST_TYPE_BI:
313  for (j = 0; j < ts->txbuf_size; j++)
314  ts->txbuf[j] = j & 0xff;
315  break;
316  }
317 
318  FD_SET (vppcom_session_index (ts->fd), &wrk->wr_fdset);
319  FD_SET (vppcom_session_index (ts->fd), &wrk->rd_fdset);
320  sidx = vppcom_session_index (ts->fd);
321  wrk->max_fd_index = vtc_max (sidx, wrk->max_fd_index);
322  }
323  wrk->max_fd_index += 1;
324 
325  return 0;
326 }
327 
328 static int
330 {
332  vcl_test_cfg_t *cfg = &wrk->cfg;
333  vcl_test_session_t *ts;
334  uint32_t n;
335  int rv;
336 
337  __wrk_index = wrk->wrk_index;
338 
339  vtinf ("Initializing worker %u ...", wrk->wrk_index);
340 
341  if (wrk->wrk_index)
342  {
343  if (vppcom_worker_register ())
344  {
345  vtwrn ("failed to register worker");
346  return -1;
347  }
348  vt_atomic_add (&vcm->active_workers, 1);
349  }
350  rv = vtc_connect_test_sessions (wrk);
351  if (rv)
352  {
353  vterr ("vtc_connect_test_sessions ()", rv);
354  return rv;
355  }
356 
357  if (vtc_worker_test_setup (wrk))
358  return -1;
359 
360  vtinf ("Sending config to server on all sessions ...");
361 
362  for (n = 0; n < cfg->num_test_sessions; n++)
363  {
364  ts = &wrk->sessions[n];
365  if (vtc_cfg_sync (ts))
366  return -1;
367  memset (&ts->stats, 0, sizeof (ts->stats));
368  }
369 
370  return 0;
371 }
372 
373 static int stats_lock = 0;
374 
375 static void
377  vcl_test_session_t * ctrl)
378 {
379  vcl_test_session_t *ts;
380  static char buf[64];
381  int i, show_rx = 0;
382 
383  while (__sync_lock_test_and_set (&stats_lock, 1))
384  ;
385 
386  if (ctrl->cfg.test == VCL_TEST_TYPE_BI
387  || ctrl->cfg.test == VCL_TEST_TYPE_ECHO)
388  show_rx = 1;
389 
390  for (i = 0; i < wrk->cfg.num_test_sessions; i++)
391  {
392  ts = &wrk->sessions[i];
393  ts->stats.start = ctrl->stats.start;
394 
395  if (ctrl->cfg.verbose > 1)
396  {
397  sprintf (buf, "CLIENT (fd %d) RESULTS", ts->fd);
398  vcl_test_stats_dump (buf, &ts->stats, show_rx, 1 /* show tx */ ,
399  ctrl->cfg.verbose);
400  }
401 
402  vcl_test_stats_accumulate (&ctrl->stats, &ts->stats);
403  if (vcl_comp_tspec (&ctrl->stats.stop, &ts->stats.stop) < 0)
404  ctrl->stats.stop = ts->stats.stop;
405  }
406 
407  __sync_lock_release (&stats_lock);
408 }
409 
410 static void
412 {
414  vcl_test_session_t *ctrl = &vcm->ctrl_session;
415  vcl_test_session_t *ts;
416  int i, verbose = ctrl->cfg.verbose;
417 
418  for (i = 0; i < wrk->cfg.num_test_sessions; i++)
419  {
420  ts = &wrk->sessions[i];
422 
423  if (verbose)
424  {
425  vtinf ("(fd %d): Sending exit cfg to server...", ts->fd);
426  vcl_test_cfg_dump (&ts->cfg, 1 /* is_client */ );
427  }
428  (void) vcl_test_write (ts->fd, (uint8_t *) & ts->cfg,
429  sizeof (ts->cfg), &ts->stats, verbose);
430  }
431 
432  wrk->n_sessions = 0;
433 }
434 
435 static void *
436 vtc_worker_loop (void *arg)
437 {
439  vcl_test_session_t *ctrl = &vcm->ctrl_session;
440  vcl_test_client_worker_t *wrk = arg;
441  uint32_t n_active_sessions, n_bytes;
442  fd_set _wfdset, *wfdset = &_wfdset;
443  fd_set _rfdset, *rfdset = &_rfdset;
444  vcl_test_session_t *ts;
445  int i, rv, check_rx = 0;
446 
447  rv = vtc_worker_init (wrk);
448  if (rv)
449  {
450  vterr ("vtc_worker_init()", rv);
451  return 0;
452  }
453 
454  vtinf ("Starting test ...");
455 
456  if (wrk->wrk_index == 0)
457  clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
458 
459  check_rx = wrk->cfg.test != VCL_TEST_TYPE_UNI;
460  n_active_sessions = wrk->cfg.num_test_sessions;
461  while (n_active_sessions)
462  {
463  _wfdset = wrk->wr_fdset;
464  _rfdset = wrk->rd_fdset;
465 
466  rv = vppcom_select (wrk->max_fd_index, (unsigned long *) rfdset,
467  (unsigned long *) wfdset, NULL, 0);
468  if (rv < 0)
469  {
470  vterr ("vppcom_select()", rv);
471  goto exit;
472  }
473  else if (rv == 0)
474  continue;
475 
476  for (i = 0; i < wrk->cfg.num_test_sessions; i++)
477  {
478  ts = &wrk->sessions[i];
479  if (!((ts->stats.stop.tv_sec == 0) &&
480  (ts->stats.stop.tv_nsec == 0)))
481  continue;
482 
483  if (FD_ISSET (vppcom_session_index (ts->fd), rfdset)
484  && ts->stats.rx_bytes < ts->cfg.total_bytes)
485  {
486  (void) vcl_test_read (ts->fd, (uint8_t *) ts->rxbuf,
487  ts->rxbuf_size, &ts->stats);
488  }
489 
490  if (FD_ISSET (vppcom_session_index (ts->fd), wfdset)
491  && ts->stats.tx_bytes < ts->cfg.total_bytes)
492  {
493  n_bytes = ts->cfg.txbuf_size;
494  if (ts->cfg.test == VCL_TEST_TYPE_ECHO)
495  n_bytes = strlen (ctrl->txbuf) + 1;
496  rv = vcl_test_write (ts->fd, (uint8_t *) ts->txbuf,
497  n_bytes, &ts->stats, ts->cfg.verbose);
498  if (rv < 0)
499  {
500  vtwrn ("vppcom_test_write (%d) failed -- aborting test",
501  ts->fd);
502  goto exit;
503  }
504  }
505  if ((!check_rx && ts->stats.tx_bytes >= ts->cfg.total_bytes)
506  || (check_rx && ts->stats.rx_bytes >= ts->cfg.total_bytes))
507  {
508  clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
509  n_active_sessions--;
510  }
511  }
512  }
513 exit:
514  vtinf ("Worker %d done ...", wrk->wrk_index);
515  if (wrk->cfg.test != VCL_TEST_TYPE_ECHO)
516  vtc_accumulate_stats (wrk, ctrl);
519  if (wrk->wrk_index)
520  vt_atomic_add (&vcm->active_workers, -1);
521  return 0;
522 }
523 
524 static void
526 {
527  int is_echo = ctrl->cfg.test == VCL_TEST_TYPE_ECHO;
528  int show_rx = 0;
529  char buf[64];
530 
531  if (ctrl->cfg.test == VCL_TEST_TYPE_BI
532  || ctrl->cfg.test == VCL_TEST_TYPE_ECHO)
533  show_rx = 1;
534 
535  vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
536  show_rx, 1 /* show tx */ ,
537  ctrl->cfg.verbose);
538  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
539 
540  if (ctrl->cfg.verbose)
541  {
542  vtinf (" ctrl session info\n"
544  " fd: %d (0x%08x)\n"
545  " rxbuf: %p\n"
546  " rxbuf size: %u (0x%08x)\n"
547  " txbuf: %p\n"
548  " txbuf size: %u (0x%08x)\n"
550  ctrl->fd, (uint32_t) ctrl->fd,
551  ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
552  ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
553  }
554 
555  if (is_echo)
556  sprintf (buf, "Echo");
557  else
558  sprintf (buf, "%s-directional Stream",
559  ctrl->cfg.test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
560 }
561 
562 static void
564 {
566  vcl_test_session_t *ctrl = &vcm->ctrl_session;
567  vcl_test_cfg_t *cfg = &ctrl->cfg;
568 
569  cfg->total_bytes = strlen (ctrl->txbuf) + 1;
570  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
571 
572  /* Echo works with only one worker */
573  wrk = vcm->workers;
574  wrk->wrk_index = 0;
575  wrk->cfg = *cfg;
576 
577  vtc_worker_loop (wrk);
578 
579  /* Not relevant for echo test
580  clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
581  vtc_accumulate_stats (wrk, ctrl);
582  vtc_print_stats (ctrl);
583  */
584 }
585 
586 static void
588 {
589  vcl_test_session_t *ctrl = &vcm->ctrl_session;
590  vcl_test_cfg_t *cfg = &ctrl->cfg;
592  uint32_t i, n_conn, n_conn_per_wrk;
593 
594  vtinf ("%s-directional Stream Test Starting!",
595  ctrl->cfg.test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
596 
597  cfg->total_bytes = cfg->num_writes * cfg->txbuf_size;
598  cfg->ctrl_handle = ~0;
599  if (vtc_cfg_sync (ctrl))
600  {
601  vtwrn ("test cfg sync failed -- aborting!");
602  return;
603  }
604  cfg->ctrl_handle = ((vcl_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
605  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
606 
607  n_conn = cfg->num_test_sessions;
608  n_conn_per_wrk = n_conn / vcm->n_workers;
609  for (i = 0; i < vcm->n_workers; i++)
610  {
611  wrk = &vcm->workers[i];
612  wrk->wrk_index = i;
613  wrk->cfg = ctrl->cfg;
614  wrk->cfg.num_test_sessions = vtc_min (n_conn_per_wrk, n_conn);
615  n_conn -= wrk->cfg.num_test_sessions;
616  }
617 
618  for (i = 1; i < vcm->n_workers; i++)
619  {
620  wrk = &vcm->workers[i];
621  pthread_create (&wrk->thread_handle, NULL, vtc_worker_loop,
622  (void *) wrk);
623  }
624  vtc_worker_loop (&vcm->workers[0]);
625 
626  while (vcm->active_workers > 0)
627  ;
628 
629  vtinf ("Sending config on ctrl session (fd %d) for stats...", ctrl->fd);
630  if (vtc_cfg_sync (ctrl))
631  {
632  vtwrn ("test cfg sync failed -- aborting!");
633  return;
634  }
635 
636  vtc_print_stats (ctrl);
637 
638  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
639  ctrl->cfg.total_bytes = 0;
640  if (vtc_cfg_sync (ctrl))
641  vtwrn ("post-test cfg sync failed!");
642 }
643 
644 static void
645 dump_help (void)
646 {
647 #define INDENT "\n "
648 
649  printf ("CLIENT: Test configuration commands:"
651  "\t\t\tDisplay help."
653  "\t\t\tExit test client & server."
655  "\t\t\tShow the current test cfg."
657  "\t\t\tRun the Uni-directional test."
659  "\t\t\tRun the Bi-directional test."
661  "\t\t\tToggle verbose setting."
663  "<rxbuf size>\tRx buffer size (bytes)."
665  "<txbuf size>\tTx buffer size (bytes)."
667  "<# of writes>\tNumber of txbuf writes to server." "\n");
668 }
669 
670 static void
672 {
674  vcl_test_session_t *ctrl = &vcm->ctrl_session;
675  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
676  uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
677 
678  if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
679  {
680  ctrl->cfg.txbuf_size = txbuf_size;
681  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
682  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
683  (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
684  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
685  }
686  else
687  vtwrn ("Invalid txbuf size (%lu) < minimum buf size (%u)!",
688  txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
689 }
690 
691 static void
693 {
695  vcl_test_session_t *ctrl = &vcm->ctrl_session;
696  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
697  uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
698 
699  if (num_writes > 0)
700  {
701  ctrl->cfg.num_writes = num_writes;
702  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
703  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
704  }
705  else
706  {
707  vtwrn ("invalid num writes: %u", num_writes);
708  }
709 }
710 
711 static void
713 {
715  vcl_test_session_t *ctrl = &vcm->ctrl_session;
716  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
717  uint32_t num_test_sessions = strtoul ((const char *) p, NULL, 10);
718 
719  if ((num_test_sessions > 0) &&
720  (num_test_sessions <= VCL_TEST_CFG_MAX_TEST_SESS))
721  {
722  ctrl->cfg.num_test_sessions = num_test_sessions;
723  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
724  }
725  else
726  {
727  vtwrn ("invalid num test sessions: %u, (%d max)",
728  num_test_sessions, VCL_TEST_CFG_MAX_TEST_SESS);
729  }
730 }
731 
732 static void
734 {
736  vcl_test_session_t *ctrl = &vcm->ctrl_session;
737  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
738  uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
739 
740  if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
741  {
742  ctrl->cfg.rxbuf_size = rxbuf_size;
743  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
744  (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
745  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
746  }
747  else
748  vtwrn ("Invalid rxbuf size (%lu) < minimum buf size (%u)!",
749  rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
750 }
751 
752 static void
754 {
756  vcl_test_session_t *ctrl = &vcm->ctrl_session;
757 
758  ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
759  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
760 
761 }
762 
763 static vcl_test_t
765 {
767  vcl_test_session_t *ctrl = &vcm->ctrl_session;
769 
770  if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
771  strlen (VCL_TEST_TOKEN_EXIT)))
772  rv = VCL_TEST_TYPE_EXIT;
773 
774  else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
775  strlen (VCL_TEST_TOKEN_HELP)))
776  dump_help ();
777 
778  else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
779  strlen (VCL_TEST_TOKEN_SHOW_CFG)))
780  vcm->dump_cfg = 1;
781 
782  else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
783  strlen (VCL_TEST_TOKEN_VERBOSE)))
785 
786  else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
787  strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
789 
790  else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
793 
794  else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
795  strlen (VCL_TEST_TOKEN_NUM_WRITES)))
797 
798  else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
799  strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
801 
802  else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
803  strlen (VCL_TEST_TOKEN_RUN_UNI)))
804  rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
805 
806  else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
807  strlen (VCL_TEST_TOKEN_RUN_BI)))
808  rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
809 
810  else
811  rv = VCL_TEST_TYPE_ECHO;
812 
813  return rv;
814 }
815 
816 void
818 {
819  fprintf (stderr,
820  "vcl_test_client [OPTIONS] <ipaddr> <port>\n"
821  " OPTIONS\n"
822  " -h Print this message and exit.\n"
823  " -6 Use IPv6\n"
824  " -c Print test config before test.\n"
825  " -w <dir> Write test results to <dir>.\n"
826  " -X Exit after running test.\n"
827  " -p <proto> Use <proto> transport layer\n"
828  " -D Use UDP transport layer\n"
829  " -L Use TLS transport layer\n"
830  " -E Run Echo test.\n"
831  " -N <num-writes> Test Cfg: number of writes.\n"
832  " -R <rxbuf-size> Test Cfg: rx buffer size.\n"
833  " -T <txbuf-size> Test Cfg: tx buffer size.\n"
834  " -U Run Uni-directional test.\n"
835  " -B Run Bi-directional test.\n"
836  " -V Verbose mode.\n"
837  " -I <N> Use N sessions.\n"
838  " -s <N> Use N sessions.\n"
839  " -q <n> QUIC : use N Ssessions on top of n Qsessions\n");
840  exit (1);
841 }
842 
843 static void
844 vtc_process_opts (vcl_test_client_main_t * vcm, int argc, char **argv)
845 {
846  vcl_test_session_t *ctrl = &vcm->ctrl_session;
847  int c, v;
848 
849  opterr = 0;
850  while ((c = getopt (argc, argv, "chnp:w:XE:I:N:R:T:UBV6DLs:q:")) != -1)
851  switch (c)
852  {
853  case 'c':
854  vcm->dump_cfg = 1;
855  break;
856 
857  case 'I': /* deprecated */
858  case 's':
859  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
860  if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
861  {
862  vtwrn ("Invalid value for option -%c!", c);
864  }
865  if (!ctrl->cfg.num_test_sessions ||
867  {
868  vtwrn ("Invalid number of sessions (%d) specified for option -%c!"
869  "\n Valid range is 1 - %d",
870  ctrl->cfg.num_test_sessions, c,
873  }
874  break;
875 
876  case 'q':
877  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions_perq) != 1)
878  if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions_perq) != 1)
879  {
880  vtwrn ("Invalid value for option -%c!", c);
882  }
883  if (!ctrl->cfg.num_test_sessions_perq ||
885  {
886  vtwrn ("Invalid number of Stream sessions (%d) per Qsession"
887  "for option -%c!\nValid range is 1 - %d",
888  ctrl->cfg.num_test_sessions_perq, c,
891  }
892  break;
893 
894  case 'w':
895  if (sscanf (optarg, "%d", &v) != 1)
896  {
897  vtwrn ("Invalid value for option -%c!", c);
899  }
900  if (v > 1)
901  vcm->n_workers = v;
902  break;
903 
904  case 'X':
906  break;
907 
908  case 'E':
909  if (strlen (optarg) > ctrl->txbuf_size)
910  {
911  vtwrn ("Option -%c value larger than txbuf size (%d)!",
912  optopt, ctrl->txbuf_size);
914  }
915  strcpy (ctrl->txbuf, optarg);
916  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
917  break;
918 
919  case 'N':
920  if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
921  if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
922  {
923  vtwrn ("Invalid value for option -%c!", c);
925  }
926  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
927  break;
928 
929  case 'R':
930  if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
931  if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
932  {
933  vtwrn ("Invalid value for option -%c!", c);
935  }
937  {
938  ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
939  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
940  (uint8_t **) & ctrl->rxbuf,
941  &ctrl->rxbuf_size);
942  }
943  else
944  {
945  vtwrn ("rxbuf size (%lu) less than minumum (%u)",
948  }
949 
950  break;
951 
952  case 'T':
953  if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
954  if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
955  {
956  vtwrn ("Invalid value for option -%c!", c);
958  }
960  {
961  ctrl->txbuf_size = ctrl->cfg.txbuf_size;
962  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
963  (uint8_t **) & ctrl->txbuf,
964  &ctrl->txbuf_size);
965  ctrl->cfg.total_bytes =
966  ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
967  }
968  else
969  {
970  vtwrn ("txbuf size (%lu) less than minumum (%u)!",
973  }
974  break;
975 
976  case 'U':
977  ctrl->cfg.test = VCL_TEST_TYPE_UNI;
978  break;
979 
980  case 'B':
981  ctrl->cfg.test = VCL_TEST_TYPE_BI;
982  break;
983 
984  case 'V':
985  ctrl->cfg.verbose = 1;
986  break;
987 
988  case '6':
989  ctrl->cfg.address_ip6 = 1;
990  break;
991 
992  case 'p':
993  if (vppcom_unformat_proto (&vcm->proto, optarg))
994  vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
995  break;
996 
997  case 'D': /* deprecated */
998  vcm->proto = VPPCOM_PROTO_UDP;
999  break;
1000 
1001  case 'L': /* deprecated */
1002  vcm->proto = VPPCOM_PROTO_TLS;
1003  break;
1004 
1005  case '?':
1006  switch (optopt)
1007  {
1008  case 'E':
1009  case 'I': /* deprecated */
1010  case 'N':
1011  case 'R':
1012  case 'T':
1013  case 'w':
1014  case 'p':
1015  case 'q':
1016  vtwrn ("Option -%c requires an argument.", optopt);
1017  break;
1018 
1019  default:
1020  if (isprint (optopt))
1021  vtwrn ("Unknown option `-%c'.", optopt);
1022  else
1023  vtwrn ("Unknown option character `\\x%x'.", optopt);
1024  }
1025  /* fall thru */
1026  case 'h':
1027  default:
1029  }
1030 
1031  if (argc < (optind + 2))
1032  {
1033  vtwrn ("Insufficient number of arguments!");
1035  }
1036 
1037  ctrl->cfg.num_test_qsessions = vcm->proto != VPPCOM_PROTO_QUIC ? 0 :
1038  (ctrl->cfg.num_test_sessions + ctrl->cfg.num_test_sessions_perq - 1) /
1040 
1041  memset (&vcm->server_addr, 0, sizeof (vcm->server_addr));
1042  if (ctrl->cfg.address_ip6)
1043  {
1044  struct sockaddr_in6 *sddr6 = (struct sockaddr_in6 *) &vcm->server_addr;
1045  sddr6->sin6_family = AF_INET6;
1046  inet_pton (AF_INET6, argv[optind++], &(sddr6->sin6_addr));
1047  sddr6->sin6_port = htons (atoi (argv[optind]));
1048 
1049  vcm->server_endpt.is_ip4 = 0;
1050  vcm->server_endpt.ip = (uint8_t *) & sddr6->sin6_addr;
1051  vcm->server_endpt.port = (uint16_t) sddr6->sin6_port;
1052  }
1053  else
1054  {
1055  struct sockaddr_in *saddr4 = (struct sockaddr_in *) &vcm->server_addr;
1056  saddr4->sin_family = AF_INET;
1057  inet_pton (AF_INET, argv[optind++], &(saddr4->sin_addr));
1058  saddr4->sin_port = htons (atoi (argv[optind]));
1059 
1060  vcm->server_endpt.is_ip4 = 1;
1061  vcm->server_endpt.ip = (uint8_t *) & saddr4->sin_addr;
1062  vcm->server_endpt.port = (uint16_t) saddr4->sin_port;
1063  }
1064 }
1065 
1066 static void
1068 {
1069  printf ("\nType some characters and hit <return>\n"
1070  "('" VCL_TEST_TOKEN_HELP "' for help): ");
1071 
1072  if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
1073  {
1074  if (strlen (ctrl->txbuf) == 1)
1075  {
1076  printf ("\nNothing to send! Please try again...\n");
1077  return;
1078  }
1079  ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline.
1080 
1081  /* Parse input for keywords */
1082  ctrl->cfg.test = parse_input ();
1083  }
1084 }
1085 
1086 static void
1088 {
1090  vcl_test_session_t *ctrl = &vcm->ctrl_session;
1091  int verbose = ctrl->cfg.verbose;
1092 
1093  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1094  if (verbose)
1095  {
1096  vtinf ("(fd %d): Sending exit cfg to server...", ctrl->fd);
1097  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1098  }
1099  (void) vcl_test_write (ctrl->fd, (uint8_t *) & ctrl->cfg,
1100  sizeof (ctrl->cfg), &ctrl->stats, verbose);
1101  sleep (1);
1102 }
1103 
1104 int
1105 main (int argc, char **argv)
1106 {
1108  vcl_test_session_t *ctrl = &vcm->ctrl_session;
1109  vcl_test_session_t *quic_session = &vcm->quic_session;
1110  int rv;
1111 
1112  vcm->n_workers = 1;
1113  vcl_test_cfg_init (&ctrl->cfg);
1115  vtc_process_opts (vcm, argc, argv);
1116 
1117  vcm->workers = calloc (vcm->n_workers, sizeof (vcl_test_client_worker_t));
1118  rv = vppcom_app_create ("vcl_test_client");
1119  if (rv < 0)
1120  vtfail ("vppcom_app_create()", rv);
1121 
1122  ctrl->fd = vppcom_session_create (vcm->proto, 0 /* is_nonblocking */ );
1123  if (ctrl->fd < 0)
1124  vtfail ("vppcom_session_create()", ctrl->fd);
1125 
1126  if (vcm->proto == VPPCOM_PROTO_TLS || vcm->proto == VPPCOM_PROTO_QUIC)
1127  {
1128  vtinf ("Adding tls certs ...");
1129  vppcom_session_tls_add_cert (ctrl->fd, vcl_test_crt_rsa,
1131  vppcom_session_tls_add_key (ctrl->fd, vcl_test_key_rsa,
1133  }
1134 
1135  vtinf ("Connecting to server...");
1136  if (vcm->proto == VPPCOM_PROTO_QUIC)
1137  {
1138  quic_session->fd = vppcom_session_create (vcm->proto,
1139  0 /* is_nonblocking */ );
1140  if (quic_session->fd < 0)
1141  vtfail ("vppcom_session_create()", quic_session->fd);
1142  rv = vppcom_session_connect (quic_session->fd, &vcm->server_endpt);
1143  if (rv)
1144  vtfail ("vppcom_session_connect()", rv);
1145  vtinf ("Connecting to stream...");
1146  rv = vppcom_session_stream_connect (ctrl->fd, quic_session->fd);
1147  }
1148  else
1149  rv = vppcom_session_connect (ctrl->fd, &vcm->server_endpt);
1150  if (rv)
1151  vtfail ("vppcom_session_connect()", rv);
1152  vtinf ("Control session (fd %d) connected.", ctrl->fd);
1153 
1154  rv = vtc_cfg_sync (ctrl);
1155  if (rv)
1156  vtfail ("vtc_cfg_sync()", rv);
1157 
1158  ctrl->cfg.ctrl_handle = ((vcl_test_cfg_t *) ctrl->rxbuf)->ctrl_handle;
1159  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
1160 
1161  while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
1162  {
1163  if (vcm->dump_cfg)
1164  {
1165  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1166  vcm->dump_cfg = 0;
1167  }
1168 
1169  switch (ctrl->cfg.test)
1170  {
1171  case VCL_TEST_TYPE_ECHO:
1172  vtc_echo_client (vcm);
1173  break;
1174 
1175  case VCL_TEST_TYPE_UNI:
1176  case VCL_TEST_TYPE_BI:
1177  vtc_stream_client (vcm);
1178  break;
1179 
1180  case VCL_TEST_TYPE_EXIT:
1181  continue;
1182 
1183  case VCL_TEST_TYPE_NONE:
1184  default:
1185  break;
1186  }
1187  switch (vcm->post_test)
1188  {
1189  case VCL_TEST_TYPE_EXIT:
1190  switch (ctrl->cfg.test)
1191  {
1192  case VCL_TEST_TYPE_EXIT:
1193  case VCL_TEST_TYPE_UNI:
1194  case VCL_TEST_TYPE_BI:
1195  case VCL_TEST_TYPE_ECHO:
1196  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1197  continue;
1198 
1199  case VCL_TEST_TYPE_NONE:
1200  default:
1201  break;
1202  }
1203  break;
1204 
1205  case VCL_TEST_TYPE_NONE:
1206  case VCL_TEST_TYPE_ECHO:
1207  case VCL_TEST_TYPE_UNI:
1208  case VCL_TEST_TYPE_BI:
1209  default:
1210  break;
1211  }
1212 
1213  memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1214  memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1215 
1216  vtc_read_user_input (ctrl);
1217  }
1218 
1220  if (quic_session)
1221  vppcom_session_close (quic_session->fd);
1222  vppcom_app_destroy ();
1223  free (vcm->workers);
1224  return 0;
1225 }
1226 
1227 /*
1228  * fd.io coding-style-patch-verification: ON
1229  *
1230  * Local Variables:
1231  * eval: (c-set-style "gnu")
1232  * End:
1233  */
static void dump_help(void)
u32 flags
Definition: vhost_user.h:141
#define VCL_TEST_TOKEN_RXBUF_SIZE
Definition: vcl_test.h:54
uint32_t vcl_test_crt_rsa_len
Definition: vcl_test.h:154
struct timespec stop
Definition: vcl_test.h:111
int main(int argc, char **argv)
static vcl_test_t parse_input()
#define NULL
Definition: clib.h:58
uint32_t num_test_qsessions
Definition: vcl_test.h:90
#define EINVAL
Definition: string.h:93
vcl_test_session_t ctrl_session
vcl_test_session_t quic_session
#define INDENT
int i
vcl_test_client_main_t vcl_client_main
uint32_t num_test_sessions
Definition: vcl_test.h:88
#define vtc_min(a, b)
#define VCL_TEST_CFG_BUF_SIZE_MIN
Definition: vcl_test.h:66
#define VCL_TEST_DELAY_DISCONNECT
Definition: vcl_test.h:70
vcl_test_session_t * sessions
struct timespec start
Definition: vcl_test.h:110
static void vtc_worker_sessions_exit(vcl_test_client_worker_t *wrk)
#define VCL_TEST_TOKEN_NUM_WRITES
Definition: vcl_test.h:53
uint64_t num_writes
Definition: vcl_test.h:96
#define VCL_TEST_TOKEN_SHOW_CFG
Definition: vcl_test.h:55
vcl_test_t
Definition: vcl_test.h:73
void print_usage_and_exit(void)
uint64_t txbuf_size
Definition: vcl_test.h:95
struct sockaddr_storage server_addr
volatile int active_workers
static int vtc_worker_test_setup(vcl_test_client_worker_t *wrk)
static void vtc_echo_client(vcl_test_client_main_t *vcm)
static void vcl_test_stats_dump(char *header, vcl_test_stats_t *stats, uint8_t show_rx, uint8_t show_tx, uint8_t verbose)
Definition: vcl_test.h:326
#define vterr(_fn, _rv)
Definition: vcl_test.h:33
static void * vtc_worker_loop(void *arg)
uint32_t txbuf_size
Definition: vcl_test.h:117
vppcom_endpt_t server_endpt
char vcl_test_key_rsa[]
Definition: vcl_test.h:156
static void vtc_stream_client(vcl_test_client_main_t *vcm)
static int stats_lock
vcl_test_client_worker_t * workers
static int vtc_cfg_sync(vcl_test_session_t *ts)
uint32_t seq_num
Definition: vcl_test.h:85
vcl_test_cfg_t cfg
Definition: vcl_test.h:121
static void cfg_num_writes_set(void)
uint32_t verbose
Definition: vcl_test.h:91
#define VCL_TEST_SEPARATOR_STRING
Definition: vcl_test.h:71
static void vcl_test_session_buf_alloc(vcl_test_session_t *socket)
Definition: vcl_test.h:252
static void vcl_test_cfg_dump(vcl_test_cfg_t *cfg, uint8_t is_client)
Definition: vcl_test.h:288
static void cfg_txbuf_size_set(void)
vcl_test_session_t * qsessions
#define VCL_TEST_CFG_CTRL_MAGIC
Definition: vcl_test.h:62
vcl_test_session_t * sessions
#define VCL_TEST_TOKEN_RUN_BI
Definition: vcl_test.h:57
uint32_t address_ip6
Definition: vcl_test.h:92
svmdb_client_t * c
uint64_t rxbuf_size
Definition: vcl_test.h:94
static void vcl_test_cfg_init(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:200
#define VCL_TEST_TOKEN_TXBUF_SIZE
Definition: vcl_test.h:51
#define VCL_TEST_TOKEN_VERBOSE
Definition: vcl_test.h:50
static void cfg_rxbuf_size_set(void)
#define vt_atomic_add(_ptr, _val)
Definition: vcl_test.h:45
char vcl_test_crt_rsa[]
Definition: vcl_test.h:130
static void vtc_print_stats(vcl_test_session_t *ctrl)
uint32_t num_test_sessions_perq
Definition: vcl_test.h:89
#define VCL_TEST_TOKEN_HELP
Definition: vcl_test.h:48
uint32_t magic
Definition: vcl_test.h:84
#define vtinf(_fmt, _args...)
Definition: vcl_test.h:42
static void vcl_test_buf_alloc(vcl_test_cfg_t *cfg, uint8_t is_rxbuf, uint8_t **buf, uint32_t *bufsize)
Definition: vcl_test.h:229
static int vcl_test_read(int fd, uint8_t *buf, uint32_t nbytes, vcl_test_stats_t *stats)
Definition: vcl_test.h:407
uint32_t ctrl_handle
Definition: vcl_test.h:87
vcl_test_stats_t stats
Definition: vcl_test.h:122
static int vtc_quic_connect_test_sessions(vcl_test_client_worker_t *wrk)
static int vcl_test_write(int fd, uint8_t *buf, uint32_t nbytes, vcl_test_stats_t *stats, uint32_t verbose)
Definition: vcl_test.h:484
static void vtc_accumulate_stats(vcl_test_client_worker_t *wrk, vcl_test_session_t *ctrl)
uint64_t tx_bytes
Definition: vcl_test.h:107
uint32_t vcl_test_key_rsa_len
Definition: vcl_test.h:184
#define vtc_max(a, b)
static int vtc_connect_test_sessions(vcl_test_client_worker_t *wrk)
#define VCL_TEST_TOKEN_RUN_UNI
Definition: vcl_test.h:56
uint32_t rxbuf_size
Definition: vcl_test.h:119
uint32_t test
Definition: vcl_test.h:86
static int vcl_comp_tspec(struct timespec *a, struct timespec *b)
Definition: vcl_test.h:392
static void vcl_test_stats_accumulate(vcl_test_stats_t *accum, vcl_test_stats_t *incr)
Definition: vcl_test.h:187
static void vtc_read_user_input(vcl_test_session_t *ctrl)
static int vtc_worker_init(vcl_test_client_worker_t *wrk)
static void cfg_verbose_toggle(void)
#define vtfail(_fn, _rv)
Definition: vcl_test.h:25
#define VCL_TEST_TOKEN_NUM_TEST_SESS
Definition: vcl_test.h:52
#define VCL_TEST_TOKEN_EXIT
Definition: vcl_test.h:49
static int vcl_test_cfg_verify(vcl_test_cfg_t *cfg, vcl_test_cfg_t *valid_cfg)
Definition: vcl_test.h:215
uint64_t rx_bytes
Definition: vcl_test.h:103
static void cfg_num_test_sessions_set(void)
static void vtc_ctrl_session_exit(void)
uint64_t total_bytes
Definition: vcl_test.h:97
static void vtc_process_opts(vcl_test_client_main_t *vcm, int argc, char **argv)
#define VCL_TEST_CFG_MAX_TEST_SESS
Definition: vcl_test.h:67
#define vtwrn(_fmt, _args...)
Definition: vcl_test.h:39