FD.io VPP  v21.06
Vector Packet Processing
vcl_test_server.c
Go to the documentation of this file.
1 /*
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:
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 <sys/types.h>
19 #include <sys/socket.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23 #include <ctype.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <hs_apps/vcl/vcl_test.h>
27 #include <sys/epoll.h>
28 #include <vppinfra/mem.h>
29 #include <pthread.h>
30 
31 typedef struct
32 {
33  uint16_t port;
34  uint32_t address_ip6;
37  vppcom_endpt_t endpt;
39 
40 typedef struct
41 {
43  uint32_t wrk_index;
44  int epfd;
46  int nfds;
48  pthread_t thread_handle;
50 
51 typedef struct
52 {
57  struct sockaddr_storage servaddr;
58  volatile int worker_fails;
59  volatile int active_workers;
63 
65 
67 
68 static inline void
70 {
71  vcl_test_session_t *conn_pool;
72  size_t new_size = wrk->conn_pool_size + expand_size;
73  int i;
74 
75  conn_pool = realloc (wrk->conn_pool, new_size * sizeof (*wrk->conn_pool));
76  if (conn_pool)
77  {
78  for (i = wrk->conn_pool_size; i < new_size; i++)
79  {
80  vcl_test_session_t *conn = &conn_pool[i];
81  memset (conn, 0, sizeof (*conn));
82  }
83 
84  wrk->conn_pool = conn_pool;
85  wrk->conn_pool_size = new_size;
86  }
87  else
88  {
89  vterr ("conn_pool_expand()", -errno);
90  }
91 }
92 
93 static inline vcl_test_session_t *
95 {
96  vcl_test_session_t *conn;
97  int i, expand = 0;
98 
99 again:
100  for (i = 0; i < wrk->conn_pool_size; i++)
101  {
102  if (!wrk->conn_pool[i].is_alloc)
103  {
104  conn = &wrk->conn_pool[i];
105  memset (conn, 0, sizeof (*conn));
106  conn->endpt.ip = wrk->conn_pool[i].ip;
107  conn->is_alloc = 1;
108  conn->session_index = i;
109  vcl_test_cfg_init (&conn->cfg);
110  return (&wrk->conn_pool[i]);
111  }
112  }
113 
114  if (expand == 0)
115  {
116  conn_pool_expand (wrk, 2 * wrk->conn_pool_size);
117  expand = 1;
118  goto again;
119  }
120  vtwrn ("Failed to allocate connection even after expand");
121  return 0;
122 }
123 
124 static inline void
126 {
127  ts->fd = 0;
128  ts->is_alloc = 0;
130 }
131 
132 static inline void
134 {
135  conn->cfg = *rx_cfg;
136  vcl_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */, (uint8_t **) &conn->rxbuf,
137  &conn->rxbuf_size);
138  conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
139 
140  if (conn->cfg.verbose)
141  {
142  vtinf ("(fd %d): Replying to cfg message!\n", conn->fd);
143  vcl_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
144  }
145  (void) vcl_test_write (conn, &conn->cfg, sizeof (conn->cfg));
146 }
147 
148 static void
150 {
153 
154  if (!conn->is_open)
155  return;
156 
157  if (vt->protos[vsm->server_cfg.proto]->close)
158  vt->protos[vsm->server_cfg.proto]->close (conn);
159 
160  vppcom_session_close (conn->fd);
161  conn->is_open = 0;
162 }
163 
164 static void
166 {
167  vts_session_close (ts);
168  conn_pool_free (ts);
169 }
170 
171 static void
173 {
174  vcl_test_session_t *conn;
175  int i;
176 
177  for (i = 0; i < wrk->conn_pool_size; i++)
178  {
179  conn = &wrk->conn_pool[i];
180  vts_session_cleanup (conn);
181  }
182 
183  wrk->nfds = 0;
184 }
185 
186 static void
188  vcl_test_cfg_t *rx_cfg)
189 {
190  u8 is_bi = rx_cfg->test == VCL_TEST_TYPE_BI;
191  vcl_test_session_t *tc;
192  char buf[64];
193  int i;
194 
195  if (rx_cfg->cmd == VCL_TEST_CMD_STOP)
196  {
197  struct timespec stop;
198  clock_gettime (CLOCK_REALTIME, &stop);
199 
200  /* Test session are not closed, e.g., connection-less or errors */
201  if (wrk->nfds > 1)
202  {
203  vtinf ("%u sessions are still open", wrk->nfds - 1);
204  stop.tv_sec -= VCL_TEST_DELAY_DISCONNECT;
205  conn->stats.stop = stop;
206  }
207 
208  /* Accumulate stats over all of the worker's sessions */
209  for (i = 0; i < wrk->conn_pool_size; i++)
210  {
211  tc = &wrk->conn_pool[i];
212  if (tc == conn)
213  continue;
214 
215  vcl_test_stats_accumulate (&conn->stats, &tc->stats);
216  if (tc->is_open)
217  {
218  vts_session_cleanup (tc);
219  continue;
220  }
221  /* Only relevant if all connections previously closed */
222  if (vcl_comp_tspec (&conn->stats.stop, &tc->stats.stop) < 0)
223  conn->stats.stop = tc->stats.stop;
224  }
225 
226  if (conn->cfg.verbose)
227  {
228  snprintf (buf, sizeof (buf), "SERVER (fd %d) RESULTS", conn->fd);
229  vcl_test_stats_dump (buf, &conn->stats, 1 /* show_rx */,
230  is_bi /* show tx */, conn->cfg.verbose);
231  }
232 
233  vcl_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
234  is_bi /* show_tx */ , conn->cfg.verbose);
235  vcl_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
236  if (conn->cfg.verbose)
237  {
238  vtinf (" vcl server main\n" VCL_TEST_SEPARATOR_STRING
239  " buf: %p\n"
240  " buf size: %u (0x%08x)\n" VCL_TEST_SEPARATOR_STRING,
241  conn->rxbuf, conn->rxbuf_size, conn->rxbuf_size);
242  }
243 
244  sync_config_and_reply (conn, rx_cfg);
245  memset (&conn->stats, 0, sizeof (conn->stats));
246  }
247  else if (rx_cfg->cmd == VCL_TEST_CMD_SYNC)
248  {
249  rx_cfg->ctrl_handle = conn->fd;
250  vtinf ("Set control fd %d for test!", conn->fd);
251  sync_config_and_reply (conn, rx_cfg);
252  }
253  else if (rx_cfg->cmd == VCL_TEST_CMD_START)
254  {
255  vtinf ("Starting %s-directional Stream Test (fd %d)!",
256  is_bi ? "Bi" : "Uni", conn->fd);
257  rx_cfg->ctrl_handle = conn->fd;
258  sync_config_and_reply (conn, rx_cfg);
259 
260  /* read the 1st chunk, record start time */
261  memset (&conn->stats, 0, sizeof (conn->stats));
262  clock_gettime (CLOCK_REALTIME, &conn->stats.start);
263  }
264 }
265 
266 static inline void
268 {
270 
271  if (conn->cfg.test == VCL_TEST_TYPE_BI)
272  {
273  if (vsm->use_ds)
274  {
275  (void) vcl_test_write (conn, conn->ds[0].data, conn->ds[0].len);
276  if (conn->ds[1].len)
277  (void) vcl_test_write (conn, conn->ds[1].data, conn->ds[1].len);
278  }
279  else
280  (void) vcl_test_write (conn, conn->rxbuf, rx_bytes);
281  }
282 
283  if (vsm->use_ds)
284  vppcom_session_free_segments (conn->fd, rx_bytes);
285 
286  if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
287  clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
288 }
289 
290 static void
291 vts_server_echo (vcl_test_session_t *conn, int rx_bytes)
292 {
293  int tx_bytes, nbytes, pos;
294 
295  /* If it looks vaguely like a string, make sure it's terminated */
296  pos = rx_bytes < conn->rxbuf_size ? rx_bytes : conn->rxbuf_size - 1;
297  ((char *) conn->rxbuf)[pos] = 0;
298  vtinf ("(fd %d): RX (%d bytes) - '%s'", conn->fd, rx_bytes, conn->rxbuf);
299 
300  if (conn->cfg.verbose)
301  vtinf ("(fd %d): Echoing back", conn->fd);
302 
303  nbytes = strlen ((const char *) conn->rxbuf) + 1;
304  tx_bytes = conn->write (conn, conn->rxbuf, nbytes);
305  if (tx_bytes >= 0)
306  vtinf ("(fd %d): TX (%d bytes) - '%s'", conn->fd, tx_bytes, conn->rxbuf);
307 }
308 
309 static vcl_test_session_t *
311 {
313  const vcl_test_proto_vft_t *tp;
314  vcl_test_session_t *conn;
315  struct epoll_event ev;
316  int rv;
317 
318  conn = conn_pool_alloc (wrk);
319  if (!conn)
320  {
321  vtwrn ("No free connections!");
322  return 0;
323  }
324 
325  if (vsm->ctrl)
326  conn->cfg = vsm->ctrl->cfg;
328  clock_gettime (CLOCK_REALTIME, &conn->old_stats.stop);
329 
330  tp = vcl_test_main.protos[vsm->server_cfg.proto];
331  if (tp->accept (listen_fd, conn))
332  return 0;
333 
334  vtinf ("Got a connection -- fd = %d (0x%08x) on listener fd = %d (0x%08x)",
335  conn->fd, conn->fd, listen_fd, listen_fd);
336 
337  ev.events = EPOLLIN;
338  ev.data.u64 = conn - wrk->conn_pool;
339  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, conn->fd, &ev);
340  if (rv < 0)
341  {
342  vterr ("vppcom_epoll_ctl()", rv);
343  return 0;
344  }
345  wrk->nfds++;
346 
347  return conn;
348 }
349 
350 static void
352 {
353  fprintf (stderr, "vcl_test_server [OPTIONS] <port>\n"
354  " OPTIONS\n"
355  " -h Print this message and exit.\n"
356  " -6 Use IPv6\n"
357  " -w <num> Number of workers\n"
358  " -p <PROTO> Use <PROTO> transport layer\n"
359  " -D Use UDP transport layer\n"
360  " -L Use TLS transport layer\n"
361  " -S Incremental stats\n");
362  exit (1);
363 }
364 
365 static void
367 {
368  struct sockaddr_storage *servaddr = &vsm->servaddr;
369  memset (servaddr, 0, sizeof (*servaddr));
370 
371  if (vsm->server_cfg.address_ip6)
372  {
373  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
374  server_addr->sin6_family = AF_INET6;
375  server_addr->sin6_addr = in6addr_any;
376  server_addr->sin6_port = htons (vsm->server_cfg.port);
377  }
378  else
379  {
380  struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
381  server_addr->sin_family = AF_INET;
382  server_addr->sin_addr.s_addr = htonl (INADDR_ANY);
383  server_addr->sin_port = htons (vsm->server_cfg.port);
384  }
385 
386  if (vsm->server_cfg.address_ip6)
387  {
388  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
389  vsm->server_cfg.endpt.is_ip4 = 0;
390  vsm->server_cfg.endpt.ip = (uint8_t *) &server_addr->sin6_addr;
391  vsm->server_cfg.endpt.port = (uint16_t) server_addr->sin6_port;
392  }
393  else
394  {
395  struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
396  vsm->server_cfg.endpt.is_ip4 = 1;
397  vsm->server_cfg.endpt.ip = (uint8_t *) &server_addr->sin_addr;
398  vsm->server_cfg.endpt.port = (uint16_t) server_addr->sin_port;
399  }
400 }
401 
402 static void
404  char **argv)
405 {
406  int v, c;
407 
408  vsm->server_cfg.proto = VPPCOM_PROTO_TCP;
409 
410  opterr = 0;
411  while ((c = getopt (argc, argv, "6DLsw:hp:S")) != -1)
412  switch (c)
413  {
414  case '6':
415  vsm->server_cfg.address_ip6 = 1;
416  break;
417 
418  case 'p':
419  if (vppcom_unformat_proto (&vsm->server_cfg.proto, optarg))
420  vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
421  break;
422 
423  case 'D':
424  vsm->server_cfg.proto = VPPCOM_PROTO_UDP;
425  break;
426 
427  case 'L':
428  vsm->server_cfg.proto = VPPCOM_PROTO_TLS;
429  break;
430 
431  case 'w':
432  v = atoi (optarg);
433  if (v > 1)
434  vsm->server_cfg.workers = v;
435  else
436  vtwrn ("Invalid number of workers %d", v);
437  break;
438  case 's':
439  vsm->use_ds = 1;
440  break;
441  case 'S':
442  vsm->incremental_stats = 1;
443  break;
444  case '?':
445  switch (optopt)
446  {
447  case 'w':
448  case 'p':
449  vtwrn ("Option `-%c' requires an argument.", optopt);
450  break;
451  default:
452  if (isprint (optopt))
453  vtwrn ("Unknown option `-%c'.", optopt);
454  else
455  vtwrn ("Unknown option character `\\x%x'.", optopt);
456  }
457  /* fall thru */
458  case 'h':
459  default:
461  }
462 
463  if (argc < (optind + 1))
464  {
465  fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
467  }
468 
469  if (sscanf (argv[optind], "%d", &v) == 1)
470  vsm->server_cfg.port = (uint16_t) v;
471  else
472  {
473  fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
475  }
476 
478 }
479 
480 int
482  vcl_test_session_t *conn, int rx_bytes)
483 {
484  if (rx_cfg->verbose)
485  {
486  vtinf ("(fd %d): Received a cfg msg!", conn->fd);
487  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
488  }
489 
490  if (rx_bytes != sizeof (*rx_cfg))
491  {
492  vtinf ("(fd %d): Invalid cfg msg size %d expected %lu!", conn->fd,
493  rx_bytes, sizeof (*rx_cfg));
494  conn->cfg.rxbuf_size = 0;
495  conn->cfg.num_writes = 0;
496  if (conn->cfg.verbose)
497  {
498  vtinf ("(fd %d): Replying to cfg msg", conn->fd);
499  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
500  }
501  conn->write (conn, &conn->cfg, sizeof (conn->cfg));
502  return -1;
503  }
504 
505  switch (rx_cfg->test)
506  {
507  case VCL_TEST_TYPE_NONE:
508  case VCL_TEST_TYPE_ECHO:
509  sync_config_and_reply (conn, rx_cfg);
510  break;
511 
512  case VCL_TEST_TYPE_BI:
513  case VCL_TEST_TYPE_UNI:
514  vts_test_cmd (wrk, conn, rx_cfg);
515  break;
516 
517  case VCL_TEST_TYPE_EXIT:
518  vtinf ("Ctrl session fd %d closing!", conn->fd);
519  vts_session_cleanup (conn);
520  wrk->nfds--;
521  if (wrk->nfds)
522  vts_wrk_cleanup_all (wrk);
523  break;
524 
525  default:
526  vtwrn ("Unknown test type %d", rx_cfg->test);
527  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
528  break;
529  }
530 
531  return 0;
532 }
533 
534 static void
536 {
539  const vcl_test_proto_vft_t *tp;
540  struct epoll_event listen_ev;
541  int rv;
542 
543  __wrk_index = wrk->wrk_index;
544 
545  vtinf ("Initializing worker ...");
546 
548  if (wrk->wrk_index)
549  if (vppcom_worker_register ())
550  vtfail ("vppcom_worker_register()", 1);
551 
552  tp = vt->protos[vsm->server_cfg.proto];
553  if ((rv = tp->listen (&wrk->listener, &vsm->server_cfg.endpt)))
554  vtfail ("proto listen", rv);
555 
556  /* First worker already has epoll fd */
557  if (wrk->wrk_index)
558  {
559  wrk->epfd = vppcom_epoll_create ();
560  if (wrk->epfd < 0)
561  vtfail ("vppcom_epoll_create()", wrk->epfd);
562  }
563 
564  listen_ev.events = EPOLLIN;
565  listen_ev.data.u32 = VCL_TEST_DATA_LISTENER;
566  rv =
567  vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listener.fd, &listen_ev);
568  if (rv < 0)
569  vtfail ("vppcom_epoll_ctl", rv);
570 
571  vsm->active_workers += 1;
572  vtinf ("Waiting for client data connections on port %d ...",
573  ntohs (vsm->server_cfg.endpt.port));
574 }
575 
576 static inline int
578 {
580  if (vsm->use_ds)
581  return vcl_test_read_ds (conn);
582  else
583  return conn->read (conn, conn->rxbuf, conn->rxbuf_size);
584 }
585 
586 static void
588 {
589  /* Avoid checking time too often because of syscall cost */
590  if (ts->stats.rx_bytes - ts->old_stats.rx_bytes < 1 << 20)
591  return;
592 
593  clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
594  if (vcl_test_time_diff (&ts->old_stats.stop, &ts->stats.stop) > 1)
595  {
596  vcl_test_stats_dump_inc (ts, 1 /* is_rx */);
597  ts->old_stats = ts->stats;
598  }
599 }
600 
601 static void *
602 vts_worker_loop (void *arg)
603 {
604  struct epoll_event ep_evts[VCL_TEST_CFG_MAX_EPOLL_EVENTS];
607  vcl_test_session_t *conn;
608  int i, rx_bytes, num_ev;
609  vcl_test_cfg_t *rx_cfg;
610 
611  if (wrk->wrk_index)
612  vts_worker_init (wrk);
613 
614  while (1)
615  {
616  num_ev =
617  vppcom_epoll_wait (wrk->epfd, ep_evts, VCL_TEST_CFG_MAX_EPOLL_EVENTS,
618  0 /* poll session events */);
619  if (num_ev < 0)
620  {
621  vterr ("vppcom_epoll_wait()", num_ev);
622  goto fail;
623  }
624  else if (num_ev == 0)
625  {
626  continue;
627  }
628  for (i = 0; i < num_ev; i++)
629  {
630  conn = &wrk->conn_pool[ep_evts[i].data.u32];
631  /*
632  * Check for close events
633  */
634  if (ep_evts[i].events & (EPOLLHUP | EPOLLRDHUP))
635  {
636  vts_session_cleanup (conn);
637  wrk->nfds--;
638  if (!wrk->nfds)
639  {
640  vtinf ("All client connections closed\n");
641  goto done;
642  }
643  continue;
644  }
645 
646  /*
647  * Check if new session needs to be accepted
648  */
649 
650  if (!wrk->wrk_index && ep_evts[i].data.u32 == VCL_TEST_CTRL_LISTENER)
651  {
652  if (vsm->ctrl)
653  {
654  vtwrn ("ctrl already exists");
655  continue;
656  }
657  vsm->ctrl = vts_accept_client (wrk, vsm->ctrl_listen_fd);
658  continue;
659  }
660  if (ep_evts[i].data.u32 == VCL_TEST_DATA_LISTENER)
661  {
662  conn = vts_accept_client (wrk, wrk->listener.fd);
663  conn->cfg = vsm->ctrl->cfg;
664  continue;
665  }
666  else if (vppcom_session_is_connectable_listener (conn->fd))
667  {
668  vts_accept_client (wrk, conn->fd);
669  continue;
670  }
671 
672  /*
673  * Message on control session
674  */
675 
676  if (!wrk->wrk_index && conn->fd == vsm->ctrl->fd)
677  {
678  rx_bytes = conn->read (conn, conn->rxbuf, conn->rxbuf_size);
679  rx_cfg = (vcl_test_cfg_t *) conn->rxbuf;
680  if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
681  {
682  vts_handle_ctrl_cfg (wrk, rx_cfg, conn, rx_bytes);
683  if (!wrk->nfds)
684  {
685  vtinf ("All client connections closed\n");
686  goto done;
687  }
688  }
689  else if (isascii (conn->rxbuf[0]))
690  {
691  vts_server_echo (conn, rx_bytes);
692  }
693  else
694  {
695  vtwrn ("FIFO not drained! extra bytes %d", rx_bytes);
696  }
697  continue;
698  }
699 
700  /*
701  * Read perf test data
702  */
703 
704  if (EPOLLIN & ep_evts[i].events)
705  {
706  read_again:
707  rx_bytes = vts_conn_read (conn);
708 
709  if (rx_bytes <= 0)
710  {
711  if (errno == ECONNRESET)
712  {
713  vtinf ("Connection reset by remote peer.\n");
714  goto fail;
715  }
716  else
717  continue;
718  }
719  vts_server_process_rx (conn, rx_bytes);
720  if (vppcom_session_attr (conn->fd, VPPCOM_ATTR_GET_NREAD, 0, 0) >
721  0)
722  goto read_again;
723  if (vsm->incremental_stats)
724  vts_inc_stats_check (conn);
725  continue;
726  }
727  else
728  {
729  vtwrn ("Unhandled event");
730  goto fail;
731  }
732  }
733  }
734 
735 fail:
736  vsm->worker_fails -= 1;
737 
738 done:
739  vppcom_session_close (wrk->listener.fd);
740  if (wrk->conn_pool)
741  free (wrk->conn_pool);
742  vsm->active_workers -= 1;
743  return 0;
744 }
745 
746 static void
748 {
750  struct epoll_event listen_ev;
751  int rv;
752 
753  vtinf ("Initializing main ctrl session ...");
754 
755  vsm->ctrl_listen_fd =
756  vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
757  if (vsm->ctrl_listen_fd < 0)
758  vtfail ("vppcom_session_create()", vsm->ctrl_listen_fd);
759 
760  rv = vppcom_session_bind (vsm->ctrl_listen_fd, &vsm->server_cfg.endpt);
761  if (rv < 0)
762  vtfail ("vppcom_session_bind()", rv);
763 
764  rv = vppcom_session_listen (vsm->ctrl_listen_fd, 10);
765  if (rv < 0)
766  vtfail ("vppcom_session_listen()", rv);
767 
768  wrk->epfd = vppcom_epoll_create ();
769  if (wrk->epfd < 0)
770  vtfail ("vppcom_epoll_create()", wrk->epfd);
771 
772  listen_ev.events = EPOLLIN;
773  listen_ev.data.u32 = VCL_TEST_CTRL_LISTENER;
774  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, vsm->ctrl_listen_fd,
775  &listen_ev);
776  if (rv < 0)
777  vtfail ("vppcom_epoll_ctl", rv);
778 
779  vtinf ("Waiting for client ctrl connection on port %d ...",
780  vsm->server_cfg.port);
781 }
782 
783 int
784 main (int argc, char **argv)
785 {
788  int rv, i;
789 
790  clib_mem_init_thread_safe (0, 64 << 20);
792  vsm->server_cfg.workers = 1;
793  vsm->active_workers = 0;
794  vcl_test_server_process_opts (vsm, argc, argv);
795 
796  rv = vppcom_app_create ("vcl_test_server");
797  if (rv)
798  vtfail ("vppcom_app_create()", rv);
799 
800  /* Protos like tls/dtls/quic need init */
801  if (vt->protos[vsm->server_cfg.proto]->init)
802  vt->protos[vsm->server_cfg.proto]->init (0);
803 
804  vsm->workers = calloc (vsm->server_cfg.workers, sizeof (*vsm->workers));
805  vts_ctrl_session_init (&vsm->workers[0]);
806 
807  /* Update ctrl port to data port */
808  vsm->server_cfg.endpt.port += 1;
809  vts_worker_init (&vsm->workers[0]);
810  for (i = 1; i < vsm->server_cfg.workers; i++)
811  {
812  vsm->workers[i].wrk_index = i;
813  rv = pthread_create (&vsm->workers[i].thread_handle, NULL,
814  vts_worker_loop, (void *) &vsm->workers[i]);
815  }
816 
817  vts_worker_loop (&vsm->workers[0]);
818 
819  while (vsm->active_workers > 0)
820  ;
821 
822  vppcom_app_destroy ();
823  free (vsm->workers);
824 
825  return vsm->worker_fails;
826 }
827 
828 /*
829  * fd.io coding-style-patch-verification: ON
830  *
831  * Local Variables:
832  * eval: (c-set-style "gnu")
833  * End:
834  */
uint32_t rxbuf_size
Definition: vcl_test.h:134
vppcom_data_segment_t ds[2]
Definition: vcl_test.h:143
struct sockaddr_storage servaddr
static double vcl_test_time_diff(struct timespec *old, struct timespec *new)
Definition: vcl_test.h:402
struct timespec stop
Definition: vcl_test.h:122
#define ntohs(x)
Definition: af_xdp.bpf.c:29
Optimized string handling code, including c11-compliant "safe C library" variants.
session_worker_t * wrk
Definition: application.c:490
static int vcl_test_write(vcl_test_session_t *ts, void *buf, uint32_t nbytes)
Definition: vcl_test.h:530
uint8_t ip[16]
Definition: vcl_test.h:142
int(* read)(struct vcl_test_session *ts, void *buf, uint32_t buflen)
Definition: vcl_test.h:131
vppcom_endpt_t endpt
int(* accept)(int listen_fd, vcl_test_session_t *ts)
Definition: vcl_test.h:160
const vcl_test_proto_vft_t * protos[VPPCOM_PROTO_SRTP+1]
Definition: vcl_test.h:173
static void vts_ctrl_session_init(vcl_test_server_worker_t *wrk)
static void vcl_test_server_process_opts(vcl_test_server_main_t *vsm, int argc, char **argv)
int(* init)(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:157
static void vts_session_close(vcl_test_session_t *conn)
static void conn_pool_expand(vcl_test_server_worker_t *wrk, size_t expand_size)
static void vts_server_process_rx(vcl_test_session_t *conn, int rx_bytes)
#define VCL_TEST_DELAY_DISCONNECT
Definition: vcl_test.h:73
unsigned char u8
Definition: types.h:56
#define VCL_TEST_SERVER_PORT
Definition: vcl_test.h:60
u8 data[128]
Definition: ipsec_types.api:92
struct timespec start
Definition: vcl_test.h:121
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
uint64_t num_writes
Definition: vcl_test.h:107
static void vts_inc_stats_check(vcl_test_session_t *ts)
static void print_usage_and_exit(void)
uint64_t txbuf_size
Definition: vcl_test.h:106
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:336
static perfmon_event_t events[]
Definition: core.c:21
#define vterr(_fn, _rv)
Definition: vcl_test.h:34
static void vcl_test_session_buf_alloc(vcl_test_session_t *ts)
Definition: vcl_test.h:253
int __clib_unused rv
Definition: application.c:491
static vcl_test_server_main_t vcl_server_main
static void * vts_worker_loop(void *arg)
vcl_test_stats_t stats
Definition: vcl_test.h:138
int vts_handle_ctrl_cfg(vcl_test_server_worker_t *wrk, vcl_test_cfg_t *rx_cfg, vcl_test_session_t *conn, int rx_bytes)
uint8_t is_alloc
Definition: vcl_test.h:127
static void conn_pool_free(vcl_test_session_t *ts)
vcl_test_cfg_t cfg
Definition: vcl_test.h:137
vcl_test_stats_t old_stats
Definition: vcl_test.h:139
vcl_test_main_t vcl_test_main
uint32_t verbose
Definition: vcl_test.h:102
int(* write)(struct vcl_test_session *ts, void *buf, uint32_t buflen)
Definition: vcl_test.h:132
#define VCL_TEST_SEPARATOR_STRING
Definition: vcl_test.h:74
static void vts_session_cleanup(vcl_test_session_t *ts)
static void vcl_test_cfg_dump(vcl_test_cfg_t *cfg, uint8_t is_client)
Definition: vcl_test.h:298
static int vts_conn_read(vcl_test_session_t *conn)
#define VCL_TEST_CFG_CTRL_MAGIC
Definition: vcl_test.h:63
static vcl_test_session_t * conn_pool_alloc(vcl_test_server_worker_t *wrk)
static void vts_worker_init(vcl_test_server_worker_t *wrk)
svmdb_client_t * c
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
vppcom_endpt_t endpt
Definition: vcl_test.h:141
uint64_t rxbuf_size
Definition: vcl_test.h:105
static void vcl_test_cfg_init(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:201
u64 buf
Definition: application.c:493
static void vcl_test_session_buf_free(vcl_test_session_t *ts)
Definition: vcl_test.h:264
static void vts_wrk_cleanup_all(vcl_test_server_worker_t *wrk)
vcl_test_session_t * conn_pool
void free(void *p)
Definition: mem.c:42
uint32_t magic
Definition: vcl_test.h:94
#define vtinf(_fmt, _args...)
Definition: vcl_test.h:43
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:230
int(* listen)(vcl_test_session_t *ts, vppcom_endpt_t *endpt)
Definition: vcl_test.h:159
uint32_t ctrl_handle
Definition: vcl_test.h:98
#define VCL_TEST_CTRL_LISTENER
Definition: vcl_test.h:71
vcl_test_session_t listener
int main(int argc, char **argv)
static void vts_test_cmd(vcl_test_server_worker_t *wrk, vcl_test_session_t *conn, vcl_test_cfg_t *rx_cfg)
void * realloc(void *p, size_t size)
Definition: mem.c:67
vcl_test_server_cfg_t server_cfg
#define VCL_TEST_DATA_LISTENER
Definition: vcl_test.h:72
uint8_t is_open
Definition: vcl_test.h:128
void * calloc(size_t nmemb, size_t size)
Definition: mem.c:54
uint32_t test
Definition: vcl_test.h:96
static int vcl_comp_tspec(struct timespec *a, struct timespec *b)
Definition: vcl_test.h:447
int(* close)(vcl_test_session_t *ts)
Definition: vcl_test.h:161
static void vcl_test_stats_accumulate(vcl_test_stats_t *accum, vcl_test_stats_t *incr)
Definition: vcl_test.h:188
static int vcl_test_read_ds(vcl_test_session_t *ts)
Definition: vcl_test.h:496
vcl_test_server_worker_t * workers
#define vtfail(_fn, _rv)
Definition: vcl_test.h:26
static void vts_server_echo(vcl_test_session_t *conn, int rx_bytes)
static void vcl_test_stats_dump_inc(vcl_test_session_t *ts, int is_rx)
Definition: vcl_test.h:419
static void vcl_test_init_endpoint_addr(vcl_test_server_main_t *vsm)
void * clib_mem_init_thread_safe(void *memory, uword memory_size)
Definition: mem_dlmalloc.c:280
vcl_test_session_t * ctrl
volatile int active_workers
uint32_t cmd
Definition: vcl_test.h:97
uint64_t rx_bytes
Definition: vcl_test.h:114
static void sync_config_and_reply(vcl_test_session_t *conn, vcl_test_cfg_t *rx_cfg)
static vcl_test_session_t * vts_accept_client(vcl_test_server_worker_t *wrk, int listen_fd)
uint64_t total_bytes
Definition: vcl_test.h:108
#define VCL_TEST_CFG_MAX_TEST_SESS
Definition: vcl_test.h:68
#define vtwrn(_fmt, _args...)
Definition: vcl_test.h:40