FD.io VPP  v21.06
Vector Packet Processing
vpp_echo.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 <stdio.h>
17 #include <signal.h>
18 
19 #include <vlibmemory/api.h>
20 #include <svm/fifo_segment.h>
21 
23 
25 
26 static void
28 {
29  /* We need to prealloc to avoid vec resize in threads */
30  echo_session_t *session;
31  int i;
32  for (i = 0; i < em->n_sessions; i++)
33  {
34  pool_get (em->sessions, session);
35  clib_memset (session, 0, sizeof (*session));
36  session->session_index = session - em->sessions;
38  session->session_state = ECHO_SESSION_STATE_INITIAL;
39  }
40 }
41 
42 static void
44 {
45  if (em->rx_results_diff)
46  CHECK_DIFF (ECHO_FAIL_TEST_ASSERT_RX_TOTAL, em->stats.rx_expected,
47  em->stats.rx_total, "Invalid amount of data received");
48  else
49  CHECK_SAME (ECHO_FAIL_TEST_ASSERT_RX_TOTAL, em->stats.rx_expected,
50  em->stats.rx_total, "Invalid amount of data received");
51 
52  if (em->tx_results_diff)
53  CHECK_DIFF (ECHO_FAIL_TEST_ASSERT_TX_TOTAL, em->stats.tx_expected,
54  em->stats.tx_total, "Invalid amount of data sent");
55  else
56  CHECK_SAME (ECHO_FAIL_TEST_ASSERT_TX_TOTAL, em->stats.tx_expected,
57  em->stats.tx_total, "Invalid amount of data sent");
58 
60  CHECK_SAME (ECHO_FAIL_TEST_ASSERT_ALL_SESSIONS_CLOSED,
62  "Some sessions are still open");
64 }
65 
66 always_inline void
68 {
69  int rv;
70  if (!svm_fifo_set_event (s->rx_fifo))
71  return;
72  if ((rv = app_send_io_evt_to_vpp (s->vpp_evt_q,
73  s->rx_fifo->shr->master_session_index,
75  ECHO_FAIL (ECHO_FAIL_SEND_IO_EVT, "app_send_io_evt_to_vpp errored %d",
76  rv);
77  svm_fifo_clear_deq_ntf (s->rx_fifo);
78 }
79 
80 static void
81 stop_signal (int signum)
82 {
83  echo_main_t *em = &echo_main;
84  em->time_to_stop = 1;
85 }
86 
87 int
89 {
90  echo_main_t *em = &echo_main;
92 
93  if (em->use_sock_api)
94  {
95  if (vl_socket_client_connect ((char *) em->socket_name, name,
96  0 /* default rx, tx buffer */ ))
97  {
98  ECHO_FAIL (ECHO_FAIL_SOCKET_CONNECT, "socket connect failed");
99  return -1;
100  }
101 
102  if (vl_socket_client_init_shm (0, 1 /* want_pthread */ ))
103  {
104  ECHO_FAIL (ECHO_FAIL_INIT_SHM_API, "init shm api failed");
105  return -1;
106  }
107  }
108  else
109  {
110  if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
111  {
112  ECHO_FAIL (ECHO_FAIL_SHMEM_CONNECT, "shmem connect failed");
113  return -1;
114  }
115  }
118  return 0;
119 }
120 
121 static void
123 {
124  u8 *start_evt =
126  u8 *end_evt =
128  u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
129  u8 end_evt_missing = (em->rx_results_diff || em->tx_results_diff) ? 0 :
130  !(em->timing.events_sent & em->timing.end_event);
131  f64 deltat = start_evt_missing || end_evt_missing ? 0 :
132  em->timing.end_time - em->timing.start_time;
133 
134  if (start_evt_missing)
135  ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
136  "Expected event %v to happen, but it did not!", start_evt);
137 
138  if (end_evt_missing)
139  ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
140  "Expected event %v to happen, but it did not!", end_evt);
141 
142  fformat (stdout, "vpp_echo JSON stats:\n{\n");
143  fformat (stdout, " \"role\": \"%s\",\n",
144  em->i_am_master ? "server" : "client");
145  fformat (stdout, " \"time\": \"%.9f\",\n", deltat);
146  fformat (stdout, " \"start_evt\": \"%v\",\n", start_evt);
147  fformat (stdout, " \"start_evt_missing\": \"%s\",\n",
148  start_evt_missing ? "True" : "False");
149  fformat (stdout, " \"end_evt\": \"%v\",\n", end_evt);
150  fformat (stdout, " \"end_evt_missing\": \"%s\",\n",
151  end_evt_missing ? "True" : "False");
152  fformat (stdout, " \"rx_data\": %lld,\n", em->stats.rx_total);
153  fformat (stdout, " \"tx_data\": %lld,\n", em->stats.tx_total);
154  fformat (stdout, " \"rx_bits_per_second\": %.1f,\n",
155  em->stats.rx_total * 8 / deltat);
156  fformat (stdout, " \"tx_bits_per_second\": %.1f,\n",
157  em->stats.tx_total * 8 / deltat);
158  fformat (stdout, " \"closing\": {\n");
159  fformat (stdout, " \"reset\": { \"q\": %d, \"s\": %d },\n",
160  em->stats.reset_count.q, em->stats.reset_count.s);
161  fformat (stdout, " \"recv evt\": { \"q\": %d, \"s\": %d },\n",
162  em->stats.close_count.q, em->stats.close_count.s);
163  fformat (stdout, " \"send evt\": { \"q\": %d, \"s\": %d },\n",
165  fformat (stdout, " \"clean\": { \"q\": %d, \"s\": %d },\n",
166  em->stats.clean_count.q, em->stats.clean_count.s);
167  fformat (stdout, " \"accepted\": { \"q\": %d, \"s\": %d },\n",
169  fformat (stdout, " \"connected\": { \"q\": %d, \"s\": %d }\n",
171  fformat (stdout, " },\n");
172  fformat (stdout, " \"results\": {\n");
173  fformat (stdout, " \"has_failed\": \"%d\",\n", em->has_failed);
174  fformat (stdout, " \"fail_descr\": \"%v\"\n", em->fail_descr);
175  fformat (stdout, " }\n");
176  fformat (stdout, "}\n");
177  fflush (stdout);
178  vec_free (start_evt);
179  vec_free (end_evt);
180 }
181 
182 static void
184 {
185  u8 *start_evt =
187  u8 *end_evt =
189  u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
190  u8 end_evt_missing = (em->rx_results_diff || em->tx_results_diff) ? 0 :
191  !(em->timing.events_sent & em->timing.end_event);
192  f64 deltat = start_evt_missing || end_evt_missing ? 0 :
193  em->timing.end_time - em->timing.start_time;
194 
195  if (start_evt_missing)
196  ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
197  "Expected event %v to happen, but it did not!", start_evt);
198 
199  if (end_evt_missing)
200  ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
201  "Expected event %v to happen, but it did not!", end_evt);
202 
203  fformat (stdout, "Timing %v:%v\n", start_evt, end_evt);
204  if (start_evt_missing)
205  fformat (stdout, "Missing Start Timing Event (%v)!\n", start_evt);
206  if (end_evt_missing)
207  fformat (stdout, "Missing End Timing Event (%v)!\n", end_evt);
208  fformat (stdout, "-------- TX --------\n");
209  fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
210  em->stats.tx_total, em->stats.tx_total / (1ULL << 20),
211  em->stats.tx_total / (1ULL << 30), deltat);
212  if (deltat)
213  fformat (stdout, "%.4f Gbit/second\n",
214  (em->stats.tx_total * 8.0) / deltat / 1e9);
215  fformat (stdout, "-------- RX --------\n");
216  fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
217  em->stats.rx_total, em->stats.rx_total / (1ULL << 20),
218  em->stats.rx_total / (1ULL << 30), deltat);
219  if (deltat)
220  fformat (stdout, "%.4f Gbit/second\n",
221  (em->stats.rx_total * 8.0) / deltat / 1e9);
222  fformat (stdout, "--------------------\n");
223  fformat (stdout, "Received close on %d streams (and %d Quic conn)\n",
224  em->stats.close_count.s, em->stats.close_count.q);
225  fformat (stdout, "Received reset on %d streams (and %d Quic conn)\n",
226  em->stats.reset_count.s, em->stats.reset_count.q);
227  fformat (stdout, "Sent close on %d streams (and %d Quic conn)\n",
229  fformat (stdout, "Discarded %d streams (and %d Quic conn)\n",
230  em->stats.clean_count.s, em->stats.clean_count.q);
231  fformat (stdout, "--------------------\n");
232  fformat (stdout, "Got accept on %d streams (and %d Quic conn)\n",
234  fformat (stdout, "Got connected on %d streams (and %d Quic conn)\n",
236  if (em->has_failed)
237  fformat (stdout, "\nFailure Return Status: %d\n%v", em->has_failed,
238  em->fail_descr);
239  vec_free (start_evt);
240  vec_free (end_evt);
241 }
242 
243 void
245 {
246 
247  ECHO_LOG (2, "[%lu/%lu] -> %U -> [%lu/%lu]",
250  s->bytes_sent + s->bytes_to_send);
251 
252  if (PREDICT_FALSE
253  ((em->stats.rx_total == em->stats.rx_expected)
254  && (em->stats.tx_total == em->stats.tx_expected)))
256 }
257 
258 static void
260 {
261  echo_main_t *em = &echo_main;
262  fifo_segment_t *fs;
263 
264  if (!s->rx_fifo)
265  return;
266 
268 
270  s->rx_fifo->segment_index);
271 
272  if (!fs)
273  goto done;
274 
275  fifo_segment_free_client_fifo (fs, s->rx_fifo);
276  fifo_segment_free_client_fifo (fs, s->tx_fifo);
277 
278 done:
280 }
281 
282 static void
284 {
285  /* Free marked sessions */
286  echo_session_t *s;
287  u32 *session_indexes = 0, *session_index;
288 
289  /* *INDENT-OFF* */
290  pool_foreach (s, em->sessions)
291  {
292  if (s->session_state == ECHO_SESSION_STATE_CLOSED)
293  vec_add1 (session_indexes, s->session_index);
294  }
295  /* *INDENT-ON* */
296  vec_foreach (session_index, session_indexes)
297  {
298  /* Free session */
299  s = pool_elt_at_index (em->sessions, *session_index);
303  clib_memset (s, 0xfe, sizeof (*s));
304  pool_put (em->sessions, s);
305  }
306 }
307 
308 static void
310  u32 n_read)
311 {
312  u32 i;
313  u8 expected;
314  for (i = 0; i < n_read; i++)
315  {
316  expected = (s->bytes_received + i) & 0xff;
317  if (rx_buf[i] == expected || em->max_test_msg > 0)
318  continue;
319  ECHO_LOG (1, "Session 0x%lx byte %lld was 0x%x expected 0x%x",
320  s->vpp_session_handle, s->bytes_received + i, rx_buf[i],
321  expected);
322  em->max_test_msg--;
323  if (em->max_test_msg == 0)
324  ECHO_LOG (1, "Too many errors, hiding next ones");
326  ECHO_FAIL (ECHO_FAIL_TEST_BYTES_ERR, "test-bytes errored");
327  }
328 }
329 
330 static int
332 {
333  int n_read;
334  n_read = app_recv ((app_session_t *) s, rx_buf, vec_len (rx_buf));
335  if (n_read <= 0)
336  return 0;
337  if (svm_fifo_needs_deq_ntf (s->rx_fifo, n_read))
339 
340  if (em->test_return_packets)
341  test_recv_bytes (em, s, rx_buf, n_read);
342 
343  s->bytes_received += n_read;
344  s->bytes_to_receive -= n_read;
345  clib_atomic_fetch_add (&em->stats.rx_total, n_read);
346  return n_read;
347 }
348 
349 static int
350 send_data_chunk (echo_session_t * s, u8 * tx_buf, int offset, int len)
351 {
352  int n_sent;
353  int bytes_this_chunk = clib_min (s->bytes_to_send, len - offset);
354  echo_main_t *em = &echo_main;
355 
356  if (!bytes_this_chunk)
357  return 0;
358  n_sent = app_send ((app_session_t *) s, tx_buf + offset,
359  bytes_this_chunk, SVM_Q_WAIT);
360  if (n_sent < 0)
361  return 0;
362  s->bytes_to_send -= n_sent;
363  s->bytes_sent += n_sent;
364  clib_atomic_fetch_add (&em->stats.tx_total, n_sent);
365  return n_sent;
366 }
367 
368 static int
370 {
371  u64 n_sent = 0;
372  while (n_sent < len && !em->time_to_stop)
373  n_sent += send_data_chunk (s, tx_buf, n_sent, len);
374  return n_sent;
375 }
376 
377 static inline void
379 {
380  echo_session_t *ls;
381  /* if parent has died, terminate gracefully */
383  {
384  ECHO_LOG (3, "%U: listener_index == SESSION_INVALID_INDEX",
386  return;
387  }
389  if (ls->session_state < ECHO_SESSION_STATE_CLOSING)
390  {
391  ECHO_LOG (3, "%U: ls->session_state (%d) < "
392  "ECHO_SESSION_STATE_CLOSING (%d)",
393  echo_format_session, ls, ls->session_state,
395  return;
396  }
397 
398  ECHO_LOG (3, "%U died, close child %U", echo_format_session, ls,
401  em->proto_cb_vft->cleanup_cb (s, 1 /* parent_died */ );
402 }
403 
404 /*
405  * Rx/Tx polling thread per connection
406  */
407 static void
409 {
410  int n_read, n_sent = 0;
411 
412  n_read = recv_data_chunk (em, s, rx_buf);
414  n_sent = send_data_chunk (s, em->connect_test_data,
415  s->bytes_sent % em->tx_buf_size,
416  em->tx_buf_size);
417  else if (em->data_source == ECHO_RX_DATA_SOURCE)
418  n_sent = mirror_data_chunk (em, s, rx_buf, n_read);
419  if (!s->bytes_to_send && !s->bytes_to_receive)
420  {
421  /* Session is done, need to close */
422  if (s->session_state == ECHO_SESSION_STATE_AWAIT_DATA)
423  s->session_state = ECHO_SESSION_STATE_CLOSING;
424  else
425  {
426  s->session_state = ECHO_SESSION_STATE_AWAIT_CLOSING;
428  {
432  }
434  {
435  s->session_state = ECHO_SESSION_STATE_CLOSING;
437  }
438  }
439  ECHO_LOG (3, "%U: %U", echo_format_session, s,
440  echo_format_session_state, s->session_state);
441  return;
442  }
443 
444  /* Check for idle clients */
445  if (em->log_lvl > 1)
446  {
447  if (n_sent || n_read)
448  s->idle_cycles = 0;
449  else if (s->idle_cycles++ == LOG_EVERY_N_IDLE_CYCLES)
450  {
451  s->idle_cycles = 0;
452  ECHO_LOG (2, "Idle client TX:%dB RX:%dB", s->bytes_to_send,
453  s->bytes_to_receive);
454  ECHO_LOG (2, "Idle FIFOs TX:%dB RX:%dB",
455  svm_fifo_max_dequeue (s->tx_fifo),
456  svm_fifo_max_dequeue (s->rx_fifo));
457  ECHO_LOG (2, "Session 0x%lx state %U", s->vpp_session_handle,
458  echo_format_session_state, s->session_state);
459  }
460  }
461 }
462 
463 static void *
465 {
466  clib_mem_set_thread_index (); /* First thing to do in client thread */
467  echo_main_t *em = &echo_main;
468  u32 N = em->n_clients;
469  u32 n = (N + em->n_rx_threads - 1) / em->n_rx_threads;
470  u32 idx = (u64) arg;
471  if (n * idx >= N)
472  {
473  ECHO_LOG (2, "Thread %u exiting, no sessions to care for", idx);
474  pthread_exit (0);
475  }
476  u32 thread_n_sessions = clib_min (n, N - n * idx);
477 
478  u32 i = 0;
479  u32 n_closed_sessions = 0;
480  u32 session_index;
481  u8 *rx_buf = 0;
482  echo_session_t *s;
483  vec_validate (rx_buf, em->rx_buf_size);
484 
485  for (i = 0; !em->time_to_stop; i = (i + 1) % thread_n_sessions)
486  {
487  n_closed_sessions = i == 0 ? 0 : n_closed_sessions;
488  session_index = em->data_thread_args[n * idx + i];
489  if (session_index == SESSION_INVALID_INDEX)
490  continue;
491  s = pool_elt_at_index (em->sessions, session_index);
492  switch (s->session_state)
493  {
496  echo_handle_data (em, s, rx_buf);
498  break;
500  ECHO_LOG (3, "%U: %U", echo_format_session, s,
501  echo_format_session_state, s->session_state);
503  break;
505  ECHO_LOG (3, "%U: %U", echo_format_session, s,
506  echo_format_session_state, s->session_state);
508  em->proto_cb_vft->cleanup_cb (s, 0 /* parent_died */ );
509  break;
511  ECHO_LOG (3, "%U: %U", echo_format_session, s,
512  echo_format_session_state, s->session_state);
513  n_closed_sessions++;
514  break;
515  }
516  if (n_closed_sessions == thread_n_sessions)
517  break;
518  }
519  ECHO_LOG (2, "Mission accomplished!");
520  pthread_exit (0);
521 }
522 
523 static void
525 {
526  echo_session_t *ls;
527  echo_main_t *em = &echo_main;
528 
529  ls = echo_get_session_from_handle (em, mp->handle);
530  if (!ls)
531  return;
532  em->proto_cb_vft->cleanup_cb (ls, 0 /* parent_died */ );
533  ls->session_state = ECHO_SESSION_STATE_CLOSED;
534  if (--em->listen_session_cnt == 0)
536 }
537 
538 static void
540 {
541  echo_main_t *em = &echo_main;
542  echo_session_t *listen_session;
543  if (mp->retval)
544  {
545  ECHO_FAIL (ECHO_FAIL_BIND, "bind failed: %U", format_api_error,
546  clib_net_to_host_u32 (mp->retval));
547  return;
548  }
549  ECHO_LOG (1, "listening on %U:%u", format_ip46_address, mp->lcl_ip,
551  clib_net_to_host_u16 (mp->lcl_port));
552 
553  /* Allocate local session and set it up */
554  listen_session = echo_session_new (em);
555  listen_session->session_type = ECHO_SESSION_TYPE_LISTEN;
556  listen_session->vpp_session_handle = mp->handle;
557  echo_session_handle_add_del (em, mp->handle, listen_session->session_index);
558  vec_add1 (em->listen_session_indexes, listen_session->session_index);
559  if (++em->listen_session_cnt == em->n_uris)
560  em->state = STATE_LISTEN;
561  if (em->proto_cb_vft->bound_uri_cb)
562  em->proto_cb_vft->bound_uri_cb (mp, listen_session);
563 }
564 
565 static void
567 {
568  app_session_evt_t _app_evt, *app_evt = &_app_evt;
570  echo_main_t *em = &echo_main;
571  echo_session_t *session, *ls;
572 
573  if (!(ls = echo_get_session_from_handle (em, mp->listener_handle)))
574  {
575  ECHO_FAIL (ECHO_FAIL_SESSION_ACCEPTED_BAD_LISTENER,
576  "Unknown listener handle 0x%lx", mp->listener_handle);
577  return;
578  }
579 
580  /* Allocate local session and set it up */
581  session = echo_session_new (em);
582 
585  session))
586  {
587  ECHO_FAIL (ECHO_FAIL_ACCEPTED_WAIT_FOR_SEG_ALLOC,
588  "accepted wait_for_segment_allocation errored");
589  return;
590  }
591 
592  session->vpp_session_handle = mp->handle;
593 
594  /* session->transport needed by app_send_dgram */
595  clib_memcpy_fast (&session->transport.rmt_ip, &mp->rmt.ip,
596  sizeof (ip46_address_t));
597  session->transport.is_ip4 = mp->rmt.is_ip4;
598  session->transport.rmt_port = mp->rmt.port;
599  clib_memcpy_fast (&session->transport.lcl_ip, &em->uri_elts.ip,
600  sizeof (ip46_address_t));
601  session->transport.lcl_port = em->uri_elts.port;
602 
603  session->vpp_session_handle = mp->handle;
604  session->listener_index = ls->session_index;
605  session->start = clib_time_now (&em->clib_time);
606 
607  /* Add it to lookup table */
608  ECHO_LOG (2, "Accepted session 0x%lx S[%u] -> 0x%lx S[%u]",
609  mp->handle, session->session_index,
610  mp->listener_handle, session->listener_index);
611  echo_session_handle_add_del (em, mp->handle, session->session_index);
612 
613  app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
615  rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
616  rmp->handle = mp->handle;
617  rmp->context = mp->context;
618  app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
619  em->proto_cb_vft->accepted_cb (mp, session);
620 }
621 
622 static void
624 {
625  echo_main_t *em = &echo_main;
626  echo_session_t *session;
627  u32 listener_index = htonl (mp->context);
628 
630 
631  if (mp->retval)
632  {
633  if (em->proto_cb_vft->connected_cb)
634  em->
635  proto_cb_vft->connected_cb ((session_connected_bundled_msg_t *) mp,
636  listener_index, 1 /* is_failed */ );
637  return;
638  }
639 
640  session = echo_session_new (em);
641 
644  session))
645  {
646  ECHO_FAIL (ECHO_FAIL_CONNECTED_WAIT_FOR_SEG_ALLOC,
647  "connected wait_for_segment_allocation errored");
648  return;
649  }
650 
651  session->vpp_session_handle = mp->handle;
652  session->start = clib_time_now (&em->clib_time);
653  session->listener_index = listener_index;
654  /* session->transport needed by app_send_dgram */
655  clib_memcpy_fast (&session->transport.lcl_ip, &mp->lcl.ip,
656  sizeof (ip46_address_t));
657  session->transport.is_ip4 = mp->lcl.is_ip4;
658  session->transport.lcl_port = mp->lcl.port;
659  clib_memcpy_fast (&session->transport.rmt_ip, &em->uri_elts.ip,
660  sizeof (ip46_address_t));
661  session->transport.rmt_port = em->uri_elts.port;
662 
663  echo_session_handle_add_del (em, mp->handle, session->session_index);
665  session->session_index, 0 /* is_failed */ );
666 }
667 
668 /*
669  *
670  * End of ECHO callback definitions
671  *
672  */
673 
674 static void
676 {
677  app_session_evt_t _app_evt, *app_evt = &_app_evt;
679  echo_main_t *em = &echo_main;
680  echo_session_t *s;
681  if (!(s = echo_get_session_from_handle (em, mp->handle)))
682  {
683  ECHO_LOG (1, "Invalid vpp_session_handle: 0x%lx", mp->handle);
684  return;
685  }
686  if (s->session_state == ECHO_SESSION_STATE_CLOSED)
687  {
688  ECHO_LOG (2, "%U: already in ECHO_SESSION_STATE_CLOSED",
690  }
691  else
692  {
693  ECHO_LOG (2, "%U: passive close", echo_format_session, s);
694  em->proto_cb_vft->disconnected_cb (mp, s);
695  }
696  app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
698  rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
699  rmp->retval = 0;
700  rmp->handle = mp->handle;
701  rmp->context = mp->context;
702  app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
703 }
704 
705 static void
707 {
708  app_session_evt_t _app_evt, *app_evt = &_app_evt;
709  echo_main_t *em = &echo_main;
711  echo_session_t *s = 0;
712  if (!(s = echo_get_session_from_handle (em, mp->handle)))
713  {
714  ECHO_LOG (1, "Invalid vpp_session_handle: 0x%lx", mp->handle);
715  return;
716  }
717  ECHO_LOG (2, "%U: session reset", echo_format_session, s);
718  em->proto_cb_vft->reset_cb (mp, s);
719 
720  app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
722  rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
723  rmp->retval = 0;
724  rmp->handle = mp->handle;
725  app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
726 }
727 
728 static void
730 {
731  fifo_segment_main_t *sm = &echo_main.segment_main;
732  fifo_segment_create_args_t _a, *a = &_a;
733  int *fds = 0, i;
734  char *seg_name = (char *) mp->segment_name;
735  u64 segment_handle = mp->segment_handle;
736 
737  if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
738  {
739  vec_validate (fds, 1);
740  if (vl_socket_client_recv_fd_msg (fds, 1, 5))
741  {
742  ECHO_FAIL (ECHO_FAIL_VL_API_RECV_FD_MSG,
743  "vl_socket_client_recv_fd_msg failed");
744  goto failed;
745  }
746 
747  if (echo_segment_attach (segment_handle, seg_name, SSVM_SEGMENT_MEMFD,
748  fds[0]))
749  {
750  ECHO_FAIL (ECHO_FAIL_VL_API_SVM_FIFO_SEG_ATTACH,
751  "svm_fifo_segment_attach ('%s') "
752  "failed on SSVM_SEGMENT_MEMFD", seg_name);
753  goto failed;
754  }
755  vec_free (fds);
756  }
757  else
758  {
759  clib_memset (a, 0, sizeof (*a));
760  a->segment_name = seg_name;
761  a->segment_size = mp->segment_size;
762  /* Attach to the segment vpp created */
763  if (fifo_segment_attach (sm, a))
764  {
765  ECHO_FAIL (ECHO_FAIL_VL_API_FIFO_SEG_ATTACH,
766  "fifo_segment_attach ('%s') failed", seg_name);
767  goto failed;
768  }
769  }
770  ECHO_LOG (2, "Mapped segment 0x%lx", segment_handle);
771  return;
772 
773 failed:
774  for (i = 0; i < vec_len (fds); i++)
775  close (fds[i]);
776  vec_free (fds);
777 }
778 
779 static void
781 {
783  ECHO_LOG (2, "Unmaped segment 0x%lx", mp->segment_handle);
784 }
785 
786 static void
788 {
789  ECHO_LOG (1, "Cleanup confirmed for 0x%lx", mp->handle);
790 }
791 
792 static void
793 handle_mq_event (session_event_t * e)
794 {
795  switch (e->event_type)
796  {
798  return session_bound_handler ((session_bound_msg_t *) e->data);
805  e->data);
807  return session_reset_handler ((session_reset_msg_t *) e->data);
810  e->data);
813  break;
816  break;
819  break;
820  case SESSION_IO_EVT_RX:
821  break;
822  default:
823  ECHO_LOG (1, "unhandled event %u", e->event_type);
824  }
825 }
826 
827 static void
829 {
830  echo_rpc_msg_t *rpc;
831  svm_msg_q_msg_t msg;
832  svm_msg_q_t *mq = &em->rpc_msq_queue;
833 
834  while (em->state < STATE_DATA_DONE && !em->time_to_stop)
835  {
836  if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
837  {
838  continue;
839  }
840  svm_msg_q_sub_raw (mq, &msg);
841  rpc = svm_msg_q_msg_data (mq, &msg);
842  ((echo_rpc_t) rpc->fp) (em, &rpc->args);
843  svm_msg_q_free_msg (mq, &msg);
844  }
845 }
846 
847 static inline void
849 {
850  f64 delta, now = clib_time_now (&em->clib_time);
851  echo_stats_t _st, *st = &_st;
852  echo_stats_t *lst = &em->last_stat_sampling;
853  delta = now - em->last_stat_sampling_ts;
854  if (delta < em->periodic_stats_delta)
855  return;
856 
857  clib_memcpy_fast (st, &em->stats, sizeof (*st));
858  if (st->rx_total - lst->rx_total)
860  (st->rx_total - lst->rx_total) / delta);
861  if (st->tx_total - lst->tx_total)
863  (st->tx_total - lst->tx_total) / delta);
864  if (st->connected_count.q - lst->connected_count.q)
865  clib_warning ("conn: %d/s",
866  st->connected_count.q - lst->connected_count.q);
867  if (st->accepted_count.q - lst->accepted_count.q)
868  clib_warning ("accept: %d/s",
869  st->accepted_count.q - lst->accepted_count.q);
870 
871  clib_memcpy_fast (lst, st, sizeof (*st));
873 }
874 
875 static void *
876 echo_mq_thread_fn (void *arg)
877 {
878  clib_mem_set_thread_index (); /* First thing to do in client thread */
879  svm_msg_q_msg_t *msg_vec = 0;
880  echo_main_t *em = &echo_main;
881  session_event_t *e;
882  svm_msg_q_msg_t *msg;
883  svm_msg_q_t *mq;
884  int i;
885 
886  vec_validate (msg_vec, em->evt_q_size);
887  vec_reset_length (msg_vec);
889  mq = em->app_mq;
890  if (em->state < STATE_ATTACHED || !mq)
891  {
892  ECHO_FAIL (ECHO_FAIL_APP_ATTACH, "Application failed to attach");
893  pthread_exit (0);
894  }
895 
896  while (em->state < STATE_DETACHED && !em->time_to_stop)
897  {
898  if (em->periodic_stats_delta)
900 
901  if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
902  {
903  continue;
904  }
905  for (i = 0; i < svm_msg_q_size (mq); i++)
906  {
907  vec_add2 (msg_vec, msg, 1);
908  svm_msg_q_sub_raw (mq, msg);
909  }
910 
911  for (i = 0; i < vec_len (msg_vec); i++)
912  {
913  msg = vec_elt_at_index (msg_vec, i);
914  e = svm_msg_q_msg_data (mq, msg);
915  handle_mq_event (e);
916  svm_msg_q_free_msg (mq, msg); /* No lock, single thread dequeuing */
917  }
918  vec_reset_length (msg_vec);
919  }
920  vec_free (msg_vec);
921  pthread_exit (0);
922 }
923 
924 static inline void
925 echo_cycle_ip (echo_main_t * em, ip46_address_t * ip, ip46_address_t * src_ip,
926  u32 i)
927 {
928  u8 *ipu8;
929  u8 l;
930  if (i % em->n_uris == 0)
931  {
932  clib_memcpy_fast (ip, src_ip, sizeof (*ip));
933  return;
934  }
935  l = em->uri_elts.is_ip4 ? 3 : 15;
936  ipu8 = em->uri_elts.is_ip4 ? ip->ip4.as_u8 : ip->ip6.as_u8;
937  while (ipu8[l] == 0xf)
938  ipu8[l--] = 0;
939  if (l)
940  ipu8[l]++;
941 }
942 
943 static void
945 {
946  echo_connect_args_t _a, *a = &_a;
947  u64 i;
948 
951  clib_memset (&a->lcl_ip, 0, sizeof (a->lcl_ip));
952 
954  for (i = 0; i < em->n_connects; i++)
955  {
956  echo_cycle_ip (em, &a->ip, &em->uri_elts.ip, i);
957  if (em->lcl_ip_set)
958  echo_cycle_ip (em, &a->lcl_ip, &em->lcl_ip, i);
959  echo_send_connect (em, a);
960  }
962  ECHO_LOG (2, "App is ready");
963  echo_process_rpcs (em);
964 }
965 
966 static void
968 {
969  echo_session_t *ls;
970  ip46_address_t _ip, *ip = &_ip;
971  u32 *listen_session_index;
972  u32 i;
973 
974  for (i = 0; i < em->n_uris; i++)
975  {
976  echo_cycle_ip (em, ip, &em->uri_elts.ip, i);
977  echo_send_listen (em, ip);
978  }
980  ECHO_LOG (2, "App is ready");
981  echo_process_rpcs (em);
982  /* Cleanup */
983  vec_foreach (listen_session_index, em->listen_session_indexes)
984  {
985  ECHO_LOG (2, "Unbind listen port %d", em->listen_session_cnt);
986  ls = pool_elt_at_index (em->sessions, *listen_session_index);
987  echo_send_unbind (em, ls);
988  }
990  {
991  ECHO_FAIL (ECHO_FAIL_SERVER_DISCONNECT_TIMEOUT,
992  "Timeout waiting for state disconnected");
993  return;
994  }
995 }
996 
997 static void
999 {
1000  echo_main_t *em = &echo_main;
1001  int i;
1002  fprintf (stderr,
1003  "Usage: vpp_echo [socket-name SOCKET] [client|server] [uri URI] [OPTIONS]\n"
1004  "Generates traffic and assert correct teardown of the hoststack\n"
1005  "\n"
1006  " socket-name PATH Specify the binary socket path to connect to VPP\n"
1007  " use-svm-api Use SVM API to connect to VPP\n"
1008  " test-bytes[:assert] Check data correctness when receiving (assert fails on first error)\n"
1009  " fifo-size N[K|M|G] Use N[K|M|G] fifos\n"
1010  " mq-size N Use mq with N slots for [vpp_echo->vpp] communication\n"
1011  " max-sim-connects N Do not allow more than N mq events inflight\n"
1012  " rx-buf N[K|M|G] Use N[Kb|Mb|GB] RX buffer\n"
1013  " tx-buf N[K|M|G] Use N[Kb|Mb|GB] TX test buffer\n"
1014  " appns NAMESPACE Use the namespace NAMESPACE\n"
1015  " all-scope all-scope option\n"
1016  " local-scope local-scope option\n"
1017  " global-scope global-scope option\n"
1018  " secret SECRET set namespace secret\n"
1019  " chroot prefix PATH Use PATH as memory root path\n"
1020  " sclose=[Y|N|W] When stream is done, send[Y]|nop[N]|wait[W] for close\n"
1021  " nuris N Cycle through N consecutive (src&dst) ips when creating connections\n"
1022  " lcl IP Set the local ip to use as a client (use with nuris to set first src ip)\n"
1023  "\n"
1024  " time START:END Time between evts START & END, events being :\n"
1025  " start - Start of the app\n"
1026  " qconnect - first Connection connect sent\n"
1027  " qconnected - last Connection connected\n"
1028  " sconnect - first Stream connect sent\n"
1029  " sconnected - last Stream got connected\n"
1030  " lastbyte - Last expected byte received\n"
1031  " exit - Exiting of the app\n"
1032  " rx-results-diff Rx results different to pass test\n"
1033  " tx-results-diff Tx results different to pass test\n"
1034  " json Output global stats in json\n"
1035  " stats N Output stats evry N secs\n"
1036  " log=N Set the log level to [0: no output, 1:errors, 2:log]\n"
1037  " crypto [engine] Set the crypto engine [openssl, vpp, picotls, mbedtls]\n"
1038  "\n"
1039  " nclients N Open N clients sending data\n"
1040  " nthreads N Use N busy loop threads for data [in addition to main & msg queue]\n"
1041  " TX=1337[K|M|G]|RX Send 1337 [K|M|G]bytes, use TX=RX to reflect the data\n"
1042  " RX=1337[K|M|G] Expect 1337 [K|M|G]bytes\n" "\n");
1043  for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
1044  {
1046  if (vft && vft->print_usage_cb)
1047  vft->print_usage_cb ();
1048  }
1049  fprintf (stderr, "\nDefault configuration is :\n"
1050  " server nclients 1 [quic-streams 1] RX=64Kb TX=RX\n"
1051  " client nclients 1 [quic-streams 1] RX=64Kb TX=64Kb\n");
1052  exit (ECHO_FAIL_USAGE);
1053 }
1054 
1055 static int
1057 {
1058  echo_main_t *em = &echo_main;
1059  int i, rv;
1060  for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
1061  {
1063  if (vft && vft->process_opts_cb)
1064  if ((rv = vft->process_opts_cb (a)))
1065  return rv;
1066  }
1067  return 0;
1068 }
1069 
1070 static void
1072 {
1073  int i;
1074  for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
1075  {
1077  if (vft && vft->set_defaults_before_opts_cb)
1079  }
1080 }
1081 
1082 void
1083 echo_process_opts (int argc, char **argv)
1084 {
1085  echo_main_t *em = &echo_main;
1086  unformat_input_t _argv, *a = &_argv;
1087  u8 *chroot_prefix;
1088  u8 *uri = 0;
1089  u8 default_f_active;
1090  uword tmp;
1091 
1092  unformat_init_command_line (a, argv);
1094  {
1096  ;
1097  else if (unformat (a, "chroot prefix %s", &chroot_prefix))
1098  vl_set_memory_root_path ((char *) chroot_prefix);
1099  else if (unformat (a, "uri %s", &uri))
1100  em->uri = format (0, "%s%c", uri, 0);
1101  else if (unformat (a, "lcl %U", unformat_ip46_address, &em->lcl_ip))
1102  em->lcl_ip_set = 1;
1103  else if (unformat (a, "nuris %u", &em->n_uris))
1104  em->n_sessions = em->n_clients + em->n_uris;
1105  else if (unformat (a, "server"))
1106  em->i_am_master = 1;
1107  else if (unformat (a, "client"))
1108  em->i_am_master = 0;
1109  else if (unformat (a, "test-bytes:assert"))
1111  else if (unformat (a, "test-bytes"))
1113  else if (unformat (a, "socket-name %s", &em->socket_name))
1114  ;
1115  else if (unformat (a, "use-svm-api"))
1116  em->use_sock_api = 0;
1117  else if (unformat (a, "fifo-size %U", unformat_memory_size, &tmp))
1118  {
1119  if (tmp >= 0x100000000ULL)
1120  {
1121  fprintf (stderr,
1122  "ERROR: fifo-size %ld (0x%lx) too large\n", tmp, tmp);
1124  }
1125  em->fifo_size = tmp;
1126  }
1127  else if (unformat (a, "prealloc-fifos %u", &em->prealloc_fifo_pairs))
1128  ;
1129  else
1130  if (unformat (a, "rx-buf %U", unformat_data_size, &em->rx_buf_size))
1131  ;
1132  else
1133  if (unformat (a, "tx-buf %U", unformat_data_size, &em->tx_buf_size))
1134  ;
1135  else if (unformat (a, "mq-size %d", &em->evt_q_size))
1136  ;
1137  else if (unformat (a, "nclients %d", &em->n_clients))
1138  {
1139  em->n_sessions = em->n_clients + em->n_uris;
1140  em->n_connects = em->n_clients;
1141  }
1142  else if (unformat (a, "nthreads %d", &em->n_rx_threads))
1143  ;
1144  else if (unformat (a, "crypto %U", echo_unformat_crypto_engine, &tmp))
1145  em->crypto_engine = tmp;
1146  else if (unformat (a, "appns %_%v%_", &em->appns_id))
1147  ;
1148  else if (unformat (a, "all-scope"))
1149  em->appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
1150  | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
1151  else if (unformat (a, "local-scope"))
1152  em->appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1153  else if (unformat (a, "global-scope"))
1154  em->appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1155  else if (unformat (a, "secret %lu", &em->appns_secret))
1156  ;
1157  else if (unformat (a, "TX=RX"))
1159  else if (unformat (a, "TX=%U", unformat_data_size, &em->bytes_to_send))
1160  ;
1161  else if (unformat (a, "RX=%U", unformat_data_size,
1162  &em->bytes_to_receive))
1163  ;
1164  else if (unformat (a, "rx-results-diff"))
1165  em->rx_results_diff = 1;
1166  else if (unformat (a, "tx-results-diff"))
1167  em->tx_results_diff = 1;
1168  else if (unformat (a, "json"))
1169  em->output_json = 1;
1170  else if (unformat (a, "stats %d", &em->periodic_stats_delta))
1171  ;
1172  else if (unformat (a, "wait-for-gdb"))
1173  em->wait_for_gdb = 1;
1174  else if (unformat (a, "log=%d", &em->log_lvl))
1175  ;
1176  else if (unformat (a, "sclose=%U",
1178  ;
1179  else if (unformat (a, "time %U:%U",
1182  ;
1183  else if (unformat (a, "max-sim-connects %d", &em->max_sim_connects))
1184  ;
1185  else
1187  }
1188 
1189  /* setting default for unset values
1190  *
1191  * bytes_to_send / bytes_to_receive & data_source */
1192  if (em->bytes_to_receive == (u64) ~ 0)
1193  em->bytes_to_receive = 64 << 10; /* default */
1194  if (em->bytes_to_send == (u64) ~ 0)
1195  em->bytes_to_send = 64 << 10; /* default */
1196  else if (em->bytes_to_send == 0)
1198  else
1200 
1202  em->data_source =
1204  if (em->data_source == ECHO_RX_DATA_SOURCE)
1205  em->bytes_to_send = em->bytes_to_receive;
1206 
1207  /* disconnect flags */
1208  if (em->i_am_master)
1209  default_f_active =
1211  else
1212  default_f_active =
1215  em->send_stream_disconnects = default_f_active;
1216 
1217  if (em->max_sim_connects == 0)
1218  em->max_sim_connects = em->evt_q_size >> 1;
1219 
1220  if (em->wait_for_gdb)
1221  {
1222  volatile u64 nop = 0;
1223 
1224  clib_warning ("Waiting for gdb...");
1225  while (em->wait_for_gdb)
1226  nop++;
1227  clib_warning ("Resuming execution (%llu)!", nop);
1228  }
1229 }
1230 
1231 void
1233 {
1234  unformat_input_t _input, *input = &_input;
1235  u32 port;
1236  unformat_init_string (input, (char *) em->uri, strlen ((char *) em->uri));
1237  if (unformat
1238  (input, "%U://%U/%d", unformat_transport_proto,
1240  &em->uri_elts.ip.ip4, &port))
1241  em->uri_elts.is_ip4 = 1;
1242  else
1243  if (unformat
1244  (input, "%U://%U/%d", unformat_transport_proto,
1246  &em->uri_elts.ip.ip6, &port))
1247  em->uri_elts.is_ip4 = 0;
1248  else
1249  ECHO_FAIL (ECHO_FAIL_INVALID_URI, "Unable to process uri");
1250  em->uri_elts.port = clib_host_to_net_u16 (port);
1251  unformat_free (input);
1252 }
1253 
1254 static void __clib_constructor
1256 {
1257  /* init memory before proto register themselves */
1258  echo_main_t *em = &echo_main;
1259  clib_mem_init_thread_safe (0, 256 << 20);
1260  clib_memset (em, 0, sizeof (*em));
1261 }
1262 
1263 int
1264 main (int argc, char **argv)
1265 {
1266  echo_main_t *em = &echo_main;
1267  fifo_segment_main_t *sm = &em->segment_main;
1268  char *app_name;
1269  u64 i;
1270  svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
1271  u32 rpc_queue_size = 256 << 10;
1272 
1273  em->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
1275  em->shared_segment_handles = hash_create (0, sizeof (uword));
1277  em->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
1278  em->use_sock_api = 1;
1279  em->fifo_size = 64 << 10;
1280  em->prealloc_fifo_pairs = 16;
1281  em->n_clients = 1;
1282  em->n_connects = 1;
1283  em->n_sessions = 2;
1284  em->max_test_msg = 50;
1285  em->time_to_stop = 0;
1286  em->i_am_master = 1;
1287  em->n_rx_threads = 4;
1288  em->evt_q_size = 256;
1289  em->lcl_ip_set = 0;
1290  clib_memset (&em->lcl_ip, 0, sizeof (em->lcl_ip));
1294  em->bytes_to_receive = ~0; /* defaulted when we know if server/client */
1295  em->bytes_to_send = ~0; /* defaulted when we know if server/client */
1296  em->rx_buf_size = 1 << 20;
1297  em->tx_buf_size = 1 << 20;
1299  em->uri = format (0, "%s%c", "tcp://0.0.0.0/1234", 0);
1300  em->n_uris = 1;
1301  em->max_sim_connects = 0;
1302  em->listen_session_cnt = 0;
1305  echo_process_opts (argc, argv);
1306  echo_process_uri (em);
1308  if (!em->proto_cb_vft)
1309  {
1310  ECHO_FAIL (ECHO_FAIL_PROTOCOL_NOT_SUPPORTED,
1311  "Protocol %U is not supported",
1313  goto exit_on_error;
1314  }
1317 
1318  em->stats.rx_expected = em->bytes_to_receive * em->n_clients;
1319  em->stats.tx_expected = em->bytes_to_send * em->n_clients;
1320 
1323  for (i = 0; i < em->n_clients; i++)
1325  clib_time_init (&em->clib_time);
1329  for (i = 0; i < em->tx_buf_size; i++)
1330  em->connect_test_data[i] = i & 0xff;
1331 
1332  /* *INDENT-OFF* */
1333  svm_msg_q_ring_cfg_t rc[1] = {
1334  {rpc_queue_size, sizeof (echo_rpc_msg_t), 0},
1335  };
1336  /* *INDENT-ON* */
1337  cfg->consumer_pid = getpid ();
1338  cfg->n_rings = 1;
1339  cfg->q_nitems = rpc_queue_size;
1340  cfg->ring_cfgs = rc;
1341  svm_msg_q_attach (&em->rpc_msq_queue, svm_msg_q_alloc (cfg));
1342 
1343  signal (SIGINT, stop_signal);
1344  signal (SIGQUIT, stop_signal);
1345  signal (SIGTERM, stop_signal);
1346  echo_api_hookup (em);
1347 
1348  app_name = em->i_am_master ? "echo_server" : "echo_client";
1349  if (connect_to_vpp (app_name))
1350  {
1351  svm_region_exit ();
1352  ECHO_FAIL (ECHO_FAIL_CONNECT_TO_VPP, "Couldn't connect to vpp");
1353  goto exit_on_error;
1354  }
1355 
1356  echo_session_prealloc (em);
1358 
1359  echo_send_attach (em);
1361  {
1362  ECHO_FAIL (ECHO_FAIL_ATTACH_TO_VPP,
1363  "Couldn't attach to vpp, did you run <session enable> ?");
1364  goto exit_on_error;
1365  }
1366 
1367  if (em->uri_elts.transport_proto != TRANSPORT_PROTO_QUIC
1368  && em->uri_elts.transport_proto != TRANSPORT_PROTO_TLS)
1369  em->state = STATE_ATTACHED;
1370  else
1371  {
1372  ECHO_LOG (2, "Adding crypto context %U", echo_format_crypto_engine,
1373  em->crypto_engine);
1376  {
1377  ECHO_FAIL (ECHO_FAIL_APP_ATTACH,
1378  "Couldn't add crypto context to vpp\n");
1379  exit (1);
1380  }
1381  }
1382 
1383  if (pthread_create (&em->mq_thread_handle,
1384  NULL /*attr */ , echo_mq_thread_fn, 0))
1385  {
1386  ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE, "pthread create errored");
1387  goto exit_on_error;
1388  }
1389 
1390  for (i = 0; i < em->n_rx_threads; i++)
1391  if (pthread_create (&em->data_thread_handles[i],
1392  NULL /*attr */ , echo_data_thread_fn, (void *) i))
1393  {
1394  ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE,
1395  "pthread create errored (index %d)", i);
1396  goto exit_on_error;
1397  }
1398  if (em->i_am_master)
1399  server_run (em);
1400  else
1401  clients_run (em);
1403  echo_free_sessions (em);
1406  {
1407  ECHO_FAIL (ECHO_FAIL_DEL_CERT_KEY, "Couldn't cleanup cert and key");
1408  goto exit_on_error;
1409  }
1410 
1411  echo_send_detach (em);
1413  {
1414  ECHO_FAIL (ECHO_FAIL_DETACH, "Couldn't detach from vpp");
1415  goto exit_on_error;
1416  }
1417  int *rv;
1418  pthread_join (em->mq_thread_handle, (void **) &rv);
1419  if (rv)
1420  {
1421  ECHO_FAIL (ECHO_FAIL_MQ_PTHREAD, "mq pthread errored %d", rv);
1422  goto exit_on_error;
1423  }
1424  if (em->use_sock_api)
1426  else
1429 exit_on_error:
1430  ECHO_LOG (1, "Test complete !\n");
1431  if (em->output_json)
1433  else
1434  print_global_stats (em);
1435  vec_free (em->fail_descr);
1436  vec_free (em->available_proto_cb_vft);
1437  exit (em->has_failed);
1438 }
1439 
1440 /*
1441  * fd.io coding-style-patch-verification: ON
1442  *
1443  * Local Variables:
1444  * eval: (c-set-style "gnu")
1445  * End:
1446  */
volatile u32 listen_session_cnt
echo_proto_cb_vft_t ** available_proto_cb_vft
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
clib_time_t clib_time
static void echo_session_prealloc(echo_main_t *em)
Definition: vpp_echo.c:27
#define CHECK_SAME(fail, expected, result, _fmt, _args...)
echo_stats_t last_stat_sampling
void * svm_msg_q_msg_data(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Get data for message in queue.
teardown_stat_t clean_count
#define clib_min(x, y)
Definition: clib.h:342
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
int vl_socket_client_init_shm(vl_api_shm_elem_config_t *config, int want_pthread)
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
u8 * echo_format_timing_event(u8 *s, va_list *args)
int vl_client_connect_to_vlib(const char *svm_name, const char *client_name, int rx_queue_size)
u8 * echo_format_session(u8 *s, va_list *args)
uword unformat_data_size(unformat_input_t *input, va_list *args)
Definition: unformat.c:1081
transport_endpoint_t rmt
a
Definition: bitmap.h:544
int svm_msg_q_sub_raw(svm_msg_q_t *mq, svm_msg_q_msg_t *elem)
Consumer dequeue one message from queue.
#define clib_atomic_add_fetch(a, b)
Definition: atomics.h:30
echo_session_t * sessions
static void * echo_mq_thread_fn(void *arg)
Definition: vpp_echo.c:876
clib_spinlock_t sid_vpp_handles_lock
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
static int echo_process_each_proto_opts(unformat_input_t *a)
Definition: vpp_echo.c:1056
static void echo_print_periodic_stats(echo_main_t *em)
Definition: vpp_echo.c:848
void echo_send_del_cert_key(echo_main_t *em)
Definition: vpp_echo_bapi.c:90
u8 use_sock_api
Flag that decides if socket, instead of svm, api is used to connect to vpp.
svm_queue_t * vl_input_queue
unsigned long u64
Definition: types.h:89
ip46_address_t ip
int my_client_index
All VLIB-side message handlers use my_client_index to identify the queue / client.
Definition: api_common.h:339
static void echo_session_dequeue_notify(echo_session_t *s)
Definition: vpp_echo.c:67
static void test_recv_bytes(echo_main_t *em, echo_session_t *s, u8 *rx_buf, u32 n_read)
Definition: vpp_echo.c:309
static u8 * format_api_error(u8 *s, va_list *args)
Definition: api_main.c:12
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
ip46_address_t lcl_ip
struct echo_main_t::@681 uri_elts
void echo_send_add_cert_key(echo_main_t *em)
Definition: vpp_echo_bapi.c:69
void echo_process_uri(echo_main_t *em)
Definition: vpp_echo.c:1232
static void echo_session_detach_fifos(echo_session_t *s)
Definition: vpp_echo.c:259
static f64 clib_time_now(clib_time_t *c)
Definition: time.h:230
static int mirror_data_chunk(echo_main_t *em, echo_session_t *s, u8 *tx_buf, u64 len)
Definition: vpp_echo.c:369
uword echo_unformat_timing_event(unformat_input_t *input, va_list *args)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
static u8 svm_msg_q_is_empty(svm_msg_q_t *mq)
Check if message queue is empty.
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:645
static void print_global_json_stats(echo_main_t *em)
Definition: vpp_echo.c:122
echo_main_t echo_main
Definition: vpp_echo.c:24
ip46_address_t lcl_ip
int vl_socket_client_connect(char *socket_path, char *client_name, u32 socket_buffer_size)
#define TIMEOUT
volatile connection_state_t state
string name[64]
Definition: fib.api:25
uword echo_unformat_crypto_engine(unformat_input_t *input, va_list *args)
void(* reset_cb)(session_reset_msg_t *mp, echo_session_t *s)
volatile int max_sim_connects
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
static void echo_free_sessions(echo_main_t *em)
Definition: vpp_echo.c:283
unsigned char u8
Definition: types.h:56
int wait_for_state_change(echo_main_t *em, connection_state_t state, f64 timeout)
static void session_accepted_handler(session_accepted_msg_t *mp)
Definition: vpp_echo.c:566
foreach_app_session_field u64 vpp_session_handle
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
static void handle_mq_event(session_event_t *e)
Definition: vpp_echo.c:793
unsigned int u32
Definition: types.h:88
fifo_segment_t * fifo_segment_get_segment_if_valid(fifo_segment_main_t *sm, u32 segment_index)
Definition: fifo_segment.c:441
u8 * connect_test_data
void(* connected_cb)(session_connected_bundled_msg_t *mp, u32 session_index, u8 is_failed)
static void echo_check_closed_listener(echo_main_t *em, echo_session_t *s)
Definition: vpp_echo.c:378
__clib_export word fformat(FILE *f, char *fmt,...)
Definition: format.c:466
static void session_reset_handler(session_reset_msg_t *mp)
Definition: vpp_echo.c:706
u8 * echo_format_session_state(u8 *s, va_list *args)
static void del_segment_handler(session_app_del_segment_msg_t *mp)
Definition: vpp_echo.c:780
static void echo_process_rpcs(echo_main_t *em)
Definition: vpp_echo.c:828
void svm_region_exit(void)
Definition: svm.c:1212
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
static void app_alloc_ctrl_evt_to_vpp(svm_msg_q_t *mq, app_session_evt_t *app_evt, u8 evt_type)
static int app_send(app_session_t *s, u8 *data, u32 len, u8 noblock)
void echo_send_attach(echo_main_t *em)
Definition: vpp_echo_bapi.c:28
echo_session_t * echo_session_new(echo_main_t *em)
static void clib_mem_set_thread_index(void)
Definition: mem.h:193
unformat_function_t unformat_ip4_address
Definition: format.h:68
volatile u64 bytes_received
void echo_session_handle_add_del(echo_main_t *em, u64 handle, u32 sid)
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Fifo max bytes to dequeue.
Definition: svm_fifo.h:516
int main(int argc, char **argv)
Definition: vpp_echo.c:1264
static void clients_run(echo_main_t *em)
Definition: vpp_echo.c:944
description fragment has unexpected format
Definition: map.api:433
void echo_send_unbind(echo_main_t *em, echo_session_t *s)
static int app_send_io_evt_to_vpp(svm_msg_q_t *mq, u32 session_index, u8 evt_type, u8 noblock)
Send fifo io event to vpp worker thread.
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
clib_spinlock_t segment_handles_lock
void echo_send_disconnect_session(echo_main_t *em, void *args)
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:294
#define ECHO_FAIL(fail, _fmt, _args...)
int __clib_unused rv
Definition: application.c:491
#define SESSION_INVALID_HANDLE
Definition: session_types.h:23
char * segment_name
segment name
Definition: fifo_segment.h:89
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1029
void(* echo_rpc_t)(echo_main_t *em, echo_rpc_args_t *arg)
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
int fifo_segment_attach(fifo_segment_main_t *sm, fifo_segment_create_args_t *a)
Attach as slave to a fifo segment.
Definition: fifo_segment.c:381
void vl_set_memory_root_path(const char *name)
static int app_recv(app_session_t *s, u8 *data, u32 len)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
void(* accepted_cb)(session_accepted_msg_t *mp, echo_session_t *session)
static char * app_name
int echo_segment_attach(u64 segment_handle, char *name, ssvm_segment_type_t type, int fd)
svm_msg_q_shared_t * svm_msg_q_alloc(svm_msg_q_cfg_t *cfg)
Allocate message queue.
struct _unformat_input_t unformat_input_t
void(* cleanup_cb)(echo_session_t *s, u8 parent_died)
u8 * echo_format_bytes_per_sec(u8 *s, va_list *args)
teardown_stat_t accepted_count
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1013
void echo_api_hookup(echo_main_t *em)
u32 * tmp
#define PREDICT_FALSE(x)
Definition: clib.h:124
#define SESSION_INVALID_INDEX
Definition: session_types.h:22
static void cleanup_handler(session_cleanup_msg_t *mp)
Definition: vpp_echo.c:787
fifo_segment_main_t segment_main
svm_msg_q_t * app_mq
void(* bound_uri_cb)(session_bound_msg_t *mp, echo_session_t *session)
data_source_t data_source
u32 periodic_stats_delta
static void server_run(echo_main_t *em)
Definition: vpp_echo.c:967
u8 len
Definition: ip_types.api:103
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
format_function_t format_ip46_address
Definition: ip46_address.h:50
#define CHECK_DIFF(fail, expected, result, _fmt, _args...)
static void __clib_constructor vpp_echo_init()
Definition: vpp_echo.c:1255
unformat_function_t unformat_ip6_address
Definition: format.h:89
static void app_send_ctrl_evt_to_vpp(svm_msg_q_t *mq, app_session_evt_t *app_evt)
u32 segment_size
size of the segment
Definition: fifo_segment.h:87
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
Definition: svm_fifo.h:790
static void print_global_stats(echo_main_t *em)
Definition: vpp_echo.c:183
int connect_to_vpp(char *name)
Definition: vpp_echo.c:88
clib_error_t * vl_socket_client_recv_fd_msg(int fds[], int n_fds, u32 wait)
static u8 svm_fifo_needs_deq_ntf(svm_fifo_t *f, u32 n_last_deq)
Check if fifo needs dequeue notification.
Definition: svm_fifo.h:882
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
int svm_msg_q_timedwait(svm_msg_q_t *mq, double timeout)
Timed wait for message queue event.
void vl_socket_client_disconnect(void)
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
struct echo_main_t::@680 timing
void fifo_segment_main_init(fifo_segment_main_t *sm, u64 baseva, u32 timeout_in_seconds)
Definition: fifo_segment.c:456
uword * shared_segment_handles
#define clib_warning(format, args...)
Definition: error.h:59
#define ECHO_LOG(lvl, _fmt, _args...)
#define LOG_EVERY_N_IDLE_CYCLES
void echo_notify_event(echo_main_t *em, echo_test_evt_t e)
u32 *volatile data_thread_args
void fifo_segment_free_client_fifo(fifo_segment_t *fs, svm_fifo_t *f)
Free fifo allocated by external applications.
Definition: fifo_segment.c:978
volatile u8 time_to_stop
static void add_segment_handler(session_app_add_segment_msg_t *mp)
Definition: vpp_echo.c:729
#define HIGH_SEGMENT_BASEVA
Definition: svm_common.h:88
blocking call - best used in combination with condvars, for eventfds we don&#39;t yield the cpu ...
Definition: queue.h:42
static void echo_handle_data(echo_main_t *em, echo_session_t *s, u8 *rx_buf)
Definition: vpp_echo.c:408
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
int echo_send_rpc(echo_main_t *em, void *fp, echo_rpc_args_t *args)
#define hash_create(elts, value_bytes)
Definition: hash.h:696
static void print_usage_and_exit(void)
Definition: vpp_echo.c:998
static uword hash_elts(void *v)
Definition: hash.h:118
uword unformat_transport_proto(unformat_input_t *input, va_list *args)
Definition: transport.c:155
static void session_bound_handler(session_bound_msg_t *mp)
Definition: vpp_echo.c:539
#define always_inline
Definition: rdma_mlx5dv.h:23
__clib_export void clib_time_init(clib_time_t *c)
Definition: time.c:207
static void echo_cycle_ip(echo_main_t *em, ip46_address_t *ip, ip46_address_t *src_ip, u32 i)
Definition: vpp_echo.c:925
static void svm_fifo_clear_deq_ntf(svm_fifo_t *f)
Clear the want notification flag and set has notification.
Definition: svm_fifo.h:848
description security check failed
Definition: map.api:373
echo_session_t * echo_get_session_from_handle(echo_main_t *em, u64 handle)
static void init_error_string_table(vat_main_t *vam)
Definition: api_main.c:29
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
teardown_stat_t close_count
void echo_update_count_on_session_close(echo_main_t *em, echo_session_t *s)
Definition: vpp_echo.c:244
void svm_msg_q_attach(svm_msg_q_t *mq, void *smq_base)
static void * echo_data_thread_fn(void *arg)
Definition: vpp_echo.c:464
void(* set_defaults_before_opts_cb)(void)
unformat_function_t unformat_ip46_address
Definition: format.h:63
#define N
Definition: aes_cbc.c:225
#define clib_atomic_fetch_add(a, b)
Definition: atomics.h:23
static void echo_set_each_proto_defaults_before_opts(echo_main_t *em)
Definition: vpp_echo.c:1071
void echo_send_detach(echo_main_t *em)
Definition: vpp_echo_bapi.c:55
template key/value backing page structure
Definition: bihash_doc.h:44
static void session_unlisten_handler(session_unlisten_reply_msg_t *mp)
Definition: vpp_echo.c:524
#define API_SOCKET_FILE
Definition: socket_api.h:26
vl_api_address_t ip
Definition: l2.api:558
void svm_msg_q_free_msg(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Free message buffer.
static int recv_data_chunk(echo_main_t *em, echo_session_t *s, u8 *rx_buf)
Definition: vpp_echo.c:331
volatile u64 bytes_to_receive
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
void echo_process_opts(int argc, char **argv)
Definition: vpp_echo.c:1083
ip46_address_t ip
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
teardown_stat_t active_count
void(* print_usage_cb)(void)
vl_api_address_t src_ip
Definition: wireguard.api:38
echo_stats_t stats
void(* set_defaults_after_opts_cb)(void)
void echo_segment_detach(u64 segment_handle)
u32 * listen_session_indexes
uword * session_index_by_vpp_handles
u16 port
Definition: lb_types.api:73
svm_msg_q_t rpc_msq_queue
static void echo_assert_test_suceeded(echo_main_t *em)
Definition: vpp_echo.c:43
unformat_function_t unformat_memory_size
Definition: format.h:288
static void session_disconnected_handler(session_disconnected_msg_t *mp)
Definition: vpp_echo.c:675
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
void vl_client_disconnect_from_vlib(void)
volatile u8 wait_for_gdb
static u32 svm_msg_q_size(svm_msg_q_t *mq)
Check length of message queue.
echo_proto_cb_vft_t * proto_cb_vft
f64 now
#define vec_foreach(var, vec)
Vector iterator.
transport_endpoint_t lcl
void echo_send_listen(echo_main_t *em, ip46_address_t *ip)
teardown_stat_t connected_count
int echo_attach_session(uword segment_handle, uword rxf_offset, uword txf_offset, uword mq_offset, echo_session_t *s)
pthread_t * data_thread_handles
int(* process_opts_cb)(unformat_input_t *a)
f64 last_stat_sampling_ts
static int send_data_chunk(echo_session_t *s, u8 *tx_buf, int offset, int len)
Definition: vpp_echo.c:350
void echo_send_connect(echo_main_t *em, void *args)
void * clib_mem_init_thread_safe(void *memory, uword memory_size)
Definition: mem_dlmalloc.c:280
static void session_connected_handler(session_connected_msg_t *mp)
Definition: vpp_echo.c:623
app_main_t * am
Definition: application.c:489
u8 * echo_format_crypto_engine(u8 *s, va_list *args)
teardown_stat_t reset_count
u8 * format_transport_proto(u8 *s, va_list *args)
Definition: transport.c:52
u8 send_stream_disconnects
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
uword echo_unformat_close(unformat_input_t *input, va_list *args)
void(* disconnected_cb)(session_disconnected_msg_t *mp, echo_session_t *s)
echo_rpc_args_t args
static void stop_signal(int signum)
Definition: vpp_echo.c:81