FD.io VPP  v18.11-rc0-18-g2a3fb1a
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 == 0) ||
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 
364  if (is_fail)
365  {
366  clib_warning ("connection %d failed!", api_context);
367  signal_evt_to_cli (-1);
368  return 0;
369  }
370 
371  thread_index = s->thread_index;
372  ASSERT (thread_index == vlib_get_thread_index ()
374 
375  if (!ecm->vpp_event_queue[thread_index])
376  ecm->vpp_event_queue[thread_index] =
378 
379  /*
380  * Setup session
381  */
383  pool_get (ecm->sessions, session);
385 
386  memset (session, 0, sizeof (*session));
387  session_index = session - ecm->sessions;
388  session->bytes_to_send = ecm->bytes_to_send;
389  session->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
390  session->data.rx_fifo = s->server_rx_fifo;
391  session->data.rx_fifo->client_session_index = session_index;
392  session->data.tx_fifo = s->server_tx_fifo;
393  session->data.tx_fifo->client_session_index = session_index;
394  session->data.vpp_evt_q = ecm->vpp_event_queue[thread_index];
395  session->vpp_session_handle = session_handle (s);
396 
397  if (ecm->is_dgram)
398  {
400  tc = session_get_transport (s);
401  clib_memcpy (&session->data.transport, tc,
402  sizeof (session->data.transport));
403  session->data.is_dgram = 1;
404  }
405 
406  vec_add1 (ecm->connection_index_by_thread[thread_index], session_index);
407  __sync_fetch_and_add (&ecm->ready_connections, 1);
408  if (ecm->ready_connections == ecm->expected_connections)
409  {
410  ecm->run_test = 1;
411  /* Signal the CLI process that the action is starting... */
412  signal_evt_to_cli (1);
413  }
414 
415  return 0;
416 }
417 
418 static void
420 {
421  if (s->session_state == SESSION_STATE_READY)
422  clib_warning ("Reset active connection %U", format_stream_session, s, 2);
424  return;
425 }
426 
427 static int
429 {
430  return 0;
431 }
432 
433 static void
435 {
437  vnet_disconnect_args_t _a, *a = &_a;
438  a->handle = session_handle (s);
439  a->app_index = ecm->app_index;
441  return;
442 }
443 
444 static int
446 {
448  eclient_session_t *sp;
449 
450  sp = pool_elt_at_index (ecm->sessions,
451  s->server_rx_fifo->client_session_index);
452  receive_data_chunk (ecm, sp);
453 
454  if (svm_fifo_max_dequeue (s->server_rx_fifo))
455  {
456  if (svm_fifo_set_event (s->server_rx_fifo))
457  session_send_io_evt_to_thread (s->server_rx_fifo,
459  }
460  return 0;
461 }
462 
463 int
465 {
466  /* New heaps may be added */
467  return 0;
468 }
469 
470 /* *INDENT-OFF* */
472  .session_reset_callback = echo_clients_session_reset_callback,
473  .session_connected_callback = echo_clients_session_connected_callback,
474  .session_accept_callback = echo_clients_session_create_callback,
475  .session_disconnect_callback = echo_clients_session_disconnect_callback,
476  .builtin_app_rx_callback = echo_clients_rx_callback,
477  .add_segment_callback = echo_client_add_segment_callback
478 };
479 /* *INDENT-ON* */
480 
481 static clib_error_t *
482 echo_clients_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
483 {
484  u32 prealloc_fifos, segment_size = 256 << 20;
486  vnet_app_attach_args_t _a, *a = &_a;
487  u64 options[16];
488  clib_error_t *error = 0;
489 
490  memset (a, 0, sizeof (*a));
491  memset (options, 0, sizeof (options));
492 
493  a->api_client_index = ecm->my_client_index;
494  a->session_cb_vft = &echo_clients;
495 
496  prealloc_fifos = ecm->prealloc_fifos ? ecm->expected_connections : 1;
497 
498  if (ecm->private_segment_size)
499  segment_size = ecm->private_segment_size;
500 
501  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
502  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
503  options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
504  options[APP_OPTIONS_RX_FIFO_SIZE] = ecm->fifo_size;
505  options[APP_OPTIONS_TX_FIFO_SIZE] = ecm->fifo_size;
507  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
508  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
509  options[APP_OPTIONS_TLS_ENGINE] = ecm->tls_engine;
510  if (appns_id)
511  {
512  options[APP_OPTIONS_FLAGS] |= appns_flags;
513  options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
514  }
515  a->options = options;
516  a->namespace_id = appns_id;
517 
518  if ((error = vnet_application_attach (a)))
519  return error;
520 
521  ecm->app_index = a->app_index;
522  return 0;
523 }
524 
525 static int
527 {
529  vnet_app_detach_args_t _da, *da = &_da;
530  int rv;
531 
532  da->app_index = ecm->app_index;
533  rv = vnet_application_detach (da);
534  ecm->test_client_attached = 0;
535  ecm->app_index = ~0;
536  return rv;
537 }
538 
539 static void *
541 {
542  return 0;
543 }
544 
545 /** Start a transmit thread */
546 int
548 {
549  if (ecm->client_thread_handle == 0)
550  {
551  int rv = pthread_create (&ecm->client_thread_handle,
552  NULL /*attr */ ,
554  if (rv)
555  {
556  ecm->client_thread_handle = 0;
557  return -1;
558  }
559  }
560  return 0;
561 }
562 
563 clib_error_t *
565 {
567  vnet_connect_args_t _a, *a = &_a;
568  clib_error_t *error = 0;
569  int i;
570 
571  memset (a, 0, sizeof (*a));
572  for (i = 0; i < n_clients; i++)
573  {
574  a->uri = (char *) ecm->connect_uri;
575  a->api_context = i;
576  a->app_index = ecm->app_index;
577 
578  if ((error = vnet_connect_uri (a)))
579  return error;
580 
581  /* Crude pacing for call setups */
582  if ((i % 4) == 0)
583  vlib_process_suspend (vm, 10e-6);
584  ASSERT (i + 1 >= ecm->ready_connections);
585  while (i + 1 - ecm->ready_connections > 1000)
586  {
587  vlib_process_suspend (vm, 100e-6);
588  }
589  }
590  return 0;
591 }
592 
593 #define ec_cli_output(_fmt, _args...) \
594  if (!ecm->no_output) \
595  vlib_cli_output(vm, _fmt, ##_args)
596 
597 static clib_error_t *
599  unformat_input_t * input, vlib_cli_command_t * cmd)
600 {
602  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
603  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
604  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
605  char *default_uri = "tcp://6.0.1.1/1234";
606  uword *event_data = 0, event_type;
607  f64 time_before_connects;
608  u32 n_clients = 1;
609  int preallocate_sessions = 0;
610  char *transfer_type;
611  clib_error_t *error = 0;
612  u8 *appns_id = 0;
613  int i;
614 
615  ecm->bytes_to_send = 8192;
616  ecm->no_return = 0;
617  ecm->fifo_size = 64 << 10;
618  ecm->connections_per_batch = 1000;
619  ecm->private_segment_count = 0;
620  ecm->private_segment_size = 0;
621  ecm->no_output = 0;
622  ecm->test_bytes = 0;
623  ecm->test_failed = 0;
624  ecm->vlib_main = vm;
626  ecm->no_copy = 0;
627 
628  if (thread_main->n_vlib_mains > 1)
630  vec_free (ecm->connect_uri);
631 
633  {
634  if (unformat (input, "uri %s", &ecm->connect_uri))
635  ;
636  else if (unformat (input, "nclients %d", &n_clients))
637  ;
638  else if (unformat (input, "mbytes %lld", &tmp))
639  ecm->bytes_to_send = tmp << 20;
640  else if (unformat (input, "gbytes %lld", &tmp))
641  ecm->bytes_to_send = tmp << 30;
642  else if (unformat (input, "bytes %lld", &ecm->bytes_to_send))
643  ;
644  else if (unformat (input, "test-timeout %f", &test_timeout))
645  ;
646  else if (unformat (input, "syn-timeout %f", &syn_timeout))
647  ;
648  else if (unformat (input, "no-return"))
649  ecm->no_return = 1;
650  else if (unformat (input, "fifo-size %d", &ecm->fifo_size))
651  ecm->fifo_size <<= 10;
652  else if (unformat (input, "private-segment-count %d",
653  &ecm->private_segment_count))
654  ;
655  else if (unformat (input, "private-segment-size %U",
656  unformat_memory_size, &tmp))
657  {
658  if (tmp >= 0x100000000ULL)
659  return clib_error_return
660  (0, "private segment size %lld (%llu) too large", tmp, tmp);
661  ecm->private_segment_size = tmp;
662  }
663  else if (unformat (input, "preallocate-fifos"))
664  ecm->prealloc_fifos = 1;
665  else if (unformat (input, "preallocate-sessions"))
666  preallocate_sessions = 1;
667  else
668  if (unformat (input, "client-batch %d", &ecm->connections_per_batch))
669  ;
670  else if (unformat (input, "appns %_%v%_", &appns_id))
671  ;
672  else if (unformat (input, "all-scope"))
673  appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
674  | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
675  else if (unformat (input, "local-scope"))
676  appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
677  else if (unformat (input, "global-scope"))
678  appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
679  else if (unformat (input, "secret %lu", &appns_secret))
680  ;
681  else if (unformat (input, "no-output"))
682  ecm->no_output = 1;
683  else if (unformat (input, "test-bytes"))
684  ecm->test_bytes = 1;
685  else if (unformat (input, "tls-engine %d", &ecm->tls_engine))
686  ;
687  else
688  return clib_error_return (0, "failed: unknown input `%U'",
689  format_unformat_error, input);
690  }
691 
692  /* Store cli process node index for signalling */
693  ecm->cli_node_index =
695 
696  if (ecm->is_init == 0)
697  {
698  if (echo_clients_init (vm))
699  return clib_error_return (0, "failed init");
700  }
701 
702 
703  ecm->ready_connections = 0;
704  ecm->expected_connections = n_clients;
705  ecm->rx_total = 0;
706  ecm->tx_total = 0;
707 
708  if (!ecm->connect_uri)
709  {
710  clib_warning ("No uri provided. Using default: %s", default_uri);
711  ecm->connect_uri = format (0, "%s%c", default_uri, 0);
712  }
713 
714  if (ecm->connect_uri[0] == 'u' && ecm->connect_uri[3] != 'c')
715  ecm->is_dgram = 1;
716 
717 #if ECHO_CLIENT_PTHREAD
719 #endif
720 
722  vnet_session_enable_disable (vm, 1 /* turn on session and transports */ );
724 
725  if (ecm->test_client_attached == 0)
726  {
727  if ((error = echo_clients_attach (appns_id, appns_flags, appns_secret)))
728  {
729  vec_free (appns_id);
730  clib_error_report (error);
731  return error;
732  }
733  vec_free (appns_id);
734  }
735  ecm->test_client_attached = 1;
736 
737  /* Turn on the builtin client input nodes */
738  for (i = 0; i < thread_main->n_vlib_mains; i++)
740  VLIB_NODE_STATE_POLLING);
741 
742  if (preallocate_sessions)
743  pool_init_fixed (ecm->sessions, 1.1 * n_clients);
744 
745  /* Fire off connect requests */
746  time_before_connects = vlib_time_now (vm);
747  if ((error = echo_clients_connect (vm, n_clients)))
748  return error;
749 
750  /* Park until the sessions come up, or ten seconds elapse... */
751  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
752  event_type = vlib_process_get_events (vm, &event_data);
753  switch (event_type)
754  {
755  case ~0:
756  ec_cli_output ("Timeout with only %d sessions active...",
757  ecm->ready_connections);
758  error = clib_error_return (0, "failed: syn timeout with %d sessions",
759  ecm->ready_connections);
760  goto cleanup;
761 
762  case 1:
763  delta = vlib_time_now (vm) - time_before_connects;
764  if (delta != 0.0)
765  ec_cli_output ("%d three-way handshakes in %.2f seconds %.2f/s",
766  n_clients, delta, ((f64) n_clients) / delta);
767 
769  ec_cli_output ("Test started at %.6f", ecm->test_start_time);
770  break;
771 
772  default:
773  ec_cli_output ("unexpected event(1): %d", event_type);
774  error = clib_error_return (0, "failed: unexpected event(1): %d",
775  event_type);
776  goto cleanup;
777  }
778 
779  /* Now wait for the sessions to finish... */
780  vlib_process_wait_for_event_or_clock (vm, test_timeout);
781  event_type = vlib_process_get_events (vm, &event_data);
782  switch (event_type)
783  {
784  case ~0:
785  ec_cli_output ("Timeout with %d sessions still active...",
786  ecm->ready_connections);
787  error = clib_error_return (0, "failed: timeout with %d sessions",
788  ecm->ready_connections);
789  goto cleanup;
790 
791  case 2:
792  ecm->test_end_time = vlib_time_now (vm);
793  ec_cli_output ("Test finished at %.6f", ecm->test_end_time);
794  break;
795 
796  default:
797  ec_cli_output ("unexpected event(2): %d", event_type);
798  error = clib_error_return (0, "failed: unexpected event(2): %d",
799  event_type);
800  goto cleanup;
801  }
802 
803  delta = ecm->test_end_time - ecm->test_start_time;
804  if (delta != 0.0)
805  {
806  total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
807  transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
808  ec_cli_output ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
809  total_bytes, total_bytes / (1ULL << 20),
810  total_bytes / (1ULL << 30), delta);
811  ec_cli_output ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
812  transfer_type);
813  ec_cli_output ("%.4f gbit/second %s",
814  (((f64) total_bytes * 8.0) / delta / 1e9),
815  transfer_type);
816  }
817  else
818  {
819  ec_cli_output ("zero delta-t?");
820  error = clib_error_return (0, "failed: zero delta-t");
821  goto cleanup;
822  }
823 
824  if (ecm->test_bytes && ecm->test_failed)
825  error = clib_error_return (0, "failed: test bytes");
826 
827 cleanup:
828  ecm->run_test = 0;
829  for (i = 0; i < vec_len (ecm->connection_index_by_thread); i++)
830  {
833  }
834 
835  pool_free (ecm->sessions);
836 
837  /* Detach the application, so we can use different fifo sizes next time */
838  if (ecm->test_client_attached)
839  {
840  if (echo_clients_detach ())
841  {
842  error = clib_error_return (0, "failed: app detach");
843  ec_cli_output ("WARNING: app detach failed...");
844  }
845  }
846  if (error)
847  ec_cli_output ("test failed");
848  vec_free (ecm->connect_uri);
849  return error;
850 }
851 
852 /* *INDENT-OFF* */
853 VLIB_CLI_COMMAND (echo_clients_command, static) =
854 {
855  .path = "test echo clients",
856  .short_help = "test echo clients [nclients %d][[m|g]bytes <bytes>]"
857  "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
858  "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
859  "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
860  "[uri <tcp://ip/port>][test-bytes][no-output]",
861  .function = echo_clients_command_fn,
862  .is_mp_safe = 1,
863 };
864 /* *INDENT-ON* */
865 
866 clib_error_t *
868 {
870  ecm->is_init = 0;
871  return 0;
872 }
873 
875 
876 /*
877  * fd.io coding-style-patch-verification: ON
878  *
879  * Local Variables:
880  * eval: (c-set-style "gnu")
881  * End:
882  */
#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:1644
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:564
#define clib_min(x, y)
Definition: clib.h:289
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:531
a
Definition: bitmap.h:538
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:471
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:526
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:225
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:1309
static u32 svm_fifo_max_enqueue(svm_fifo_t *f)
Definition: svm_fifo.h:117
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:434
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:212
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:213
connectionless service
clib_error_t * echo_clients_main_init(vlib_main_t *vm)
Definition: echo_client.c:867
static svm_msg_q_t * session_manager_get_vpp_event_queue(u32 thread_index)
Definition: session.h:575
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
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:547
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Definition: svm_fifo.h:105
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:538
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:1150
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:86
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:598
#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:952
struct _unformat_input_t unformat_input_t
static session_handle_t session_handle(stream_session_t *s)
Definition: session.h:329
static void cleanup(void)
Definition: client.c:119
#define ELOG_DATA(em, f)
Definition: elog.h:481
#define PREDICT_FALSE(x)
Definition: clib.h:105
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:473
static int echo_clients_rx_callback(stream_session_t *s)
Definition: echo_client.c:445
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: session.c:1481
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:428
static u8 svm_fifo_set_event(svm_fifo_t *f)
Sets fifo event flag.
Definition: svm_fifo.h:140
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:153
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
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:482
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:55
#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:1166
#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: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:364
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#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:464
#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:792
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:593
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:540
static void echo_clients_session_reset_callback(stream_session_t *s)
Definition: echo_client.c:419
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:1513
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
int session_send_io_evt_to_thread_custom(svm_fifo_t *f, u32 thread_index, session_evt_type_t evt_type)
Definition: session.c:92
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)