FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
echo_client.c
Go to the documentation of this file.
1 /*
2  * echo_client.c - vpp built-in echo client code
3  *
4  * Copyright (c) 2017 by Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vlibapi/api.h>
20 #include <vlibmemory/api.h>
22 
24 
25 #define ECHO_CLIENT_DBG (0)
26 
27 static void
29 {
31  ASSERT (vlib_get_thread_index () == 0);
32  vlib_process_signal_event (ecm->vlib_main, ecm->cli_node_index, *code, 0);
33 }
34 
35 static void
37 {
38  if (vlib_get_thread_index () != 0)
40  sizeof (code));
41  else
42  signal_evt_to_cli_i (&code);
43 }
44 
45 static void
47 {
48  u8 *test_data = ecm->connect_test_data;
49  int test_buf_offset;
50  u32 bytes_this_chunk;
51  session_fifo_event_t evt;
52  svm_fifo_t *txf;
53  int rv;
54 
55  ASSERT (vec_len (test_data) > 0);
56 
57  test_buf_offset = s->bytes_sent % vec_len (test_data);
58  bytes_this_chunk = vec_len (test_data) - test_buf_offset;
59 
60  bytes_this_chunk = bytes_this_chunk < s->bytes_to_send
61  ? bytes_this_chunk : s->bytes_to_send;
62 
63  txf = s->server_tx_fifo;
64  rv = svm_fifo_enqueue_nowait (txf, bytes_this_chunk,
65  test_data + test_buf_offset);
66 
67  /* If we managed to enqueue data... */
68  if (rv > 0)
69  {
70  /* Account for it... */
71  s->bytes_to_send -= rv;
72  s->bytes_sent += rv;
73 
74  if (ECHO_CLIENT_DBG)
75  {
76  /* *INDENT-OFF* */
77  ELOG_TYPE_DECLARE (e) =
78  {
79  .format = "tx-enq: xfer %d bytes, sent %u remain %u",
80  .format_args = "i4i4i4",
81  };
82  /* *INDENT-ON* */
83  struct
84  {
85  u32 data[3];
86  } *ed;
88  ed->data[0] = rv;
89  ed->data[1] = s->bytes_sent;
90  ed->data[2] = s->bytes_to_send;
91  }
92 
93  /* Poke the session layer */
94  if (svm_fifo_set_event (txf))
95  {
96  /* Fabricate TX event, send to vpp */
97  evt.fifo = txf;
98  evt.event_type = FIFO_EVENT_APP_TX;
99 
100  if (svm_queue_add
101  (ecm->vpp_event_queue[txf->master_thread_index], (u8 *) & evt,
102  0 /* do wait for mutex */ ))
103  clib_warning ("could not enqueue event");
104  }
105  }
106 }
107 
108 static void
110 {
111  svm_fifo_t *rx_fifo = s->server_rx_fifo;
112  u32 my_thread_index = vlib_get_thread_index ();
113  int n_read, i;
114 
115  if (ecm->test_bytes)
116  {
117  n_read = svm_fifo_dequeue_nowait (rx_fifo,
118  vec_len (ecm->rx_buf
119  [my_thread_index]),
120  ecm->rx_buf[my_thread_index]);
121  }
122  else
123  {
124  n_read = svm_fifo_max_dequeue (rx_fifo);
125  svm_fifo_dequeue_drop (rx_fifo, n_read);
126  }
127 
128  if (n_read > 0)
129  {
130  if (ECHO_CLIENT_DBG)
131  {
132  /* *INDENT-OFF* */
133  ELOG_TYPE_DECLARE (e) =
134  {
135  .format = "rx-deq: %d bytes",
136  .format_args = "i4",
137  };
138  /* *INDENT-ON* */
139  struct
140  {
141  u32 data[1];
142  } *ed;
144  ed->data[0] = n_read;
145  }
146 
147  if (ecm->test_bytes)
148  {
149  for (i = 0; i < n_read; i++)
150  {
151  if (ecm->rx_buf[my_thread_index][i]
152  != ((s->bytes_received + i) & 0xff))
153  {
154  clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
155  n_read, s->bytes_received + i,
156  ecm->rx_buf[my_thread_index][i],
157  ((s->bytes_received + i) & 0xff));
158  ecm->test_failed = 1;
159  }
160  }
161  }
162  s->bytes_to_receive -= n_read;
163  s->bytes_received += n_read;
164  }
165 }
166 
167 static uword
169  vlib_frame_t * frame)
170 {
172  int my_thread_index = vlib_get_thread_index ();
173  session_t *sp;
174  int i;
175  int delete_session;
176  u32 *connection_indices;
177  u32 *connections_this_batch;
178  u32 nconnections_this_batch;
179 
180  connection_indices = ecm->connection_index_by_thread[my_thread_index];
181  connections_this_batch =
182  ecm->connections_this_batch_by_thread[my_thread_index];
183 
184  if ((ecm->run_test == 0) ||
185  ((vec_len (connection_indices) == 0)
186  && vec_len (connections_this_batch) == 0))
187  return 0;
188 
189  /* Grab another pile of connections */
190  if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
191  {
192  nconnections_this_batch =
193  clib_min (ecm->connections_per_batch, vec_len (connection_indices));
194 
195  ASSERT (nconnections_this_batch > 0);
196  vec_validate (connections_this_batch, nconnections_this_batch - 1);
197  clib_memcpy (connections_this_batch,
198  connection_indices + vec_len (connection_indices)
199  - nconnections_this_batch,
200  nconnections_this_batch * sizeof (u32));
201  _vec_len (connection_indices) -= nconnections_this_batch;
202  }
203 
205  && ecm->prev_conns == vec_len (connections_this_batch)))
206  {
207  ecm->repeats++;
208  ecm->prev_conns = vec_len (connections_this_batch);
209  if (ecm->repeats == 500000)
210  {
211  clib_warning ("stuck clients");
212  }
213  }
214  else
215  {
216  ecm->prev_conns = vec_len (connections_this_batch);
217  ecm->repeats = 0;
218  }
219 
220  for (i = 0; i < vec_len (connections_this_batch); i++)
221  {
222  delete_session = 1;
223 
224  sp = pool_elt_at_index (ecm->sessions, connections_this_batch[i]);
225 
226  if (sp->bytes_to_send > 0)
227  {
228  send_data_chunk (ecm, sp);
229  delete_session = 0;
230  }
231  if (sp->bytes_to_receive > 0)
232  {
233  receive_data_chunk (ecm, sp);
234  delete_session = 0;
235  }
236  if (PREDICT_FALSE (delete_session == 1))
237  {
238  u32 index, thread_index;
239  stream_session_t *s;
240 
241  __sync_fetch_and_add (&ecm->tx_total, sp->bytes_sent);
242  __sync_fetch_and_add (&ecm->rx_total, sp->bytes_received);
243 
245  &index, &thread_index);
246  s = session_get_if_valid (index, thread_index);
247 
248  if (s)
249  {
250  vnet_disconnect_args_t _a, *a = &_a;
251  a->handle = session_handle (s);
252  a->app_index = ecm->app_index;
254 
255  vec_delete (connections_this_batch, 1, i);
256  i--;
257  __sync_fetch_and_add (&ecm->ready_connections, -1);
258  }
259  else
260  {
261  clib_warning ("session AWOL?");
262  vec_delete (connections_this_batch, 1, i);
263  }
264 
265  /* Kick the debug CLI process */
266  if (ecm->ready_connections == 0)
267  {
268  signal_evt_to_cli (2);
269  }
270  }
271  }
272 
273  ecm->connection_index_by_thread[my_thread_index] = connection_indices;
274  ecm->connections_this_batch_by_thread[my_thread_index] =
275  connections_this_batch;
276  return 0;
277 }
278 
279 /* *INDENT-OFF* */
281 {
282  .function = echo_client_node_fn,
283  .name = "echo-clients",
284  .type = VLIB_NODE_TYPE_INPUT,
285  .state = VLIB_NODE_STATE_DISABLED,
286 };
287 /* *INDENT-ON* */
288 
289 static int
291 {
292  api_main_t *am = &api_main;
294 
295  shmem_hdr = am->shmem_hdr;
296  ecm->vl_input_queue = shmem_hdr->vl_input_queue;
297  ecm->my_client_index = vl_api_memclnt_create_internal ("echo_client",
298  ecm->vl_input_queue);
299  return 0;
300 }
301 
302 static int
304 {
307  u32 num_threads;
308  int i;
309 
310  if (create_api_loopback (ecm))
311  return -1;
312 
313  num_threads = 1 /* main thread */ + vtm->n_threads;
314 
315  /* Init test data. Bigecmuffer */
316  vec_validate (ecm->connect_test_data, 1024 * 1024 - 1);
317  for (i = 0; i < vec_len (ecm->connect_test_data); i++)
318  ecm->connect_test_data[i] = i & 0xff;
319 
320  vec_validate (ecm->rx_buf, num_threads - 1);
321  for (i = 0; i < num_threads; i++)
322  vec_validate (ecm->rx_buf[i], vec_len (ecm->connect_test_data) - 1);
323 
324  ecm->is_init = 1;
325 
329 
330  return 0;
331 }
332 
333 static int
335  stream_session_t * s, u8 is_fail)
336 {
338  session_t *session;
339  u32 session_index;
340  u8 thread_index = vlib_get_thread_index ();
341 
342  if (is_fail)
343  {
344  clib_warning ("connection %d failed!", api_context);
345  signal_evt_to_cli (-1);
346  return 0;
347  }
348 
349  ASSERT (s->thread_index == thread_index);
350 
351  if (!ecm->vpp_event_queue[thread_index])
352  ecm->vpp_event_queue[thread_index] =
354 
355  /*
356  * Setup session
357  */
359  pool_get (ecm->sessions, session);
361 
362  memset (session, 0, sizeof (*session));
363  session_index = session - ecm->sessions;
364  session->bytes_to_send = ecm->bytes_to_send;
365  session->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
366  session->server_rx_fifo = s->server_rx_fifo;
367  session->server_rx_fifo->client_session_index = session_index;
368  session->server_tx_fifo = s->server_tx_fifo;
369  session->server_tx_fifo->client_session_index = session_index;
370  session->vpp_session_handle = session_handle (s);
371 
372  vec_add1 (ecm->connection_index_by_thread[thread_index], session_index);
373  __sync_fetch_and_add (&ecm->ready_connections, 1);
374  if (ecm->ready_connections == ecm->expected_connections)
375  {
376  ecm->run_test = 1;
377  /* Signal the CLI process that the action is starting... */
378  signal_evt_to_cli (1);
379  }
380 
381  return 0;
382 }
383 
384 static void
386 {
387  if (s->session_state == SESSION_STATE_READY)
388  clib_warning ("Reset active connection %U", format_stream_session, s, 2);
390  return;
391 }
392 
393 static int
395 {
396  return 0;
397 }
398 
399 static void
401 {
403  vnet_disconnect_args_t _a, *a = &_a;
404  a->handle = session_handle (s);
405  a->app_index = ecm->app_index;
407  return;
408 }
409 
410 static int
412 {
413  return 0;
414 }
415 
416 int
418 {
419  /* New heaps may be added */
420  return 0;
421 }
422 
423 /* *INDENT-OFF* */
425  .session_reset_callback = echo_clients_session_reset_callback,
426  .session_connected_callback = echo_clients_session_connected_callback,
427  .session_accept_callback = echo_clients_session_create_callback,
428  .session_disconnect_callback = echo_clients_session_disconnect_callback,
429  .builtin_app_rx_callback = echo_clients_rx_callback,
430  .add_segment_callback = echo_client_add_segment_callback
431 };
432 /* *INDENT-ON* */
433 
434 static clib_error_t *
435 echo_clients_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
436 {
437  u32 prealloc_fifos, segment_size = 256 << 20;
439  vnet_app_attach_args_t _a, *a = &_a;
440  u64 options[16];
441  clib_error_t *error = 0;
442 
443  memset (a, 0, sizeof (*a));
444  memset (options, 0, sizeof (options));
445 
446  a->api_client_index = ecm->my_client_index;
447  a->session_cb_vft = &echo_clients;
448 
449  prealloc_fifos = ecm->prealloc_fifos ? ecm->expected_connections : 1;
450 
451  if (ecm->private_segment_size)
452  segment_size = ecm->private_segment_size;
453 
454  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
455  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
456  options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
457  options[APP_OPTIONS_RX_FIFO_SIZE] = ecm->fifo_size;
458  options[APP_OPTIONS_TX_FIFO_SIZE] = ecm->fifo_size;
460  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
461  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
462  options[APP_OPTIONS_TLS_ENGINE] = ecm->tls_engine;
463  if (appns_id)
464  {
465  options[APP_OPTIONS_FLAGS] |= appns_flags;
466  options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
467  }
468  a->options = options;
469  a->namespace_id = appns_id;
470 
471  if ((error = vnet_application_attach (a)))
472  return error;
473 
474  ecm->app_index = a->app_index;
475  return 0;
476 }
477 
478 static int
480 {
482  vnet_app_detach_args_t _da, *da = &_da;
483  int rv;
484 
485  da->app_index = ecm->app_index;
486  rv = vnet_application_detach (da);
487  ecm->test_client_attached = 0;
488  ecm->app_index = ~0;
489  return rv;
490 }
491 
492 static void *
494 {
495  return 0;
496 }
497 
498 /** Start a transmit thread */
499 int
501 {
502  if (ecm->client_thread_handle == 0)
503  {
504  int rv = pthread_create (&ecm->client_thread_handle,
505  NULL /*attr */ ,
507  if (rv)
508  {
509  ecm->client_thread_handle = 0;
510  return -1;
511  }
512  }
513  return 0;
514 }
515 
516 clib_error_t *
518 {
520  vnet_connect_args_t _a, *a = &_a;
521  clib_error_t *error = 0;
522  int i;
523 
524  memset (a, 0, sizeof (*a));
525  for (i = 0; i < n_clients; i++)
526  {
527  a->uri = (char *) ecm->connect_uri;
528  a->api_context = i;
529  a->app_index = ecm->app_index;
530 
531  if ((error = vnet_connect_uri (a)))
532  return error;
533 
534  /* Crude pacing for call setups */
535  if ((i % 4) == 0)
536  vlib_process_suspend (vm, 10e-6);
537  ASSERT (i + 1 >= ecm->ready_connections);
538  while (i + 1 - ecm->ready_connections > 1000)
539  {
540  vlib_process_suspend (vm, 100e-6);
541  }
542  }
543  return 0;
544 }
545 
546 #define ec_cli_output(_fmt, _args...) \
547  if (!ecm->no_output) \
548  vlib_cli_output(vm, _fmt, ##_args)
549 
550 static clib_error_t *
552  unformat_input_t * input, vlib_cli_command_t * cmd)
553 {
555  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
556  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
557  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
558  char *default_uri = "tcp://6.0.1.1/1234";
559  uword *event_data = 0, event_type;
560  f64 time_before_connects;
561  u32 n_clients = 1;
562  int preallocate_sessions = 0;
563  char *transfer_type;
564  clib_error_t *error = 0;
565  u8 *appns_id = 0;
566  int i;
567 
568  ecm->bytes_to_send = 8192;
569  ecm->no_return = 0;
570  ecm->fifo_size = 64 << 10;
571  ecm->connections_per_batch = 1000;
572  ecm->private_segment_count = 0;
573  ecm->private_segment_size = 0;
574  ecm->no_output = 0;
575  ecm->test_bytes = 0;
576  ecm->test_failed = 0;
577  ecm->vlib_main = vm;
579 
580  if (thread_main->n_vlib_mains > 1)
582  vec_free (ecm->connect_uri);
583 
585  {
586  if (unformat (input, "uri %s", &ecm->connect_uri))
587  ;
588  else if (unformat (input, "nclients %d", &n_clients))
589  ;
590  else if (unformat (input, "mbytes %lld", &tmp))
591  ecm->bytes_to_send = tmp << 20;
592  else if (unformat (input, "gbytes %lld", &tmp))
593  ecm->bytes_to_send = tmp << 30;
594  else if (unformat (input, "bytes %lld", &ecm->bytes_to_send))
595  ;
596  else if (unformat (input, "test-timeout %f", &test_timeout))
597  ;
598  else if (unformat (input, "syn-timeout %f", &syn_timeout))
599  ;
600  else if (unformat (input, "no-return"))
601  ecm->no_return = 1;
602  else if (unformat (input, "fifo-size %d", &ecm->fifo_size))
603  ecm->fifo_size <<= 10;
604  else if (unformat (input, "private-segment-count %d",
605  &ecm->private_segment_count))
606  ;
607  else if (unformat (input, "private-segment-size %U",
608  unformat_memory_size, &tmp))
609  {
610  if (tmp >= 0x100000000ULL)
611  return clib_error_return
612  (0, "private segment size %lld (%llu) too large", tmp, tmp);
613  ecm->private_segment_size = tmp;
614  }
615  else if (unformat (input, "preallocate-fifos"))
616  ecm->prealloc_fifos = 1;
617  else if (unformat (input, "preallocate-sessions"))
618  preallocate_sessions = 1;
619  else
620  if (unformat (input, "client-batch %d", &ecm->connections_per_batch))
621  ;
622  else if (unformat (input, "appns %_%v%_", &appns_id))
623  ;
624  else if (unformat (input, "all-scope"))
625  appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
626  | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
627  else if (unformat (input, "local-scope"))
628  appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
629  else if (unformat (input, "global-scope"))
630  appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
631  else if (unformat (input, "secret %lu", &appns_secret))
632  ;
633  else if (unformat (input, "no-output"))
634  ecm->no_output = 1;
635  else if (unformat (input, "test-bytes"))
636  ecm->test_bytes = 1;
637  else if (unformat (input, "tls-engine %d", &ecm->tls_engine))
638  ;
639  else
640  return clib_error_return (0, "failed: unknown input `%U'",
641  format_unformat_error, input);
642  }
643 
644  /* Store cli process node index for signalling */
645  ecm->cli_node_index =
647 
648  if (ecm->is_init == 0)
649  {
650  if (echo_clients_init (vm))
651  return clib_error_return (0, "failed init");
652  }
653 
654 
655  ecm->ready_connections = 0;
656  ecm->expected_connections = n_clients;
657  ecm->rx_total = 0;
658  ecm->tx_total = 0;
659 
660  if (!ecm->connect_uri)
661  {
662  clib_warning ("No uri provided. Using default: %s", default_uri);
663  ecm->connect_uri = format (0, "%s%c", default_uri, 0);
664  }
665 
666 #if ECHO_CLIENT_PTHREAD
668 #endif
669 
671  vnet_session_enable_disable (vm, 1 /* turn on session and transports */ );
673 
674  if (ecm->test_client_attached == 0)
675  {
676  if ((error = echo_clients_attach (appns_id, appns_flags, appns_secret)))
677  {
678  vec_free (appns_id);
679  clib_error_report (error);
680  return error;
681  }
682  vec_free (appns_id);
683  }
684  ecm->test_client_attached = 1;
685 
686  /* Turn on the builtin client input nodes */
687  for (i = 0; i < thread_main->n_vlib_mains; i++)
689  VLIB_NODE_STATE_POLLING);
690 
691  if (preallocate_sessions)
692  {
693  session_t *sp __attribute__ ((unused));
694  for (i = 0; i < n_clients; i++)
695  pool_get (ecm->sessions, sp);
696  for (i = 0; i < n_clients; i++)
697  pool_put_index (ecm->sessions, i);
698  }
699 
700  /* Fire off connect requests */
701  time_before_connects = vlib_time_now (vm);
702  if ((error = echo_clients_connect (vm, n_clients)))
703  return error;
704 
705  /* Park until the sessions come up, or ten seconds elapse... */
706  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
707  event_type = vlib_process_get_events (vm, &event_data);
708  switch (event_type)
709  {
710  case ~0:
711  ec_cli_output ("Timeout with only %d sessions active...",
712  ecm->ready_connections);
713  error = clib_error_return (0, "failed: syn timeout with %d sessions",
714  ecm->ready_connections);
715  goto cleanup;
716 
717  case 1:
718  delta = vlib_time_now (vm) - time_before_connects;
719  if (delta != 0.0)
720  ec_cli_output ("%d three-way handshakes in %.2f seconds %.2f/s",
721  n_clients, delta, ((f64) n_clients) / delta);
722 
724  ec_cli_output ("Test started at %.6f", ecm->test_start_time);
725  break;
726 
727  default:
728  ec_cli_output ("unexpected event(1): %d", event_type);
729  error = clib_error_return (0, "failed: unexpected event(1): %d",
730  event_type);
731  goto cleanup;
732  }
733 
734  /* Now wait for the sessions to finish... */
735  vlib_process_wait_for_event_or_clock (vm, test_timeout);
736  event_type = vlib_process_get_events (vm, &event_data);
737  switch (event_type)
738  {
739  case ~0:
740  ec_cli_output ("Timeout with %d sessions still active...",
741  ecm->ready_connections);
742  error = clib_error_return (0, "failed: timeout with %d sessions",
743  ecm->ready_connections);
744  goto cleanup;
745 
746  case 2:
747  ecm->test_end_time = vlib_time_now (vm);
748  ec_cli_output ("Test finished at %.6f", ecm->test_end_time);
749  break;
750 
751  default:
752  ec_cli_output ("unexpected event(2): %d", event_type);
753  error = clib_error_return (0, "failed: unexpected event(2): %d",
754  event_type);
755  goto cleanup;
756  }
757 
758  delta = ecm->test_end_time - ecm->test_start_time;
759  if (delta != 0.0)
760  {
761  total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
762  transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
763  ec_cli_output ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
764  total_bytes, total_bytes / (1ULL << 20),
765  total_bytes / (1ULL << 30), delta);
766  ec_cli_output ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
767  transfer_type);
768  ec_cli_output ("%.4f gbit/second %s",
769  (((f64) total_bytes * 8.0) / delta / 1e9),
770  transfer_type);
771  }
772  else
773  {
774  ec_cli_output ("zero delta-t?");
775  error = clib_error_return (0, "failed: zero delta-t");
776  goto cleanup;
777  }
778 
779  if (ecm->test_bytes && ecm->test_failed)
780  error = clib_error_return (0, "failed: test bytes");
781 
782 cleanup:
783  ecm->run_test = 0;
784  for (i = 0; i < vec_len (ecm->connection_index_by_thread); i++)
785  {
788  }
789 
790  pool_free (ecm->sessions);
791 
792  /* Detach the application, so we can use different fifo sizes next time */
793  if (ecm->test_client_attached)
794  {
795  if (echo_clients_detach ())
796  {
797  error = clib_error_return (0, "failed: app detach");
798  ec_cli_output ("WARNING: app detach failed...");
799  }
800  }
801  if (error)
802  ec_cli_output ("test failed");
803  vec_free (ecm->connect_uri);
804  return error;
805 }
806 
807 /* *INDENT-OFF* */
808 VLIB_CLI_COMMAND (echo_clients_command, static) =
809 {
810  .path = "test echo clients",
811  .short_help = "test echo clients [nclients %d][[m|g]bytes <bytes>]"
812  "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
813  "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
814  "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
815  "[uri <tcp://ip/port>][test-bytes][no-output]",
816  .function = echo_clients_command_fn,
817  .is_mp_safe = 1,
818 };
819 /* *INDENT-ON* */
820 
821 clib_error_t *
823 {
825  ecm->is_init = 0;
826  return 0;
827 }
828 
830 
831 /*
832  * fd.io coding-style-patch-verification: ON
833  *
834  * Local Variables:
835  * eval: (c-set-style "gnu")
836  * End:
837  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:434
static svm_queue_t * session_manager_get_vpp_event_queue(u32 thread_index)
Definition: session.h:505
vlib_main_t vlib_global_main
Definition: main.c:1642
vlib_main_t * vlib_main
Definition: echo_client.h:103
clib_error_t * echo_clients_connect(vlib_main_t *vm, u32 n_clients)
Definition: echo_client.c:517
svm_queue_t ** vpp_event_queue
Definition: echo_client.h:50
#define clib_min(x, y)
Definition: clib.h:340
int svm_queue_add(svm_queue_t *q, u8 *elem, int nowait)
Definition: queue.c:184
u32 vl_api_memclnt_create_internal(char *name, svm_queue_t *q)
Definition: memory_api.c:112
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:699
vlib_node_runtime_t node_runtime
Definition: node.h:495
a
Definition: bitmap.h:516
u64 bytes_received
Definition: echo_client.h:36
struct _vnet_connect_args vnet_connect_args_t
static session_cb_vft_t echo_clients
Definition: echo_client.c:424
u32 tls_engine
TLS engine mbedtls/openssl.
Definition: echo_client.h:67
static int echo_clients_detach()
Definition: echo_client.c:479
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
static uword echo_client_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: echo_client.c:168
u32 expected_connections
Number of clients/connections.
Definition: echo_client.h:63
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
Definition: lock.h:98
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:520
u64 bytes_to_send
Bytes to send.
Definition: echo_client.h:60
int i
u64 bytes_to_receive
Definition: echo_client.h:35
volatile int run_test
Signal start of test.
Definition: echo_client.h:83
static void session_parse_handle(session_handle_t handle, u32 *index, u32 *thread_index)
Definition: session.h:279
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
vlib_main_t ** vlib_mains
Definition: buffer.c:303
static void echo_clients_session_disconnect_callback(stream_session_t *s)
Definition: echo_client.c:400
u8 * connect_test_data
Pre-computed test data.
Definition: echo_client.h:74
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:212
struct _svm_fifo svm_fifo_t
u64 bytes_to_send
Definition: echo_client.h:33
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:448
clib_error_t * echo_clients_main_init(vlib_main_t *vm)
Definition: echo_client.c:822
static void receive_data_chunk(echo_client_main_t *ecm, session_t *s)
Definition: echo_client.c:109
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:542
struct _vnet_disconnect_args_t vnet_disconnect_args_t
int echo_clients_start_tx_pthread(echo_client_main_t *ecm)
Start a transmit thread.
Definition: echo_client.c:500
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Definition: svm_fifo.h:100
struct _stream_session_cb_vft session_cb_vft_t
svm_fifo_t * server_tx_fifo
Definition: echo_client.h:39
#define clib_error_return(e, args...)
Definition: error.h:99
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:644
u32 app_index
app index after attach
Definition: echo_client.h:54
int svm_fifo_enqueue_nowait(svm_fifo_t *f, u32 max_bytes, const u8 *copy_from_here)
Definition: svm_fifo.c:534
svm_queue_t * vl_input_queue
vpe input queue
Definition: echo_client.h:49
unsigned long u64
Definition: types.h:89
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:262
void stream_session_cleanup(stream_session_t *s)
Cleanup transport and session state.
Definition: session.c:1049
struct _stream_session_t stream_session_t
struct _vnet_app_attach_args_t vnet_app_attach_args_t
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:57
vl_shmem_hdr_t * shmem_hdr
static int create_api_loopback(echo_client_main_t *ecm)
Definition: echo_client.c:290
static void signal_evt_to_cli(int code)
Definition: echo_client.c:36
static clib_error_t * echo_clients_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: echo_client.c:551
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
volatile u32 ready_connections
Definition: echo_client.h:79
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:952
struct _unformat_input_t unformat_input_t
static session_handle_t session_handle(stream_session_t *s)
Definition: session.h:261
static void cleanup(void)
Definition: client.c:90
#define ELOG_DATA(em, f)
Definition: elog.h:481
#define PREDICT_FALSE(x)
Definition: clib.h:105
u32 ** connection_index_by_thread
Definition: echo_client.h:75
u64 bytes_sent
Definition: echo_client.h:34
u32 private_segment_count
Number of private fifo segs.
Definition: echo_client.h:65
u32 ** connections_this_batch_by_thread
active connection batch
Definition: echo_client.h:76
static stream_session_t * session_get_if_valid(u64 si, u32 thread_index)
Definition: session.h:248
u32 node_index
Node index.
Definition: node.h:437
static int echo_clients_rx_callback(stream_session_t *s)
Definition: echo_client.c:411
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: session.c:1312
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:199
#define pool_free(p)
Free a pool.
Definition: pool.h:354
static int echo_clients_session_create_callback(stream_session_t *s)
Definition: echo_client.c:394
static u8 svm_fifo_set_event(svm_fifo_t *f)
Sets fifo event flag.
Definition: svm_fifo.h:123
u32 connections_per_batch
Connections to rx/tx at once.
Definition: echo_client.h:64
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
static clib_error_t * echo_clients_attach(u8 *appns_id, u64 appns_flags, u64 appns_secret)
Definition: echo_client.c:435
static vlib_process_t * vlib_get_current_process(vlib_main_t *vm)
Definition: node_funcs.h:417
vlib_main_t * vm
Definition: buffer.c:294
static void send_data_chunk(echo_client_main_t *ecm, session_t *s)
Definition: echo_client.c:46
vlib_node_registration_t echo_clients_node
(constructor) VLIB_REGISTER_NODE (echo_clients_node)
Definition: echo_client.c:280
u8 * format_stream_session(u8 *s, va_list *args)
Format stream session as per the following format.
Definition: session_cli.c:52
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#define clib_warning(format, args...)
Definition: error.h:59
echo_client_main_t echo_client_main
Definition: echo_client.c:23
#define clib_memcpy(a, b, c)
Definition: string.h:75
elog_main_t elog_main
Definition: main.h:158
int vnet_disconnect_session(vnet_disconnect_args_t *a)
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:439
u32 private_segment_size
size of private fifo segs
Definition: echo_client.h:66
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:296
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 cli_node_index
cli process node index
Definition: echo_client.h:52
static int echo_clients_session_connected_callback(u32 app_index, u32 api_context, stream_session_t *s, u8 is_fail)
Definition: echo_client.c:334
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:783
u32 my_client_index
loopback API client handle
Definition: echo_client.h:53
#define clib_error_report(e)
Definition: error.h:113
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:147
int echo_client_add_segment_callback(u32 client_index, const ssvm_private_t *sp)
Definition: echo_client.c:417
#define ECHO_CLIENT_DBG
Definition: echo_client.c:25
struct _vnet_app_detach_args_t vnet_app_detach_args_t
u8 ** rx_buf
intermediate rx buffers
Definition: echo_client.h:73
u64 uword
Definition: types.h:112
u8 prealloc_fifos
Request fifo preallocation.
Definition: echo_client.h:98
volatile u64 tx_total
Definition: echo_client.h:82
int svm_fifo_dequeue_drop(svm_fifo_t *f, u32 max_bytes)
Definition: svm_fifo.c:774
volatile u64 rx_total
Definition: echo_client.h:81
clib_error_t * vnet_connect_uri(vnet_connect_args_t *a)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
clib_error_t * vnet_application_attach(vnet_app_attach_args_t *a)
Attach application to vpp.
u8 * connect_uri
URI for slave&#39;s connect.
Definition: echo_client.h:59
#define ec_cli_output(_fmt, _args...)
Definition: echo_client.c:546
clib_spinlock_t sessions_lock
Definition: echo_client.h:72
static void * echo_client_thread_fn(void *arg)
Definition: echo_client.c:493
u64 vpp_session_handle
Definition: echo_client.h:41
static void echo_clients_session_reset_callback(stream_session_t *s)
Definition: echo_client.c:385
unformat_function_t unformat_memory_size
Definition: format.h:294
static void signal_evt_to_cli_i(int *code)
Definition: echo_client.c:28
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1497
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
pthread_t client_thread_handle
Definition: echo_client.h:77
api_main_t api_main
Definition: api_shared.c:35
int vnet_application_detach(vnet_app_detach_args_t *a)
Detach application from vpp.
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
Definition: lock.h:82
int svm_fifo_dequeue_nowait(svm_fifo_t *f, u32 max_bytes, u8 *copy_here)
Definition: svm_fifo.c:692
session_t * sessions
Session pool, shared.
Definition: echo_client.h:71
svm_fifo_t * server_rx_fifo
Definition: echo_client.h:38
static int echo_clients_init(vlib_main_t *vm)
Definition: echo_client.c:303
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169