FD.io VPP  v19.08.1-401-g8e4ed521a
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  CHECK (ECHO_FAIL_TEST_ASSERT_RX_TOTAL,
47  "Invalid amount of data received");
48  CHECK (ECHO_FAIL_TEST_ASSERT_TX_TOTAL,
49  em->n_clients * em->bytes_to_send, em->stats.tx_total,
50  "Invalid amount of data sent");
52  CHECK (ECHO_FAIL_TEST_ASSERT_ALL_SESSIONS_CLOSED,
54  "Some sessions are still open");
56 }
57 
58 always_inline void
60 {
61  int rv;
62  if (!svm_fifo_set_event (s->rx_fifo))
63  return;
64  if ((rv =
65  app_send_io_evt_to_vpp (s->vpp_evt_q, s->rx_fifo->master_session_index,
67  ECHO_FAIL (ECHO_FAIL_SEND_IO_EVT, "app_send_io_evt_to_vpp errored %d",
68  rv);
69  svm_fifo_clear_deq_ntf (s->rx_fifo);
70 }
71 
72 static void
73 stop_signal (int signum)
74 {
75  echo_main_t *em = &echo_main;
76  em->time_to_stop = 1;
77 }
78 
79 int
81 {
82  echo_main_t *em = &echo_main;
83  api_main_t *am = &api_main;
84 
85  if (em->use_sock_api)
86  {
87  if (vl_socket_client_connect ((char *) em->socket_name, name,
88  0 /* default rx, tx buffer */ ))
89  {
90  ECHO_FAIL (ECHO_FAIL_SOCKET_CONNECT, "socket connect failed");
91  return -1;
92  }
93 
94  if (vl_socket_client_init_shm (0, 1 /* want_pthread */ ))
95  {
96  ECHO_FAIL (ECHO_FAIL_INIT_SHM_API, "init shm api failed");
97  return -1;
98  }
99  }
100  else
101  {
102  if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
103  {
104  ECHO_FAIL (ECHO_FAIL_SHMEM_CONNECT, "shmem connect failed");
105  return -1;
106  }
107  }
110  return 0;
111 }
112 
113 static void
115 {
116  u8 *start_evt =
118  u8 *end_evt =
120  u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
121  u8 end_evt_missing = !(em->timing.events_sent & em->timing.end_event);
122  f64 deltat = start_evt_missing || end_evt_missing ? 0 :
123  em->timing.end_time - em->timing.start_time;
124 
125  if (start_evt_missing)
126  ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
127  "Expected event %v to happen, but it did not!", start_evt);
128 
129  if (end_evt_missing)
130  ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
131  "Expected event %v to happen, but it did not!", end_evt);
132 
133  fformat (stdout, "vpp_echo JSON stats:\n{\n");
134  fformat (stdout, " \"role\": \"%s\",\n",
135  em->i_am_master ? "server" : "client");
136  fformat (stdout, " \"time\": \"%.9f\",\n", deltat);
137  fformat (stdout, " \"start_evt\": \"%v\",\n", start_evt);
138  fformat (stdout, " \"start_evt_missing\": \"%s\",\n",
139  start_evt_missing ? "True" : "False");
140  fformat (stdout, " \"end_evt\": \"%v\",\n", end_evt);
141  fformat (stdout, " \"end_evt_missing\": \"%s\",\n",
142  end_evt_missing ? "True" : "False");
143  fformat (stdout, " \"rx_data\": %lld,\n", em->stats.rx_total);
144  fformat (stdout, " \"tx_rx\": %lld,\n", em->stats.tx_total);
145  fformat (stdout, " \"closing\": {\n");
146  fformat (stdout, " \"reset\": { \"q\": %d, \"s\": %d },\n",
147  em->stats.reset_count.q, em->stats.reset_count.s);
148  fformat (stdout, " \"close\": { \"q\": %d, \"s\": %d },\n",
149  em->stats.close_count.q, em->stats.close_count.s);
150  fformat (stdout, " \"active\": { \"q\": %d, \"s\": %d },\n",
152  fformat (stdout, " \"clean\": { \"q\": %d, \"s\": %d }\n",
153  em->stats.clean_count.q, em->stats.clean_count.s);
154  fformat (stdout, " }\n");
155  fformat (stdout, " \"results\": {\n");
156  fformat (stdout, " \"has_failed\": \"%d\"\n", em->has_failed);
157  fformat (stdout, " \"fail_descr\": \"%v\"\n", em->fail_descr);
158  fformat (stdout, " }\n");
159  fformat (stdout, "}\n");
160  fflush (stdout);
161  vec_free (start_evt);
162  vec_free (end_evt);
163 }
164 
165 static void
167 {
168  u8 *start_evt =
170  u8 *end_evt =
172  u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
173  u8 end_evt_missing = !(em->timing.events_sent & em->timing.end_event);
174  f64 deltat = start_evt_missing || end_evt_missing ? 0 :
175  em->timing.end_time - em->timing.start_time;
176 
177  if (start_evt_missing)
178  ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
179  "Expected event %v to happen, but it did not!", start_evt);
180 
181  if (end_evt_missing)
182  ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
183  "Expected event %v to happen, but it did not!", end_evt);
184 
185  fformat (stdout, "Timing %v:%v\n", start_evt, end_evt);
186  if (start_evt_missing)
187  fformat (stdout, "Missing Start Timing Event (%v)!\n", start_evt);
188  if (end_evt_missing)
189  fformat (stdout, "Missing End Timing Event (%v)!\n", end_evt);
190  fformat (stdout, "-------- TX --------\n");
191  fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
192  em->stats.tx_total, em->stats.tx_total / (1ULL << 20),
193  em->stats.tx_total / (1ULL << 30), deltat);
194  if (deltat)
195  fformat (stdout, "%.4f Gbit/second\n",
196  (em->stats.tx_total * 8.0) / deltat / 1e9);
197  fformat (stdout, "-------- RX --------\n");
198  fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
199  em->stats.rx_total, em->stats.rx_total / (1ULL << 20),
200  em->stats.rx_total / (1ULL << 30), deltat);
201  if (deltat)
202  fformat (stdout, "%.4f Gbit/second\n",
203  (em->stats.rx_total * 8.0) / deltat / 1e9);
204  fformat (stdout, "--------------------\n");
205  fformat (stdout, "Received close on %d streams (and %d Quic conn)\n",
206  em->stats.close_count.s, em->stats.close_count.q);
207  fformat (stdout, "Received reset on %d streams (and %d Quic conn)\n",
208  em->stats.reset_count.s, em->stats.reset_count.q);
209  fformat (stdout, "Sent close on %d streams (and %d Quic conn)\n",
211  fformat (stdout, "Discarded %d streams (and %d Quic conn)\n",
212  em->stats.clean_count.s, em->stats.clean_count.q);
213  if (em->has_failed)
214  fformat (stdout, "\nFailure Return Status: %d\n%v", em->has_failed,
215  em->fail_descr);
216  vec_free (start_evt);
217  vec_free (end_evt);
218 }
219 
220 void
222 {
223 
224  ECHO_LOG (1, "[%lu/%lu] -> S(%x) -> [%lu/%lu]",
226  s->session_index, s->bytes_sent,
227  s->bytes_sent + s->bytes_to_send);
230 
231  if (PREDICT_FALSE (em->stats.rx_total ==
232  em->n_clients * em->bytes_to_receive))
234 }
235 
236 static void
238 {
239  /* Free marked sessions */
240  echo_session_t *s;
241  u32 *session_indexes = 0, *session_index;
242 
243  /* *INDENT-OFF* */
244  pool_foreach (s, em->sessions,
245  ({
246  if (s->session_state == ECHO_SESSION_STATE_CLOSED)
247  vec_add1 (session_indexes, s->session_index);}
248  ));
249  /* *INDENT-ON* */
250  vec_foreach (session_index, session_indexes)
251  {
252  /* Free session */
253  s = pool_elt_at_index (em->sessions, *session_index);
256  clib_memset (s, 0xfe, sizeof (*s));
257  pool_put (em->sessions, s);
258  }
259 }
260 
261 static void
263  u32 n_read)
264 {
265  u32 i;
266  u8 expected;
267  for (i = 0; i < n_read; i++)
268  {
269  expected = (s->bytes_received + i) & 0xff;
270  if (rx_buf[i] == expected || em->max_test_msg > 0)
271  continue;
272  ECHO_LOG (0, "Session 0x%lx byte %lld was 0x%x expected 0x%x",
273  s->vpp_session_handle, s->bytes_received + i, rx_buf[i],
274  expected);
275  em->max_test_msg--;
276  if (em->max_test_msg == 0)
277  ECHO_LOG (0, "Too many errors, hiding next ones");
279  ECHO_FAIL (ECHO_FAIL_TEST_BYTES_ERR, "test-bytes errored");
280  }
281 }
282 
283 static int
285 {
286  int n_read;
287  n_read = app_recv ((app_session_t *) s, rx_buf, vec_len (rx_buf));
288  if (n_read <= 0)
289  return 0;
290  if (svm_fifo_needs_deq_ntf (s->rx_fifo, n_read))
292 
293  if (em->test_return_packets)
294  test_recv_bytes (em, s, rx_buf, n_read);
295 
296  s->bytes_received += n_read;
297  s->bytes_to_receive -= n_read;
298  return n_read;
299 }
300 
301 static int
302 send_data_chunk (echo_session_t * s, u8 * tx_buf, int offset, int len)
303 {
304  int n_sent;
305  int bytes_this_chunk = clib_min (s->bytes_to_send, len - offset);
306  if (!bytes_this_chunk)
307  return 0;
308  n_sent = app_send ((app_session_t *) s, tx_buf + offset,
309  bytes_this_chunk, SVM_Q_WAIT);
310  if (n_sent < 0)
311  return 0;
312  s->bytes_to_send -= n_sent;
313  s->bytes_sent += n_sent;
314  return n_sent;
315 }
316 
317 static int
319 {
320  u64 n_sent = 0;
321  while (n_sent < len && !em->time_to_stop)
322  n_sent += send_data_chunk (s, tx_buf, n_sent, len);
323  return n_sent;
324 }
325 
326 static inline void
328 {
329  echo_session_t *ls;
330  /* if parent has died, terminate gracefully */
332  return;
334  if (ls->session_state < ECHO_SESSION_STATE_CLOSING)
335  return;
336  ECHO_LOG (2, "Session 0%lx died, close child 0x%lx", ls->vpp_session_handle,
337  s->vpp_session_handle);
339  em->proto_cb_vft->cleanup_cb (s, 1 /* parent_died */ );
340 }
341 
342 /*
343  * Rx/Tx polling thread per connection
344  */
345 static void
347 {
348  int n_read, n_sent = 0;
349 
350  n_read = recv_data_chunk (em, s, rx_buf);
352  n_sent = send_data_chunk (s, em->connect_test_data,
353  s->bytes_sent % em->tx_buf_size,
354  em->tx_buf_size);
355  else if (em->data_source == ECHO_RX_DATA_SOURCE)
356  n_sent = mirror_data_chunk (em, s, rx_buf, n_read);
357  if (!s->bytes_to_send && !s->bytes_to_receive)
358  {
359  /* Session is done, need to close */
360  if (s->session_state == ECHO_SESSION_STATE_AWAIT_DATA)
361  s->session_state = ECHO_SESSION_STATE_CLOSING;
362  else
363  {
364  s->session_state = ECHO_SESSION_STATE_AWAIT_CLOSING;
366  {
368  (void *) s->vpp_session_handle, 0);
370  }
372  {
373  s->session_state = ECHO_SESSION_STATE_CLOSING;
375  }
376  }
377  return;
378  }
379 
380  /* Check for idle clients */
381  if (em->log_lvl > 1)
382  {
383  if (n_sent || n_read)
384  s->idle_cycles = 0;
385  else if (s->idle_cycles++ == 1e7)
386  {
387  s->idle_cycles = 0;
388  ECHO_LOG (1, "Idle client TX:%dB RX:%dB", s->bytes_to_send,
389  s->bytes_to_receive);
390  ECHO_LOG (1, "Idle FIFOs TX:%dB RX:%dB",
391  svm_fifo_max_dequeue (s->tx_fifo),
392  svm_fifo_max_dequeue (s->rx_fifo));
393  ECHO_LOG (1, "Session 0x%lx state %u", s->vpp_session_handle,
394  s->session_state);
395  }
396  }
397 }
398 
399 static void *
401 {
402  clib_mem_set_thread_index (); /* First thing to do in client thread */
403  echo_main_t *em = &echo_main;
404  u32 N = em->n_clients;
405  u32 n = (N + em->n_rx_threads - 1) / em->n_rx_threads;
406  u32 idx = (u64) arg;
407  if (n * idx >= N)
408  {
409  ECHO_LOG (1, "Thread %u exiting, no sessions to care for", idx);
410  pthread_exit (0);
411  }
412  u32 thread_n_sessions = clib_min (n, N - n * idx);
413 
414  u32 i = 0;
415  u32 n_closed_sessions = 0;
416  u32 session_index;
417  u8 *rx_buf = 0;
418  echo_session_t *s;
419  vec_validate (rx_buf, em->rx_buf_size);
420 
421  for (i = 0; !em->time_to_stop; i = (i + 1) % thread_n_sessions)
422  {
423  n_closed_sessions = i == 0 ? 0 : n_closed_sessions;
424  session_index = em->data_thread_args[n * idx + i];
425  if (session_index == SESSION_INVALID_INDEX)
426  continue;
427  s = pool_elt_at_index (em->sessions, session_index);
428  switch (s->session_state)
429  {
432  echo_handle_data (em, s, rx_buf);
434  break;
437  break;
440  em->proto_cb_vft->cleanup_cb (s, 0 /* parent_died */ );
441  break;
443  n_closed_sessions++;
444  break;
445  }
446  if (n_closed_sessions == thread_n_sessions)
447  break;
448  }
449  pthread_exit (0);
450 }
451 
452 static void
454 {
455  echo_main_t *em = &echo_main;
456  echo_session_t *listen_session;
457  if (mp->retval)
458  {
459  ECHO_FAIL (ECHO_FAIL_BIND, "bind failed: %U", format_api_error,
460  clib_net_to_host_u32 (mp->retval));
461  return;
462  }
463  ECHO_LOG (0, "listening on %U:%u", format_ip46_address, mp->lcl_ip,
465  clib_net_to_host_u16 (mp->lcl_port));
466 
467  /* Allocate local session and set it up */
468  listen_session = echo_session_new (em);
469  listen_session->session_type = ECHO_SESSION_TYPE_LISTEN;
470  listen_session->vpp_session_handle = mp->handle;
471  echo_session_handle_add_del (em, mp->handle, listen_session->session_index);
472  em->state = STATE_LISTEN;
473  em->listen_session_index = listen_session->session_index;
474  if (em->proto_cb_vft->bound_uri_cb)
475  em->proto_cb_vft->bound_uri_cb (mp, listen_session);
476 }
477 
478 static void
480 {
481  app_session_evt_t _app_evt, *app_evt = &_app_evt;
483  svm_fifo_t *rx_fifo, *tx_fifo;
484  echo_main_t *em = &echo_main;
485  echo_session_t *session, *ls;
486  /* Allocate local session and set it up */
487  session = echo_session_new (em);
488 
490  {
491  ECHO_FAIL (ECHO_FAIL_ACCEPTED_WAIT_FOR_SEG_ALLOC,
492  "accepted wait_for_segment_allocation errored");
493  return;
494  }
495 
496  rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
497  rx_fifo->client_session_index = session->session_index;
498  tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
499  tx_fifo->client_session_index = session->session_index;
500 
501  session->rx_fifo = rx_fifo;
502  session->tx_fifo = tx_fifo;
503 
504  /* session->transport needed by app_send_dgram */
505  clib_memcpy_fast (&session->transport.rmt_ip, &mp->rmt.ip,
506  sizeof (ip46_address_t));
507  session->transport.is_ip4 = mp->rmt.is_ip4;
508  session->transport.rmt_port = mp->rmt.port;
509  clib_memcpy_fast (&session->transport.lcl_ip, &em->uri_elts.ip,
510  sizeof (ip46_address_t));
511  session->transport.lcl_port = em->uri_elts.port;
512 
513  session->vpp_session_handle = mp->handle;
514  session->start = clib_time_now (&em->clib_time);
515  session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
516  svm_msg_q_t *);
517  if (!(ls = echo_get_session_from_handle (em, mp->listener_handle)))
518  return;
519  session->listener_index = ls->session_index;
520 
521  /* Add it to lookup table */
522  ECHO_LOG (1, "Accepted session 0x%lx -> 0x%lx", mp->handle,
523  mp->listener_handle);
524  echo_session_handle_add_del (em, mp->handle, session->session_index);
525 
526  app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
528  rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
529  rmp->handle = mp->handle;
530  rmp->context = mp->context;
531  app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
532  em->proto_cb_vft->accepted_cb (mp, session);
533 }
534 
535 static void
537 {
538  echo_main_t *em = &echo_main;
539  echo_session_t *session;
540  u32 listener_index = htonl (mp->context);
541  svm_fifo_t *rx_fifo, *tx_fifo;
542 
543  if (mp->retval)
544  {
545  ECHO_FAIL (ECHO_FAIL_SESSION_CONNECT,
546  "connection failed with code: %U", format_api_error,
547  clib_net_to_host_u32 (mp->retval));
548  return;
549  }
550 
551  session = echo_session_new (em);
553  {
554  ECHO_FAIL (ECHO_FAIL_CONNECTED_WAIT_FOR_SEG_ALLOC,
555  "connected wait_for_segment_allocation errored");
556  return;
557  }
558 
559  rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
560  rx_fifo->client_session_index = session->session_index;
561  tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
562  tx_fifo->client_session_index = session->session_index;
563 
564  session->rx_fifo = rx_fifo;
565  session->tx_fifo = tx_fifo;
566  session->vpp_session_handle = mp->handle;
567  session->start = clib_time_now (&em->clib_time);
568  session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
569  svm_msg_q_t *);
570  session->listener_index = listener_index;
571  /* session->transport needed by app_send_dgram */
572  clib_memcpy_fast (&session->transport.lcl_ip, &mp->lcl.ip,
573  sizeof (ip46_address_t));
574  session->transport.is_ip4 = mp->lcl.is_ip4;
575  session->transport.lcl_port = mp->lcl.port;
576  clib_memcpy_fast (&session->transport.rmt_ip, &em->uri_elts.ip,
577  sizeof (ip46_address_t));
578  session->transport.rmt_port = em->uri_elts.port;
579 
580  echo_session_handle_add_del (em, mp->handle, session->session_index);
582  session->session_index, 0 /* is_failed */ );
583 }
584 
585 /*
586  *
587  * End of ECHO callback definitions
588  *
589  */
590 
591 static void
593 {
594  app_session_evt_t _app_evt, *app_evt = &_app_evt;
596  echo_main_t *em = &echo_main;
597  echo_session_t *s;
598  ECHO_LOG (1, "passive close session 0x%lx", mp->handle);
599  if (!(s = echo_get_session_from_handle (em, mp->handle)))
600  return;
601  em->proto_cb_vft->disconnected_cb (mp, s);
602 
603  app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
605  rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
606  rmp->retval = 0;
607  rmp->handle = mp->handle;
608  rmp->context = mp->context;
609  app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
610 }
611 
612 static void
614 {
615  app_session_evt_t _app_evt, *app_evt = &_app_evt;
616  echo_main_t *em = &echo_main;
618  echo_session_t *s = 0;
619  ECHO_LOG (1, "Reset session 0x%lx", mp->handle);
620  if (!(s = echo_get_session_from_handle (em, mp->handle)))
621  return;
622  em->proto_cb_vft->reset_cb (mp, s);
623 
624  app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
626  rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
627  rmp->retval = 0;
628  rmp->handle = mp->handle;
629  app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
630 }
631 
632 static void
633 handle_mq_event (session_event_t * e)
634 {
635  switch (e->event_type)
636  {
639  break;
642  break;
645  break;
648  break;
651  break;
652  case SESSION_IO_EVT_RX:
653  break;
654  default:
655  ECHO_LOG (0, "unhandled event %u", e->event_type);
656  }
657 }
658 
659 static void
661 {
662  echo_rpc_msg_t *rpc;
663  svm_msg_q_msg_t msg;
664  svm_msg_q_t *mq = em->rpc_msq_queue;
665 
666  while (em->state < STATE_DATA_DONE && !em->time_to_stop)
667  {
668  svm_msg_q_lock (mq);
669  if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
670  {
671  svm_msg_q_unlock (mq);
672  continue;
673  }
674  svm_msg_q_sub_w_lock (mq, &msg);
675  rpc = svm_msg_q_msg_data (mq, &msg);
676  svm_msg_q_unlock (mq);
677  ((echo_rpc_t) rpc->fp) (rpc->arg, rpc->opaque);
678  svm_msg_q_free_msg (mq, &msg);
679  }
680 }
681 
682 static inline int
684  u32 n_max_msg)
685 {
686  svm_msg_q_msg_t *msg;
687  u32 n_msgs;
688  int i;
689 
690  n_msgs = clib_min (svm_msg_q_size (mq), n_max_msg);
691  for (i = 0; i < n_msgs; i++)
692  {
693  vec_add2 (msg_vec, msg, 1);
694  svm_msg_q_sub_w_lock (mq, msg);
695  }
696  return n_msgs;
697 }
698 
699 static void *
700 echo_mq_thread_fn (void *arg)
701 {
702  clib_mem_set_thread_index (); /* First thing to do in client thread */
703  svm_msg_q_msg_t *msg_vec = 0;
704  echo_main_t *em = &echo_main;
705  session_event_t *e;
706  svm_msg_q_msg_t *msg;
707  svm_msg_q_t *mq;
708  int i;
709 
710  vec_validate (msg_vec, em->evt_q_size);
711  vec_reset_length (msg_vec);
713  mq = em->our_event_queue;
714  if (em->state < STATE_ATTACHED || !mq)
715  {
716  ECHO_FAIL (ECHO_FAIL_APP_ATTACH, "Application failed to attach");
717  pthread_exit (0);
718  }
719 
720  while (em->state < STATE_DETACHED && !em->time_to_stop)
721  {
722  svm_msg_q_lock (mq);
723  if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
724  {
725  svm_msg_q_unlock (mq);
726  continue;
727  }
728  echo_mq_dequeue_batch (mq, msg_vec, ~0);
729  svm_msg_q_unlock (mq);
730 
731  for (i = 0; i < vec_len (msg_vec); i++)
732  {
733  msg = vec_elt_at_index (msg_vec, i);
734  e = svm_msg_q_msg_data (mq, msg);
735  handle_mq_event (e);
736  svm_msg_q_free_msg (mq, msg); /* No lock, single thread dequeuing */
737  }
738  vec_reset_length (msg_vec);
739  }
740  vec_free (msg_vec);
741  pthread_exit (0);
742 }
743 
744 static void
746 {
747  u64 i;
749  for (i = 0; i < em->n_connects; i++)
752  ECHO_LOG (1, "App is ready");
753  echo_process_rpcs (em);
754 }
755 
756 static void
758 {
759  echo_send_listen (em);
761  ECHO_LOG (1, "App is ready");
762  echo_process_rpcs (em);
763  /* Cleanup */
764  echo_send_unbind (em);
766  {
767  ECHO_FAIL (ECHO_FAIL_SERVER_DISCONNECT_TIMEOUT,
768  "Timeout waiting for state disconnected");
769  return;
770  }
771 }
772 
773 static void
775 {
776  echo_main_t *em = &echo_main;
777  int i;
778  fprintf (stderr,
779  "Usage: vpp_echo [socket-name SOCKET] [client|server] [uri URI] [OPTIONS]\n"
780  "Generates traffic and assert correct teardown of the QUIC hoststack\n"
781  "\n"
782  " socket-name PATH Specify the binary socket path to connect to VPP\n"
783  " use-svm-api Use SVM API to connect to VPP\n"
784  " test-bytes[:assert] Check data correctness when receiving (assert fails on first error)\n"
785  " fifo-size N Use N Kb fifos\n"
786  " mq-size N Use N event slots for vpp_echo <-> vpp events\n"
787  " rx-buf N[Kb|Mb|GB] Use N[Kb|Mb|GB] RX buffer\n"
788  " tx-buf N[Kb|Mb|GB] Use N[Kb|Mb|GB] TX test buffer\n"
789  " appns NAMESPACE Use the namespace NAMESPACE\n"
790  " all-scope all-scope option\n"
791  " local-scope local-scope option\n"
792  " global-scope global-scope option\n"
793  " secret SECRET set namespace secret\n"
794  " chroot prefix PATH Use PATH as memory root path\n"
795  " sclose=[Y|N|W] When a stream is done, pass[N] send[Y] or wait[W] for close\n"
796  "\n"
797  " time START:END Time between evts START & END, events being :\n"
798  " start - Start of the app\n"
799  " qconnect - first Connection connect sent\n"
800  " qconnected - last Connection connected\n"
801  " sconnect - first Stream connect sent\n"
802  " sconnected - last Stream got connected\n"
803  " lastbyte - Last expected byte received\n"
804  " exit - Exiting of the app\n"
805  " json Output global stats in json\n"
806  " log=N Set the log level to [0: no output, 1:errors, 2:log]\n"
807  "\n"
808  " nclients N Open N clients sending data\n"
809  " nthreads N Use N busy loop threads for data [in addition to main & msg queue]\n"
810  " TX=1337[Kb|Mb|GB] Send 1337 [K|M|G]bytes, use TX=RX to reflect the data\n"
811  " RX=1337[Kb|Mb|GB] Expect 1337 [K|M|G]bytes\n" "\n");
812  for (i = 0; i < TRANSPORT_N_PROTO; i++)
813  {
815  if (vft && vft->print_usage_cb)
816  vft->print_usage_cb ();
817  }
818  fprintf (stderr, "\nDefault configuration is :\n"
819  " server nclients 1/1 RX=64Kb TX=RX\n"
820  " client nclients 1/1 RX=64Kb TX=64Kb\n");
821  exit (1);
822 }
823 
824 static int
826 {
827  echo_main_t *em = &echo_main;
828  int i, rv;
829  for (i = 0; i < TRANSPORT_N_PROTO; i++)
830  {
832  if (vft && vft->process_opts_cb)
833  if ((rv = vft->process_opts_cb (a)))
834  return rv;
835  }
836  return 0;
837 }
838 
839 static void
841 {
842  int i;
843  for (i = 0; i < TRANSPORT_N_PROTO; i++)
844  {
846  if (vft && vft->set_defaults_before_opts_cb)
848  }
849 }
850 
851 void
852 echo_process_opts (int argc, char **argv)
853 {
854  echo_main_t *em = &echo_main;
855  unformat_input_t _argv, *a = &_argv;
856  u32 tmp;
857  u8 *chroot_prefix;
858  u8 *uri = 0;
859  u8 default_f_active;
860 
861  unformat_init_command_line (a, argv);
863  {
865  ;
866  else if (unformat (a, "chroot prefix %s", &chroot_prefix))
867  vl_set_memory_root_path ((char *) chroot_prefix);
868  else if (unformat (a, "uri %s", &uri))
869  em->uri = format (0, "%s%c", uri, 0);
870  else if (unformat (a, "server"))
871  em->i_am_master = 1;
872  else if (unformat (a, "client"))
873  em->i_am_master = 0;
874  else if (unformat (a, "test-bytes:assert"))
876  else if (unformat (a, "test-bytes"))
878  else if (unformat (a, "socket-name %s", &em->socket_name))
879  ;
880  else if (unformat (a, "use-svm-api"))
881  em->use_sock_api = 0;
882  else if (unformat (a, "fifo-size %d", &tmp))
883  em->fifo_size = tmp << 10;
884  else if (unformat (a, "prealloc-fifos %u", &em->prealloc_fifo_pairs))
885  ;
886  else if (unformat (a, "rx-buf %U", unformat_data, &em->rx_buf_size))
887  ;
888  else if (unformat (a, "tx-buf %U", unformat_data, &em->tx_buf_size))
889  ;
890  else if (unformat (a, "mq-size %d", &em->evt_q_size))
891  ;
892  else if (unformat (a, "nclients %d", &em->n_clients))
893  {
894  em->n_sessions = em->n_clients + 1;
895  em->n_connects = em->n_clients;
896  }
897  else if (unformat (a, "nthreads %d", &em->n_rx_threads))
898  ;
899  else if (unformat (a, "appns %_%v%_", &em->appns_id))
900  ;
901  else if (unformat (a, "all-scope"))
902  em->appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
903  | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
904  else if (unformat (a, "local-scope"))
905  em->appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
906  else if (unformat (a, "global-scope"))
907  em->appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
908  else if (unformat (a, "secret %lu", &em->appns_secret))
909  ;
910  else if (unformat (a, "TX=RX"))
912  else if (unformat (a, "TX=%U", unformat_data, &em->bytes_to_send))
913  ;
914  else if (unformat (a, "RX=%U", unformat_data, &em->bytes_to_receive))
915  ;
916  else if (unformat (a, "json"))
917  em->output_json = 1;
918  else if (unformat (a, "log=%d", &em->log_lvl))
919  ;
920  else if (unformat (a, "sclose=%U",
922  ;
923  else if (unformat (a, "time %U:%U",
926  ;
927  else
929  }
930 
931  /* setting default for unset values
932  *
933  * bytes_to_send / bytes_to_receive & data_source */
934  if (em->bytes_to_receive == (u64) ~ 0)
935  em->bytes_to_receive = 64 << 10; /* default */
936  if (em->bytes_to_send == (u64) ~ 0)
937  em->bytes_to_send = 64 << 10; /* default */
938  else if (em->bytes_to_send == 0)
940  else
942 
944  em->data_source =
946  if (em->data_source == ECHO_RX_DATA_SOURCE)
948 
949  /* disconnect flags */
950  if (em->i_am_master)
951  default_f_active =
953  else
954  default_f_active =
957  em->send_stream_disconnects = default_f_active;
958 }
959 
960 void
962 {
963  unformat_input_t _input, *input = &_input;
964  u32 port;
965  unformat_init_string (input, (char *) em->uri, strlen ((char *) em->uri));
966  if (unformat
967  (input, "%U://%U/%d", unformat_transport_proto,
969  &em->uri_elts.ip.ip4, &port))
970  em->uri_elts.is_ip4 = 1;
971  else
972  if (unformat
973  (input, "%U://%U/%d", unformat_transport_proto,
975  &em->uri_elts.ip.ip6, &port))
976  em->uri_elts.is_ip4 = 0;
977  else
978  ECHO_FAIL (ECHO_FAIL_INVALID_URI, "Unable to process uri");
979  em->uri_elts.port = clib_host_to_net_u16 (port);
980  unformat_free (input);
981 }
982 
983 static void __clib_constructor
985 {
986  /* init memory before proto register themselves */
987  echo_main_t *em = &echo_main;
988  clib_mem_init_thread_safe (0, 256 << 20);
989  clib_memset (em, 0, sizeof (*em));
990 }
991 
992 int
993 main (int argc, char **argv)
994 {
995  echo_main_t *em = &echo_main;
997  char *app_name;
998  u64 i;
999  svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
1000  u32 rpc_queue_size = 64 << 10;
1001 
1002  em->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
1004  em->shared_segment_handles = hash_create (0, sizeof (uword));
1006  em->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
1007  em->use_sock_api = 1;
1008  em->fifo_size = 64 << 10;
1009  em->prealloc_fifo_pairs = 16;
1010  em->n_clients = 1;
1011  em->n_connects = 1;
1012  em->n_sessions = 2;
1013  em->max_test_msg = 50;
1014  em->time_to_stop = 0;
1015  em->i_am_master = 1;
1016  em->n_rx_threads = 4;
1017  em->evt_q_size = 256;
1021  em->bytes_to_receive = ~0; /* defaulted when we know if server/client */
1022  em->bytes_to_send = ~0; /* defaulted when we know if server/client */
1023  em->rx_buf_size = 1 << 20;
1024  em->tx_buf_size = 1 << 20;
1026  em->uri = format (0, "%s%c", "tcp://0.0.0.0/1234", 0);
1028  echo_process_opts (argc, argv);
1029  echo_process_uri (em);
1031  if (!em->proto_cb_vft)
1032  {
1033  ECHO_FAIL (ECHO_FAIL_PROTOCOL_NOT_SUPPORTED,
1034  "Protocol %U is not supported",
1036  goto exit_on_error;
1037  }
1040 
1043  for (i = 0; i < em->n_clients; i++)
1045  clib_time_init (&em->clib_time);
1049  for (i = 0; i < em->tx_buf_size; i++)
1050  em->connect_test_data[i] = i & 0xff;
1051 
1052  /* *INDENT-OFF* */
1053  svm_msg_q_ring_cfg_t rc[1] = {
1054  {rpc_queue_size, sizeof (echo_rpc_msg_t), 0},
1055  };
1056  /* *INDENT-ON* */
1057  cfg->consumer_pid = getpid ();
1058  cfg->n_rings = 1;
1059  cfg->q_nitems = rpc_queue_size;
1060  cfg->ring_cfgs = rc;
1061  em->rpc_msq_queue = svm_msg_q_alloc (cfg);
1062 
1063  signal (SIGINT, stop_signal);
1064  signal (SIGQUIT, stop_signal);
1065  signal (SIGTERM, stop_signal);
1066  echo_api_hookup (em);
1067 
1068  app_name = em->i_am_master ? "echo_server" : "echo_client";
1069  if (connect_to_vpp (app_name))
1070  {
1071  svm_region_exit ();
1072  ECHO_FAIL (ECHO_FAIL_CONNECT_TO_VPP, "Couldn't connect to vpp");
1073  goto exit_on_error;
1074  }
1075 
1076  echo_session_prealloc (em);
1078 
1079  echo_send_attach (em);
1081  {
1082  ECHO_FAIL (ECHO_FAIL_ATTACH_TO_VPP,
1083  "Couldn't attach to vpp, did you run <session enable> ?");
1084  goto exit_on_error;
1085  }
1086  if (pthread_create (&em->mq_thread_handle,
1087  NULL /*attr */ , echo_mq_thread_fn, 0))
1088  {
1089  ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE, "pthread create errored");
1090  goto exit_on_error;
1091  }
1092  for (i = 0; i < em->n_rx_threads; i++)
1093  if (pthread_create (&em->data_thread_handles[i],
1094  NULL /*attr */ , echo_data_thread_fn, (void *) i))
1095  {
1096  ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE,
1097  "pthread create errored (index %d)", i);
1098  goto exit_on_error;
1099  }
1100  if (em->i_am_master)
1101  server_run (em);
1102  else
1103  clients_run (em);
1105  echo_free_sessions (em);
1107  echo_send_detach (em);
1109  {
1110  ECHO_FAIL (ECHO_FAIL_DETACH, "Couldn't detach from vpp");
1111  goto exit_on_error;
1112  }
1113  int *rv;
1114  pthread_join (em->mq_thread_handle, (void **) &rv);
1115  if (rv)
1116  {
1117  ECHO_FAIL (ECHO_FAIL_MQ_PTHREAD, "mq pthread errored %d", rv);
1118  goto exit_on_error;
1119  }
1120  if (em->use_sock_api)
1122  else
1124 exit_on_error:
1125  ECHO_LOG (0, "Test complete !\n");
1126  if (em->output_json)
1128  else
1129  print_global_stats (em);
1130  vec_free (em->fail_descr);
1131  exit (em->has_failed);
1132 }
1133 
1134 /*
1135  * fd.io coding-style-patch-verification: ON
1136  *
1137  * Local Variables:
1138  * eval: (c-set-style "gnu")
1139  * End:
1140  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
uword unformat_data(unformat_input_t *input, va_list *args)
clib_time_t clib_time
static void echo_session_prealloc(echo_main_t *em)
Definition: vpp_echo.c:27
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:295
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:102
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:80
u8 * echo_format_timing_event(u8 *s, va_list *args)
struct echo_main_t::@483 uri_elts
u32 listen_session_index
int vl_client_connect_to_vlib(const char *svm_name, const char *client_name, int rx_queue_size)
transport_endpoint_t rmt
a
Definition: bitmap.h:538
echo_session_t * sessions
static void * echo_mq_thread_fn(void *arg)
Definition: vpp_echo.c:700
clib_spinlock_t sid_vpp_handles_lock
static int echo_process_each_proto_opts(unformat_input_t *a)
Definition: vpp_echo.c:825
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
int my_client_index
All VLIB-side message handlers use my_client_index to identify the queue / client.
Definition: api_common.h:311
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static void echo_session_dequeue_notify(echo_session_t *s)
Definition: vpp_echo.c:59
#define NULL
Definition: clib.h:58
static void test_recv_bytes(echo_main_t *em, echo_session_t *s, u8 *rx_buf, u32 n_read)
Definition: vpp_echo.c:262
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)
void echo_process_uri(echo_main_t *em)
Definition: vpp_echo.c:961
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:318
uword echo_unformat_timing_event(unformat_input_t *input, va_list *args)
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:560
int i
static void print_global_json_stats(echo_main_t *em)
Definition: vpp_echo.c:114
echo_main_t echo_main
Definition: vpp_echo.c:24
format_function_t format_ip46_address
Definition: format.h:61
int vl_socket_client_connect(char *socket_path, char *client_name, u32 socket_buffer_size)
#define TIMEOUT
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
volatile connection_state_t state
void(* reset_cb)(session_reset_msg_t *mp, echo_session_t *s)
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
static void echo_free_sessions(echo_main_t *em)
Definition: vpp_echo.c:237
unsigned char u8
Definition: types.h:56
int wait_for_state_change(echo_main_t *em, connection_state_t state, f64 timeout)
void echo_send_disconnect_session(u64 handle, u32 opaque)
static void session_accepted_handler(session_accepted_msg_t *mp)
Definition: vpp_echo.c:479
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:633
struct _svm_fifo svm_fifo_t
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:327
static void session_reset_handler(session_reset_msg_t *mp)
Definition: vpp_echo.c:613
static void echo_process_rpcs(echo_main_t *em)
Definition: vpp_echo.c:660
void svm_region_exit(void)
Definition: svm.c:1224
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:64
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
unformat_function_t unformat_ip4_address
Definition: format.h:70
svm_msg_q_t * svm_msg_q_alloc(svm_msg_q_cfg_t *cfg)
Allocate message queue.
Definition: message_queue.c:40
volatile u64 bytes_received
#define always_inline
Definition: clib.h:98
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:527
int main(int argc, char **argv)
Definition: vpp_echo.c:993
static void clients_run(echo_main_t *em)
Definition: vpp_echo.c:745
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
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:266
#define ECHO_FAIL(fail, _fmt, _args...)
unsigned int u32
Definition: types.h:88
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1029
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:63
void vl_set_memory_root_path(const char *name)
static int echo_mq_dequeue_batch(svm_msg_q_t *mq, svm_msg_q_msg_t *msg_vec, u32 n_max_msg)
Definition: vpp_echo.c:683
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:514
void(* accepted_cb)(session_accepted_msg_t *mp, echo_session_t *session)
struct _unformat_input_t unformat_input_t
void(* cleanup_cb)(echo_session_t *s, u8 parent_died)
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1013
void echo_api_hookup(echo_main_t *em)
#define PREDICT_FALSE(x)
Definition: clib.h:111
u16 port
Definition: punt.api:40
#define SESSION_INVALID_INDEX
Definition: session_types.h:22
fifo_segment_main_t segment_main
void clib_time_init(clib_time_t *c)
Definition: time.c:207
u8 name[64]
Definition: memclnt.api:152
void(* bound_uri_cb)(session_bound_msg_t *mp, echo_session_t *session)
data_source_t data_source
word fformat(FILE *f, char *fmt,...)
Definition: format.c:462
static void server_run(echo_main_t *em)
Definition: vpp_echo.c:757
u8 len
Definition: ip_types.api:90
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:203
static void __clib_constructor vpp_echo_init()
Definition: vpp_echo.c:984
unformat_function_t unformat_ip6_address
Definition: format.h:91
static void app_send_ctrl_evt_to_vpp(svm_msg_q_t *mq, app_session_evt_t *app_evt)
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
Definition: svm_fifo.h:748
static void print_global_stats(echo_main_t *em)
Definition: vpp_echo.c:166
int connect_to_vpp(char *name)
Definition: vpp_echo.c:80
void echo_send_connect(u8 *uri, u32 opaque)
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:839
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
void vl_socket_client_disconnect(void)
#define CHECK(x)
echo_proto_cb_vft_t * available_proto_cb_vft[TRANSPORT_N_PROTO]
static void svm_msg_q_unlock(svm_msg_q_t *mq)
Unlock message queue.
static int svm_msg_q_timedwait(svm_msg_q_t *mq, double timeout)
Timed wait for message queue event.
svm_msg_q_t * our_event_queue
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
void fifo_segment_main_init(fifo_segment_main_t *sm, u64 baseva, u32 timeout_in_seconds)
Definition: fifo_segment.c:162
uword * shared_segment_handles
#define ECHO_LOG(lvl, _fmt, _args...)
void echo_notify_event(echo_main_t *em, echo_test_evt_t e)
u32 *volatile data_thread_args
volatile u8 time_to_stop
#define HIGH_SEGMENT_BASEVA
Definition: svm_common.h:84
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:346
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
teardown_stat_t reset_count
struct echo_main_t::@482 timing
#define hash_create(elts, value_bytes)
Definition: hash.h:696
#define uword_to_pointer(u, type)
Definition: types.h:136
static void print_usage_and_exit(void)
Definition: vpp_echo.c:774
static uword hash_elts(void *v)
Definition: hash.h:118
uword unformat_transport_proto(unformat_input_t *input, va_list *args)
Definition: transport.c:140
static void session_bound_handler(session_bound_msg_t *mp)
Definition: vpp_echo.c:453
void echo_send_unbind(echo_main_t *em)
static void svm_fifo_clear_deq_ntf(svm_fifo_t *f)
Clear the want notification flag and set has notification.
Definition: svm_fifo.h:806
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
void echo_update_count_on_session_close(echo_main_t *em, echo_session_t *s)
Definition: vpp_echo.c:221
static void * echo_data_thread_fn(void *arg)
Definition: vpp_echo.c:400
void(* set_defaults_before_opts_cb)(void)
#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:840
void echo_send_detach(echo_main_t *em)
Definition: vpp_echo_bapi.c:78
template key/value backing page structure
Definition: bihash_doc.h:44
teardown_stat_t close_count
#define API_SOCKET_FILE
Definition: socket_api.h:25
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:284
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:852
void echo_send_listen(echo_main_t *em)
Definition: vpp_echo_bapi.c:91
ip46_address_t ip
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
void(* print_usage_cb)(void)
void(* set_defaults_after_opts_cb)(void)
teardown_stat_t active_count
uword * session_index_by_vpp_handles
int wait_for_segment_allocation(u64 segment_handle)
static void echo_assert_test_suceeded(echo_main_t *em)
Definition: vpp_echo.c:43
svm_msg_q_t * rpc_msq_queue
static void session_disconnected_handler(session_disconnected_msg_t *mp)
Definition: vpp_echo.c:592
void vl_client_disconnect_from_vlib(void)
static u32 svm_msg_q_size(svm_msg_q_t *mq)
Check length of message queue.
echo_proto_cb_vft_t * proto_cb_vft
#define vec_foreach(var, vec)
Vector iterator.
transport_endpoint_t lcl
int echo_send_rpc(echo_main_t *em, void *fp, void *arg, u32 opaque)
pthread_t * data_thread_handles
int(* process_opts_cb)(unformat_input_t *a)
static int send_data_chunk(echo_session_t *s, u8 *tx_buf, int offset, int len)
Definition: vpp_echo.c:302
void(* echo_rpc_t)(void *arg, u32 opaque)
void * clib_mem_init_thread_safe(void *memory, uword memory_size)
Definition: mem_dlmalloc.c:226
static int svm_msg_q_lock(svm_msg_q_t *mq)
Lock, or block trying, the message queue.
static void session_connected_handler(session_connected_msg_t *mp)
Definition: vpp_echo.c:536
api_main_t api_main
Definition: api_shared.c:35
u8 * format_transport_proto(u8 *s, va_list *args)
Definition: transport.c:46
u8 send_stream_disconnects
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
struct echo_main_t::@481 stats
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
uword echo_unformat_close(unformat_input_t *input, va_list *args)
void(* disconnected_cb)(session_disconnected_msg_t *mp, echo_session_t *s)
void svm_msg_q_sub_w_lock(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Consumer dequeue one message from queue with mutex held.
static void stop_signal(int signum)
Definition: vpp_echo.c:73