FD.io VPP  v21.10.1-2-g0a485f517
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[VPPCOM_PROTO_TCP];
331  if (tp->accept (listen_fd, conn))
332  return 0;
333 
334  vtinf ("CTRL accepted fd = %d (0x%08x) on listener fd = %d (0x%08x)",
335  conn->fd, conn->fd, listen_fd, listen_fd);
336 
337  ev.events = EPOLLET | 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 
346  wrk->nfds++;
347 
348  return conn;
349 }
350 
351 static vcl_test_session_t *
353 {
355  const vcl_test_proto_vft_t *tp;
356  vcl_test_session_t *conn;
357  struct epoll_event ev;
358  int rv;
359 
360  conn = conn_pool_alloc (wrk);
361  if (!conn)
362  {
363  vtwrn ("No free connections!");
364  return 0;
365  }
366 
367  if (vsm->ctrl)
368  conn->cfg = vsm->ctrl->cfg;
370  clock_gettime (CLOCK_REALTIME, &conn->old_stats.stop);
371 
373  if (tp->accept (listen_fd, conn))
374  return 0;
375 
376  vtinf ("Got a connection -- fd = %d (0x%08x) on listener fd = %d (0x%08x)",
377  conn->fd, conn->fd, listen_fd, listen_fd);
378 
379  ev.events = EPOLLET | EPOLLIN;
380  ev.data.u64 = conn - wrk->conn_pool;
381  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, conn->fd, &ev);
382  if (rv < 0)
383  {
384  vterr ("vppcom_epoll_ctl()", rv);
385  return 0;
386  }
387  wrk->nfds++;
388 
389  return conn;
390 }
391 
392 static void
394 {
395  fprintf (stderr, "vcl_test_server [OPTIONS] <port>\n"
396  " OPTIONS\n"
397  " -h Print this message and exit.\n"
398  " -6 Use IPv6\n"
399  " -w <num> Number of workers\n"
400  " -p <PROTO> Use <PROTO> transport layer\n"
401  " -D Use UDP transport layer\n"
402  " -L Use TLS transport layer\n"
403  " -S Incremental stats\n");
404  exit (1);
405 }
406 
407 static void
409 {
410  struct sockaddr_storage *servaddr = &vsm->servaddr;
411  memset (servaddr, 0, sizeof (*servaddr));
412 
413  if (vsm->server_cfg.address_ip6)
414  {
415  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
416  server_addr->sin6_family = AF_INET6;
417  server_addr->sin6_addr = in6addr_any;
418  server_addr->sin6_port = htons (vsm->server_cfg.port);
419  }
420  else
421  {
422  struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
423  server_addr->sin_family = AF_INET;
424  server_addr->sin_addr.s_addr = htonl (INADDR_ANY);
425  server_addr->sin_port = htons (vsm->server_cfg.port);
426  }
427 
428  if (vsm->server_cfg.address_ip6)
429  {
430  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
431  vsm->server_cfg.endpt.is_ip4 = 0;
432  vsm->server_cfg.endpt.ip = (uint8_t *) &server_addr->sin6_addr;
433  vsm->server_cfg.endpt.port = (uint16_t) server_addr->sin6_port;
434  }
435  else
436  {
437  struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
438  vsm->server_cfg.endpt.is_ip4 = 1;
439  vsm->server_cfg.endpt.ip = (uint8_t *) &server_addr->sin_addr;
440  vsm->server_cfg.endpt.port = (uint16_t) server_addr->sin_port;
441  }
442 }
443 
444 static void
446  char **argv)
447 {
448  int v, c;
449 
450  vsm->server_cfg.proto = VPPCOM_PROTO_TCP;
451 
452  opterr = 0;
453  while ((c = getopt (argc, argv, "6DLsw:hp:S")) != -1)
454  switch (c)
455  {
456  case '6':
457  vsm->server_cfg.address_ip6 = 1;
458  break;
459 
460  case 'p':
461  if (vppcom_unformat_proto (&vsm->server_cfg.proto, optarg))
462  vtwrn ("Invalid vppcom protocol %s, defaulting to TCP", optarg);
463  break;
464 
465  case 'D':
466  vsm->server_cfg.proto = VPPCOM_PROTO_UDP;
467  break;
468 
469  case 'L':
470  vsm->server_cfg.proto = VPPCOM_PROTO_TLS;
471  break;
472 
473  case 'w':
474  v = atoi (optarg);
475  if (v > 1)
476  vsm->server_cfg.workers = v;
477  else
478  vtwrn ("Invalid number of workers %d", v);
479  break;
480  case 's':
481  vsm->use_ds = 1;
482  break;
483  case 'S':
484  vsm->incremental_stats = 1;
485  break;
486  case '?':
487  switch (optopt)
488  {
489  case 'w':
490  case 'p':
491  vtwrn ("Option `-%c' requires an argument.", optopt);
492  break;
493  default:
494  if (isprint (optopt))
495  vtwrn ("Unknown option `-%c'.", optopt);
496  else
497  vtwrn ("Unknown option character `\\x%x'.", optopt);
498  }
499  /* fall thru */
500  case 'h':
501  default:
503  }
504 
505  if (argc < (optind + 1))
506  {
507  fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
509  }
510 
511  if (sscanf (argv[optind], "%d", &v) == 1)
512  vsm->server_cfg.port = (uint16_t) v;
513  else
514  {
515  fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
517  }
518 
520 }
521 
522 int
524  vcl_test_session_t *conn, int rx_bytes)
525 {
526  if (rx_cfg->verbose)
527  {
528  vtinf ("(fd %d): Received a cfg msg!", conn->fd);
529  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
530  }
531 
532  if (rx_bytes != sizeof (*rx_cfg))
533  {
534  vtinf ("(fd %d): Invalid cfg msg size %d expected %lu!", conn->fd,
535  rx_bytes, sizeof (*rx_cfg));
536  conn->cfg.rxbuf_size = 0;
537  conn->cfg.num_writes = 0;
538  if (conn->cfg.verbose)
539  {
540  vtinf ("(fd %d): Replying to cfg msg", conn->fd);
541  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
542  }
543  conn->write (conn, &conn->cfg, sizeof (conn->cfg));
544  return -1;
545  }
546 
547  switch (rx_cfg->test)
548  {
549  case VCL_TEST_TYPE_NONE:
550  case VCL_TEST_TYPE_ECHO:
551  sync_config_and_reply (conn, rx_cfg);
552  break;
553 
554  case VCL_TEST_TYPE_BI:
555  case VCL_TEST_TYPE_UNI:
556  vts_test_cmd (wrk, conn, rx_cfg);
557  break;
558 
559  case VCL_TEST_TYPE_EXIT:
560  vtinf ("Ctrl session fd %d closing!", conn->fd);
561  vts_session_cleanup (conn);
562  wrk->nfds--;
563  if (wrk->nfds)
565  break;
566 
567  default:
568  vtwrn ("Unknown test type %d", rx_cfg->test);
569  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
570  break;
571  }
572 
573  return 0;
574 }
575 
576 static void
578 {
581  const vcl_test_proto_vft_t *tp;
582  struct epoll_event listen_ev;
583  int rv;
584 
585  __wrk_index = wrk->wrk_index;
586 
587  vtinf ("Initializing worker ...");
588 
590  if (wrk->wrk_index)
591  if (vppcom_worker_register ())
592  vtfail ("vppcom_worker_register()", 1);
593 
594  tp = vt->protos[vsm->server_cfg.proto];
595  if ((rv = tp->listen (&wrk->listener, &vsm->server_cfg.endpt)))
596  vtfail ("proto listen", rv);
597 
598  /* First worker already has epoll fd */
599  if (wrk->wrk_index)
600  {
601  wrk->epfd = vppcom_epoll_create ();
602  if (wrk->epfd < 0)
603  vtfail ("vppcom_epoll_create()", wrk->epfd);
604  }
605 
606  listen_ev.events = EPOLLET | EPOLLIN;
607  listen_ev.data.u32 = VCL_TEST_DATA_LISTENER;
608  rv =
609  vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listener.fd, &listen_ev);
610  if (rv < 0)
611  vtfail ("vppcom_epoll_ctl", rv);
612 
613  vsm->active_workers += 1;
614  vtinf ("Waiting for client data connections on port %d ...",
615  ntohs (vsm->server_cfg.endpt.port));
616 }
617 
618 static inline int
620 {
622  if (vsm->use_ds)
623  return vcl_test_read_ds (conn);
624  else
625  return conn->read (conn, conn->rxbuf, conn->rxbuf_size);
626 }
627 
628 static void
630 {
631  /* Avoid checking time too often because of syscall cost */
632  if (ts->stats.rx_bytes - ts->old_stats.rx_bytes < 1 << 20)
633  return;
634 
635  clock_gettime (CLOCK_REALTIME, &ts->stats.stop);
636  if (vcl_test_time_diff (&ts->old_stats.stop, &ts->stats.stop) > 1)
637  {
638  vcl_test_stats_dump_inc (ts, 1 /* is_rx */);
639  ts->old_stats = ts->stats;
640  }
641 }
642 
643 static void *
644 vts_worker_loop (void *arg)
645 {
646  struct epoll_event ep_evts[VCL_TEST_CFG_MAX_EPOLL_EVENTS];
649  vcl_test_session_t *conn;
650  int i, rx_bytes, num_ev;
651  vcl_test_cfg_t *rx_cfg;
652 
653  if (wrk->wrk_index)
655 
656  while (1)
657  {
658  num_ev =
659  vppcom_epoll_wait (wrk->epfd, ep_evts, VCL_TEST_CFG_MAX_EPOLL_EVENTS,
660  0 /* poll session events */);
661  if (num_ev < 0)
662  {
663  vterr ("vppcom_epoll_wait()", num_ev);
664  goto fail;
665  }
666  else if (num_ev == 0)
667  {
668  continue;
669  }
670  for (i = 0; i < num_ev; i++)
671  {
672  conn = &wrk->conn_pool[ep_evts[i].data.u32];
673  /*
674  * Check for close events
675  */
676  if (ep_evts[i].events & (EPOLLHUP | EPOLLRDHUP))
677  {
678  vts_session_cleanup (conn);
679  wrk->nfds--;
680  if (!wrk->nfds)
681  {
682  vtinf ("All client connections closed\n");
683  goto done;
684  }
685  continue;
686  }
687 
688  /*
689  * Check if new session needs to be accepted
690  */
691 
692  if (!wrk->wrk_index && ep_evts[i].data.u32 == VCL_TEST_CTRL_LISTENER)
693  {
694  if (vsm->ctrl)
695  {
696  vtwrn ("ctrl already exists");
697  continue;
698  }
699  vsm->ctrl = vts_accept_ctrl (wrk, vsm->ctrl_listen_fd);
700  continue;
701  }
702  if (ep_evts[i].data.u32 == VCL_TEST_DATA_LISTENER)
703  {
704  conn = vts_accept_client (wrk, wrk->listener.fd);
705  conn->cfg = vsm->ctrl->cfg;
706  continue;
707  }
708  else if (vppcom_session_is_connectable_listener (conn->fd))
709  {
710  vts_accept_client (wrk, conn->fd);
711  continue;
712  }
713 
714  /*
715  * Message on control session
716  */
717 
718  if (!wrk->wrk_index && conn->fd == vsm->ctrl->fd)
719  {
720  rx_bytes = conn->read (conn, conn->rxbuf, conn->rxbuf_size);
721  rx_cfg = (vcl_test_cfg_t *) conn->rxbuf;
722  if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
723  {
724  vts_handle_ctrl_cfg (wrk, rx_cfg, conn, rx_bytes);
725  if (!wrk->nfds)
726  {
727  vtinf ("All client connections closed\n");
728  goto done;
729  }
730  }
731  else if (isascii (conn->rxbuf[0]))
732  {
733  vts_server_echo (conn, rx_bytes);
734  }
735  else
736  {
737  vtwrn ("FIFO not drained! extra bytes %d", rx_bytes);
738  }
739  continue;
740  }
741 
742  /*
743  * Read perf test data
744  */
745 
746  if (EPOLLIN & ep_evts[i].events)
747  {
748  read_again:
749  rx_bytes = vts_conn_read (conn);
750 
751  if (rx_bytes <= 0)
752  {
753  if (errno == ECONNRESET)
754  {
755  vtinf ("Connection reset by remote peer.\n");
756  goto fail;
757  }
758  else
759  continue;
760  }
761  vts_server_process_rx (conn, rx_bytes);
762  if (vppcom_session_attr (conn->fd, VPPCOM_ATTR_GET_NREAD, 0, 0) >
763  0)
764  goto read_again;
765  if (vsm->incremental_stats)
766  vts_inc_stats_check (conn);
767  continue;
768  }
769  else
770  {
771  vtwrn ("Unhandled event");
772  goto fail;
773  }
774  }
775  }
776 
777 fail:
778  vsm->worker_fails -= 1;
779 
780 done:
781  vppcom_session_close (wrk->listener.fd);
782  if (wrk->conn_pool)
783  free (wrk->conn_pool);
784  vsm->active_workers -= 1;
785  return 0;
786 }
787 
788 static void
790 {
792  struct epoll_event listen_ev;
793  int rv;
794 
795  vtinf ("Initializing main ctrl session ...");
796 
797  vsm->ctrl_listen_fd =
798  vppcom_session_create (VPPCOM_PROTO_TCP, 0 /* is_nonblocking */);
799  if (vsm->ctrl_listen_fd < 0)
800  vtfail ("vppcom_session_create()", vsm->ctrl_listen_fd);
801 
802  rv = vppcom_session_bind (vsm->ctrl_listen_fd, &vsm->server_cfg.endpt);
803  if (rv < 0)
804  vtfail ("vppcom_session_bind()", rv);
805 
806  rv = vppcom_session_listen (vsm->ctrl_listen_fd, 10);
807  if (rv < 0)
808  vtfail ("vppcom_session_listen()", rv);
809 
810  wrk->epfd = vppcom_epoll_create ();
811  if (wrk->epfd < 0)
812  vtfail ("vppcom_epoll_create()", wrk->epfd);
813 
814  listen_ev.events = EPOLLET | EPOLLIN;
815  listen_ev.data.u32 = VCL_TEST_CTRL_LISTENER;
816  rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, vsm->ctrl_listen_fd,
817  &listen_ev);
818  if (rv < 0)
819  vtfail ("vppcom_epoll_ctl", rv);
820 
821  vtinf ("Waiting for client ctrl connection on port %d ...",
822  vsm->server_cfg.port);
823 }
824 
825 int
826 main (int argc, char **argv)
827 {
830  int rv, i;
831 
832  clib_mem_init_thread_safe (0, 64 << 20);
834  vsm->server_cfg.workers = 1;
835  vsm->active_workers = 0;
836  vcl_test_server_process_opts (vsm, argc, argv);
837 
838  rv = vppcom_app_create ("vcl_test_server");
839  if (rv)
840  vtfail ("vppcom_app_create()", rv);
841 
842  /* Protos like tls/dtls/quic need init */
843  if (vt->protos[vsm->server_cfg.proto]->init)
844  vt->protos[vsm->server_cfg.proto]->init (0);
845 
846  vsm->workers = calloc (vsm->server_cfg.workers, sizeof (*vsm->workers));
847  vts_ctrl_session_init (&vsm->workers[0]);
848 
849  /* Update ctrl port to data port */
850  vsm->server_cfg.endpt.port += 1;
851  vts_worker_init (&vsm->workers[0]);
852  for (i = 1; i < vsm->server_cfg.workers; i++)
853  {
854  vsm->workers[i].wrk_index = i;
855  rv = pthread_create (&vsm->workers[i].thread_handle, NULL,
856  vts_worker_loop, (void *) &vsm->workers[i]);
857  }
858 
859  vts_worker_loop (&vsm->workers[0]);
860 
861  while (vsm->active_workers > 0)
862  ;
863 
864  vppcom_app_destroy ();
865  free (vsm->workers);
866 
867  return vsm->worker_fails;
868 }
869 
870 /*
871  * fd.io coding-style-patch-verification: ON
872  *
873  * Local Variables:
874  * eval: (c-set-style "gnu")
875  * End:
876  */
vcl_test_server_cfg_t::port
uint16_t port
Definition: vcl_test_server.c:33
vcl_test_server_worker_t::conn_pool_size
int conn_pool_size
Definition: vcl_test_server.c:45
vcl_test_session::old_stats
vcl_test_stats_t old_stats
Definition: vcl_test.h:139
vcl_test_read_ds
static int vcl_test_read_ds(vcl_test_session_t *ts)
Definition: vcl_test.h:496
sync_config_and_reply
static void sync_config_and_reply(vcl_test_session_t *conn, vcl_test_cfg_t *rx_cfg)
Definition: vcl_test_server.c:133
vts_server_echo
static void vts_server_echo(vcl_test_session_t *conn, int rx_bytes)
Definition: vcl_test_server.c:291
ntohs
#define ntohs(x)
Definition: af_xdp.bpf.c:29
vcl_test_cfg_t::magic
uint32_t magic
Definition: vcl_test.h:94
realloc
void * realloc(void *p, size_t size)
Definition: mem.c:67
VCL_TEST_TYPE_EXIT
@ VCL_TEST_TYPE_EXIT
Definition: vcl_test.h:82
vcl_test_session::session_index
int session_index
Definition: vcl_test.h:140
VCL_TEST_TYPE_NONE
@ VCL_TEST_TYPE_NONE
Definition: vcl_test.h:78
vts_server_process_rx
static void vts_server_process_rx(vcl_test_session_t *conn, int rx_bytes)
Definition: vcl_test_server.c:267
VCL_TEST_DATA_LISTENER
#define VCL_TEST_DATA_LISTENER
Definition: vcl_test.h:72
string.h
vcl_test_server_main_t::worker_fails
volatile int worker_fails
Definition: vcl_test_server.c:58
vts_worker_loop
static void * vts_worker_loop(void *arg)
Definition: vcl_test_server.c:644
vcl_test_main_t
Definition: vcl_test.h:171
wrk
session_worker_t * wrk
Definition: application.c:490
vcl_test_server_worker_t::thread_handle
pthread_t thread_handle
Definition: vcl_test_server.c:48
vcl_test_cfg_t::rxbuf_size
uint64_t rxbuf_size
Definition: vcl_test.h:105
vcl_test_server_worker_t::nfds
int nfds
Definition: vcl_test_server.c:46
vcl_test_cfg_t::test
uint32_t test
Definition: vcl_test.h:96
vcl_test_time_diff
static double vcl_test_time_diff(struct timespec *old, struct timespec *new)
Definition: vcl_test.h:402
vcl_test_cfg_dump
static void vcl_test_cfg_dump(vcl_test_cfg_t *cfg, uint8_t is_client)
Definition: vcl_test.h:298
vcl_test_server_cfg_t::proto
u8 proto
Definition: vcl_test_server.c:35
vcl_test_server_main_t::servaddr
struct sockaddr_storage servaddr
Definition: vcl_test_server.c:57
vcl_test_cfg_t::ctrl_handle
uint32_t ctrl_handle
Definition: vcl_test.h:98
vcl_test.h
vcl_test_session::rxbuf
char * rxbuf
Definition: vcl_test.h:136
VCL_TEST_SERVER_PORT
#define VCL_TEST_SERVER_PORT
Definition: vcl_test.h:60
vts_handle_ctrl_cfg
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)
Definition: vcl_test_server.c:523
vts_ctrl_session_init
static void vts_ctrl_session_init(vcl_test_server_worker_t *wrk)
Definition: vcl_test_server.c:789
vcl_test_session::is_open
uint8_t is_open
Definition: vcl_test.h:128
vcl_test_server_worker_t::epfd
int epfd
Definition: vcl_test_server.c:44
vcl_test_server_main_t
Definition: vcl_test_server.c:51
conn_pool_alloc
static vcl_test_session_t * conn_pool_alloc(vcl_test_server_worker_t *wrk)
Definition: vcl_test_server.c:94
vts_inc_stats_check
static void vts_inc_stats_check(vcl_test_session_t *ts)
Definition: vcl_test_server.c:629
VCL_TEST_CTRL_LISTENER
#define VCL_TEST_CTRL_LISTENER
Definition: vcl_test.h:71
vts_session_cleanup
static void vts_session_cleanup(vcl_test_session_t *ts)
Definition: vcl_test_server.c:165
VCL_TEST_TYPE_ECHO
@ VCL_TEST_TYPE_ECHO
Definition: vcl_test.h:79
vcl_test_session
Definition: vcl_test.h:125
vcl_test_init_endpoint_addr
static void vcl_test_init_endpoint_addr(vcl_test_server_main_t *vsm)
Definition: vcl_test_server.c:408
vcl_test_stats_t::start
struct timespec start
Definition: vcl_test.h:121
vcl_test_server_main_t::incremental_stats
u8 incremental_stats
Definition: vcl_test_server.c:61
vterr
#define vterr(_fn, _rv)
Definition: vcl_test.h:34
vcl_test_session_buf_alloc
static void vcl_test_session_buf_alloc(vcl_test_session_t *ts)
Definition: vcl_test.h:253
vcl_test_session::write
int(* write)(struct vcl_test_session *ts, void *buf, uint32_t buflen)
Definition: vcl_test.h:132
c
svmdb_client_t * c
Definition: vpp_get_metrics.c:48
vcl_test_server_worker_t::wrk_index
uint32_t wrk_index
Definition: vcl_test_server.c:43
vcl_test_buf_alloc
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
vcl_test_stats_t::stop
struct timespec stop
Definition: vcl_test.h:122
vcl_test_server_main_t::ctrl_listen_fd
int ctrl_listen_fd
Definition: vcl_test_server.c:56
print_usage_and_exit
static void print_usage_and_exit(void)
Definition: vcl_test_server.c:393
vcl_test_proto_vft_t::accept
int(* accept)(int listen_fd, vcl_test_session_t *ts)
Definition: vcl_test.h:160
vcl_test_session_buf_free
static void vcl_test_session_buf_free(vcl_test_session_t *ts)
Definition: vcl_test.h:264
if
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
vcl_test_proto_vft_t::close
int(* close)(vcl_test_session_t *ts)
Definition: vcl_test.h:161
conn_pool_free
static void conn_pool_free(vcl_test_session_t *ts)
Definition: vcl_test_server.c:125
time.h
vcl_test_proto_vft_t::listen
int(* listen)(vcl_test_session_t *ts, vppcom_endpt_t *endpt)
Definition: vcl_test.h:159
vcl_test_stats_dump
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
events
static perfmon_event_t events[]
Definition: core.c:21
vts_wrk_cleanup_all
static void vts_wrk_cleanup_all(vcl_test_server_worker_t *wrk)
Definition: vcl_test_server.c:172
vcl_test_cfg_t::txbuf_size
uint64_t txbuf_size
Definition: vcl_test.h:106
VCL_TEST_TYPE_BI
@ VCL_TEST_TYPE_BI
Definition: vcl_test.h:81
vcl_test_server_process_opts
static void vcl_test_server_process_opts(vcl_test_server_main_t *vsm, int argc, char **argv)
Definition: vcl_test_server.c:445
vcl_test_main
vcl_test_main_t vcl_test_main
Definition: vcl_test_server.c:64
vts_test_cmd
static void vts_test_cmd(vcl_test_server_worker_t *wrk, vcl_test_session_t *conn, vcl_test_cfg_t *rx_cfg)
Definition: vcl_test_server.c:187
vts_accept_ctrl
static vcl_test_session_t * vts_accept_ctrl(vcl_test_server_worker_t *wrk, int listen_fd)
Definition: vcl_test_server.c:310
VCL_TEST_CMD_STOP
@ VCL_TEST_CMD_STOP
Definition: vcl_test.h:89
vcl_test_cfg_t::total_bytes
uint64_t total_bytes
Definition: vcl_test.h:108
vcl_test_session::read
int(* read)(struct vcl_test_session *ts, void *buf, uint32_t buflen)
Definition: vcl_test.h:131
vcl_test_server_cfg_t::endpt
vppcom_endpt_t endpt
Definition: vcl_test_server.c:37
vcl_test_main_t::protos
const vcl_test_proto_vft_t * protos[VPPCOM_PROTO_SRTP+1]
Definition: vcl_test.h:173
vts_conn_read
static int vts_conn_read(vcl_test_session_t *conn)
Definition: vcl_test_server.c:619
vcl_test_session::ds
vppcom_data_segment_t ds[2]
Definition: vcl_test.h:143
data
u8 data[128]
Definition: ipsec_types.api:95
vcl_test_cfg_t::verbose
uint32_t verbose
Definition: vcl_test.h:102
clib_mem_init_thread_safe
void * clib_mem_init_thread_safe(void *memory, uword memory_size)
Definition: mem_dlmalloc.c:280
vcl_test_server_main_t::use_ds
u8 use_ds
Definition: vcl_test_server.c:60
main
int main(int argc, char **argv)
Definition: vcl_test_server.c:826
VCL_TEST_CFG_MAX_EPOLL_EVENTS
#define VCL_TEST_CFG_MAX_EPOLL_EVENTS
Definition: vcl_test.h:69
VCL_TEST_SEPARATOR_STRING
#define VCL_TEST_SEPARATOR_STRING
Definition: vcl_test.h:74
vcl_test_session::stats
vcl_test_stats_t stats
Definition: vcl_test.h:138
vcl_test_session::fd
int fd
Definition: vcl_test.h:130
VCL_TEST_CFG_MAX_TEST_SESS
#define VCL_TEST_CFG_MAX_TEST_SESS
Definition: vcl_test.h:68
vts_worker_init
static void vts_worker_init(vcl_test_server_worker_t *wrk)
Definition: vcl_test_server.c:577
vcl_test_server_worker_t::listener
vcl_test_session_t listener
Definition: vcl_test_server.c:47
vcl_test_stats_dump_inc
static void vcl_test_stats_dump_inc(vcl_test_session_t *ts, int is_rx)
Definition: vcl_test.h:419
vcl_test_session::is_alloc
uint8_t is_alloc
Definition: vcl_test.h:127
vcl_test_session::rxbuf_size
uint32_t rxbuf_size
Definition: vcl_test.h:134
vcl_test_stats_t::rx_bytes
uint64_t rx_bytes
Definition: vcl_test.h:114
buf
u64 buf
Definition: application.c:493
vcl_test_server_worker_t::conn_pool
vcl_test_session_t * conn_pool
Definition: vcl_test_server.c:42
vcl_test_session::endpt
vppcom_endpt_t endpt
Definition: vcl_test.h:141
vcl_test_server_main_t::workers
vcl_test_server_worker_t * workers
Definition: vcl_test_server.c:53
vcl_test_server_cfg_t
Definition: vcl_test_server.c:31
vcl_test_stats_accumulate
static void vcl_test_stats_accumulate(vcl_test_stats_t *accum, vcl_test_stats_t *incr)
Definition: vcl_test.h:188
vcl_test_server_worker_t
Definition: vcl_test_server.c:40
vcl_test_server_main_t::server_cfg
vcl_test_server_cfg_t server_cfg
Definition: vcl_test_server.c:55
vtwrn
#define vtwrn(_fmt, _args...)
Definition: vcl_test.h:40
calloc
void * calloc(size_t nmemb, size_t size)
Definition: mem.c:54
vcl_test_server_main_t::ctrl
vcl_test_session_t * ctrl
Definition: vcl_test_server.c:54
vts_accept_client
static vcl_test_session_t * vts_accept_client(vcl_test_server_worker_t *wrk, int listen_fd)
Definition: vcl_test_server.c:352
u8
unsigned char u8
Definition: types.h:56
vcl_server_main
static vcl_test_server_main_t vcl_server_main
Definition: vcl_test_server.c:66
vcl_test_server_cfg_t::workers
u8 workers
Definition: vcl_test_server.c:36
vtinf
#define vtinf(_fmt, _args...)
Definition: vcl_test.h:43
vcl_test_server_cfg_t::address_ip6
uint32_t address_ip6
Definition: vcl_test_server.c:34
i
int i
Definition: flowhash_template.h:376
free
void free(void *p)
Definition: mem.c:42
VCL_TEST_CMD_SYNC
@ VCL_TEST_CMD_SYNC
Definition: vcl_test.h:87
VCL_TEST_CFG_CTRL_MAGIC
#define VCL_TEST_CFG_CTRL_MAGIC
Definition: vcl_test.h:63
vcl_test_cfg_init
static void vcl_test_cfg_init(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:201
vts_session_close
static void vts_session_close(vcl_test_session_t *conn)
Definition: vcl_test_server.c:149
rv
int __clib_unused rv
Definition: application.c:491
vcl_test_session::cfg
vcl_test_cfg_t cfg
Definition: vcl_test.h:137
mem.h
conn_pool_expand
static void conn_pool_expand(vcl_test_server_worker_t *wrk, size_t expand_size)
Definition: vcl_test_server.c:69
vcl_test_write
static int vcl_test_write(vcl_test_session_t *ts, void *buf, uint32_t nbytes)
Definition: vcl_test.h:530
vcl_test_cfg_t
Definition: vcl_test.h:92
vcl_test_cfg_t::cmd
uint32_t cmd
Definition: vcl_test.h:97
vcl_comp_tspec
static int vcl_comp_tspec(struct timespec *a, struct timespec *b)
Definition: vcl_test.h:447
vcl_test_proto_vft_t::init
int(* init)(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:157
VCL_TEST_CMD_START
@ VCL_TEST_CMD_START
Definition: vcl_test.h:88
vcl_test_cfg_t::num_writes
uint64_t num_writes
Definition: vcl_test.h:107
vtfail
#define vtfail(_fn, _rv)
Definition: vcl_test.h:26
vcl_test_server_main_t::active_workers
volatile int active_workers
Definition: vcl_test_server.c:59
vcl_test_proto_vft_t
Definition: vcl_test.h:155
VCL_TEST_TYPE_UNI
@ VCL_TEST_TYPE_UNI
Definition: vcl_test.h:80
VCL_TEST_DELAY_DISCONNECT
#define VCL_TEST_DELAY_DISCONNECT
Definition: vcl_test.h:73