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:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
19 #include <hs_apps/sapi/vpp_echo_common.h>
28 format_ip4_address (u8 * s, va_list * args)
30 u8 *a = va_arg (*args, u8 *);
31 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
35 format_ip6_address (u8 * s, va_list * args)
37 ip6_address_t *a = va_arg (*args, ip6_address_t *);
38 u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
40 i_max_n_zero = ARRAY_LEN (a->as_u16);
42 i_first_zero = i_max_n_zero;
44 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
46 u32 is_zero = a->as_u16[i] == 0;
47 if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
53 if ((!is_zero && n_zeros > max_n_zeros)
54 || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
56 i_max_n_zero = i_first_zero;
57 max_n_zeros = n_zeros;
58 i_first_zero = ARRAY_LEN (a->as_u16);
63 last_double_colon = 0;
64 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
66 if (i == i_max_n_zero && max_n_zeros > 1)
70 last_double_colon = 1;
74 s = format (s, "%s%x",
75 (last_double_colon || i == 0) ? "" : ":",
76 clib_net_to_host_u16 (a->as_u16[i]));
77 last_double_colon = 0;
84 /* Format an IP46 address. */
86 format_ip46_address (u8 * s, va_list * args)
88 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
89 ip46_type_t type = va_arg (*args, ip46_type_t);
95 is_ip4 = ip46_address_is_ip4 (ip46);
106 format (s, "%U", format_ip4_address, &ip46->ip4) :
107 format (s, "%U", format_ip6_address, &ip46->ip6);
111 unformat_data (unformat_input_t * input, va_list * args)
114 u64 *a = va_arg (*args, u64 *);
115 if (unformat (input, "%lluGb", &_a))
117 else if (unformat (input, "%lluG", &_a))
119 else if (unformat (input, "%lluMb", &_a))
121 else if (unformat (input, "%lluM", &_a))
123 else if (unformat (input, "%lluKb", &_a))
125 else if (unformat (input, "%lluK", &_a))
127 else if (unformat (input, "%llu", a))
135 format_api_error (u8 * s, va_list * args)
137 echo_main_t *em = &echo_main;
138 i32 error = va_arg (*args, u32);
141 p = hash_get (em->error_string_by_error_number, -error);
144 s = format (s, "%s", p[0]);
146 s = format (s, "%d", error);
151 init_error_string_table ()
153 echo_main_t *em = &echo_main;
154 em->error_string_by_error_number = hash_create (0, sizeof (uword));
156 #define _(n,v,s) hash_set (em->error_string_by_error_number, -v, s);
157 foreach_vnet_api_error;
160 hash_set (em->error_string_by_error_number, 99, "Misc");
164 echo_format_app_state (u8 * s, va_list * args)
166 u32 state = va_arg (*args, u32);
167 if (state == STATE_START)
168 return format (s, "STATE_START");
169 if (state == STATE_ATTACHED)
170 return format (s, "STATE_ATTACHED");
171 if (state == STATE_LISTEN)
172 return format (s, "STATE_LISTEN");
173 if (state == STATE_READY)
174 return format (s, "STATE_READY");
175 if (state == STATE_DATA_DONE)
176 return format (s, "STATE_DATA_DONE");
177 if (state == STATE_DISCONNECTED)
178 return format (s, "STATE_DISCONNECTED");
179 if (state == STATE_DETACHED)
180 return format (s, "STATE_DETACHED");
182 return format (s, "unknown state");
186 echo_unformat_close (unformat_input_t * input, va_list * args)
188 u8 *a = va_arg (*args, u8 *);
189 if (unformat (input, "Y"))
190 *a = ECHO_CLOSE_F_ACTIVE;
191 else if (unformat (input, "N"))
192 *a = ECHO_CLOSE_F_NONE;
193 else if (unformat (input, "W"))
194 *a = ECHO_CLOSE_F_PASSIVE;
201 echo_unformat_timing_event (unformat_input_t * input, va_list * args)
203 u8 *a = va_arg (*args, u8 *);
204 if (unformat (input, "start"))
206 else if (unformat (input, "qconnected"))
207 *a = ECHO_EVT_LAST_QCONNECTED;
208 else if (unformat (input, "qconnect"))
209 *a = ECHO_EVT_FIRST_QCONNECT;
210 else if (unformat (input, "sconnected"))
211 *a = ECHO_EVT_LAST_SCONNECTED;
212 else if (unformat (input, "sconnect"))
213 *a = ECHO_EVT_FIRST_SCONNECT;
214 else if (unformat (input, "lastbyte"))
215 *a = ECHO_EVT_LAST_BYTE;
216 else if (unformat (input, "exit"))
224 echo_format_timing_event (u8 * s, va_list * args)
226 u32 timing_event = va_arg (*args, u32);
227 if (timing_event == ECHO_EVT_START)
228 return format (s, "start");
229 if (timing_event == ECHO_EVT_FIRST_QCONNECT)
230 return format (s, "qconnect");
231 if (timing_event == ECHO_EVT_LAST_QCONNECTED)
232 return format (s, "qconnected");
233 if (timing_event == ECHO_EVT_FIRST_SCONNECT)
234 return format (s, "sconnect");
235 if (timing_event == ECHO_EVT_LAST_SCONNECTED)
236 return format (s, "sconnected");
237 if (timing_event == ECHO_EVT_LAST_BYTE)
238 return format (s, "lastbyte");
239 if (timing_event == ECHO_EVT_EXIT)
240 return format (s, "exit");
242 return format (s, "unknown timing event");
246 unformat_transport_proto (unformat_input_t * input, va_list * args)
248 u32 *proto = va_arg (*args, u32 *);
249 if (unformat (input, "tcp"))
250 *proto = TRANSPORT_PROTO_TCP;
251 else if (unformat (input, "TCP"))
252 *proto = TRANSPORT_PROTO_TCP;
253 else if (unformat (input, "udpc"))
254 *proto = TRANSPORT_PROTO_UDPC;
255 else if (unformat (input, "UDPC"))
256 *proto = TRANSPORT_PROTO_UDPC;
257 else if (unformat (input, "udp"))
258 *proto = TRANSPORT_PROTO_UDP;
259 else if (unformat (input, "UDP"))
260 *proto = TRANSPORT_PROTO_UDP;
261 else if (unformat (input, "sctp"))
262 *proto = TRANSPORT_PROTO_SCTP;
263 else if (unformat (input, "SCTP"))
264 *proto = TRANSPORT_PROTO_SCTP;
265 else if (unformat (input, "tls"))
266 *proto = TRANSPORT_PROTO_TLS;
267 else if (unformat (input, "TLS"))
268 *proto = TRANSPORT_PROTO_TLS;
269 else if (unformat (input, "quic"))
270 *proto = TRANSPORT_PROTO_QUIC;
271 else if (unformat (input, "QUIC"))
272 *proto = TRANSPORT_PROTO_QUIC;
279 format_transport_proto (u8 * s, va_list * args)
281 u32 transport_proto = va_arg (*args, u32);
282 switch (transport_proto)
284 case TRANSPORT_PROTO_TCP:
285 s = format (s, "TCP");
287 case TRANSPORT_PROTO_UDP:
288 s = format (s, "UDP");
290 case TRANSPORT_PROTO_SCTP:
291 s = format (s, "SCTP");
293 case TRANSPORT_PROTO_NONE:
294 s = format (s, "NONE");
296 case TRANSPORT_PROTO_TLS:
297 s = format (s, "TLS");
299 case TRANSPORT_PROTO_UDPC:
300 s = format (s, "UDPC");
302 case TRANSPORT_PROTO_QUIC:
303 s = format (s, "QUIC");
306 s = format (s, "UNKNOWN");
313 unformat_ip4_address (unformat_input_t * input, va_list * args)
315 u8 *result = va_arg (*args, u8 *);
318 if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
321 if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
333 unformat_ip6_address (unformat_input_t * input, va_list * args)
335 ip6_address_t *result = va_arg (*args, ip6_address_t *);
337 uword hex_quad, n_hex_quads, hex_digit, n_hex_digits;
338 uword c, n_colon, double_colon_index;
340 n_hex_quads = hex_quad = n_hex_digits = n_colon = 0;
341 double_colon_index = ARRAY_LEN (hex_quads);
342 while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
345 if (c >= '0' && c <= '9')
347 else if (c >= 'a' && c <= 'f')
348 hex_digit = c + 10 - 'a';
349 else if (c >= 'A' && c <= 'F')
350 hex_digit = c + 10 - 'A';
351 else if (c == ':' && n_colon < 2)
355 unformat_put_input (input);
359 /* Too many hex quads. */
360 if (n_hex_quads >= ARRAY_LEN (hex_quads))
365 hex_quad = (hex_quad << 4) | hex_digit;
367 /* Hex quad must fit in 16 bits. */
368 if (n_hex_digits >= 4)
375 /* Save position of :: */
378 /* More than one :: ? */
379 if (double_colon_index < ARRAY_LEN (hex_quads))
381 double_colon_index = n_hex_quads;
384 if (n_colon > 0 && n_hex_digits > 0)
386 hex_quads[n_hex_quads++] = hex_quad;
392 if (n_hex_digits > 0)
393 hex_quads[n_hex_quads++] = hex_quad;
398 /* Expand :: to appropriate number of zero hex quads. */
399 if (double_colon_index < ARRAY_LEN (hex_quads))
401 word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads;
403 for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--)
404 hex_quads[n_zero + i] = hex_quads[i];
406 for (i = 0; i < n_zero; i++)
407 hex_quads[double_colon_index + i] = 0;
409 n_hex_quads = ARRAY_LEN (hex_quads);
412 /* Too few hex quads given. */
413 if (n_hex_quads < ARRAY_LEN (hex_quads))
416 for (i = 0; i < ARRAY_LEN (hex_quads); i++)
417 result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]);
425 * End of format functions
430 echo_session_handle_add_del (echo_main_t * em, u64 handle, u32 sid)
432 clib_spinlock_lock (&em->sid_vpp_handles_lock);
433 if (sid == SESSION_INVALID_INDEX)
434 hash_unset (em->session_index_by_vpp_handles, handle);
436 hash_set (em->session_index_by_vpp_handles, handle, sid);
437 clib_spinlock_unlock (&em->sid_vpp_handles_lock);
441 echo_session_new (echo_main_t * em)
443 /* thread safe new prealloced session */
444 return pool_elt_at_index (em->sessions,
445 clib_atomic_fetch_add (&em->nxt_available_sidx,
450 echo_send_rpc (echo_main_t * em, void *fp, void *arg, u32 opaque)
454 if (PREDICT_FALSE (svm_msg_q_lock (em->rpc_msq_queue)))
456 ECHO_LOG (1, "RPC lock failed");
459 if (PREDICT_FALSE (svm_msg_q_ring_is_full (em->rpc_msq_queue, 0)))
461 svm_msg_q_unlock (em->rpc_msq_queue);
462 ECHO_LOG (1, "RPC ring is full");
465 msg = svm_msg_q_alloc_msg_w_ring (em->rpc_msq_queue, 0);
466 if (PREDICT_FALSE (svm_msg_q_msg_is_invalid (&msg)))
468 ECHO_LOG (1, "RPC msg is invalid");
469 svm_msg_q_unlock (em->rpc_msq_queue);
472 evt = (echo_rpc_msg_t *) svm_msg_q_msg_data (em->rpc_msq_queue, &msg);
474 evt->opaque = opaque;
477 svm_msg_q_add_and_unlock (em->rpc_msq_queue, &msg);
482 echo_get_session_from_handle (echo_main_t * em, u64 handle)
485 clib_spinlock_lock (&em->sid_vpp_handles_lock);
486 p = hash_get (em->session_index_by_vpp_handles, handle);
487 clib_spinlock_unlock (&em->sid_vpp_handles_lock);
490 ECHO_FAIL ("unknown handle 0x%lx", handle);
493 return pool_elt_at_index (em->sessions, p[0]);
497 wait_for_segment_allocation (u64 segment_handle)
499 echo_main_t *em = &echo_main;
501 timeout = clib_time_now (&em->clib_time) + TIMEOUT;
502 uword *segment_present;
503 ECHO_LOG (1, "Waiting for segment 0x%lx...", segment_handle);
504 while (clib_time_now (&em->clib_time) < timeout)
506 clib_spinlock_lock (&em->segment_handles_lock);
507 segment_present = hash_get (em->shared_segment_handles, segment_handle);
508 clib_spinlock_unlock (&em->segment_handles_lock);
509 if (segment_present != 0)
511 if (em->time_to_stop == 1)
514 ECHO_LOG (1, "timeout wait_for_segment_allocation (0x%lx)", segment_handle);
519 wait_for_state_change (echo_main_t * em, connection_state_t state,
522 f64 end_time = clib_time_now (&em->clib_time) + timeout;
523 while (!timeout || clib_time_now (&em->clib_time) < end_time)
525 if (em->state == state)
527 if (em->time_to_stop)
530 ECHO_LOG (1, "timeout waiting for %U", echo_format_app_state, state);
535 echo_notify_event (echo_main_t * em, echo_test_evt_t e)
537 if (em->timing.events_sent & e)
539 if (em->timing.start_event == e)
540 em->timing.start_time = clib_time_now (&em->clib_time);
541 else if (em->timing.end_event == e)
542 em->timing.end_time = clib_time_now (&em->clib_time);
543 em->timing.events_sent |= e;
547 echo_session_print_stats (echo_main_t * em, echo_session_t * session)
549 f64 deltat = clib_time_now (&em->clib_time) - session->start;
550 ECHO_LOG (0, "Session 0x%x done in %.6fs RX[%.4f] TX[%.4f] Gbit/s\n",
551 session->vpp_session_handle, deltat,
552 (session->bytes_received * 8.0) / deltat / 1e9,
553 (session->bytes_sent * 8.0) / deltat / 1e9);
557 * fd.io coding-style-patch-verification: ON
560 * eval: (c-set-style "gnu")