blob: 54e00b181bd976257aff210054ed49de8be7bc1c [file] [log] [blame]
Dave Barach68b0fb02017-02-28 15:15:56 -05001/*
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:
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 <setjmp.h>
18#include <signal.h>
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>
Florin Corase04c2992017-03-01 08:17:34 -080029#include <vpp/api/vpe_msg_enum.h>
30#include <svm/svm_fifo_segment.h>
31#include <pthread.h>
32#include <vnet/session/application_interface.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050033
34#define vl_typedefs /* define message structures */
Florin Corase04c2992017-03-01 08:17:34 -080035#include <vpp/api/vpe_all_api_h.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050036#undef vl_typedefs
37
38/* declare message handlers for each api */
39
40#define vl_endianfun /* define message structures */
Florin Corase04c2992017-03-01 08:17:34 -080041#include <vpp/api/vpe_all_api_h.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050042#undef vl_endianfun
43
44/* instantiate all the print functions we know about */
45#define vl_print(handle, ...)
46#define vl_printfun
Florin Corase04c2992017-03-01 08:17:34 -080047#include <vpp/api/vpe_all_api_h.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050048#undef vl_printfun
49
Dave Barach68b0fb02017-02-28 15:15:56 -050050typedef enum
51{
52 STATE_START,
Florin Coras3cbc04b2017-10-02 00:18:51 -070053 STATE_BOUND,
Dave Barach68b0fb02017-02-28 15:15:56 -050054 STATE_READY,
Florin Coras6cf30ad2017-04-04 23:08:23 -070055 STATE_FAILED,
Dave Barach68b0fb02017-02-28 15:15:56 -050056 STATE_DISCONNECTING,
57} connection_state_t;
58
59typedef struct
60{
Dave Barach68b0fb02017-02-28 15:15:56 -050061 /* vpe input queue */
Florin Corase86a8ed2018-01-05 03:20:25 -080062 svm_queue_t *vl_input_queue;
Dave Barach68b0fb02017-02-28 15:15:56 -050063
64 /* API client handle */
65 u32 my_client_index;
66
67 /* The URI we're playing with */
Florin Coras7fb0fe12018-04-09 09:24:52 -070068 u8 *listen_uri;
69
70 /* URI for connect */
71 u8 *connect_uri;
Dave Barach68b0fb02017-02-28 15:15:56 -050072
73 /* Session pool */
Florin Coras7fb0fe12018-04-09 09:24:52 -070074 app_session_t *sessions;
Dave Barach68b0fb02017-02-28 15:15:56 -050075
76 /* Hash table for disconnect processing */
77 uword *session_index_by_vpp_handles;
78
79 /* fifo segment */
80 svm_fifo_segment_private_t *seg;
81
82 /* intermediate rx buffer */
83 u8 *rx_buf;
84
Florin Coras7fb0fe12018-04-09 09:24:52 -070085 u32 fifo_size;
86 int i_am_server;
87 u8 is_connected;
Florin Corase04c2992017-03-01 08:17:34 -080088
Dave Barach68b0fb02017-02-28 15:15:56 -050089 /* Our event queue */
Florin Corase86a8ed2018-01-05 03:20:25 -080090 svm_queue_t *our_event_queue;
Dave Barach68b0fb02017-02-28 15:15:56 -050091
92 /* $$$ single thread only for the moment */
Florin Corase86a8ed2018-01-05 03:20:25 -080093 svm_queue_t *vpp_event_queue;
Dave Barach68b0fb02017-02-28 15:15:56 -050094
Florin Corase04c2992017-03-01 08:17:34 -080095 /* $$$$ hack: cut-through session index */
96 volatile u32 cut_through_session_index;
Florin Coras3cbc04b2017-10-02 00:18:51 -070097 volatile u32 connected_session;
Florin Corase04c2992017-03-01 08:17:34 -080098
99 /* unique segment name counter */
100 u32 unique_segment_index;
101
102 pid_t my_pid;
103
104 /* pthread handle */
105 pthread_t cut_through_thread_handle;
106
Dave Barach68b0fb02017-02-28 15:15:56 -0500107 /* For deadman timers */
108 clib_time_t clib_time;
109
110 /* State of the connection, shared between msg RX thread and main thread */
111 volatile connection_state_t state;
112
113 volatile int time_to_stop;
114 volatile int time_to_print_stats;
115
Florin Corase04c2992017-03-01 08:17:34 -0800116 u32 configured_segment_size;
117
Dave Barach68b0fb02017-02-28 15:15:56 -0500118 /* VNET_API_ERROR_FOO -> "Foo" hash table */
119 uword *error_string_by_error_number;
Florin Corase04c2992017-03-01 08:17:34 -0800120
121 /* convenience */
122 svm_fifo_segment_main_t *segment_main;
123
Florin Coras3cbc04b2017-10-02 00:18:51 -0700124 u8 *connect_test_data;
Florin Corasf8f516a2018-02-08 15:10:09 -0800125
126 uword *segments_table;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700127 u8 do_echo;
Florin Coras8e43d042018-05-04 15:46:57 -0700128 u8 have_return;
129 u64 bytes_to_send;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700130} udp_echo_main_t;
Dave Barach68b0fb02017-02-28 15:15:56 -0500131
132#if CLIB_DEBUG > 0
Florin Corase04c2992017-03-01 08:17:34 -0800133#define NITER 10000
Dave Barach68b0fb02017-02-28 15:15:56 -0500134#else
Florin Corase04c2992017-03-01 08:17:34 -0800135#define NITER 4000000
Dave Barach68b0fb02017-02-28 15:15:56 -0500136#endif
137
Florin Coras7fb0fe12018-04-09 09:24:52 -0700138udp_echo_main_t udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -0500139
140static void
141stop_signal (int signum)
142{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700143 udp_echo_main_t *um = &udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -0500144
145 um->time_to_stop = 1;
146}
147
148static void
149stats_signal (int signum)
150{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700151 udp_echo_main_t *um = &udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -0500152 um->time_to_print_stats = 1;
153}
154
155static clib_error_t *
156setup_signal_handlers (void)
157{
158 signal (SIGINT, stats_signal);
159 signal (SIGQUIT, stop_signal);
160 signal (SIGTERM, stop_signal);
161
162 return 0;
163}
164
Florin Coras7fb0fe12018-04-09 09:24:52 -0700165uword
166unformat_ip4_address (unformat_input_t * input, va_list * args)
167{
168 u8 *result = va_arg (*args, u8 *);
169 unsigned a[4];
170
171 if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
172 return 0;
173
174 if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
175 return 0;
176
177 result[0] = a[0];
178 result[1] = a[1];
179 result[2] = a[2];
180 result[3] = a[3];
181
182 return 1;
183}
184
185uword
186unformat_ip6_address (unformat_input_t * input, va_list * args)
187{
188 ip6_address_t *result = va_arg (*args, ip6_address_t *);
189 u16 hex_quads[8];
190 uword hex_quad, n_hex_quads, hex_digit, n_hex_digits;
191 uword c, n_colon, double_colon_index;
192
193 n_hex_quads = hex_quad = n_hex_digits = n_colon = 0;
194 double_colon_index = ARRAY_LEN (hex_quads);
195 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
196 {
197 hex_digit = 16;
198 if (c >= '0' && c <= '9')
199 hex_digit = c - '0';
200 else if (c >= 'a' && c <= 'f')
201 hex_digit = c + 10 - 'a';
202 else if (c >= 'A' && c <= 'F')
203 hex_digit = c + 10 - 'A';
204 else if (c == ':' && n_colon < 2)
205 n_colon++;
206 else
207 {
208 unformat_put_input (input);
209 break;
210 }
211
212 /* Too many hex quads. */
213 if (n_hex_quads >= ARRAY_LEN (hex_quads))
214 return 0;
215
216 if (hex_digit < 16)
217 {
218 hex_quad = (hex_quad << 4) | hex_digit;
219
220 /* Hex quad must fit in 16 bits. */
221 if (n_hex_digits >= 4)
222 return 0;
223
224 n_colon = 0;
225 n_hex_digits++;
226 }
227
228 /* Save position of :: */
229 if (n_colon == 2)
230 {
231 /* More than one :: ? */
232 if (double_colon_index < ARRAY_LEN (hex_quads))
233 return 0;
234 double_colon_index = n_hex_quads;
235 }
236
237 if (n_colon > 0 && n_hex_digits > 0)
238 {
239 hex_quads[n_hex_quads++] = hex_quad;
240 hex_quad = 0;
241 n_hex_digits = 0;
242 }
243 }
244
245 if (n_hex_digits > 0)
246 hex_quads[n_hex_quads++] = hex_quad;
247
248 {
249 word i;
250
251 /* Expand :: to appropriate number of zero hex quads. */
252 if (double_colon_index < ARRAY_LEN (hex_quads))
253 {
254 word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads;
255
256 for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--)
257 hex_quads[n_zero + i] = hex_quads[i];
258
259 for (i = 0; i < n_zero; i++)
260 hex_quads[double_colon_index + i] = 0;
261
262 n_hex_quads = ARRAY_LEN (hex_quads);
263 }
264
265 /* Too few hex quads given. */
266 if (n_hex_quads < ARRAY_LEN (hex_quads))
267 return 0;
268
269 for (i = 0; i < ARRAY_LEN (hex_quads); i++)
270 result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]);
271
272 return 1;
273 }
274}
275
276uword
277unformat_uri (unformat_input_t * input, va_list * args)
278{
279 session_endpoint_extended_t *sep = va_arg (*args,
280 session_endpoint_extended_t *);
281 u32 port;
282 char *tmp;
283
284 if (unformat (input, "%s://%U/%d", &tmp, unformat_ip4_address, &sep->ip.ip4,
285 &port))
286 {
287 sep->port = clib_host_to_net_u16 (port);
288 sep->is_ip4 = 1;
289 return 1;
290 }
291 else if (unformat (input, "%s://%U/%d", &tmp, unformat_ip6_address,
292 &sep->ip.ip6, &port))
293 {
294 sep->port = clib_host_to_net_u16 (port);
295 sep->is_ip4 = 0;
296 return 1;
297 }
298 return 0;
299}
300
Florin Coras6cf30ad2017-04-04 23:08:23 -0700301void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700302application_send_attach (udp_echo_main_t * utm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700303{
304 vl_api_application_attach_t *bmp;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700305 bmp = vl_msg_api_alloc (sizeof (*bmp));
306 memset (bmp, 0, sizeof (*bmp));
307
308 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
309 bmp->client_index = utm->my_client_index;
310 bmp->context = ntohl (0xfeedface);
Florin Corasf8f516a2018-02-08 15:10:09 -0800311 bmp->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_ADD_SEGMENT;
312 bmp->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
313 bmp->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700314 bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 2;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700315 bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = utm->fifo_size;
316 bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = utm->fifo_size;
Florin Corasff6e7692017-12-11 04:59:01 -0800317 bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = 128 << 20;
318 bmp->options[APP_OPTIONS_SEGMENT_SIZE] = 256 << 20;
319 bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = 16768;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700320 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & bmp);
321}
322
323void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700324application_detach (udp_echo_main_t * utm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700325{
326 vl_api_application_detach_t *bmp;
327 bmp = vl_msg_api_alloc (sizeof (*bmp));
328 memset (bmp, 0, sizeof (*bmp));
329
330 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
331 bmp->client_index = utm->my_client_index;
332 bmp->context = ntohl (0xfeedface);
333 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & bmp);
334}
335
336static void
337vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
338 mp)
339{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700340 udp_echo_main_t *utm = &udp_echo_main;
Florin Coras84a30ef2018-01-24 10:49:23 -0800341 svm_fifo_segment_create_args_t _a = { 0 }, *a = &_a;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700342 int rv;
343
344 if (mp->retval)
345 {
346 clib_warning ("attach failed: %d", mp->retval);
347 utm->state = STATE_FAILED;
348 return;
349 }
350
351 if (mp->segment_name_length == 0)
352 {
353 clib_warning ("segment_name_length zero");
354 return;
355 }
356
357 a->segment_name = (char *) mp->segment_name;
358 a->segment_size = mp->segment_size;
359
360 ASSERT (mp->app_event_queue_address);
361
362 /* Attach to the segment vpp created */
363 rv = svm_fifo_segment_attach (a);
364 if (rv)
365 {
366 clib_warning ("svm_fifo_segment_attach ('%s') failed",
367 mp->segment_name);
368 return;
369 }
370
371 utm->our_event_queue =
Florin Corase86a8ed2018-01-05 03:20:25 -0800372 uword_to_pointer (mp->app_event_queue_address, svm_queue_t *);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700373}
374
375static void
376vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
377 mp)
378{
379 if (mp->retval)
380 clib_warning ("detach returned with err: %d", mp->retval);
381}
382
Dave Barach68b0fb02017-02-28 15:15:56 -0500383u8 *
384format_api_error (u8 * s, va_list * args)
385{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700386 udp_echo_main_t *utm = va_arg (*args, udp_echo_main_t *);
Dave Barach68b0fb02017-02-28 15:15:56 -0500387 i32 error = va_arg (*args, u32);
388 uword *p;
389
390 p = hash_get (utm->error_string_by_error_number, -error);
391
392 if (p)
393 s = format (s, "%s", p[0]);
394 else
395 s = format (s, "%d", error);
396 return s;
397}
398
399int
Florin Coras7fb0fe12018-04-09 09:24:52 -0700400wait_for_state_change (udp_echo_main_t * utm, connection_state_t state)
Dave Barach68b0fb02017-02-28 15:15:56 -0500401{
Florin Corase04c2992017-03-01 08:17:34 -0800402#if CLIB_DEBUG > 0
403#define TIMEOUT 600.0
404#else
405#define TIMEOUT 600.0
406#endif
407
408 f64 timeout = clib_time_now (&utm->clib_time) + TIMEOUT;
Dave Barach68b0fb02017-02-28 15:15:56 -0500409
410 while (clib_time_now (&utm->clib_time) < timeout)
411 {
412 if (utm->state == state)
413 return 0;
414 }
415 return -1;
416}
417
Florin Corase04c2992017-03-01 08:17:34 -0800418u64 server_bytes_received, server_bytes_sent;
419
420static void *
421cut_through_thread_fn (void *arg)
422{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700423 app_session_t *s;
Florin Corase04c2992017-03-01 08:17:34 -0800424 svm_fifo_t *rx_fifo;
425 svm_fifo_t *tx_fifo;
426 u8 *my_copy_buffer = 0;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700427 udp_echo_main_t *utm = &udp_echo_main;
Florin Corase04c2992017-03-01 08:17:34 -0800428 i32 actual_transfer;
429 int rv;
430 u32 buffer_offset;
431
432 while (utm->cut_through_session_index == ~0)
433 ;
434
435 s = pool_elt_at_index (utm->sessions, utm->cut_through_session_index);
436
Florin Coras7fb0fe12018-04-09 09:24:52 -0700437 rx_fifo = s->rx_fifo;
438 tx_fifo = s->tx_fifo;
Florin Corase04c2992017-03-01 08:17:34 -0800439
440 vec_validate (my_copy_buffer, 64 * 1024 - 1);
441
442 while (true)
443 {
444 /* We read from the tx fifo and write to the rx fifo */
445 do
446 {
Florin Corasf8f516a2018-02-08 15:10:09 -0800447 actual_transfer = svm_fifo_dequeue_nowait (rx_fifo,
Florin Corase04c2992017-03-01 08:17:34 -0800448 vec_len (my_copy_buffer),
449 my_copy_buffer);
450 }
451 while (actual_transfer <= 0);
452
453 server_bytes_received += actual_transfer;
454
455 buffer_offset = 0;
456 while (actual_transfer > 0)
457 {
Florin Corasf8f516a2018-02-08 15:10:09 -0800458 rv = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer,
Florin Corase04c2992017-03-01 08:17:34 -0800459 my_copy_buffer + buffer_offset);
460 if (rv > 0)
461 {
462 actual_transfer -= rv;
463 buffer_offset += rv;
464 server_bytes_sent += rv;
465 }
466
467 }
468 if (PREDICT_FALSE (utm->time_to_stop))
469 break;
470 }
471
472 pthread_exit (0);
473}
474
475static void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700476udp_client_connect (udp_echo_main_t * utm)
Florin Corase04c2992017-03-01 08:17:34 -0800477{
478 vl_api_connect_uri_t *cmp;
Florin Corase04c2992017-03-01 08:17:34 -0800479 cmp = vl_msg_api_alloc (sizeof (*cmp));
480 memset (cmp, 0, sizeof (*cmp));
481
482 cmp->_vl_msg_id = ntohs (VL_API_CONNECT_URI);
483 cmp->client_index = utm->my_client_index;
484 cmp->context = ntohl (0xfeedface);
485 memcpy (cmp->uri, utm->connect_uri, vec_len (utm->connect_uri));
486 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & cmp);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700487}
Florin Corase04c2992017-03-01 08:17:34 -0800488
Florin Coras6cf30ad2017-04-04 23:08:23 -0700489static void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700490client_send_cut_through (udp_echo_main_t * utm, app_session_t * session)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700491{
492 int i;
493 u8 *test_data = 0;
494 u64 bytes_received = 0, bytes_sent = 0;
495 i32 bytes_to_read;
496 int rv;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700497 f64 before, after, delta, bytes_per_second;
498 svm_fifo_t *rx_fifo, *tx_fifo;
499 int buffer_offset, bytes_to_send = 0;
Florin Corase04c2992017-03-01 08:17:34 -0800500
Florin Coras6cf30ad2017-04-04 23:08:23 -0700501 /*
502 * Prepare test data
503 */
504 vec_validate (test_data, 64 * 1024 - 1);
505 for (i = 0; i < vec_len (test_data); i++)
506 test_data[i] = i & 0xff;
507
Florin Coras7fb0fe12018-04-09 09:24:52 -0700508 rx_fifo = session->rx_fifo;
509 tx_fifo = session->tx_fifo;
Florin Corase04c2992017-03-01 08:17:34 -0800510
511 before = clib_time_now (&utm->clib_time);
512
513 vec_validate (utm->rx_buf, vec_len (test_data) - 1);
514
515 for (i = 0; i < NITER; i++)
516 {
517 bytes_to_send = vec_len (test_data);
518 buffer_offset = 0;
519 while (bytes_to_send > 0)
520 {
Florin Corasa5464812017-04-19 13:00:05 -0700521 rv = svm_fifo_enqueue_nowait (tx_fifo, bytes_to_send,
Florin Corase04c2992017-03-01 08:17:34 -0800522 test_data + buffer_offset);
523
524 if (rv > 0)
525 {
526 bytes_to_send -= rv;
527 buffer_offset += rv;
528 bytes_sent += rv;
529 }
530 }
531
532 bytes_to_read = svm_fifo_max_dequeue (rx_fifo);
Florin Corase04c2992017-03-01 08:17:34 -0800533 bytes_to_read = vec_len (utm->rx_buf) > bytes_to_read ?
534 bytes_to_read : vec_len (utm->rx_buf);
535
536 buffer_offset = 0;
537 while (bytes_to_read > 0)
538 {
Florin Corasa5464812017-04-19 13:00:05 -0700539 rv = svm_fifo_dequeue_nowait (rx_fifo,
Florin Corase04c2992017-03-01 08:17:34 -0800540 bytes_to_read,
541 utm->rx_buf + buffer_offset);
542 if (rv > 0)
543 {
544 bytes_to_read -= rv;
545 buffer_offset += rv;
546 bytes_received += rv;
547 }
548 }
549 }
550 while (bytes_received < bytes_sent)
551 {
Florin Corasa5464812017-04-19 13:00:05 -0700552 rv =
553 svm_fifo_dequeue_nowait (rx_fifo, vec_len (utm->rx_buf), utm->rx_buf);
Florin Corase04c2992017-03-01 08:17:34 -0800554 if (rv > 0)
555 {
556#if CLIB_DEBUG > 0
557 int j;
558 for (j = 0; j < rv; j++)
559 {
560 if (utm->rx_buf[j] != ((bytes_received + j) & 0xff))
561 {
562 clib_warning ("error at byte %lld, 0x%x not 0x%x",
563 bytes_received + j,
564 utm->rx_buf[j],
565 ((bytes_received + j) & 0xff));
566 }
567 }
568#endif
569 bytes_received += (u64) rv;
570 }
571 }
572
573 after = clib_time_now (&utm->clib_time);
574 delta = after - before;
575 bytes_per_second = 0.0;
576
577 if (delta > 0.0)
578 bytes_per_second = (f64) bytes_received / delta;
579
580 fformat (stdout,
581 "Done: %lld recv bytes in %.2f seconds, %.2f bytes/sec...\n\n",
582 bytes_received, delta, bytes_per_second);
583 fformat (stdout,
584 "Done: %lld sent bytes in %.2f seconds, %.2f bytes/sec...\n\n",
585 bytes_sent, delta, bytes_per_second);
586 fformat (stdout,
587 "client -> server -> client round trip: %.2f Gbit/sec \n\n",
588 (bytes_per_second * 8.0) / 1e9);
589}
590
Dave Barach68b0fb02017-02-28 15:15:56 -0500591static void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700592send_test_chunk (udp_echo_main_t * utm, app_session_t * s, u32 bytes)
Florin Coras3cbc04b2017-10-02 00:18:51 -0700593{
594 u8 *test_data = utm->connect_test_data;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700595 int test_buf_offset = 0;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700596 u64 bytes_sent = 0;
Florin Coras8e43d042018-05-04 15:46:57 -0700597 u32 bytes_to_snd, enq_space, min_chunk;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700598 int rv;
599
Florin Coras8e43d042018-05-04 15:46:57 -0700600 min_chunk = clib_min (65536, s->tx_fifo->nitems);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700601 bytes_to_snd = (bytes == 0) ? vec_len (test_data) : bytes;
602 if (bytes_to_snd > vec_len (test_data))
603 bytes_to_snd = vec_len (test_data);
604
605 while (bytes_to_snd > 0 && !utm->time_to_stop)
606 {
Florin Coras8e43d042018-05-04 15:46:57 -0700607 enq_space = svm_fifo_max_enqueue (s->tx_fifo);
608 if (enq_space < clib_min (bytes_to_snd, min_chunk))
609 continue;
610
Florin Coras7fb0fe12018-04-09 09:24:52 -0700611 rv = app_send (s, test_data + test_buf_offset, bytes_to_snd, 0);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700612 if (rv > 0)
613 {
614 bytes_to_snd -= rv;
615 test_buf_offset += rv;
616 bytes_sent += rv;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700617 }
618 }
619}
620
621static void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700622recv_test_chunk (udp_echo_main_t * utm, app_session_t * s)
Florin Coras3cbc04b2017-10-02 00:18:51 -0700623{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700624 app_recv (s, utm->rx_buf, vec_len (utm->rx_buf));
Florin Coras3cbc04b2017-10-02 00:18:51 -0700625}
626
627void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700628client_send_data (udp_echo_main_t * utm)
Florin Coras3cbc04b2017-10-02 00:18:51 -0700629{
Florin Coras8e43d042018-05-04 15:46:57 -0700630 f64 start_time, end_time, delta;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700631 app_session_t *session;
Florin Coras8e43d042018-05-04 15:46:57 -0700632 char *transfer_type;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700633 u32 n_iterations;
Florin Coras8e43d042018-05-04 15:46:57 -0700634 u8 *test_data;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700635 int i;
636
Florin Coras8e43d042018-05-04 15:46:57 -0700637 vec_validate (utm->connect_test_data, 1024 * 1024 - 1);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700638 for (i = 0; i < vec_len (utm->connect_test_data); i++)
639 utm->connect_test_data[i] = i & 0xff;
640
641 test_data = utm->connect_test_data;
642 session = pool_elt_at_index (utm->sessions, utm->connected_session);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700643 ASSERT (vec_len (test_data) > 0);
644
645 vec_validate (utm->rx_buf, vec_len (test_data) - 1);
Florin Coras8e43d042018-05-04 15:46:57 -0700646 n_iterations = utm->bytes_to_send / vec_len (test_data);
647 if (!n_iterations)
648 n_iterations = 1;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700649
Florin Coras8e43d042018-05-04 15:46:57 -0700650 start_time = clib_time_now (&utm->clib_time);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700651 for (i = 0; i < n_iterations; i++)
652 {
Florin Coras7fb0fe12018-04-09 09:24:52 -0700653 send_test_chunk (utm, session, 0);
Florin Coras8e43d042018-05-04 15:46:57 -0700654 if (utm->have_return)
655 recv_test_chunk (utm, session);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700656 if (utm->time_to_stop)
657 break;
658 }
659
Florin Coras8e43d042018-05-04 15:46:57 -0700660 if (utm->have_return)
Florin Coras3cbc04b2017-10-02 00:18:51 -0700661 {
Florin Coras8e43d042018-05-04 15:46:57 -0700662 f64 timeout = clib_time_now (&utm->clib_time) + 5;
663 while (clib_time_now (&utm->clib_time) < timeout)
664 recv_test_chunk (utm, session);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700665 }
666
Florin Coras8e43d042018-05-04 15:46:57 -0700667 end_time = clib_time_now (&utm->clib_time);
668 delta = end_time - start_time;
669 transfer_type = utm->have_return ? "full-duplex" : "half-duplex";
670 clib_warning ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
671 utm->bytes_to_send, utm->bytes_to_send / (1ULL << 20),
672 utm->bytes_to_send / (1ULL << 30), delta);
673 clib_warning ("%.2f bytes/second %s", ((f64) utm->bytes_to_send) / (delta),
674 transfer_type);
675 clib_warning ("%.4f gbit/second %s",
676 (((f64) utm->bytes_to_send * 8.0) / delta / 1e9),
677 transfer_type);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700678}
679
680static void
Florin Coras7fb0fe12018-04-09 09:24:52 -0700681client_test (udp_echo_main_t * utm)
Florin Coras6cf30ad2017-04-04 23:08:23 -0700682{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700683 app_session_t *session;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700684
Florin Corasa5464812017-04-19 13:00:05 -0700685 application_send_attach (utm);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700686 udp_client_connect (utm);
687
688 if (wait_for_state_change (utm, STATE_READY))
689 {
690 clib_warning ("timeout waiting for STATE_READY");
691 return;
692 }
693
Florin Coras3cbc04b2017-10-02 00:18:51 -0700694 if (utm->cut_through_session_index != ~0)
695 {
696 session = pool_elt_at_index (utm->sessions,
697 utm->cut_through_session_index);
698 client_send_cut_through (utm, session);
699 }
700 else
701 {
702 session = pool_elt_at_index (utm->sessions, utm->connected_session);
703 client_send_data (utm);
704 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700705
Florin Coras6cf30ad2017-04-04 23:08:23 -0700706 application_detach (utm);
707}
708
709static void
Dave Barach68b0fb02017-02-28 15:15:56 -0500710vl_api_bind_uri_reply_t_handler (vl_api_bind_uri_reply_t * mp)
711{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700712 udp_echo_main_t *utm = &udp_echo_main;
713 svm_fifo_t *rx_fifo, *tx_fifo;
714 app_session_t *session;
715 u32 session_index;
Dave Barach68b0fb02017-02-28 15:15:56 -0500716
Florin Coras6cf30ad2017-04-04 23:08:23 -0700717 if (mp->retval)
Dave Barach68b0fb02017-02-28 15:15:56 -0500718 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700719 clib_warning ("bind failed: %d", mp->retval);
720 utm->state = STATE_FAILED;
Dave Barach68b0fb02017-02-28 15:15:56 -0500721 return;
722 }
723
Florin Coras7fb0fe12018-04-09 09:24:52 -0700724 rx_fifo = uword_to_pointer (mp->rx_fifo, svm_fifo_t *);
725 tx_fifo = uword_to_pointer (mp->tx_fifo, svm_fifo_t *);
726
727 pool_get (utm->sessions, session);
728 memset (session, 0, sizeof (*session));
729 session_index = session - utm->sessions;
730
731 rx_fifo->client_session_index = session_index;
732 tx_fifo->client_session_index = session_index;
733 session->rx_fifo = rx_fifo;
734 session->tx_fifo = tx_fifo;
735 clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
736 sizeof (ip46_address_t));
737 session->transport.is_ip4 = mp->lcl_is_ip4;
738 session->transport.lcl_port = mp->lcl_port;
739 session->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_queue_t *);
740
741 utm->state = utm->is_connected ? STATE_BOUND : STATE_READY;
Dave Barach68b0fb02017-02-28 15:15:56 -0500742}
743
744static void
Florin Corase04c2992017-03-01 08:17:34 -0800745vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
746{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700747 udp_echo_main_t *utm = &udp_echo_main;
Florin Corase04c2992017-03-01 08:17:34 -0800748 svm_fifo_segment_create_args_t _a, *a = &_a;
Florin Corasf8f516a2018-02-08 15:10:09 -0800749 svm_fifo_segment_private_t *seg;
750 u8 *seg_name;
Florin Corase04c2992017-03-01 08:17:34 -0800751 int rv;
752
Florin Coras3cbc04b2017-10-02 00:18:51 -0700753 memset (a, 0, sizeof (*a));
Florin Corase04c2992017-03-01 08:17:34 -0800754 a->segment_name = (char *) mp->segment_name;
755 a->segment_size = mp->segment_size;
756 /* Attach to the segment vpp created */
757 rv = svm_fifo_segment_attach (a);
758 if (rv)
759 {
760 clib_warning ("svm_fifo_segment_attach ('%s') failed",
761 mp->segment_name);
762 return;
763 }
Florin Corasf8f516a2018-02-08 15:10:09 -0800764 seg = svm_fifo_segment_get_segment (a->new_segment_indices[0]);
765 clib_warning ("Mapped new segment '%s' size %d", seg->ssvm.name,
766 seg->ssvm.ssvm_size);
767 seg_name = format (0, "%s", (char *) mp->segment_name);
768 hash_set_mem (utm->segments_table, seg_name, a->new_segment_indices[0]);
769 vec_free (seg_name);
770}
771
772static void
773vl_api_unmap_segment_t_handler (vl_api_unmap_segment_t * mp)
774{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700775 udp_echo_main_t *utm = &udp_echo_main;
Florin Corasf8f516a2018-02-08 15:10:09 -0800776 svm_fifo_segment_private_t *seg;
777 u64 *seg_indexp;
778 u8 *seg_name;
779
780
781 seg_name = format (0, "%s", mp->segment_name);
782 seg_indexp = hash_get_mem (utm->segments_table, seg_name);
783 if (!seg_indexp)
784 {
785 clib_warning ("segment not mapped: %s", seg_name);
786 return;
787 }
788 hash_unset_mem (utm->segments_table, seg_name);
789 seg = svm_fifo_segment_get_segment ((u32) seg_indexp[0]);
790 svm_fifo_segment_delete (seg);
791 clib_warning ("Unmapped segment '%s'", seg_name);
792 vec_free (seg_name);
Florin Corase04c2992017-03-01 08:17:34 -0800793}
794
Florin Coras6cf30ad2017-04-04 23:08:23 -0700795/**
796 * Acting as server for redirected connect requests
797 */
Florin Corase04c2992017-03-01 08:17:34 -0800798static void
799vl_api_connect_uri_t_handler (vl_api_connect_uri_t * mp)
800{
801 u32 segment_index;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700802 udp_echo_main_t *utm = &udp_echo_main;
Florin Corase04c2992017-03-01 08:17:34 -0800803 svm_fifo_segment_main_t *sm = &svm_fifo_segment_main;
804 svm_fifo_segment_create_args_t _a, *a = &_a;
805 svm_fifo_segment_private_t *seg;
Florin Corase86a8ed2018-01-05 03:20:25 -0800806 svm_queue_t *client_q;
Dave Wallace33e002b2017-09-06 01:20:02 -0400807 vl_api_connect_session_reply_t *rmp;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700808 app_session_t *session = 0;
Florin Corase04c2992017-03-01 08:17:34 -0800809 int rv = 0;
810
811 /* Create the segment */
812 a->segment_name = (char *) format (0, "%d:segment%d%c", utm->my_pid,
813 utm->unique_segment_index++, 0);
814 a->segment_size = utm->configured_segment_size;
815
816 rv = svm_fifo_segment_create (a);
817 if (rv)
818 {
819 clib_warning ("sm_fifo_segment_create ('%s') failed", a->segment_name);
820 rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
821 goto send_reply;
822 }
823
824 vec_add2 (utm->seg, seg, 1);
825
826 segment_index = vec_len (sm->segments) - 1;
Florin Corase04c2992017-03-01 08:17:34 -0800827 memcpy (seg, sm->segments + segment_index, sizeof (utm->seg[0]));
828
829 pool_get (utm->sessions, session);
830
Florin Coras7fb0fe12018-04-09 09:24:52 -0700831 session->rx_fifo = svm_fifo_segment_alloc_fifo
Dave Barach10d8cc62017-05-30 09:30:07 -0400832 (utm->seg, 128 * 1024, FIFO_SEGMENT_RX_FREELIST);
Florin Coras7fb0fe12018-04-09 09:24:52 -0700833 ASSERT (session->rx_fifo);
Florin Corase04c2992017-03-01 08:17:34 -0800834
Florin Coras7fb0fe12018-04-09 09:24:52 -0700835 session->tx_fifo = svm_fifo_segment_alloc_fifo
Dave Barach10d8cc62017-05-30 09:30:07 -0400836 (utm->seg, 128 * 1024, FIFO_SEGMENT_TX_FREELIST);
Florin Coras7fb0fe12018-04-09 09:24:52 -0700837 ASSERT (session->tx_fifo);
Florin Corase04c2992017-03-01 08:17:34 -0800838
Florin Coras7fb0fe12018-04-09 09:24:52 -0700839 session->rx_fifo->master_session_index = session - utm->sessions;
840 session->tx_fifo->master_session_index = session - utm->sessions;
Florin Corase04c2992017-03-01 08:17:34 -0800841 utm->cut_through_session_index = session - utm->sessions;
842
843 rv = pthread_create (&utm->cut_through_thread_handle,
844 NULL /*attr */ , cut_through_thread_fn, 0);
845 if (rv)
846 {
847 clib_warning ("pthread_create returned %d", rv);
848 rv = VNET_API_ERROR_SYSCALL_ERROR_1;
849 }
850
851send_reply:
852 rmp = vl_msg_api_alloc (sizeof (*rmp));
853 memset (rmp, 0, sizeof (*rmp));
854
Dave Wallace33e002b2017-09-06 01:20:02 -0400855 rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY);
Florin Corase04c2992017-03-01 08:17:34 -0800856 rmp->context = mp->context;
857 rmp->retval = ntohl (rv);
858 rmp->segment_name_length = vec_len (a->segment_name);
Dave Barach10d8cc62017-05-30 09:30:07 -0400859 if (session)
860 {
Florin Coras7fb0fe12018-04-09 09:24:52 -0700861 rmp->server_rx_fifo = pointer_to_uword (session->rx_fifo);
862 rmp->server_tx_fifo = pointer_to_uword (session->tx_fifo);
Dave Barach10d8cc62017-05-30 09:30:07 -0400863 }
864
Florin Corase04c2992017-03-01 08:17:34 -0800865 memcpy (rmp->segment_name, a->segment_name, vec_len (a->segment_name));
866
867 vec_free (a->segment_name);
868
Florin Corase86a8ed2018-01-05 03:20:25 -0800869 client_q = uword_to_pointer (mp->client_queue_address, svm_queue_t *);
Florin Corase04c2992017-03-01 08:17:34 -0800870 vl_msg_api_send_shmem (client_q, (u8 *) & rmp);
871}
872
873static void
Dave Barach68b0fb02017-02-28 15:15:56 -0500874vl_api_unbind_uri_reply_t_handler (vl_api_unbind_uri_reply_t * mp)
875{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700876 udp_echo_main_t *utm = &udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -0500877
878 if (mp->retval != 0)
879 clib_warning ("returned %d", ntohl (mp->retval));
880
881 utm->state = STATE_START;
882}
883
884static void
885vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
886{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700887 udp_echo_main_t *utm = &udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -0500888 vl_api_accept_session_reply_t *rmp;
889 svm_fifo_t *rx_fifo, *tx_fifo;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700890 app_session_t *session;
Dave Barach68b0fb02017-02-28 15:15:56 -0500891 static f64 start_time;
Florin Corasf8f516a2018-02-08 15:10:09 -0800892 u32 session_index;
893 int rv = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500894
895 if (start_time == 0.0)
896 start_time = clib_time_now (&utm->clib_time);
897
Florin Coras7fb0fe12018-04-09 09:24:52 -0700898 utm->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
899 svm_queue_t *);
Damjan Marion7bee80c2017-04-26 15:32:12 +0200900 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
Damjan Marion7bee80c2017-04-26 15:32:12 +0200901 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
Dave Barach68b0fb02017-02-28 15:15:56 -0500902
Florin Corasf8f516a2018-02-08 15:10:09 -0800903 pool_get (utm->sessions, session);
904 memset (session, 0, sizeof (*session));
905 session_index = session - utm->sessions;
Dave Barach68b0fb02017-02-28 15:15:56 -0500906
Florin Corasf8f516a2018-02-08 15:10:09 -0800907 /* Cut-through case */
908 if (mp->server_event_queue_address)
909 {
910 clib_warning ("cut-through session");
911 utm->our_event_queue = uword_to_pointer (mp->server_event_queue_address,
912 svm_queue_t *);
913 rx_fifo->master_session_index = session_index;
914 tx_fifo->master_session_index = session_index;
915 utm->cut_through_session_index = session_index;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700916 session->rx_fifo = rx_fifo;
917 session->tx_fifo = tx_fifo;
Dave Barach68b0fb02017-02-28 15:15:56 -0500918
Florin Corasf8f516a2018-02-08 15:10:09 -0800919 rv = pthread_create (&utm->cut_through_thread_handle,
920 NULL /*attr */ , cut_through_thread_fn, 0);
921 if (rv)
922 {
923 clib_warning ("pthread_create returned %d", rv);
924 rv = VNET_API_ERROR_SYSCALL_ERROR_1;
925 }
Florin Coras7fb0fe12018-04-09 09:24:52 -0700926 utm->do_echo = 1;
Florin Corasf8f516a2018-02-08 15:10:09 -0800927 }
928 else
929 {
930 rx_fifo->client_session_index = session_index;
931 tx_fifo->client_session_index = session_index;
Florin Coras7fb0fe12018-04-09 09:24:52 -0700932 session->rx_fifo = rx_fifo;
933 session->tx_fifo = tx_fifo;
934 clib_memcpy (&session->transport.rmt_ip, mp->ip,
935 sizeof (ip46_address_t));
936 session->transport.is_ip4 = mp->is_ip4;
937 session->transport.rmt_port = mp->port;
Florin Corasf8f516a2018-02-08 15:10:09 -0800938 }
939
940 hash_set (utm->session_index_by_vpp_handles, mp->handle, session_index);
Dave Barach68b0fb02017-02-28 15:15:56 -0500941 if (pool_elts (utm->sessions) && (pool_elts (utm->sessions) % 20000) == 0)
942 {
943 f64 now = clib_time_now (&utm->clib_time);
944 fformat (stdout, "%d active sessions in %.2f seconds, %.2f/sec...\n",
945 pool_elts (utm->sessions), now - start_time,
946 (f64) pool_elts (utm->sessions) / (now - start_time));
947 }
948
949 rmp = vl_msg_api_alloc (sizeof (*rmp));
950 memset (rmp, 0, sizeof (*rmp));
951 rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700952 rmp->handle = mp->handle;
Florin Coras3cbc04b2017-10-02 00:18:51 -0700953 rmp->context = mp->context;
Florin Corasf8f516a2018-02-08 15:10:09 -0800954 rmp->retval = rv;
Dave Barach68b0fb02017-02-28 15:15:56 -0500955 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & rmp);
Florin Coras3cbc04b2017-10-02 00:18:51 -0700956
957 CLIB_MEMORY_BARRIER ();
958 utm->state = STATE_READY;
Dave Barach68b0fb02017-02-28 15:15:56 -0500959}
960
961static void
962vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
963{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700964 udp_echo_main_t *utm = &udp_echo_main;
965 app_session_t *session;
Dave Barach68b0fb02017-02-28 15:15:56 -0500966 vl_api_disconnect_session_reply_t *rmp;
967 uword *p;
968 int rv = 0;
Dave Barach68b0fb02017-02-28 15:15:56 -0500969
Florin Coras6cf30ad2017-04-04 23:08:23 -0700970 p = hash_get (utm->session_index_by_vpp_handles, mp->handle);
Dave Barach68b0fb02017-02-28 15:15:56 -0500971
972 if (p)
973 {
974 session = pool_elt_at_index (utm->sessions, p[0]);
Florin Coras6cf30ad2017-04-04 23:08:23 -0700975 hash_unset (utm->session_index_by_vpp_handles, mp->handle);
Dave Barach68b0fb02017-02-28 15:15:56 -0500976 pool_put (utm->sessions, session);
977 }
978 else
979 {
Florin Coras6cf30ad2017-04-04 23:08:23 -0700980 clib_warning ("couldn't find session key %llx", mp->handle);
Dave Barach68b0fb02017-02-28 15:15:56 -0500981 rv = -11;
982 }
983
984 rmp = vl_msg_api_alloc (sizeof (*rmp));
985 memset (rmp, 0, sizeof (*rmp));
986 rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
987 rmp->retval = rv;
Florin Coras6cf30ad2017-04-04 23:08:23 -0700988 rmp->handle = mp->handle;
Florin Corasf8f516a2018-02-08 15:10:09 -0800989 rmp->context = mp->context;
Dave Barach68b0fb02017-02-28 15:15:56 -0500990 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & rmp);
991}
992
Florin Corase04c2992017-03-01 08:17:34 -0800993static void
Dave Wallace33e002b2017-09-06 01:20:02 -0400994vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
Florin Corase04c2992017-03-01 08:17:34 -0800995{
Florin Coras7fb0fe12018-04-09 09:24:52 -0700996 udp_echo_main_t *utm = &udp_echo_main;
997 unformat_input_t _input, *input = &_input;
998 session_endpoint_extended_t _sep, *sep = &_sep;
999 app_session_t *session;
Florin Corase04c2992017-03-01 08:17:34 -08001000
Florin Coras7fb0fe12018-04-09 09:24:52 -07001001 ASSERT (utm->i_am_server == 0);
Florin Corase04c2992017-03-01 08:17:34 -08001002
Florin Coras3cbc04b2017-10-02 00:18:51 -07001003 if (mp->retval)
1004 {
1005 clib_warning ("failed connect");
1006 return;
1007 }
1008
Florin Coras7fb0fe12018-04-09 09:24:52 -07001009 ASSERT (mp->server_rx_fifo && mp->server_tx_fifo);
Florin Corase04c2992017-03-01 08:17:34 -08001010
Florin Coras7fb0fe12018-04-09 09:24:52 -07001011 pool_get (utm->sessions, session);
1012 session->rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1013 session->tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1014 session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
1015 svm_queue_t *);
Florin Corasf8f516a2018-02-08 15:10:09 -08001016 /* Cut-through case */
1017 if (mp->client_event_queue_address)
1018 {
1019 clib_warning ("cut-through session");
1020 utm->cut_through_session_index = session - utm->sessions;
1021 utm->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1022 svm_queue_t *);
1023 utm->our_event_queue = uword_to_pointer (mp->client_event_queue_address,
1024 svm_queue_t *);
Florin Coras7fb0fe12018-04-09 09:24:52 -07001025 utm->do_echo = 1;
Florin Corasf8f516a2018-02-08 15:10:09 -08001026 }
Florin Coras3cbc04b2017-10-02 00:18:51 -07001027 else
1028 {
1029 utm->connected_session = session - utm->sessions;
1030 utm->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
Florin Corase86a8ed2018-01-05 03:20:25 -08001031 svm_queue_t *);
Florin Coras7fb0fe12018-04-09 09:24:52 -07001032
1033 clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
1034 sizeof (ip46_address_t));
1035 session->transport.is_ip4 = mp->is_ip4;
1036 session->transport.lcl_port = mp->lcl_port;
1037
1038 unformat_init_vector (input, utm->connect_uri);
1039 if (!unformat (input, "%U", unformat_uri, sep))
1040 {
1041 clib_warning ("can't figure out remote ip and port");
1042 utm->state = STATE_FAILED;
1043 unformat_free (input);
1044 return;
1045 }
1046 unformat_free (input);
1047 clib_memcpy (&session->transport.rmt_ip, &sep->ip,
1048 sizeof (ip46_address_t));
1049 session->transport.rmt_port = sep->port;
1050 session->is_dgram = !utm->is_connected;
Florin Coras3cbc04b2017-10-02 00:18:51 -07001051 }
Florin Corase04c2992017-03-01 08:17:34 -08001052 utm->state = STATE_READY;
1053}
1054
Florin Corasb384b542018-01-15 01:08:33 -08001055#define foreach_tcp_echo_msg \
Florin Coras6cf30ad2017-04-04 23:08:23 -07001056_(BIND_URI_REPLY, bind_uri_reply) \
1057_(CONNECT_URI, connect_uri) \
Dave Wallace33e002b2017-09-06 01:20:02 -04001058_(CONNECT_SESSION_REPLY, connect_session_reply) \
Florin Coras6cf30ad2017-04-04 23:08:23 -07001059_(UNBIND_URI_REPLY, unbind_uri_reply) \
1060_(ACCEPT_SESSION, accept_session) \
1061_(DISCONNECT_SESSION, disconnect_session) \
1062_(MAP_ANOTHER_SEGMENT, map_another_segment) \
Florin Corasf8f516a2018-02-08 15:10:09 -08001063_(UNMAP_SEGMENT, unmap_segment) \
Florin Coras6cf30ad2017-04-04 23:08:23 -07001064_(APPLICATION_ATTACH_REPLY, application_attach_reply) \
1065_(APPLICATION_DETACH_REPLY, application_detach_reply) \
Dave Barach68b0fb02017-02-28 15:15:56 -05001066
1067void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001068tcp_echo_api_hookup (udp_echo_main_t * utm)
Dave Barach68b0fb02017-02-28 15:15:56 -05001069{
1070#define _(N,n) \
1071 vl_msg_api_set_handlers(VL_API_##N, #n, \
Florin Corase04c2992017-03-01 08:17:34 -08001072 vl_api_##n##_t_handler, \
Dave Barach68b0fb02017-02-28 15:15:56 -05001073 vl_noop_handler, \
1074 vl_api_##n##_t_endian, \
1075 vl_api_##n##_t_print, \
1076 sizeof(vl_api_##n##_t), 1);
Florin Corasb384b542018-01-15 01:08:33 -08001077 foreach_tcp_echo_msg;
Dave Barach68b0fb02017-02-28 15:15:56 -05001078#undef _
1079
1080}
1081
Dave Barach68b0fb02017-02-28 15:15:56 -05001082int
1083connect_to_vpp (char *name)
1084{
Florin Coras7fb0fe12018-04-09 09:24:52 -07001085 udp_echo_main_t *utm = &udp_echo_main;
Dave Barach68b0fb02017-02-28 15:15:56 -05001086 api_main_t *am = &api_main;
1087
1088 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
1089 return -1;
1090
1091 utm->vl_input_queue = am->shmem_hdr->vl_input_queue;
1092 utm->my_client_index = am->my_client_index;
1093
1094 return 0;
1095}
1096
1097void
1098vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
1099{
1100 clib_warning ("BUG");
1101}
1102
1103static void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001104init_error_string_table (udp_echo_main_t * utm)
Dave Barach68b0fb02017-02-28 15:15:56 -05001105{
1106 utm->error_string_by_error_number = hash_create (0, sizeof (uword));
1107
1108#define _(n,v,s) hash_set (utm->error_string_by_error_number, -v, s);
1109 foreach_vnet_api_error;
1110#undef _
1111
1112 hash_set (utm->error_string_by_error_number, 99, "Misc");
1113}
1114
1115void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001116server_handle_fifo_event_rx (udp_echo_main_t * utm, session_fifo_event_t * e)
Dave Barach68b0fb02017-02-28 15:15:56 -05001117{
Florin Coras7fb0fe12018-04-09 09:24:52 -07001118 app_session_t *s;
Dave Barach68b0fb02017-02-28 15:15:56 -05001119 int rv;
1120
Florin Coras7fb0fe12018-04-09 09:24:52 -07001121 s = pool_elt_at_index (utm->sessions, e->fifo->client_session_index);
1122 app_recv (s, utm->rx_buf, vec_len (utm->rx_buf));
Dave Barach68b0fb02017-02-28 15:15:56 -05001123
Florin Coras7fb0fe12018-04-09 09:24:52 -07001124 if (utm->do_echo)
Dave Barach68b0fb02017-02-28 15:15:56 -05001125 {
Florin Coras7fb0fe12018-04-09 09:24:52 -07001126 do
1127 {
1128 rv = app_send_stream (s, utm->rx_buf, vec_len (utm->rx_buf), 0);
1129 }
1130 while (rv == SVM_FIFO_FULL);
Florin Coras6792ec02017-03-13 03:49:51 -07001131 }
Dave Barach68b0fb02017-02-28 15:15:56 -05001132}
1133
1134void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001135server_handle_event_queue (udp_echo_main_t * utm)
Dave Barach68b0fb02017-02-28 15:15:56 -05001136{
Florin Coras6792ec02017-03-13 03:49:51 -07001137 session_fifo_event_t _e, *e = &_e;
Dave Barach68b0fb02017-02-28 15:15:56 -05001138
Florin Coras3cbc04b2017-10-02 00:18:51 -07001139 while (utm->state != STATE_READY)
1140 sleep (5);
1141
Dave Barach68b0fb02017-02-28 15:15:56 -05001142 while (1)
1143 {
Mohsin Kazmi3fca5672018-01-04 18:57:26 +01001144 svm_queue_sub (utm->our_event_queue, (u8 *) e, SVM_Q_WAIT, 0);
Dave Barach68b0fb02017-02-28 15:15:56 -05001145 switch (e->event_type)
1146 {
Florin Corasa5464812017-04-19 13:00:05 -07001147 case FIFO_EVENT_APP_RX:
Florin Corase04c2992017-03-01 08:17:34 -08001148 server_handle_fifo_event_rx (utm, e);
Dave Barach68b0fb02017-02-28 15:15:56 -05001149 break;
1150
Florin Corasa5464812017-04-19 13:00:05 -07001151 case FIFO_EVENT_DISCONNECT:
Dave Barach68b0fb02017-02-28 15:15:56 -05001152 return;
1153
1154 default:
1155 clib_warning ("unknown event type %d", e->event_type);
1156 break;
1157 }
1158 if (PREDICT_FALSE (utm->time_to_stop == 1))
Florin Coras3cbc04b2017-10-02 00:18:51 -07001159 return;
Dave Barach68b0fb02017-02-28 15:15:56 -05001160 if (PREDICT_FALSE (utm->time_to_print_stats == 1))
1161 {
1162 utm->time_to_print_stats = 0;
1163 fformat (stdout, "%d connections\n", pool_elts (utm->sessions));
1164 }
1165 }
1166}
1167
Florin Coras6cf30ad2017-04-04 23:08:23 -07001168static void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001169server_unbind (udp_echo_main_t * utm)
Florin Coras6cf30ad2017-04-04 23:08:23 -07001170{
1171 vl_api_unbind_uri_t *ump;
1172
1173 ump = vl_msg_api_alloc (sizeof (*ump));
1174 memset (ump, 0, sizeof (*ump));
1175
1176 ump->_vl_msg_id = ntohs (VL_API_UNBIND_URI);
1177 ump->client_index = utm->my_client_index;
Florin Coras7fb0fe12018-04-09 09:24:52 -07001178 memcpy (ump->uri, utm->listen_uri, vec_len (utm->listen_uri));
Florin Coras6cf30ad2017-04-04 23:08:23 -07001179 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & ump);
1180}
1181
1182static void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001183server_bind (udp_echo_main_t * utm)
Dave Barach68b0fb02017-02-28 15:15:56 -05001184{
1185 vl_api_bind_uri_t *bmp;
Dave Barach68b0fb02017-02-28 15:15:56 -05001186
1187 bmp = vl_msg_api_alloc (sizeof (*bmp));
1188 memset (bmp, 0, sizeof (*bmp));
1189
1190 bmp->_vl_msg_id = ntohs (VL_API_BIND_URI);
1191 bmp->client_index = utm->my_client_index;
1192 bmp->context = ntohl (0xfeedface);
Florin Coras7fb0fe12018-04-09 09:24:52 -07001193 memcpy (bmp->uri, utm->listen_uri, vec_len (utm->listen_uri));
Dave Barach68b0fb02017-02-28 15:15:56 -05001194 vl_msg_api_send_shmem (utm->vl_input_queue, (u8 *) & bmp);
Florin Coras6cf30ad2017-04-04 23:08:23 -07001195}
1196
1197void
Florin Coras7fb0fe12018-04-09 09:24:52 -07001198udp_server_test (udp_echo_main_t * utm)
Florin Coras6cf30ad2017-04-04 23:08:23 -07001199{
Florin Coras7fb0fe12018-04-09 09:24:52 -07001200 u8 wait_for_state = utm->is_connected ? STATE_BOUND : STATE_READY;
Florin Corasa5464812017-04-19 13:00:05 -07001201 application_send_attach (utm);
Florin Coras6cf30ad2017-04-04 23:08:23 -07001202
1203 /* Bind to uri */
Florin Coras3cbc04b2017-10-02 00:18:51 -07001204 server_bind (utm);
Dave Barach68b0fb02017-02-28 15:15:56 -05001205
Florin Coras7fb0fe12018-04-09 09:24:52 -07001206 if (wait_for_state_change (utm, wait_for_state))
Dave Barach68b0fb02017-02-28 15:15:56 -05001207 {
Florin Coras7fb0fe12018-04-09 09:24:52 -07001208 clib_warning ("timeout waiting for state change");
Dave Barach68b0fb02017-02-28 15:15:56 -05001209 return;
1210 }
1211
Florin Corase04c2992017-03-01 08:17:34 -08001212 server_handle_event_queue (utm);
Dave Barach68b0fb02017-02-28 15:15:56 -05001213
Florin Coras6cf30ad2017-04-04 23:08:23 -07001214 /* Cleanup */
1215 server_unbind (utm);
Dave Barach68b0fb02017-02-28 15:15:56 -05001216
1217 if (wait_for_state_change (utm, STATE_START))
1218 {
1219 clib_warning ("timeout waiting for STATE_START");
1220 return;
1221 }
1222
Florin Coras6cf30ad2017-04-04 23:08:23 -07001223 application_detach (utm);
1224
Dave Barach68b0fb02017-02-28 15:15:56 -05001225 fformat (stdout, "Test complete...\n");
1226}
1227
1228int
1229main (int argc, char **argv)
1230{
Florin Coras7fb0fe12018-04-09 09:24:52 -07001231 udp_echo_main_t *utm = &udp_echo_main;
Florin Coras8e43d042018-05-04 15:46:57 -07001232 u8 *uri = (u8 *) "udp://6.0.1.1/1234";
Florin Corasb384b542018-01-15 01:08:33 -08001233 unformat_input_t _argv, *a = &_argv;
Florin Coras7fb0fe12018-04-09 09:24:52 -07001234 int i_am_server = 1;
1235 app_session_t *session;
Florin Corasb384b542018-01-15 01:08:33 -08001236 u8 *chroot_prefix;
1237 char *app_name;
1238 mheap_t *h;
1239 u8 *heap;
1240 u32 tmp;
1241 int i;
Dave Barach68b0fb02017-02-28 15:15:56 -05001242
1243 clib_mem_init (0, 256 << 20);
Dave Barach68b0fb02017-02-28 15:15:56 -05001244 heap = clib_mem_get_per_cpu_heap ();
1245 h = mheap_header (heap);
Dave Barach68b0fb02017-02-28 15:15:56 -05001246 /* make the main heap thread-safe */
1247 h->flags |= MHEAP_FLAG_THREAD_SAFE;
Florin Coras8e43d042018-05-04 15:46:57 -07001248 svm_fifo_segment_main_init (0x200000000ULL, 20);
Dave Barach68b0fb02017-02-28 15:15:56 -05001249
1250 vec_validate (utm->rx_buf, 8192);
Dave Barach68b0fb02017-02-28 15:15:56 -05001251 utm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
Florin Corase04c2992017-03-01 08:17:34 -08001252 utm->my_pid = getpid ();
1253 utm->configured_segment_size = 1 << 20;
Florin Corasf8f516a2018-02-08 15:10:09 -08001254 utm->segments_table = hash_create_vec (0, sizeof (u8), sizeof (u64));
Florin Coras8e43d042018-05-04 15:46:57 -07001255 utm->have_return = 1;
1256 utm->bytes_to_send = 1024;
Florin Coras7fb0fe12018-04-09 09:24:52 -07001257 utm->fifo_size = 128 << 10;
Florin Coras8e43d042018-05-04 15:46:57 -07001258 utm->segment_main = &svm_fifo_segment_main;
1259 utm->cut_through_session_index = ~0;
1260 clib_time_init (&utm->clib_time);
1261
1262 init_error_string_table (utm);
1263 unformat_init_command_line (a, argv);
Florin Coras7fb0fe12018-04-09 09:24:52 -07001264
Dave Barach68b0fb02017-02-28 15:15:56 -05001265 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
1266 {
1267 if (unformat (a, "chroot prefix %s", &chroot_prefix))
1268 {
1269 vl_set_memory_root_path ((char *) chroot_prefix);
1270 }
Florin Coras7fb0fe12018-04-09 09:24:52 -07001271 else if (unformat (a, "uri %s", &uri))
Dave Barach68b0fb02017-02-28 15:15:56 -05001272 ;
Florin Corase04c2992017-03-01 08:17:34 -08001273 else if (unformat (a, "segment-size %dM", &tmp))
1274 utm->configured_segment_size = tmp << 20;
1275 else if (unformat (a, "segment-size %dG", &tmp))
1276 utm->configured_segment_size = tmp << 30;
Florin Coras7fb0fe12018-04-09 09:24:52 -07001277 else if (unformat (a, "server"))
1278 i_am_server = 1;
1279 else if (unformat (a, "client"))
1280 i_am_server = 0;
Florin Coras8e43d042018-05-04 15:46:57 -07001281 else if (unformat (a, "no-return"))
1282 utm->have_return = 0;
1283 else if (unformat (a, "mbytes %d", &tmp))
1284 utm->bytes_to_send = (u64) tmp << 20;
1285 else if (unformat (a, "fifo-size %d", &tmp))
1286 utm->fifo_size = tmp << 10;
Dave Barach68b0fb02017-02-28 15:15:56 -05001287 else
1288 {
Florin Coras7fb0fe12018-04-09 09:24:52 -07001289 fformat (stderr, "%s: usage [server|client]\n");
Dave Barach68b0fb02017-02-28 15:15:56 -05001290 exit (1);
1291 }
1292 }
1293
Florin Coras7fb0fe12018-04-09 09:24:52 -07001294 utm->i_am_server = i_am_server;
Dave Barach68b0fb02017-02-28 15:15:56 -05001295
1296 setup_signal_handlers ();
Florin Corasb384b542018-01-15 01:08:33 -08001297 tcp_echo_api_hookup (utm);
Dave Barach68b0fb02017-02-28 15:15:56 -05001298
Florin Coras7fb0fe12018-04-09 09:24:52 -07001299 if (i_am_server)
1300 {
1301 utm->listen_uri = format (0, "%s%c", uri, 0);
1302 utm->is_connected = (utm->listen_uri[4] == 'c');
1303 app_name = "udp_echo_server";
1304 }
1305 else
1306 {
1307 app_name = "udp_echo_client";
1308 utm->connect_uri = format (0, "%s%c", uri, 0);
1309 utm->is_connected = (utm->connect_uri[4] == 'c');
1310 }
Florin Corasb384b542018-01-15 01:08:33 -08001311 if (connect_to_vpp (app_name) < 0)
Dave Barach68b0fb02017-02-28 15:15:56 -05001312 {
1313 svm_region_exit ();
1314 fformat (stderr, "Couldn't connect to vpe, exiting...\n");
1315 exit (1);
1316 }
1317
Florin Coras7fb0fe12018-04-09 09:24:52 -07001318 if (i_am_server == 0)
Florin Corase04c2992017-03-01 08:17:34 -08001319 {
Florin Coras3cbc04b2017-10-02 00:18:51 -07001320 client_test (utm);
Florin Coras8e43d042018-05-04 15:46:57 -07001321 goto done;
Florin Corase04c2992017-03-01 08:17:34 -08001322 }
1323
Dave Barach68b0fb02017-02-28 15:15:56 -05001324 /* $$$$ hack preallocation */
1325 for (i = 0; i < 200000; i++)
1326 {
1327 pool_get (utm->sessions, session);
1328 memset (session, 0, sizeof (*session));
1329 }
1330 for (i = 0; i < 200000; i++)
1331 pool_put_index (utm->sessions, i);
1332
Florin Coras6cf30ad2017-04-04 23:08:23 -07001333 udp_server_test (utm);
Dave Barach68b0fb02017-02-28 15:15:56 -05001334
Florin Coras8e43d042018-05-04 15:46:57 -07001335done:
Dave Barach68b0fb02017-02-28 15:15:56 -05001336 vl_client_disconnect_from_vlib ();
1337 exit (0);
1338}
1339
1340#undef vl_api_version
1341#define vl_api_version(n,v) static u32 vpe_api_version = v;
Florin Corase04c2992017-03-01 08:17:34 -08001342#include <vpp/api/vpe.api.h>
Dave Barach68b0fb02017-02-28 15:15:56 -05001343#undef vl_api_version
1344
1345void
1346vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
1347{
1348 /*
1349 * Send the main API signature in slot 0. This bit of code must
1350 * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
1351 */
1352 mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
1353}
1354
Florin Corase04c2992017-03-01 08:17:34 -08001355u32
1356vl (void *p)
1357{
1358 return vec_len (p);
1359}
1360
Dave Barach68b0fb02017-02-28 15:15:56 -05001361/*
1362 * fd.io coding-style-patch-verification: ON
1363 *
1364 * Local Variables:
1365 * eval: (c-set-style "gnu")
1366 * End:
1367 */