2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
19 #include <vppinfra/clib.h>
20 #include <vppinfra/format.h>
21 #include <vppinfra/error.h>
22 #include <vppinfra/time.h>
23 #include <vppinfra/macros.h>
24 #include <vnet/vnet.h>
25 #include <vlib/vlib.h>
26 #include <vlib/unix/unix.h>
27 #include <vlibapi/api.h>
28 #include <vlibmemory/api.h>
29 #include <vpp-api/vpe_msg_enum.h>
30 #include <svm_fifo_segment.h>
32 #include <vnet/uri/uri.h>
34 #define vl_typedefs /* define message structures */
35 #include <vpp-api/vpe_all_api_h.h>
38 /* declare message handlers for each api */
40 #define vl_endianfun /* define message structures */
41 #include <vpp-api/vpe_all_api_h.h>
44 /* instantiate all the print functions we know about */
45 #define vl_print(handle, ...)
47 #include <vpp-api/vpe_all_api_h.h>
50 /* Satisfy external references when not linking with -lvlib */
51 vlib_main_t vlib_global_main;
52 vlib_main_t **vlib_mains;
63 svm_fifo_t *server_rx_fifo;
64 svm_fifo_t *server_tx_fifo;
70 unix_shared_memory_queue_t *vl_input_queue;
72 /* API client handle */
75 /* The URI we're playing with */
81 /* Hash table for disconnect processing */
82 uword *session_index_by_vpp_handles;
85 svm_fifo_segment_private_t *seg;
87 /* intermediate rx buffer */
91 unix_shared_memory_queue_t *our_event_queue;
93 /* $$$ single thread only for the moment */
94 unix_shared_memory_queue_t *vpp_event_queue;
96 /* For deadman timers */
97 clib_time_t clib_time;
99 /* State of the connection, shared between msg RX thread and main thread */
100 volatile connection_state_t state;
102 volatile int time_to_stop;
103 volatile int time_to_print_stats;
105 /* VNET_API_ERROR_FOO -> "Foo" hash table */
106 uword *error_string_by_error_number;
107 } uri_udp_test_main_t;
112 #define NITER 1000000
115 uri_udp_test_main_t uri_udp_test_main;
118 stop_signal (int signum)
120 uri_udp_test_main_t *um = &uri_udp_test_main;
122 um->time_to_stop = 1;
126 stats_signal (int signum)
128 uri_udp_test_main_t *um = &uri_udp_test_main;
130 um->time_to_print_stats = 1;
133 static clib_error_t *
134 setup_signal_handlers (void)
136 signal (SIGINT, stats_signal);
137 signal (SIGQUIT, stop_signal);
138 signal (SIGTERM, stop_signal);
144 format_api_error (u8 * s, va_list * args)
146 uri_udp_test_main_t *utm = va_arg (*args, uri_udp_test_main_t *);
147 i32 error = va_arg (*args, u32);
150 p = hash_get (utm->error_string_by_error_number, -error);
153 s = format (s, "%s", p[0]);
155 s = format (s, "%d", error);
160 wait_for_state_change (uri_udp_test_main_t * utm, connection_state_t state)
162 f64 timeout = clib_time_now (&utm->clib_time) + 5.0;
164 while (clib_time_now (&utm->clib_time) < timeout)
166 if (utm->state == state)
173 vl_api_bind_uri_reply_t_handler (vl_api_bind_uri_reply_t * mp)
175 uri_udp_test_main_t *utm = &uri_udp_test_main;
176 svm_fifo_segment_create_args_t _a, *a = &_a;
179 if (mp->segment_name_length == 0)
181 clib_warning ("segment_name_length zero");
185 a->segment_name = (char *) mp->segment_name;
187 /* Attach to the segment vpp created */
188 rv = svm_fifo_segment_attach (a);
191 clib_warning ("sm_fifo_segment_create ('%s') failed", mp->segment_name);
195 utm->our_event_queue = (unix_shared_memory_queue_t *)
196 mp->server_event_queue_address;
198 utm->state = STATE_READY;
202 vl_api_unbind_uri_reply_t_handler (vl_api_unbind_uri_reply_t * mp)
204 uri_udp_test_main_t *utm = &uri_udp_test_main;
207 clib_warning ("returned %d", ntohl (mp->retval));
209 utm->state = STATE_START;
213 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
215 uri_udp_test_main_t *utm = &uri_udp_test_main;
216 vl_api_accept_session_reply_t *rmp;
217 svm_fifo_t *rx_fifo, *tx_fifo;
219 static f64 start_time;
222 if (start_time == 0.0)
223 start_time = clib_time_now (&utm->clib_time);
225 utm->vpp_event_queue = (unix_shared_memory_queue_t *)
226 mp->vpp_event_queue_address;
228 pool_get (utm->sessions, session);
230 rx_fifo = (svm_fifo_t *) mp->server_rx_fifo;
231 rx_fifo->client_session_index = session - utm->sessions;
232 tx_fifo = (svm_fifo_t *) mp->server_tx_fifo;
233 tx_fifo->client_session_index = session - utm->sessions;
235 session->server_rx_fifo = rx_fifo;
236 session->server_tx_fifo = tx_fifo;
238 key = (((u64) mp->session_thread_index) << 32) | (u64) mp->session_index;
240 hash_set (utm->session_index_by_vpp_handles, key, session - utm->sessions);
242 utm->state = STATE_READY;
244 if (pool_elts (utm->sessions) && (pool_elts (utm->sessions) % 20000) == 0)
246 f64 now = clib_time_now (&utm->clib_time);
247 fformat (stdout, "%d active sessions in %.2f seconds, %.2f/sec...\n",
248 pool_elts (utm->sessions), now - start_time,
249 (f64) pool_elts (utm->sessions) / (now - start_time));
252 rmp = vl_msg_api_alloc (sizeof (*rmp));
253 memset (rmp, 0, sizeof (*rmp));
254 rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
255 rmp->session_type = mp->session_type;
256 rmp->session_index = mp->session_index;
257 rmp->session_thread_index = mp->session_thread_index;
258 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & rmp);
262 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
264 uri_udp_test_main_t *utm = &uri_udp_test_main;
266 vl_api_disconnect_session_reply_t *rmp;
271 key = (((u64) mp->session_thread_index) << 32) | (u64) mp->session_index;
273 p = hash_get (utm->session_index_by_vpp_handles, key);
277 session = pool_elt_at_index (utm->sessions, p[0]);
278 hash_unset (utm->session_index_by_vpp_handles, key);
279 pool_put (utm->sessions, session);
283 clib_warning ("couldn't find session key %llx", key);
287 rmp = vl_msg_api_alloc (sizeof (*rmp));
288 memset (rmp, 0, sizeof (*rmp));
289 rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
291 rmp->session_index = mp->session_index;
292 rmp->session_thread_index = mp->session_thread_index;
293 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & rmp);
296 #define foreach_uri_msg \
297 _(BIND_URI_REPLY, bind_uri_reply) \
298 _(UNBIND_URI_REPLY, unbind_uri_reply) \
299 _(ACCEPT_SESSION, accept_session) \
300 _(DISCONNECT_SESSION, disconnect_session)
303 uri_api_hookup (uri_udp_test_main_t * utm)
306 vl_msg_api_set_handlers(VL_API_##N, #n, \
307 vl_api_##n##_t_handler, \
309 vl_api_##n##_t_endian, \
310 vl_api_##n##_t_print, \
311 sizeof(vl_api_##n##_t), 1);
319 connect_to_vpp (char *name)
321 uri_udp_test_main_t *utm = &uri_udp_test_main;
322 api_main_t *am = &api_main;
324 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
327 utm->vl_input_queue = am->shmem_hdr->vl_input_queue;
328 utm->my_client_index = am->my_client_index;
334 vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
336 clib_warning ("BUG");
340 init_error_string_table (uri_udp_test_main_t * utm)
342 utm->error_string_by_error_number = hash_create (0, sizeof (uword));
344 #define _(n,v,s) hash_set (utm->error_string_by_error_number, -v, s);
345 foreach_vnet_api_error;
348 hash_set (utm->error_string_by_error_number, 99, "Misc");
352 handle_fifo_event_server_rx (uri_udp_test_main_t * utm,
353 session_fifo_event_t * e)
355 svm_fifo_t *rx_fifo, *tx_fifo;
358 session_fifo_event_t evt;
359 unix_shared_memory_queue_t *q;
363 tx_fifo = utm->sessions[rx_fifo->client_session_index].server_tx_fifo;
367 nbytes = svm_fifo_dequeue_nowait (rx_fifo, 0,
368 vec_len (utm->rx_buf), utm->rx_buf);
373 rv = svm_fifo_enqueue_nowait (tx_fifo, 0, nbytes, utm->rx_buf);
377 /* Fabricate TX event, send to vpp */
379 evt.event_type = FIFO_EVENT_SERVER_TX;
380 /* $$$$ for event logging */
381 evt.enqueue_length = nbytes;
382 evt.event_id = e->event_id;
383 q = utm->vpp_event_queue;
384 unix_shared_memory_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
388 handle_event_queue (uri_udp_test_main_t * utm)
390 session_fifo_event_t _e, *e = &_e;;
394 unix_shared_memory_queue_sub (utm->our_event_queue, (u8 *) e,
396 switch (e->event_type)
398 case FIFO_EVENT_SERVER_RX:
399 handle_fifo_event_server_rx (utm, e);
402 case FIFO_EVENT_SERVER_EXIT:
406 clib_warning ("unknown event type %d", e->event_type);
409 if (PREDICT_FALSE (utm->time_to_stop == 1))
411 if (PREDICT_FALSE (utm->time_to_print_stats == 1))
413 utm->time_to_print_stats = 0;
414 fformat (stdout, "%d connections\n", pool_elts (utm->sessions));
420 uri_udp_test (uri_udp_test_main_t * utm)
422 vl_api_bind_uri_t *bmp;
423 vl_api_unbind_uri_t *ump;
425 bmp = vl_msg_api_alloc (sizeof (*bmp));
426 memset (bmp, 0, sizeof (*bmp));
428 bmp->_vl_msg_id = ntohs (VL_API_BIND_URI);
429 bmp->client_index = utm->my_client_index;
430 bmp->context = ntohl (0xfeedface);
431 bmp->segment_size = 2 << 30;
432 memcpy (bmp->uri, utm->uri, vec_len (utm->uri));
433 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & bmp);
435 if (wait_for_state_change (utm, STATE_READY))
437 clib_warning ("timeout waiting for STATE_READY");
441 handle_event_queue (utm);
443 ump = vl_msg_api_alloc (sizeof (*ump));
444 memset (ump, 0, sizeof (*ump));
446 ump->_vl_msg_id = ntohs (VL_API_UNBIND_URI);
447 ump->client_index = utm->my_client_index;
448 memcpy (ump->uri, utm->uri, vec_len (utm->uri));
449 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & ump);
451 if (wait_for_state_change (utm, STATE_START))
453 clib_warning ("timeout waiting for STATE_START");
457 fformat (stdout, "Test complete...\n");
461 main (int argc, char **argv)
463 uri_udp_test_main_t *utm = &uri_udp_test_main;
464 unformat_input_t _argv, *a = &_argv;
467 u8 *bind_name = (u8 *) "udp4:1234";
472 clib_mem_init (0, 256 << 20);
474 heap = clib_mem_get_per_cpu_heap ();
475 h = mheap_header (heap);
477 /* make the main heap thread-safe */
478 h->flags |= MHEAP_FLAG_THREAD_SAFE;
480 vec_validate (utm->rx_buf, 8192);
482 utm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
484 clib_time_init (&utm->clib_time);
485 init_error_string_table (utm);
486 svm_fifo_segment_init (0x200000000ULL, 20);
487 unformat_init_command_line (a, argv);
489 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
491 if (unformat (a, "chroot prefix %s", &chroot_prefix))
493 vl_set_memory_root_path ((char *) chroot_prefix);
495 else if (unformat (a, "uri %s", &bind_name))
499 fformat (stderr, "%s: usage [master|slave]\n");
504 utm->uri = format (0, "%s%c", bind_name, 0);
506 setup_signal_handlers ();
508 uri_api_hookup (utm);
510 if (connect_to_vpp ("uri_udp_test") < 0)
513 fformat (stderr, "Couldn't connect to vpe, exiting...\n");
517 /* $$$$ hack preallocation */
518 for (i = 0; i < 200000; i++)
520 pool_get (utm->sessions, session);
521 memset (session, 0, sizeof (*session));
523 for (i = 0; i < 200000; i++)
524 pool_put_index (utm->sessions, i);
528 vl_client_disconnect_from_vlib ();
532 #undef vl_api_version
533 #define vl_api_version(n,v) static u32 vpe_api_version = v;
534 #include <vpp-api/vpe.api.h>
535 #undef vl_api_version
538 vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
541 * Send the main API signature in slot 0. This bit of code must
542 * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
544 mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
548 * fd.io coding-style-patch-verification: ON
551 * eval: (c-set-style "gnu")