blob: 29b33f5aeb7b12dc2d019db558f88a50794a788c [file] [log] [blame]
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001/*
2 * Copyright (c) 2019 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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15
16#include <stdio.h>
17#include <signal.h>
18
19#include <vnet/session/application_interface.h>
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +010020#include <vlibmemory/api.h>
21
22#include <vpp/api/vpe_msg_enum.h>
Florin Coras88001c62019-04-24 14:44:46 -070023#include <svm/fifo_segment.h>
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +010024
25#define vl_typedefs /* define message structures */
26#include <vpp/api/vpe_all_api_h.h>
27#undef vl_typedefs
28
29/* declare message handlers for each api */
30
31#define vl_endianfun /* define message structures */
32#include <vpp/api/vpe_all_api_h.h>
33#undef vl_endianfun
34
35/* instantiate all the print functions we know about */
36#define vl_print(handle, ...)
37#define vl_printfun
38#include <vpp/api/vpe_all_api_h.h>
39#undef vl_printfun
40
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +020041#define QUIC_ECHO_DBG 0
42#define DBG(_fmt, _args...) \
43 if (QUIC_ECHO_DBG) \
44 clib_warning (_fmt, ##_args)
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +010045
46typedef struct
47{
48 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
49#define _(type, name) type name;
50 foreach_app_session_field
51#undef _
52 u64 vpp_session_handle;
53 u64 bytes_sent;
54 u64 bytes_to_send;
55 volatile u64 bytes_received;
56 volatile u64 bytes_to_receive;
57 f64 start;
58} echo_session_t;
59
60typedef enum
61{
62 STATE_START,
63 STATE_ATTACHED,
64 STATE_LISTEN,
65 STATE_READY,
66 STATE_DISCONNECTING,
67 STATE_FAILED,
68 STATE_DETACHED
69} connection_state_t;
70
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +020071enum quic_session_type_t
72{
73 QUIC_SESSION_TYPE_QUIC = 0,
74 QUIC_SESSION_TYPE_STREAM = 1,
75 QUIC_SESSION_TYPE_LISTEN = INT32_MAX,
76};
77
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +010078typedef struct
79{
80 /* vpe input queue */
81 svm_queue_t *vl_input_queue;
82
83 /* API client handle */
84 u32 my_client_index;
85
86 /* The URI we're playing with */
87 u8 *uri;
88
89 /* Session pool */
90 echo_session_t *sessions;
91
92 /* Hash table for disconnect processing */
93 uword *session_index_by_vpp_handles;
94
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +020095 /* Hash table for shared segment_names */
96 uword *shared_segment_names;
97 clib_spinlock_t segment_names_lock;
98
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +010099 /* intermediate rx buffer */
100 u8 *rx_buf;
101
102 /* URI for slave's connect */
103 u8 *connect_uri;
104
105 u32 connected_session_index;
106
107 int i_am_master;
108
109 /* drop all packets */
110 int no_return;
111
112 /* Our event queue */
113 svm_msg_q_t *our_event_queue;
114
115 u8 *socket_name;
116
117 pid_t my_pid;
118
119 /* For deadman timers */
120 clib_time_t clib_time;
121
122 /* State of the connection, shared between msg RX thread and main thread */
123 volatile connection_state_t state;
124
125 /* Signal variables */
126 volatile int time_to_stop;
127 volatile int time_to_print_stats;
128
129 u32 configured_segment_size;
130
131 /* VNET_API_ERROR_FOO -> "Foo" hash table */
132 uword *error_string_by_error_number;
133
134 u8 *connect_test_data;
135 pthread_t *client_thread_handles;
136 u32 *thread_args;
137 u32 client_bytes_received;
138 u8 test_return_packets;
139 u64 bytes_to_send;
140 u32 fifo_size;
141
142 u32 n_clients;
143 u64 tx_total;
144 u64 rx_total;
145
146 volatile u32 n_clients_connected;
147 volatile u32 n_active_clients;
148
149
150 /** Flag that decides if socket, instead of svm, api is used to connect to
151 * vpp. If sock api is used, shm binary api is subsequently bootstrapped
152 * and all other messages are exchanged using shm IPC. */
153 u8 use_sock_api;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200154 int max_test_msg;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100155
Florin Coras88001c62019-04-24 14:44:46 -0700156 fifo_segment_main_t segment_main;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100157} echo_main_t;
158
159echo_main_t echo_main;
160
161#if CLIB_DEBUG > 0
162#define NITER 10000
163#else
164#define NITER 4000000
165#endif
166
167static u8 *
168format_api_error (u8 * s, va_list * args)
169{
170 echo_main_t *em = &echo_main;
171 i32 error = va_arg (*args, u32);
172 uword *p;
173
174 p = hash_get (em->error_string_by_error_number, -error);
175
176 if (p)
177 s = format (s, "%s", p[0]);
178 else
179 s = format (s, "%d", error);
180 return s;
181}
182
183static void
184init_error_string_table (echo_main_t * em)
185{
186 em->error_string_by_error_number = hash_create (0, sizeof (uword));
187
188#define _(n,v,s) hash_set (em->error_string_by_error_number, -v, s);
189 foreach_vnet_api_error;
190#undef _
191
192 hash_set (em->error_string_by_error_number, 99, "Misc");
193}
194
195static void handle_mq_event (session_event_t * e);
196
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200197#if CLIB_DEBUG > 0
198#define TIMEOUT 10.0
199#else
200#define TIMEOUT 10.0
201#endif
202
203static int
204wait_for_segment_allocation (u64 segment_handle)
205{
206 echo_main_t *em = &echo_main;
207 f64 timeout;
208 timeout = clib_time_now (&em->clib_time) + TIMEOUT;
209 uword *segment_present;
210 DBG ("ASKING for %lu", segment_handle);
211 while (clib_time_now (&em->clib_time) < timeout)
212 {
213 clib_spinlock_lock (&em->segment_names_lock);
214 segment_present = hash_get (em->shared_segment_names, segment_handle);
215 clib_spinlock_unlock (&em->segment_names_lock);
216 if (segment_present != 0)
217 return 0;
218 if (em->time_to_stop == 1)
219 return 0;
220 }
221 DBG ("timeout waiting for segment_allocation %lu", segment_handle);
222 return -1;
223}
224
225static int
226wait_for_disconnected_sessions (echo_main_t * em)
227{
228 f64 timeout;
229 timeout = clib_time_now (&em->clib_time) + TIMEOUT;
230 while (clib_time_now (&em->clib_time) < timeout)
231 {
232 if (hash_elts (em->session_index_by_vpp_handles) == 0)
233 return 0;
234 }
235 DBG ("timeout waiting for disconnected_sessions");
236 return -1;
237}
238
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100239static int
240wait_for_state_change (echo_main_t * em, connection_state_t state)
241{
242 svm_msg_q_msg_t msg;
243 session_event_t *e;
244 f64 timeout;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100245 timeout = clib_time_now (&em->clib_time) + TIMEOUT;
246
247 while (clib_time_now (&em->clib_time) < timeout)
248 {
249 if (em->state == state)
250 return 0;
251 if (em->state == STATE_FAILED)
252 return -1;
253 if (em->time_to_stop == 1)
254 return 0;
255 if (!em->our_event_queue || em->state < STATE_ATTACHED)
256 continue;
257
258 if (svm_msg_q_sub (em->our_event_queue, &msg, SVM_Q_NOWAIT, 0))
259 continue;
260 e = svm_msg_q_msg_data (em->our_event_queue, &msg);
261 handle_mq_event (e);
262 svm_msg_q_free_msg (em->our_event_queue, &msg);
263 }
264 clib_warning ("timeout waiting for state %d", state);
265 return -1;
266}
267
268void
269application_send_attach (echo_main_t * em)
270{
271 vl_api_application_attach_t *bmp;
272 vl_api_application_tls_cert_add_t *cert_mp;
273 vl_api_application_tls_key_add_t *key_mp;
274
275 bmp = vl_msg_api_alloc (sizeof (*bmp));
276 clib_memset (bmp, 0, sizeof (*bmp));
277
278 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
279 bmp->client_index = em->my_client_index;
280 bmp->context = ntohl (0xfeedface);
281 bmp->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
282 bmp->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ADD_SEGMENT;
283 bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 16;
284 bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = em->fifo_size;
285 bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = em->fifo_size;
286 bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = 128 << 20;
287 bmp->options[APP_OPTIONS_SEGMENT_SIZE] = 256 << 20;
288 bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = 256;
289 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
290
291 cert_mp = vl_msg_api_alloc (sizeof (*cert_mp) + test_srv_crt_rsa_len);
292 clib_memset (cert_mp, 0, sizeof (*cert_mp));
293 cert_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_CERT_ADD);
294 cert_mp->client_index = em->my_client_index;
295 cert_mp->context = ntohl (0xfeedface);
296 cert_mp->cert_len = clib_host_to_net_u16 (test_srv_crt_rsa_len);
297 clib_memcpy_fast (cert_mp->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
298 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & cert_mp);
299
300 key_mp = vl_msg_api_alloc (sizeof (*key_mp) + test_srv_key_rsa_len);
301 clib_memset (key_mp, 0, sizeof (*key_mp) + test_srv_key_rsa_len);
302 key_mp->_vl_msg_id = ntohs (VL_API_APPLICATION_TLS_KEY_ADD);
303 key_mp->client_index = em->my_client_index;
304 key_mp->context = ntohl (0xfeedface);
305 key_mp->key_len = clib_host_to_net_u16 (test_srv_key_rsa_len);
306 clib_memcpy_fast (key_mp->key, test_srv_key_rsa, test_srv_key_rsa_len);
307 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & key_mp);
308}
309
310static int
311application_attach (echo_main_t * em)
312{
313 application_send_attach (em);
314 if (wait_for_state_change (em, STATE_ATTACHED))
315 {
316 clib_warning ("timeout waiting for STATE_ATTACHED");
317 return -1;
318 }
319 return 0;
320}
321
322void
323application_detach (echo_main_t * em)
324{
325 vl_api_application_detach_t *bmp;
326 bmp = vl_msg_api_alloc (sizeof (*bmp));
327 clib_memset (bmp, 0, sizeof (*bmp));
328
329 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
330 bmp->client_index = em->my_client_index;
331 bmp->context = ntohl (0xfeedface);
332 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
333
334 DBG ("%s", "Sent detach");
335}
336
337static int
338ssvm_segment_attach (char *name, ssvm_segment_type_t type, int fd)
339{
Florin Coras88001c62019-04-24 14:44:46 -0700340 fifo_segment_create_args_t _a, *a = &_a;
341 fifo_segment_main_t *sm = &echo_main.segment_main;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100342 int rv;
343
344 clib_memset (a, 0, sizeof (*a));
345 a->segment_name = (char *) name;
346 a->segment_type = type;
347
348 if (type == SSVM_SEGMENT_MEMFD)
349 a->memfd_fd = fd;
350
Florin Coras88001c62019-04-24 14:44:46 -0700351 if ((rv = fifo_segment_attach (sm, a)))
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100352 {
353 clib_warning ("svm_fifo_segment_attach ('%s') failed", name);
354 return rv;
355 }
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100356 vec_reset_length (a->new_segment_indices);
357 return 0;
358}
359
360static void
361vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
362 mp)
363{
364 echo_main_t *em = &echo_main;
365 int *fds = 0;
366 u32 n_fds = 0;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200367 u64 segment_handle;
368 segment_handle = clib_net_to_host_u64 (mp->segment_handle);
369 DBG ("Attached returned app %u", htons (mp->app_index));
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100370
371 if (mp->retval)
372 {
373 clib_warning ("attach failed: %U", format_api_error,
374 clib_net_to_host_u32 (mp->retval));
375 goto failed;
376 }
377
378 if (mp->segment_name_length == 0)
379 {
380 clib_warning ("segment_name_length zero");
381 goto failed;
382 }
383
384 ASSERT (mp->app_event_queue_address);
385 em->our_event_queue = uword_to_pointer (mp->app_event_queue_address,
386 svm_msg_q_t *);
387
388 if (mp->n_fds)
389 {
390 vec_validate (fds, mp->n_fds);
391 vl_socket_client_recv_fd_msg (fds, mp->n_fds, 5);
392
393 if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
394 if (ssvm_segment_attach (0, SSVM_SEGMENT_MEMFD, fds[n_fds++]))
395 goto failed;
396
397 if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
398 if (ssvm_segment_attach ((char *) mp->segment_name,
399 SSVM_SEGMENT_MEMFD, fds[n_fds++]))
400 goto failed;
401
402 if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
403 svm_msg_q_set_consumer_eventfd (em->our_event_queue, fds[n_fds++]);
404
405 vec_free (fds);
406 }
407 else
408 {
409 if (ssvm_segment_attach ((char *) mp->segment_name, SSVM_SEGMENT_SHM,
410 -1))
411 goto failed;
412 }
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200413 DBG ("SETTING for %lu", segment_handle);
414 clib_spinlock_lock (&em->segment_names_lock);
415 hash_set (em->shared_segment_names, segment_handle, 1);
416 clib_spinlock_unlock (&em->segment_names_lock);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100417
418 em->state = STATE_ATTACHED;
419 return;
420failed:
421 em->state = STATE_FAILED;
422 return;
423}
424
425static void
426vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
427 mp)
428{
429 if (mp->retval)
430 clib_warning ("detach returned with err: %d", mp->retval);
431 echo_main.state = STATE_DETACHED;
432}
433
434static void
435stop_signal (int signum)
436{
437 echo_main_t *um = &echo_main;
438 um->time_to_stop = 1;
439}
440
441static void
442stats_signal (int signum)
443{
444 echo_main_t *um = &echo_main;
445 um->time_to_print_stats = 1;
446}
447
448static clib_error_t *
449setup_signal_handlers (void)
450{
451 signal (SIGUSR2, stats_signal);
452 signal (SIGINT, stop_signal);
453 signal (SIGQUIT, stop_signal);
454 signal (SIGTERM, stop_signal);
455 return 0;
456}
457
458void
459vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
460{
461 clib_warning ("BUG");
462}
463
464int
465connect_to_vpp (char *name)
466{
467 echo_main_t *em = &echo_main;
468 api_main_t *am = &api_main;
469
470 if (em->use_sock_api)
471 {
472 if (vl_socket_client_connect ((char *) em->socket_name, name,
473 0 /* default rx, tx buffer */ ))
474 {
475 clib_warning ("socket connect failed");
476 return -1;
477 }
478
479 if (vl_socket_client_init_shm (0, 1 /* want_pthread */ ))
480 {
481 clib_warning ("init shm api failed");
482 return -1;
483 }
484 }
485 else
486 {
487 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
488 {
489 clib_warning ("shmem connect failed");
490 return -1;
491 }
492 }
493 em->vl_input_queue = am->shmem_hdr->vl_input_queue;
494 em->my_client_index = am->my_client_index;
495 return 0;
496}
497
498void
499disconnect_from_vpp (echo_main_t * em)
500{
501 if (em->use_sock_api)
502 vl_socket_client_disconnect ();
503 else
504 vl_client_disconnect_from_vlib ();
505}
506
507static void
508vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
509{
Florin Coras88001c62019-04-24 14:44:46 -0700510 fifo_segment_main_t *sm = &echo_main.segment_main;
511 fifo_segment_create_args_t _a, *a = &_a;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200512 echo_main_t *em = &echo_main;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100513 int rv;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200514 int *fds = 0;
515
516 if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
517 {
518 vec_validate (fds, 1);
519 vl_socket_client_recv_fd_msg (fds, 1, 5);
520 if (ssvm_segment_attach
521 ((char *) mp->segment_name, SSVM_SEGMENT_MEMFD, fds[0]))
522 clib_warning
523 ("svm_fifo_segment_attach ('%s') failed on SSVM_SEGMENT_MEMFD",
524 mp->segment_name);
525 DBG ("SETTING for %lu", mp->segment_name);
526 clib_spinlock_lock (&em->segment_names_lock);
527 hash_set (em->shared_segment_names, mp->segment_name, 1);
528 clib_spinlock_unlock (&em->segment_names_lock);
529 vec_free (fds);
530 return;
531 }
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100532
533 clib_memset (a, 0, sizeof (*a));
534 a->segment_name = (char *) mp->segment_name;
535 a->segment_size = mp->segment_size;
536 /* Attach to the segment vpp created */
Florin Coras88001c62019-04-24 14:44:46 -0700537 rv = fifo_segment_attach (sm, a);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100538 if (rv)
539 {
540 clib_warning ("svm_fifo_segment_attach ('%s') failed",
541 mp->segment_name);
542 return;
543 }
544 clib_warning ("Mapped new segment '%s' size %d", mp->segment_name,
545 mp->segment_size);
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200546 clib_spinlock_lock (&em->segment_names_lock);
547 hash_set (em->shared_segment_names, mp->segment_name, 1);
548 clib_spinlock_unlock (&em->segment_names_lock);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100549}
550
551static void
552session_print_stats (echo_main_t * em, echo_session_t * session)
553{
554 f64 deltat;
555 u64 bytes;
556
557 deltat = clib_time_now (&em->clib_time) - session->start;
558 bytes = em->i_am_master ? session->bytes_received : em->bytes_to_send;
559 fformat (stdout, "Finished in %.6f\n", deltat);
560 fformat (stdout, "%.4f Gbit/second\n", (bytes * 8.0) / deltat / 1e9);
561}
562
563static void
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200564test_recv_bytes (echo_main_t * em, echo_session_t * s, u8 * rx_buf,
565 u32 n_read)
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100566{
567 int i;
568 for (i = 0; i < n_read; i++)
569 {
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200570 if (rx_buf[i] != ((s->bytes_received + i) & 0xff)
571 && em->max_test_msg > 0)
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100572 {
573 clib_warning ("error at byte %lld, 0x%x not 0x%x",
574 s->bytes_received + i, rx_buf[i],
575 ((s->bytes_received + i) & 0xff));
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200576 em->max_test_msg--;
577 if (em->max_test_msg == 0)
578 clib_warning ("Too many errors, hiding next ones");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100579 }
580 }
581}
582
583static void
584recv_data_chunk (echo_main_t * em, echo_session_t * s, u8 * rx_buf)
585{
586 int n_to_read, n_read;
587
588 n_to_read = svm_fifo_max_dequeue (s->rx_fifo);
589 if (!n_to_read)
590 return;
591
592 do
593 {
594 n_read = app_recv_stream ((app_session_t *) s, rx_buf,
595 vec_len (rx_buf));
596
597 if (n_read > 0)
598 {
599 if (em->test_return_packets)
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200600 test_recv_bytes (em, s, rx_buf, n_read);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100601
602 n_to_read -= n_read;
603
604 s->bytes_received += n_read;
605 s->bytes_to_receive -= n_read;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200606 ASSERT (s->bytes_to_receive >= 0);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100607 }
608 else
609 break;
610 }
611 while (n_to_read > 0);
612}
613
614static void
615send_data_chunk (echo_main_t * em, echo_session_t * s)
616{
617 u64 test_buf_len, bytes_this_chunk, test_buf_offset;
618 u8 *test_data = em->connect_test_data;
619 int n_sent;
620
621 test_buf_len = vec_len (test_data);
622 test_buf_offset = s->bytes_sent % test_buf_len;
623 bytes_this_chunk = clib_min (test_buf_len - test_buf_offset,
624 s->bytes_to_send);
625
626 n_sent = app_send_stream ((app_session_t *) s, test_data + test_buf_offset,
627 bytes_this_chunk, 0);
628
629 if (n_sent > 0)
630 {
631 s->bytes_to_send -= n_sent;
632 s->bytes_sent += n_sent;
633 }
634}
635
636/*
637 * Rx/Tx polling thread per connection
638 */
639static void *
640client_thread_fn (void *arg)
641{
642 echo_main_t *em = &echo_main;
643 static u8 *rx_buf = 0;
644 u32 session_index = *(u32 *) arg;
645 echo_session_t *s;
646
647 vec_validate (rx_buf, 1 << 20);
648
649 while (!em->time_to_stop && em->state != STATE_READY)
650 ;
651
652 s = pool_elt_at_index (em->sessions, session_index);
653 while (!em->time_to_stop)
654 {
655 send_data_chunk (em, s);
656 recv_data_chunk (em, s, rx_buf);
657 if (!s->bytes_to_send && !s->bytes_to_receive)
658 break;
659 }
660
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200661 DBG ("session %d done send %lu to do, %lu done || recv %lu to do, %lu done",
662 session_index, s->bytes_to_send, s->bytes_sent, s->bytes_to_receive,
663 s->bytes_received);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100664 em->tx_total += s->bytes_sent;
665 em->rx_total += s->bytes_received;
666 em->n_active_clients--;
667
668 pthread_exit (0);
669}
670
671void
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200672client_send_connect (echo_main_t * em, u8 * uri, u32 opaque)
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100673{
674 vl_api_connect_uri_t *cmp;
675 cmp = vl_msg_api_alloc (sizeof (*cmp));
676 clib_memset (cmp, 0, sizeof (*cmp));
677
678 cmp->_vl_msg_id = ntohs (VL_API_CONNECT_URI);
679 cmp->client_index = em->my_client_index;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200680 cmp->context = ntohl (opaque);
681 memcpy (cmp->uri, uri, vec_len (uri));
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100682 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & cmp);
683}
684
685void
686client_send_disconnect (echo_main_t * em, echo_session_t * s)
687{
688 vl_api_disconnect_session_t *dmp;
689 dmp = vl_msg_api_alloc (sizeof (*dmp));
690 clib_memset (dmp, 0, sizeof (*dmp));
691 dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
692 dmp->client_index = em->my_client_index;
693 dmp->handle = s->vpp_session_handle;
694 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & dmp);
695}
696
697int
698client_disconnect (echo_main_t * em, echo_session_t * s)
699{
700 client_send_disconnect (em, s);
701 pool_put (em->sessions, s);
702 clib_memset (s, 0xfe, sizeof (*s));
703 return 0;
704}
705
706static void
707session_bound_handler (session_bound_msg_t * mp)
708{
709 echo_main_t *em = &echo_main;
710
711 if (mp->retval)
712 {
713 clib_warning ("bind failed: %U", format_api_error,
714 clib_net_to_host_u32 (mp->retval));
715 em->state = STATE_FAILED;
716 return;
717 }
718
719 clib_warning ("listening on %U:%u", format_ip46_address, mp->lcl_ip,
Aloys Augustincdb71702019-04-08 17:54:39 +0200720 mp->lcl_is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
721 clib_net_to_host_u16 (mp->lcl_port));
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100722 em->state = STATE_READY;
723}
724
725static void
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200726quic_qsession_accepted_handler (session_accepted_msg_t * mp)
727{
728 DBG ("Accept on QSession index %u", mp->handle);
729}
730
731
732static void
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100733session_accepted_handler (session_accepted_msg_t * mp)
734{
735 app_session_evt_t _app_evt, *app_evt = &_app_evt;
736 session_accepted_reply_msg_t *rmp;
737 svm_fifo_t *rx_fifo, *tx_fifo;
738 echo_main_t *em = &echo_main;
739 echo_session_t *session;
740 static f64 start_time;
741 u32 session_index;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200742 u64 segment_handle;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100743 u8 *ip_str;
744
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200745 segment_handle = mp->segment_handle;
746
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100747 if (start_time == 0.0)
748 start_time = clib_time_now (&em->clib_time);
749
Florin Coras09d18c22019-04-24 11:10:02 -0700750 ip_str = format (0, "%U", format_ip46_address, &mp->rmt.ip, mp->rmt.is_ip4);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100751 clib_warning ("Accepted session from: %s:%d", ip_str,
Florin Coras09d18c22019-04-24 11:10:02 -0700752 clib_net_to_host_u16 (mp->rmt.port));
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100753
754 /* Allocate local session and set it up */
755 pool_get (em->sessions, session);
756 session_index = session - em->sessions;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200757 DBG ("Setting session_index %lu", session_index);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100758
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200759 if (wait_for_segment_allocation (segment_handle))
760 {
761 clib_warning ("timeout waiting for segment allocation %lu",
762 segment_handle);
763 return;
764 }
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100765 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
766 rx_fifo->client_session_index = session_index;
767 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
768 tx_fifo->client_session_index = session_index;
769
770 session->rx_fifo = rx_fifo;
771 session->tx_fifo = tx_fifo;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200772 session->vpp_session_handle = mp->handle;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100773 session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
774 svm_msg_q_t *);
775
776 /* Add it to lookup table */
777 hash_set (em->session_index_by_vpp_handles, mp->handle, session_index);
778
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200779 /*
780 * Send accept reply to vpp
781 */
782 app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
783 SESSION_CTRL_EVT_ACCEPTED_REPLY);
784 rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
785 rmp->handle = mp->handle;
786 rmp->context = mp->context;
787 app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
788
789 /* TODO : this is very ugly */
790 if (mp->rmt.is_ip4 != 255)
791 return quic_qsession_accepted_handler (mp);
792 DBG ("SSession handle is %lu", mp->handle);
793
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100794 em->state = STATE_READY;
795
796 /* Stats printing */
797 if (pool_elts (em->sessions) && (pool_elts (em->sessions) % 20000) == 0)
798 {
799 f64 now = clib_time_now (&em->clib_time);
800 fformat (stdout, "%d active sessions in %.2f seconds, %.2f/sec...\n",
801 pool_elts (em->sessions), now - start_time,
802 (f64) pool_elts (em->sessions) / (now - start_time));
803 }
804
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100805 session->bytes_received = 0;
806 session->start = clib_time_now (&em->clib_time);
807}
808
809static void
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200810quic_session_connected_handler (session_connected_msg_t * mp)
811{
812 echo_main_t *em = &echo_main;
813 u8 *uri = format (0, "QUIC://session/%lu", mp->handle);
814 DBG ("QSession Connect : %s", uri);
815 client_send_connect (em, uri, QUIC_SESSION_TYPE_STREAM);
816}
817
818static void
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100819session_connected_handler (session_connected_msg_t * mp)
820{
821 echo_main_t *em = &echo_main;
822 echo_session_t *session;
823 u32 session_index;
824 svm_fifo_t *rx_fifo, *tx_fifo;
825 int rv;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200826 u64 segment_handle;
827 segment_handle = mp->segment_handle;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100828
829 if (mp->retval)
830 {
831 clib_warning ("connection failed with code: %U", format_api_error,
832 clib_net_to_host_u32 (mp->retval));
833 em->state = STATE_FAILED;
834 return;
835 }
836
837 /*
838 * Setup session
839 */
840
841 pool_get (em->sessions, session);
842 clib_memset (session, 0, sizeof (*session));
843 session_index = session - em->sessions;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200844 DBG ("Setting session_index %lu", session_index);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100845
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200846 if (wait_for_segment_allocation (segment_handle))
847 {
848 clib_warning ("timeout waiting for segment allocation %lu",
849 segment_handle);
850 return;
851 }
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100852 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
853 rx_fifo->client_session_index = session_index;
854 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
855 tx_fifo->client_session_index = session_index;
856
857 session->rx_fifo = rx_fifo;
858 session->tx_fifo = tx_fifo;
859 session->vpp_session_handle = mp->handle;
860 session->start = clib_time_now (&em->clib_time);
861 session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
862 svm_msg_q_t *);
863
864 hash_set (em->session_index_by_vpp_handles, mp->handle, session_index);
865
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200866 if (mp->context == QUIC_SESSION_TYPE_QUIC)
867 return quic_session_connected_handler (mp);
868
869 DBG ("SSession Connected");
870
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100871 /*
872 * Start RX thread
873 */
874 em->thread_args[em->n_clients_connected] = session_index;
875 rv = pthread_create (&em->client_thread_handles[em->n_clients_connected],
876 NULL /*attr */ , client_thread_fn,
877 (void *) &em->thread_args[em->n_clients_connected]);
878 if (rv)
879 {
880 clib_warning ("pthread_create returned %d", rv);
881 return;
882 }
883
884 em->n_clients_connected += 1;
885 clib_warning ("session %u (0x%llx) connected with local ip %U port %d",
Florin Coras09d18c22019-04-24 11:10:02 -0700886 session_index, mp->handle, format_ip46_address, &mp->lcl.ip,
887 mp->lcl.is_ip4, clib_net_to_host_u16 (mp->lcl.port));
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100888}
889
890static void
891session_disconnected_handler (session_disconnected_msg_t * mp)
892{
893 app_session_evt_t _app_evt, *app_evt = &_app_evt;
894 session_disconnected_reply_msg_t *rmp;
895 echo_main_t *em = &echo_main;
896 echo_session_t *session = 0;
897 uword *p;
898 int rv = 0;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200899 DBG ("Got a SESSION_CTRL_EVT_DISCONNECTED for session %lu", mp->handle);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100900
901 p = hash_get (em->session_index_by_vpp_handles, mp->handle);
902 if (!p)
903 {
904 clib_warning ("couldn't find session key %llx", mp->handle);
905 return;
906 }
907
908 session = pool_elt_at_index (em->sessions, p[0]);
909 hash_unset (em->session_index_by_vpp_handles, mp->handle);
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200910
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100911 pool_put (em->sessions, session);
912
913 app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
914 SESSION_CTRL_EVT_DISCONNECTED_REPLY);
915 rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
916 rmp->retval = rv;
917 rmp->handle = mp->handle;
918 rmp->context = mp->context;
919 app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
920
921 session_print_stats (em, session);
922}
923
924static void
925session_reset_handler (session_reset_msg_t * mp)
926{
927 app_session_evt_t _app_evt, *app_evt = &_app_evt;
928 echo_main_t *em = &echo_main;
929 session_reset_reply_msg_t *rmp;
930 echo_session_t *session = 0;
931 uword *p;
932 int rv = 0;
933
934 p = hash_get (em->session_index_by_vpp_handles, mp->handle);
935
936 if (p)
937 {
938 session = pool_elt_at_index (em->sessions, p[0]);
939 clib_warning ("got reset");
940 /* Cleanup later */
941 em->time_to_stop = 1;
942 }
943 else
944 {
945 clib_warning ("couldn't find session key %llx", mp->handle);
946 return;
947 }
948
949 app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
950 SESSION_CTRL_EVT_RESET_REPLY);
951 rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
952 rmp->retval = rv;
953 rmp->handle = mp->handle;
954 app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
955}
956
957static void
958handle_mq_event (session_event_t * e)
959{
960 switch (e->event_type)
961 {
962 case SESSION_CTRL_EVT_BOUND:
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200963 DBG ("SESSION_CTRL_EVT_BOUND");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100964 session_bound_handler ((session_bound_msg_t *) e->data);
965 break;
966 case SESSION_CTRL_EVT_ACCEPTED:
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200967 DBG ("SESSION_CTRL_EVT_ACCEPTED");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100968 session_accepted_handler ((session_accepted_msg_t *) e->data);
969 break;
970 case SESSION_CTRL_EVT_CONNECTED:
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200971 DBG ("SESSION_CTRL_EVT_CONNECTED");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100972 session_connected_handler ((session_connected_msg_t *) e->data);
973 break;
974 case SESSION_CTRL_EVT_DISCONNECTED:
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200975 DBG ("SESSION_CTRL_EVT_DISCONNECTED");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100976 session_disconnected_handler ((session_disconnected_msg_t *) e->data);
977 break;
978 case SESSION_CTRL_EVT_RESET:
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200979 DBG ("SESSION_CTRL_EVT_RESET");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100980 session_reset_handler ((session_reset_msg_t *) e->data);
981 break;
982 default:
983 clib_warning ("unhandled %u", e->event_type);
984 }
985}
986
987static void
988clients_run (echo_main_t * em)
989{
990 f64 start_time, deltat, timeout = 100.0;
991 svm_msg_q_msg_t msg;
992 session_event_t *e;
993 echo_session_t *s;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +0200994 hash_pair_t *p;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +0100995 int i;
996
997 /* Init test data */
998 vec_validate (em->connect_test_data, 1024 * 1024 - 1);
999 for (i = 0; i < vec_len (em->connect_test_data); i++)
1000 em->connect_test_data[i] = i & 0xff;
1001
1002 /*
1003 * Attach and connect the clients
1004 */
1005 if (application_attach (em))
1006 return;
1007
1008 for (i = 0; i < em->n_clients; i++)
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001009 client_send_connect (em, em->connect_uri, QUIC_SESSION_TYPE_QUIC);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001010
1011 start_time = clib_time_now (&em->clib_time);
1012 while (em->n_clients_connected < em->n_clients
1013 && (clib_time_now (&em->clib_time) - start_time < timeout)
1014 && em->state != STATE_FAILED && em->time_to_stop != 1)
1015
1016 {
1017 int rc = svm_msg_q_sub (em->our_event_queue, &msg, SVM_Q_TIMEDWAIT, 1);
1018 if (rc == ETIMEDOUT && em->time_to_stop)
1019 break;
1020 if (rc == ETIMEDOUT)
1021 continue;
1022 e = svm_msg_q_msg_data (em->our_event_queue, &msg);
1023 handle_mq_event (e);
1024 svm_msg_q_free_msg (em->our_event_queue, &msg);
1025 }
1026
1027 if (em->n_clients_connected != em->n_clients)
1028 {
1029 clib_warning ("failed to initialize all connections");
1030 return;
1031 }
1032
1033 /*
1034 * Initialize connections
1035 */
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001036 DBG ("Initialize connections on %u clients", em->n_clients);
1037
1038 /* *INDENT-OFF* */
1039 hash_foreach_pair (p, em->session_index_by_vpp_handles,
1040 ({
1041 s = pool_elt_at_index (em->sessions, p->value[0]);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001042 s->bytes_to_send = em->bytes_to_send;
1043 if (!em->no_return)
1044 s->bytes_to_receive = em->bytes_to_send;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001045 }));
1046 /* *INDENT-ON* */
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001047 em->n_active_clients = em->n_clients_connected;
1048
1049 /*
1050 * Wait for client threads to send the data
1051 */
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001052 DBG ("Waiting for data on %u clients", em->n_active_clients);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001053 start_time = clib_time_now (&em->clib_time);
1054 em->state = STATE_READY;
1055 while (em->n_active_clients)
1056 if (!svm_msg_q_is_empty (em->our_event_queue))
1057 {
1058 if (svm_msg_q_sub (em->our_event_queue, &msg, SVM_Q_TIMEDWAIT, 0))
1059 {
1060 clib_warning ("svm msg q returned");
1061 continue;
1062 }
1063 e = svm_msg_q_msg_data (em->our_event_queue, &msg);
1064 if (e->event_type != FIFO_EVENT_APP_RX)
1065 handle_mq_event (e);
1066 svm_msg_q_free_msg (em->our_event_queue, &msg);
1067 }
1068
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001069 /* *INDENT-OFF* */
1070 hash_foreach_pair (p, em->session_index_by_vpp_handles,
1071 ({
1072 s = pool_elt_at_index (em->sessions, p->value[0]);
1073 DBG ("Sending disconnect on session %lu", p->key);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001074 client_disconnect (em, s);
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001075 }));
1076 /* *INDENT-ON* */
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001077
1078 /*
1079 * Stats and detach
1080 */
1081 deltat = clib_time_now (&em->clib_time) - start_time;
1082 fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds\n",
1083 em->tx_total, em->tx_total / (1ULL << 20),
1084 em->tx_total / (1ULL << 30), deltat);
1085 fformat (stdout, "%.4f Gbit/second\n", (em->tx_total * 8.0) / deltat / 1e9);
1086
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001087 wait_for_disconnected_sessions (em);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001088 application_detach (em);
1089}
1090
1091static void
1092vl_api_bind_uri_reply_t_handler (vl_api_bind_uri_reply_t * mp)
1093{
1094 echo_main_t *em = &echo_main;
1095
1096 if (mp->retval)
1097 {
1098 clib_warning ("bind failed: %U", format_api_error,
1099 clib_net_to_host_u32 (mp->retval));
1100 em->state = STATE_FAILED;
1101 return;
1102 }
1103
1104 em->state = STATE_READY;
1105}
1106
1107static void
1108vl_api_unbind_uri_reply_t_handler (vl_api_unbind_uri_reply_t * mp)
1109{
1110 echo_main_t *em = &echo_main;
1111
1112 if (mp->retval != 0)
1113 clib_warning ("returned %d", ntohl (mp->retval));
1114
1115 em->state = STATE_START;
1116}
1117
1118u8 *
1119format_ip4_address (u8 * s, va_list * args)
1120{
1121 u8 *a = va_arg (*args, u8 *);
1122 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
1123}
1124
1125u8 *
1126format_ip6_address (u8 * s, va_list * args)
1127{
1128 ip6_address_t *a = va_arg (*args, ip6_address_t *);
1129 u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
1130
1131 i_max_n_zero = ARRAY_LEN (a->as_u16);
1132 max_n_zeros = 0;
1133 i_first_zero = i_max_n_zero;
1134 n_zeros = 0;
1135 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1136 {
1137 u32 is_zero = a->as_u16[i] == 0;
1138 if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
1139 {
1140 i_first_zero = i;
1141 n_zeros = 0;
1142 }
1143 n_zeros += is_zero;
1144 if ((!is_zero && n_zeros > max_n_zeros)
1145 || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
1146 {
1147 i_max_n_zero = i_first_zero;
1148 max_n_zeros = n_zeros;
1149 i_first_zero = ARRAY_LEN (a->as_u16);
1150 n_zeros = 0;
1151 }
1152 }
1153
1154 last_double_colon = 0;
1155 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1156 {
1157 if (i == i_max_n_zero && max_n_zeros > 1)
1158 {
1159 s = format (s, "::");
1160 i += max_n_zeros - 1;
1161 last_double_colon = 1;
1162 }
1163 else
1164 {
1165 s = format (s, "%s%x",
1166 (last_double_colon || i == 0) ? "" : ":",
1167 clib_net_to_host_u16 (a->as_u16[i]));
1168 last_double_colon = 0;
1169 }
1170 }
1171
1172 return s;
1173}
1174
1175/* Format an IP46 address. */
1176u8 *
1177format_ip46_address (u8 * s, va_list * args)
1178{
1179 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1180 ip46_type_t type = va_arg (*args, ip46_type_t);
1181 int is_ip4 = 1;
1182
1183 switch (type)
1184 {
1185 case IP46_TYPE_ANY:
1186 is_ip4 = ip46_address_is_ip4 (ip46);
1187 break;
1188 case IP46_TYPE_IP4:
1189 is_ip4 = 1;
1190 break;
1191 case IP46_TYPE_IP6:
1192 is_ip4 = 0;
1193 break;
1194 }
1195
1196 return is_ip4 ?
1197 format (s, "%U", format_ip4_address, &ip46->ip4) :
1198 format (s, "%U", format_ip6_address, &ip46->ip6);
1199}
1200
1201static void
1202server_handle_rx (echo_main_t * em, session_event_t * e)
1203{
1204 int n_read, max_dequeue, n_sent;
1205 u32 offset, to_dequeue;
1206 echo_session_t *s;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001207 s = pool_elt_at_index (em->sessions, e->session_index);
1208
1209 /* Clear event only once. Otherwise, if we do it in the loop by calling
1210 * app_recv_stream, we may end up with a lot of unhandled rx events on the
1211 * message queue */
1212 svm_fifo_unset_event (s->rx_fifo);
1213
1214 max_dequeue = svm_fifo_max_dequeue (s->rx_fifo);
1215 if (PREDICT_FALSE (!max_dequeue))
1216 return;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001217 do
1218 {
1219 /* The options here are to limit ourselves to max_dequeue or read
1220 * even the data that was enqueued while we were dequeueing and which
1221 * now has an rx event in the mq. Either of the two work. */
1222 to_dequeue = clib_min (max_dequeue, vec_len (em->rx_buf));
1223 n_read = app_recv_stream_raw (s->rx_fifo, em->rx_buf, to_dequeue,
1224 0 /* clear evt */ , 0 /* peek */ );
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001225
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001226 if (n_read > 0)
1227 {
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001228 if (em->test_return_packets)
1229 test_recv_bytes (em, s, em->rx_buf, n_read);
1230
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001231 max_dequeue -= n_read;
1232 s->bytes_received += n_read;
1233 }
1234 else
1235 break;
1236
1237 /* Reflect if a non-drop session */
1238 if (!em->no_return && n_read > 0)
1239 {
1240 offset = 0;
1241 do
1242 {
1243 n_sent = app_send_stream ((app_session_t *) s,
1244 &em->rx_buf[offset],
1245 n_read, SVM_Q_WAIT);
1246 if (n_sent > 0)
1247 {
1248 n_read -= n_sent;
1249 offset += n_sent;
1250 }
1251 }
1252 while ((n_sent <= 0 || n_read > 0) && !em->time_to_stop);
1253 }
1254 }
1255 while (max_dequeue > 0 && !em->time_to_stop);
1256}
1257
1258static void
1259server_handle_mq (echo_main_t * em)
1260{
1261 svm_msg_q_msg_t msg;
1262 session_event_t *e;
1263
1264 while (1)
1265 {
1266 int rc = svm_msg_q_sub (em->our_event_queue, &msg, SVM_Q_TIMEDWAIT, 1);
1267 if (PREDICT_FALSE (rc == ETIMEDOUT && em->time_to_stop))
1268 break;
1269 if (PREDICT_FALSE (em->time_to_print_stats == 1))
1270 {
1271 em->time_to_print_stats = 0;
1272 fformat (stdout, "%d connections\n", pool_elts (em->sessions));
1273 }
1274 if (rc == ETIMEDOUT)
1275 continue;
1276 e = svm_msg_q_msg_data (em->our_event_queue, &msg);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001277 switch (e->event_type)
1278 {
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001279 case SESSION_IO_EVT_RX:
1280 DBG ("SESSION_IO_EVT_RX");
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001281 server_handle_rx (em, e);
1282 break;
1283 default:
1284 handle_mq_event (e);
1285 break;
1286 }
1287 svm_msg_q_free_msg (em->our_event_queue, &msg);
1288 }
1289}
1290
1291void
1292server_send_listen (echo_main_t * em)
1293{
1294 vl_api_bind_uri_t *bmp;
1295 bmp = vl_msg_api_alloc (sizeof (*bmp));
1296 clib_memset (bmp, 0, sizeof (*bmp));
1297
1298 bmp->_vl_msg_id = ntohs (VL_API_BIND_URI);
1299 bmp->client_index = em->my_client_index;
1300 bmp->context = ntohl (0xfeedface);
1301 memcpy (bmp->uri, em->uri, vec_len (em->uri));
1302 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & bmp);
1303}
1304
1305int
1306server_listen (echo_main_t * em)
1307{
1308 server_send_listen (em);
1309 if (wait_for_state_change (em, STATE_READY))
1310 {
1311 clib_warning ("timeout waiting for STATE_READY");
1312 return -1;
1313 }
1314 return 0;
1315}
1316
1317void
1318server_send_unbind (echo_main_t * em)
1319{
1320 vl_api_unbind_uri_t *ump;
1321
1322 ump = vl_msg_api_alloc (sizeof (*ump));
1323 clib_memset (ump, 0, sizeof (*ump));
1324
1325 ump->_vl_msg_id = ntohs (VL_API_UNBIND_URI);
1326 ump->client_index = em->my_client_index;
1327 memcpy (ump->uri, em->uri, vec_len (em->uri));
1328 vl_msg_api_send_shmem (em->vl_input_queue, (u8 *) & ump);
1329}
1330
1331void
1332server_run (echo_main_t * em)
1333{
1334 echo_session_t *session;
1335 int i;
1336
1337 /* $$$$ hack preallocation */
1338 for (i = 0; i < 200000; i++)
1339 {
1340 pool_get (em->sessions, session);
1341 clib_memset (session, 0, sizeof (*session));
1342 }
1343 for (i = 0; i < 200000; i++)
1344 pool_put_index (em->sessions, i);
1345
1346 if (application_attach (em))
1347 return;
1348
1349 /* Bind to uri */
1350 if (server_listen (em))
1351 return;
1352
1353 /* Enter handle event loop */
1354 server_handle_mq (em);
1355
1356 /* Cleanup */
1357 server_send_unbind (em);
1358
1359 application_detach (em);
1360
1361 fformat (stdout, "Test complete...\n");
1362}
1363
1364static void
1365vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
1366 mp)
1367{
1368 echo_main_t *em = &echo_main;
1369 uword *p;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001370 DBG ("Got disonnected reply for session %lu", mp->handle);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001371
1372 if (mp->retval)
1373 {
1374 clib_warning ("vpp complained about disconnect: %d",
1375 ntohl (mp->retval));
1376 return;
1377 }
1378
1379 em->state = STATE_START;
1380
1381 p = hash_get (em->session_index_by_vpp_handles, mp->handle);
1382 if (p)
1383 {
1384 hash_unset (em->session_index_by_vpp_handles, mp->handle);
1385 }
1386 else
1387 {
1388 clib_warning ("couldn't find session key %llx", mp->handle);
1389 }
1390}
1391
1392static void
1393 vl_api_application_tls_cert_add_reply_t_handler
1394 (vl_api_application_tls_cert_add_reply_t * mp)
1395{
1396 if (mp->retval)
1397 clib_warning ("failed to add tls cert");
1398}
1399
1400static void
1401 vl_api_application_tls_key_add_reply_t_handler
1402 (vl_api_application_tls_key_add_reply_t * mp)
1403{
1404 if (mp->retval)
1405 clib_warning ("failed to add tls key");
1406}
1407
1408#define foreach_quic_echo_msg \
1409_(BIND_URI_REPLY, bind_uri_reply) \
1410_(UNBIND_URI_REPLY, unbind_uri_reply) \
1411_(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \
1412_(APPLICATION_ATTACH_REPLY, application_attach_reply) \
1413_(APPLICATION_DETACH_REPLY, application_detach_reply) \
1414_(MAP_ANOTHER_SEGMENT, map_another_segment) \
1415_(APPLICATION_TLS_CERT_ADD_REPLY, application_tls_cert_add_reply) \
1416_(APPLICATION_TLS_KEY_ADD_REPLY, application_tls_key_add_reply) \
1417
1418void
1419quic_echo_api_hookup (echo_main_t * em)
1420{
1421#define _(N,n) \
1422 vl_msg_api_set_handlers(VL_API_##N, #n, \
1423 vl_api_##n##_t_handler, \
1424 vl_noop_handler, \
1425 vl_api_##n##_t_endian, \
1426 vl_api_##n##_t_print, \
1427 sizeof(vl_api_##n##_t), 1);
1428 foreach_quic_echo_msg;
1429#undef _
1430}
1431
1432int
1433main (int argc, char **argv)
1434{
1435 int i_am_server = 1, test_return_packets = 0;
1436 echo_main_t *em = &echo_main;
Florin Coras88001c62019-04-24 14:44:46 -07001437 fifo_segment_main_t *sm = &em->segment_main;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001438 unformat_input_t _argv, *a = &_argv;
1439 u8 *chroot_prefix;
1440 u8 *uri = 0;
1441 u8 *bind_uri = (u8 *) "quic://0.0.0.0/1234";
1442 u8 *connect_uri = (u8 *) "quic://6.0.1.1/1234";
1443 u64 bytes_to_send = 64 << 10, mbytes;
1444 char *app_name;
1445 u32 tmp;
1446
1447 clib_mem_init_thread_safe (0, 256 << 20);
1448
1449 clib_memset (em, 0, sizeof (*em));
1450 em->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001451 em->shared_segment_names = hash_create (0, sizeof (uword));
1452 clib_spinlock_init (&em->segment_names_lock);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001453 em->my_pid = getpid ();
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001454 em->socket_name = 0;
1455 em->use_sock_api = 1;
1456 em->fifo_size = 64 << 10;
1457 em->n_clients = 1;
Nathan Skrzypczak3a34b1d2019-05-03 14:20:27 +02001458 em->max_test_msg = 50;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001459
1460 clib_time_init (&em->clib_time);
1461 init_error_string_table (em);
Florin Coras88001c62019-04-24 14:44:46 -07001462 fifo_segment_main_init (sm, HIGH_SEGMENT_BASEVA, 20);
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001463 unformat_init_command_line (a, argv);
1464
1465 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
1466 {
1467 if (unformat (a, "chroot prefix %s", &chroot_prefix))
1468 {
1469 vl_set_memory_root_path ((char *) chroot_prefix);
1470 }
1471 else if (unformat (a, "uri %s", &uri))
1472 ;
Nathan Skrzypczak60f3e652019-03-19 13:57:31 +01001473 else if (unformat (a, "server"))
1474 i_am_server = 1;
1475 else if (unformat (a, "client"))
1476 i_am_server = 0;
1477 else if (unformat (a, "no-return"))
1478 em->no_return = 1;
1479 else if (unformat (a, "test"))
1480 test_return_packets = 1;
1481 else if (unformat (a, "bytes %lld", &mbytes))
1482 {
1483 bytes_to_send = mbytes;
1484 }
1485 else if (unformat (a, "mbytes %lld", &mbytes))
1486 {
1487 bytes_to_send = mbytes << 20;
1488 }
1489 else if (unformat (a, "gbytes %lld", &mbytes))
1490 {
1491 bytes_to_send = mbytes << 30;
1492 }
1493 else if (unformat (a, "socket-name %s", &em->socket_name))
1494 ;
1495 else if (unformat (a, "use-svm-api"))
1496 em->use_sock_api = 0;
1497 else if (unformat (a, "fifo-size %d", &tmp))
1498 em->fifo_size = tmp << 10;
1499 else if (unformat (a, "nclients %d", &em->n_clients))
1500 ;
1501 else
1502 {
1503 fformat (stderr, "%s: usage [master|slave]\n", argv[0]);
1504 exit (1);
1505 }
1506 }
1507
1508 if (!em->socket_name)
1509 em->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
1510
1511 if (uri)
1512 {
1513 em->uri = format (0, "%s%c", uri, 0);
1514 em->connect_uri = format (0, "%s%c", uri, 0);
1515 }
1516 else
1517 {
1518 em->uri = format (0, "%s%c", bind_uri, 0);
1519 em->connect_uri = format (0, "%s%c", connect_uri, 0);
1520 }
1521
1522 em->i_am_master = i_am_server;
1523 em->test_return_packets = test_return_packets;
1524 em->bytes_to_send = bytes_to_send;
1525 em->time_to_stop = 0;
1526 vec_validate (em->rx_buf, 4 << 20);
1527 vec_validate (em->client_thread_handles, em->n_clients - 1);
1528 vec_validate (em->thread_args, em->n_clients - 1);
1529
1530 setup_signal_handlers ();
1531 quic_echo_api_hookup (em);
1532
1533 app_name = i_am_server ? "quic_echo_server" : "quic_echo_client";
1534 if (connect_to_vpp (app_name) < 0)
1535 {
1536 svm_region_exit ();
1537 fformat (stderr, "Couldn't connect to vpe, exiting...\n");
1538 exit (1);
1539 }
1540
1541 if (i_am_server == 0)
1542 clients_run (em);
1543 else
1544 server_run (em);
1545
1546 /* Make sure detach finishes */
1547 wait_for_state_change (em, STATE_DETACHED);
1548
1549 disconnect_from_vpp (em);
1550 exit (0);
1551}
1552
1553/*
1554 * fd.io coding-style-patch-verification: ON
1555 *
1556 * Local Variables:
1557 * eval: (c-set-style "gnu")
1558 * End:
1559 */