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