FD.io VPP  v18.10-34-gcce845e
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_len, test_buf_offset, rv;
50  u32 bytes_this_chunk;
51 
52  test_buf_len = vec_len (test_data);
53  ASSERT (test_buf_len > 0);
54  test_buf_offset = s->bytes_sent % test_buf_len;
55  bytes_this_chunk = clib_min (test_buf_len - test_buf_offset,
56  s->bytes_to_send);
57 
58  if (!ecm->is_dgram)
59  {
60  if (ecm->no_copy)
61  {
62  svm_fifo_t *f = s->data.tx_fifo;
63  rv = clib_min (svm_fifo_max_enqueue (f), bytes_this_chunk);
67  }
68  else
69  rv = app_send_stream (&s->data, test_data + test_buf_offset,
70  bytes_this_chunk, 0);
71  }
72  else
73  {
74  if (ecm->no_copy)
75  {
76  session_dgram_hdr_t hdr;
77  svm_fifo_t *f = s->data.tx_fifo;
78  app_session_transport_t *at = &s->data.transport;
79  u32 max_enqueue = svm_fifo_max_enqueue (f);
80 
81  if (max_enqueue <= sizeof (session_dgram_hdr_t))
82  return;
83 
84  max_enqueue -= sizeof (session_dgram_hdr_t);
85  rv = clib_min (max_enqueue, bytes_this_chunk);
86 
87  hdr.data_length = rv;
88  hdr.data_offset = 0;
89  clib_memcpy (&hdr.rmt_ip, &at->rmt_ip, sizeof (ip46_address_t));
90  hdr.is_ip4 = at->is_ip4;
91  hdr.rmt_port = at->rmt_port;
92  clib_memcpy (&hdr.lcl_ip, &at->lcl_ip, sizeof (ip46_address_t));
93  hdr.lcl_port = at->lcl_port;
94  svm_fifo_enqueue_nowait (f, sizeof (hdr), (u8 *) & hdr);
98  }
99  else
100  rv = app_send_dgram (&s->data, test_data + test_buf_offset,
101  bytes_this_chunk, 0);
102  }
103 
104  /* If we managed to enqueue data... */
105  if (rv > 0)
106  {
107  /* Account for it... */
108  s->bytes_to_send -= rv;
109  s->bytes_sent += rv;
110 
111  if (ECHO_CLIENT_DBG)
112  {
113  /* *INDENT-OFF* */
114  ELOG_TYPE_DECLARE (e) =
115  {
116  .format = "tx-enq: xfer %d bytes, sent %u remain %u",
117  .format_args = "i4i4i4",
118  };
119  /* *INDENT-ON* */
120  struct
121  {
122  u32 data[3];
123  } *ed;
125  ed->data[0] = rv;
126  ed->data[1] = s->bytes_sent;
127  ed->data[2] = s->bytes_to_send;
128  }
129  }
130 }
131 
132 static void
134 {
135  svm_fifo_t *rx_fifo = s->data.rx_fifo;
136  u32 thread_index = vlib_get_thread_index ();
137  int n_read, i;
138 
139  if (ecm->test_bytes)
140  {
141  if (!ecm->is_dgram)
142  n_read = app_recv_stream (&s->data, ecm->rx_buf[thread_index],
143  vec_len (ecm->rx_buf[thread_index]));
144  else
145  n_read = app_recv_dgram (&s->data, ecm->rx_buf[thread_index],
146  vec_len (ecm->rx_buf[thread_index]));
147  }
148  else
149  {
150  n_read = svm_fifo_max_dequeue (rx_fifo);
151  svm_fifo_dequeue_drop (rx_fifo, n_read);
152  }
153 
154  if (n_read > 0)
155  {
156  if (ECHO_CLIENT_DBG)
157  {
158  /* *INDENT-OFF* */
159  ELOG_TYPE_DECLARE (e) =
160  {
161  .format = "rx-deq: %d bytes",
162  .format_args = "i4",
163  };
164  /* *INDENT-ON* */
165  struct
166  {
167  u32 data[1];
168  } *ed;
170  ed->data[0] = n_read;
171  }
172 
173  if (ecm->test_bytes)
174  {
175  for (i = 0; i < n_read; i++)
176  {
177  if (ecm->rx_buf[thread_index][i]
178  != ((s->bytes_received + i) & 0xff))
179  {
180  clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
181  n_read, s->bytes_received + i,
182  ecm->rx_buf[thread_index][i],
183  ((s->bytes_received + i) & 0xff));
184  ecm->test_failed = 1;
185  }
186  }
187  }
188  ASSERT (n_read <= s->bytes_to_receive);
189  s->bytes_to_receive -= n_read;
190  s->bytes_received += n_read;
191  }
192 }
193 
194 static uword
196  vlib_frame_t * frame)
197 {
199  int my_thread_index = vlib_get_thread_index ();
200  eclient_session_t *sp;
201  int i;
202  int delete_session;
203  u32 *connection_indices;
204  u32 *connections_this_batch;
205  u32 nconnections_this_batch;
206 
207  connection_indices = ecm->connection_index_by_thread[my_thread_index];
208  connections_this_batch =
209  ecm->connections_this_batch_by_thread[my_thread_index];
210 
211  if ((ecm->run_test != ECHO_CLIENTS_RUNNING) ||
212  ((vec_len (connection_indices) == 0)
213  && vec_len (connections_this_batch) == 0))
214  return 0;
215 
216  /* Grab another pile of connections */
217  if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
218  {
219  nconnections_this_batch =
220  clib_min (ecm->connections_per_batch, vec_len (connection_indices));
221 
222  ASSERT (nconnections_this_batch > 0);
223  vec_validate (connections_this_batch, nconnections_this_batch - 1);
224  clib_memcpy (connections_this_batch,
225  connection_indices + vec_len (connection_indices)
226  - nconnections_this_batch,
227  nconnections_this_batch * sizeof (u32));
228  _vec_len (connection_indices) -= nconnections_this_batch;
229  }
230 
232  && ecm->prev_conns == vec_len (connections_this_batch)))
233  {
234  ecm->repeats++;
235  ecm->prev_conns = vec_len (connections_this_batch);
236  if (ecm->repeats == 500000)
237  {
238  clib_warning ("stuck clients");
239  }
240  }
241  else
242  {
243  ecm->prev_conns = vec_len (connections_this_batch);
244  ecm->repeats = 0;
245  }
246 
247  for (i = 0; i < vec_len (connections_this_batch); i++)
248  {
249  delete_session = 1;
250 
251  sp = pool_elt_at_index (ecm->sessions, connections_this_batch[i]);
252 
253  if (sp->bytes_to_send > 0)
254  {
255  send_data_chunk (ecm, sp);
256  delete_session = 0;
257  }
258  if (sp->bytes_to_receive > 0)
259  {
260  delete_session = 0;
261  }
262  if (PREDICT_FALSE (delete_session == 1))
263  {
264  stream_session_t *s;
265 
266  __sync_fetch_and_add (&ecm->tx_total, sp->bytes_sent);
267  __sync_fetch_and_add (&ecm->rx_total, sp->bytes_received);
269 
270  if (s)
271  {
272  vnet_disconnect_args_t _a, *a = &_a;
273  a->handle = session_handle (s);
274  a->app_index = ecm->app_index;
276 
277  vec_delete (connections_this_batch, 1, i);
278  i--;
279  __sync_fetch_and_add (&ecm->ready_connections, -1);
280  }
281  else
282  {
283  clib_warning ("session AWOL?");
284  vec_delete (connections_this_batch, 1, i);
285  }
286 
287  /* Kick the debug CLI process */
288  if (ecm->ready_connections == 0)
289  {
290  signal_evt_to_cli (2);
291  }
292  }
293  }
294 
295  ecm->connection_index_by_thread[my_thread_index] = connection_indices;
296  ecm->connections_this_batch_by_thread[my_thread_index] =
297  connections_this_batch;
298  return 0;
299 }
300 
301 /* *INDENT-OFF* */
303 {
304  .function = echo_client_node_fn,
305  .name = "echo-clients",
306  .type = VLIB_NODE_TYPE_INPUT,
307  .state = VLIB_NODE_STATE_DISABLED,
308 };
309 /* *INDENT-ON* */
310 
311 static int
313 {
314  api_main_t *am = &api_main;
316 
317  shmem_hdr = am->shmem_hdr;
318  ecm->vl_input_queue = shmem_hdr->vl_input_queue;
319  ecm->my_client_index = vl_api_memclnt_create_internal ("echo_client",
320  ecm->vl_input_queue);
321  return 0;
322 }
323 
324 static int
326 {
329  u32 num_threads;
330  int i;
331 
332  if (create_api_loopback (ecm))
333  return -1;
334 
335  num_threads = 1 /* main thread */ + vtm->n_threads;
336 
337  /* Init test data. Big buffer */
338  vec_validate (ecm->connect_test_data, 4 * 1024 * 1024 - 1);
339  for (i = 0; i < vec_len (ecm->connect_test_data); i++)
340  ecm->connect_test_data[i] = i & 0xff;
341 
342  vec_validate (ecm->rx_buf, num_threads - 1);
343  for (i = 0; i < num_threads; i++)
344  vec_validate (ecm->rx_buf[i], vec_len (ecm->connect_test_data) - 1);
345 
346  ecm->is_init = 1;
347 
351 
352  return 0;
353 }
354 
355 static int
357  stream_session_t * s, u8 is_fail)
358 {
360  eclient_session_t *session;
361  u32 session_index;
362  u8 thread_index;
363 
365  return -1;
366 
367  if (is_fail)
368  {
369  clib_warning ("connection %d failed!", api_context);
371  signal_evt_to_cli (-1);
372  return 0;
373  }
374 
375  thread_index = s->thread_index;
376  ASSERT (thread_index == vlib_get_thread_index ()
378 
379  if (!ecm->vpp_event_queue[thread_index])
380  ecm->vpp_event_queue[thread_index] =
382 
383  /*
384  * Setup session
385  */
387  pool_get (ecm->sessions, session);
389 
390  memset (session, 0, sizeof (*session));
391  session_index = session - ecm->sessions;
392  session->bytes_to_send = ecm->bytes_to_send;
393  session->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
394  session->data.rx_fifo = s->server_rx_fifo;
395  session->data.rx_fifo->client_session_index = session_index;
396  session->data.tx_fifo = s->server_tx_fifo;
397  session->data.tx_fifo->client_session_index = session_index;
398  session->data.vpp_evt_q = ecm->vpp_event_queue[thread_index];
399  session->vpp_session_handle = session_handle (s);
400 
401  if (ecm->is_dgram)
402  {
404  tc = session_get_transport (s);
405  clib_memcpy (&session->data.transport, tc,
406  sizeof (session->data.transport));
407  session->data.is_dgram = 1;
408  }
409 
410  vec_add1 (ecm->connection_index_by_thread[thread_index], session_index);
411  __sync_fetch_and_add (&ecm->ready_connections, 1);
412  if (ecm->ready_connections == ecm->expected_connections)
413  {
415  /* Signal the CLI process that the action is starting... */
416  signal_evt_to_cli (1);
417  }
418 
419  return 0;
420 }
421 
422 static void
424 {
425  if (s->session_state == SESSION_STATE_READY)
426  clib_warning ("Reset active connection %U", format_stream_session, s, 2);
428  return;
429 }
430 
431 static int
433 {
434  return 0;
435 }
436 
437 static void
439 {
441  vnet_disconnect_args_t _a, *a = &_a;
442  a->handle = session_handle (s);
443  a->app_index = ecm->app_index;
445  return;
446 }
447 
448 void
450 {
452  vnet_disconnect_args_t _a, *a = &_a;
453  a->handle = session_handle (s);
454  a->app_index = ecm->app_index;
456 }
457 
458 static int
460 {
462  eclient_session_t *sp;
463 
465  {
467  return -1;
468  }
469 
470  sp = pool_elt_at_index (ecm->sessions,
471  s->server_rx_fifo->client_session_index);
472  receive_data_chunk (ecm, sp);
473 
474  if (svm_fifo_max_dequeue (s->server_rx_fifo))
475  {
476  if (svm_fifo_set_event (s->server_rx_fifo))
477  session_send_io_evt_to_thread (s->server_rx_fifo,
479  }
480  return 0;
481 }
482 
483 int
485 {
486  /* New heaps may be added */
487  return 0;
488 }
489 
490 /* *INDENT-OFF* */
492  .session_reset_callback = echo_clients_session_reset_callback,
493  .session_connected_callback = echo_clients_session_connected_callback,
494  .session_accept_callback = echo_clients_session_create_callback,
495  .session_disconnect_callback = echo_clients_session_disconnect_callback,
496  .builtin_app_rx_callback = echo_clients_rx_callback,
497  .add_segment_callback = echo_client_add_segment_callback
498 };
499 /* *INDENT-ON* */
500 
501 static clib_error_t *
502 echo_clients_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
503 {
504  u32 prealloc_fifos, segment_size = 256 << 20;
506  vnet_app_attach_args_t _a, *a = &_a;
507  u64 options[16];
508  clib_error_t *error = 0;
509 
510  memset (a, 0, sizeof (*a));
511  memset (options, 0, sizeof (options));
512 
513  a->api_client_index = ecm->my_client_index;
514  a->session_cb_vft = &echo_clients;
515 
516  prealloc_fifos = ecm->prealloc_fifos ? ecm->expected_connections : 1;
517 
518  if (ecm->private_segment_size)
519  segment_size = ecm->private_segment_size;
520 
521  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
522  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
523  options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
524  options[APP_OPTIONS_RX_FIFO_SIZE] = ecm->fifo_size;
525  options[APP_OPTIONS_TX_FIFO_SIZE] = ecm->fifo_size;
527  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
528  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
529  options[APP_OPTIONS_TLS_ENGINE] = ecm->tls_engine;
530  if (appns_id)
531  {
532  options[APP_OPTIONS_FLAGS] |= appns_flags;
533  options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
534  }
535  a->options = options;
536  a->namespace_id = appns_id;
537 
538  if ((error = vnet_application_attach (a)))
539  return error;
540 
541  ecm->app_index = a->app_index;
542  return 0;
543 }
544 
545 static int
547 {
549  vnet_app_detach_args_t _da, *da = &_da;
550  int rv;
551 
552  da->app_index = ecm->app_index;
553  rv = vnet_application_detach (da);
554  ecm->test_client_attached = 0;
555  ecm->app_index = ~0;
556  return rv;
557 }
558 
559 static void *
561 {
562  return 0;
563 }
564 
565 /** Start a transmit thread */
566 int
568 {
569  if (ecm->client_thread_handle == 0)
570  {
571  int rv = pthread_create (&ecm->client_thread_handle,
572  NULL /*attr */ ,
574  if (rv)
575  {
576  ecm->client_thread_handle = 0;
577  return -1;
578  }
579  }
580  return 0;
581 }
582 
583 clib_error_t *
585 {
587  vnet_connect_args_t _a, *a = &_a;
588  clib_error_t *error = 0;
589  int i;
590 
591  memset (a, 0, sizeof (*a));
592  for (i = 0; i < n_clients; i++)
593  {
594  a->uri = (char *) ecm->connect_uri;
595  a->api_context = i;
596  a->app_index = ecm->app_index;
597 
598  if ((error = vnet_connect_uri (a)))
599  return error;
600 
601  /* Crude pacing for call setups */
602  if ((i % 4) == 0)
603  vlib_process_suspend (vm, 10e-6);
604  ASSERT (i + 1 >= ecm->ready_connections);
605  while (i + 1 - ecm->ready_connections > 1000)
606  {
607  vlib_process_suspend (vm, 100e-6);
608  }
609  }
610  return 0;
611 }
612 
613 #define ec_cli_output(_fmt, _args...) \
614  if (!ecm->no_output) \
615  vlib_cli_output(vm, _fmt, ##_args)
616 
617 static clib_error_t *
619  unformat_input_t * input, vlib_cli_command_t * cmd)
620 {
622  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
623  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
624  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
625  char *default_uri = "tcp://6.0.1.1/1234";
626  uword *event_data = 0, event_type;
627  f64 time_before_connects;
628  u32 n_clients = 1;
629  int preallocate_sessions = 0;
630  char *transfer_type;
631  clib_error_t *error = 0;
632  u8 *appns_id = 0;
633  int i;
634 
635  ecm->bytes_to_send = 8192;
636  ecm->no_return = 0;
637  ecm->fifo_size = 64 << 10;
638  ecm->connections_per_batch = 1000;
639  ecm->private_segment_count = 0;
640  ecm->private_segment_size = 0;
641  ecm->no_output = 0;
642  ecm->test_bytes = 0;
643  ecm->test_failed = 0;
644  ecm->vlib_main = vm;
646  ecm->no_copy = 0;
648 
649  if (thread_main->n_vlib_mains > 1)
651  vec_free (ecm->connect_uri);
652 
654  {
655  if (unformat (input, "uri %s", &ecm->connect_uri))
656  ;
657  else if (unformat (input, "nclients %d", &n_clients))
658  ;
659  else if (unformat (input, "mbytes %lld", &tmp))
660  ecm->bytes_to_send = tmp << 20;
661  else if (unformat (input, "gbytes %lld", &tmp))
662  ecm->bytes_to_send = tmp << 30;
663  else if (unformat (input, "bytes %lld", &ecm->bytes_to_send))
664  ;
665  else if (unformat (input, "test-timeout %f", &test_timeout))
666  ;
667  else if (unformat (input, "syn-timeout %f", &syn_timeout))
668  ;
669  else if (unformat (input, "no-return"))
670  ecm->no_return = 1;
671  else if (unformat (input, "fifo-size %d", &ecm->fifo_size))
672  ecm->fifo_size <<= 10;
673  else if (unformat (input, "private-segment-count %d",
674  &ecm->private_segment_count))
675  ;
676  else if (unformat (input, "private-segment-size %U",
677  unformat_memory_size, &tmp))
678  {
679  if (tmp >= 0x100000000ULL)
680  return clib_error_return
681  (0, "private segment size %lld (%llu) too large", tmp, tmp);
682  ecm->private_segment_size = tmp;
683  }
684  else if (unformat (input, "preallocate-fifos"))
685  ecm->prealloc_fifos = 1;
686  else if (unformat (input, "preallocate-sessions"))
687  preallocate_sessions = 1;
688  else
689  if (unformat (input, "client-batch %d", &ecm->connections_per_batch))
690  ;
691  else if (unformat (input, "appns %_%v%_", &appns_id))
692  ;
693  else if (unformat (input, "all-scope"))
694  appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
695  | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
696  else if (unformat (input, "local-scope"))
697  appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
698  else if (unformat (input, "global-scope"))
699  appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
700  else if (unformat (input, "secret %lu", &appns_secret))
701  ;
702  else if (unformat (input, "no-output"))
703  ecm->no_output = 1;
704  else if (unformat (input, "test-bytes"))
705  ecm->test_bytes = 1;
706  else if (unformat (input, "tls-engine %d", &ecm->tls_engine))
707  ;
708  else
709  return clib_error_return (0, "failed: unknown input `%U'",
710  format_unformat_error, input);
711  }
712 
713  /* Store cli process node index for signalling */
714  ecm->cli_node_index =
716 
717  if (ecm->is_init == 0)
718  {
719  if (echo_clients_init (vm))
720  return clib_error_return (0, "failed init");
721  }
722 
723 
724  ecm->ready_connections = 0;
725  ecm->expected_connections = n_clients;
726  ecm->rx_total = 0;
727  ecm->tx_total = 0;
728 
729  if (!ecm->connect_uri)
730  {
731  clib_warning ("No uri provided. Using default: %s", default_uri);
732  ecm->connect_uri = format (0, "%s%c", default_uri, 0);
733  }
734 
735  if (ecm->connect_uri[0] == 'u' && ecm->connect_uri[3] != 'c')
736  ecm->is_dgram = 1;
737 
738 #if ECHO_CLIENT_PTHREAD
740 #endif
741 
743  vnet_session_enable_disable (vm, 1 /* turn on session and transports */ );
745 
746  if (ecm->test_client_attached == 0)
747  {
748  if ((error = echo_clients_attach (appns_id, appns_flags, appns_secret)))
749  {
750  vec_free (appns_id);
751  clib_error_report (error);
752  return error;
753  }
754  vec_free (appns_id);
755  }
756  ecm->test_client_attached = 1;
757 
758  /* Turn on the builtin client input nodes */
759  for (i = 0; i < thread_main->n_vlib_mains; i++)
761  VLIB_NODE_STATE_POLLING);
762 
763  if (preallocate_sessions)
764  pool_init_fixed (ecm->sessions, 1.1 * n_clients);
765 
766  /* Fire off connect requests */
767  time_before_connects = vlib_time_now (vm);
768  if ((error = echo_clients_connect (vm, n_clients)))
769  goto cleanup;
770 
771  /* Park until the sessions come up, or ten seconds elapse... */
772  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
773  event_type = vlib_process_get_events (vm, &event_data);
774  switch (event_type)
775  {
776  case ~0:
777  ec_cli_output ("Timeout with only %d sessions active...",
778  ecm->ready_connections);
779  error = clib_error_return (0, "failed: syn timeout with %d sessions",
780  ecm->ready_connections);
781  goto cleanup;
782 
783  case 1:
784  delta = vlib_time_now (vm) - time_before_connects;
785  if (delta != 0.0)
786  ec_cli_output ("%d three-way handshakes in %.2f seconds %.2f/s",
787  n_clients, delta, ((f64) n_clients) / delta);
788 
790  ec_cli_output ("Test started at %.6f", ecm->test_start_time);
791  break;
792 
793  default:
794  ec_cli_output ("unexpected event(1): %d", event_type);
795  error = clib_error_return (0, "failed: unexpected event(1): %d",
796  event_type);
797  goto cleanup;
798  }
799 
800  /* Now wait for the sessions to finish... */
801  vlib_process_wait_for_event_or_clock (vm, test_timeout);
802  event_type = vlib_process_get_events (vm, &event_data);
803  switch (event_type)
804  {
805  case ~0:
806  ec_cli_output ("Timeout with %d sessions still active...",
807  ecm->ready_connections);
808  error = clib_error_return (0, "failed: timeout with %d sessions",
809  ecm->ready_connections);
810  goto cleanup;
811 
812  case 2:
813  ecm->test_end_time = vlib_time_now (vm);
814  ec_cli_output ("Test finished at %.6f", ecm->test_end_time);
815  break;
816 
817  default:
818  ec_cli_output ("unexpected event(2): %d", event_type);
819  error = clib_error_return (0, "failed: unexpected event(2): %d",
820  event_type);
821  goto cleanup;
822  }
823 
824  delta = ecm->test_end_time - ecm->test_start_time;
825  if (delta != 0.0)
826  {
827  total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
828  transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
829  ec_cli_output ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
830  total_bytes, total_bytes / (1ULL << 20),
831  total_bytes / (1ULL << 30), delta);
832  ec_cli_output ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
833  transfer_type);
834  ec_cli_output ("%.4f gbit/second %s",
835  (((f64) total_bytes * 8.0) / delta / 1e9),
836  transfer_type);
837  }
838  else
839  {
840  ec_cli_output ("zero delta-t?");
841  error = clib_error_return (0, "failed: zero delta-t");
842  goto cleanup;
843  }
844 
845  if (ecm->test_bytes && ecm->test_failed)
846  error = clib_error_return (0, "failed: test bytes");
847 
848 cleanup:
851  for (i = 0; i < vec_len (ecm->connection_index_by_thread); i++)
852  {
855  }
856 
857  pool_free (ecm->sessions);
858 
859  /* Detach the application, so we can use different fifo sizes next time */
860  if (ecm->test_client_attached)
861  {
862  if (echo_clients_detach ())
863  {
864  error = clib_error_return (0, "failed: app detach");
865  ec_cli_output ("WARNING: app detach failed...");
866  }
867  }
868  if (error)
869  ec_cli_output ("test failed");
870  vec_free (ecm->connect_uri);
871  return error;
872 }
873 
874 /* *INDENT-OFF* */
875 VLIB_CLI_COMMAND (echo_clients_command, static) =
876 {
877  .path = "test echo clients",
878  .short_help = "test echo clients [nclients %d][[m|g]bytes <bytes>]"
879  "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
880  "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
881  "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
882  "[uri <tcp://ip/port>][test-bytes][no-output]",
883  .function = echo_clients_command_fn,
884  .is_mp_safe = 1,
885 };
886 /* *INDENT-ON* */
887 
888 clib_error_t *
890 {
892  ecm->is_init = 0;
893  return 0;
894 }
895 
897 
898 /*
899  * fd.io coding-style-patch-verification: ON
900  *
901  * Local Variables:
902  * eval: (c-set-style "gnu")
903  * End:
904  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
vlib_main_t vlib_global_main
Definition: main.c:1638
vlib_main_t * vlib_main
Definition: echo_client.h:105
clib_error_t * echo_clients_connect(vlib_main_t *vm, u32 n_clients)
Definition: echo_client.c:584
#define clib_min(x, y)
Definition: clib.h:291
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
u8 is_ip4
set if uses ip4 networking
vlib_node_runtime_t node_runtime
Definition: node.h:552
a
Definition: bitmap.h:538
void echo_clients_session_disconnect(stream_session_t *s)
Definition: echo_client.c:449
struct _transport_connection transport_connection_t
struct _vnet_connect_args vnet_connect_args_t
static session_cb_vft_t echo_clients
Definition: echo_client.c:491
unsigned long u64
Definition: types.h:89
u32 tls_engine
TLS engine mbedtls/openssl.
Definition: echo_client.h:66
static int echo_clients_detach()
Definition: echo_client.c:546
#define NULL
Definition: clib.h:57
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:195
u32 expected_connections
Number of clients/connections.
Definition: echo_client.h:62
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:523
eclient_session_t * sessions
Session pool, shared.
Definition: echo_client.h:73
static int app_send_stream(app_session_t *s, u8 *data, u32 len, u8 noblock)
u64 bytes_to_send
Bytes to send.
Definition: echo_client.h:59
int i
static void receive_data_chunk(echo_client_main_t *ecm, eclient_session_t *s)
Definition: echo_client.c:133
volatile int run_test
Signal start of test.
Definition: echo_client.h:85
transport_connection_t * session_get_transport(stream_session_t *s)
Definition: session.c:1289
static u32 svm_fifo_max_enqueue(svm_fifo_t *f)
Definition: svm_fifo.h:132
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:228
vlib_main_t ** vlib_mains
Definition: buffer.c:303
unsigned char u8
Definition: types.h:56
static void echo_clients_session_disconnect_callback(stream_session_t *s)
Definition: echo_client.c:438
app_session_t data
Definition: echo_client.h:34
u8 * connect_test_data
Pre-computed test data.
Definition: echo_client.h:76
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:204
struct _svm_fifo svm_fifo_t
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
static void svm_fifo_enqueue_nocopy(svm_fifo_t *f, u32 bytes)
Advance tail pointer.
Definition: svm_fifo.h:246
connectionless service
memset(h->entries, 0, sizeof(h->entries[0])*entries)
clib_error_t * echo_clients_main_init(vlib_main_t *vm)
Definition: echo_client.c:889
static svm_msg_q_t * session_manager_get_vpp_event_queue(u32 thread_index)
Definition: session.h:590
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
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:567
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Definition: svm_fifo.h:114
struct _stream_session_cb_vft session_cb_vft_t
#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:638
u32 app_index
app index after attach
Definition: echo_client.h:53
int svm_fifo_enqueue_nowait(svm_fifo_t *f, u32 max_bytes, const u8 *copy_from_here)
Definition: svm_fifo.c:523
svm_queue_t * vl_input_queue
vpe input queue
Definition: echo_client.h:48
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:264
void stream_session_cleanup(stream_session_t *s)
Cleanup transport and session state.
Definition: session.c:1127
svm_msg_q_t ** vpp_event_queue
Definition: echo_client.h:49
unsigned int u32
Definition: types.h:88
struct _stream_session_t stream_session_t
int session_send_io_evt_to_thread(svm_fifo_t *f, session_evt_type_t evt_type)
Definition: session.c:87
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:312
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:618
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
volatile u32 ready_connections
Definition: echo_client.h:81
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:960
struct _unformat_input_t unformat_input_t
static session_handle_t session_handle(stream_session_t *s)
Definition: session.h:334
static void cleanup(void)
Definition: client.c:130
#define ELOG_DATA(em, f)
Definition: elog.h:481
#define PREDICT_FALSE(x)
Definition: clib.h:107
ip46_address_t rmt_ip
remote ip
u32 ** connection_index_by_thread
Definition: echo_client.h:77
u32 private_segment_count
Number of private fifo segs.
Definition: echo_client.h:64
u32 ** connections_this_batch_by_thread
active connection batch
Definition: echo_client.h:78
u32 node_index
Node index.
Definition: node.h:494
static int echo_clients_rx_callback(stream_session_t *s)
Definition: echo_client.c:459
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: session.c:1461
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:201
#define pool_free(p)
Free a pool.
Definition: pool.h:357
static int echo_clients_session_create_callback(stream_session_t *s)
Definition: echo_client.c:432
static u8 svm_fifo_set_event(svm_fifo_t *f)
Sets fifo event flag.
Definition: svm_fifo.h:157
u32 no_copy
Don&#39;t memcpy data to tx fifo.
Definition: echo_client.h:68
u32 connections_per_batch
Connections to rx/tx at once.
Definition: echo_client.h:63
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:211
static clib_error_t * echo_clients_attach(u8 *appns_id, u64 appns_flags, u64 appns_secret)
Definition: echo_client.c:502
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
vlib_node_registration_t echo_clients_node
(constructor) VLIB_REGISTER_NODE (echo_clients_node)
Definition: echo_client.c:302
u8 * format_stream_session(u8 *s, va_list *args)
Format stream session as per the following format.
Definition: session_cli.c:57
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
transport_service_type_t session_transport_service_type(stream_session_t *s)
Definition: session.c:1141
#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:157
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:65
static int app_recv_stream(app_session_t *s, u8 *buf, u32 len)
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
static void send_data_chunk(echo_client_main_t *ecm, eclient_session_t *s)
Definition: echo_client.c:46
#define pool_init_fixed(pool, max_elts)
initialize a fixed-size, preallocated pool
Definition: pool.h:86
static stream_session_t * session_get_from_handle_if_valid(session_handle_t handle)
Definition: session.h:369
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
#define ASSERT(truth)
u32 cli_node_index
cli process node index
Definition: echo_client.h:51
static int echo_clients_session_connected_callback(u32 app_index, u32 api_context, stream_session_t *s, u8 is_fail)
Definition: echo_client.c:356
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:786
u32 my_client_index
loopback API client handle
Definition: echo_client.h:52
static int app_send_dgram(app_session_t *s, u8 *data, u32 len, u8 noblock)
#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:484
#define ECHO_CLIENT_DBG
Definition: echo_client.c:25
u16 lcl_port
local port (network order)
struct _vnet_app_detach_args_t vnet_app_detach_args_t
u8 ** rx_buf
intermediate rx buffers
Definition: echo_client.h:75
ip46_address_t lcl_ip
local ip
u8 prealloc_fifos
Request fifo preallocation.
Definition: echo_client.h:100
volatile u64 tx_total
Definition: echo_client.h:84
int svm_fifo_dequeue_drop(svm_fifo_t *f, u32 max_bytes)
Definition: svm_fifo.c:726
volatile u64 rx_total
Definition: echo_client.h:83
clib_error_t * vnet_connect_uri(vnet_connect_args_t *a)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
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:58
#define ec_cli_output(_fmt, _args...)
Definition: echo_client.c:613
u64 uword
Definition: types.h:112
clib_spinlock_t sessions_lock
Definition: echo_client.h:74
static void * echo_client_thread_fn(void *arg)
Definition: echo_client.c:560
int session_send_io_evt_to_thread_custom(void *data, u32 thread_index, session_evt_type_t evt_type)
Definition: session.c:93
static void echo_clients_session_reset_callback(stream_session_t *s)
Definition: echo_client.c:423
unformat_function_t unformat_memory_size
Definition: format.h:295
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:1455
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
pthread_t client_thread_handle
Definition: echo_client.h:79
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
static int echo_clients_init(vlib_main_t *vm)
Definition: echo_client.c:325
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static int app_recv_dgram(app_session_t *s, u8 *buf, u32 len)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
u16 rmt_port
remote port (network order)