FD.io VPP  v21.06
Vector Packet Processing
vpp_echo_common.c
Go to the documentation of this file.
1 /*
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 
20 
21 char *echo_fail_code_str[] = {
22 #define _(sym, str) str,
24 #undef _
25 };
26 
27 /*
28  *
29  * Format functions
30  *
31  */
32 
33 u8 *
34 format_ip4_address (u8 * s, va_list * args)
35 {
36  u8 *a = va_arg (*args, u8 *);
37  return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
38 }
39 
40 u8 *
41 format_ip6_address (u8 * s, va_list * args)
42 {
43  ip6_address_t *a = va_arg (*args, ip6_address_t *);
44  u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
45 
46  i_max_n_zero = ARRAY_LEN (a->as_u16);
47  max_n_zeros = 0;
48  i_first_zero = i_max_n_zero;
49  n_zeros = 0;
50  for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
51  {
52  u32 is_zero = a->as_u16[i] == 0;
53  if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
54  {
55  i_first_zero = i;
56  n_zeros = 0;
57  }
58  n_zeros += is_zero;
59  if ((!is_zero && n_zeros > max_n_zeros)
60  || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
61  {
62  i_max_n_zero = i_first_zero;
63  max_n_zeros = n_zeros;
64  i_first_zero = ARRAY_LEN (a->as_u16);
65  n_zeros = 0;
66  }
67  }
68 
69  last_double_colon = 0;
70  for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
71  {
72  if (i == i_max_n_zero && max_n_zeros > 1)
73  {
74  s = format (s, "::");
75  i += max_n_zeros - 1;
76  last_double_colon = 1;
77  }
78  else
79  {
80  s = format (s, "%s%x",
81  (last_double_colon || i == 0) ? "" : ":",
82  clib_net_to_host_u16 (a->as_u16[i]));
83  last_double_colon = 0;
84  }
85  }
86 
87  return s;
88 }
89 
90 /* Format an IP46 address. */
91 u8 *
92 format_ip46_address (u8 * s, va_list * args)
93 {
94  ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
95  ip46_type_t type = va_arg (*args, ip46_type_t);
96  int is_ip4 = 1;
97 
98  switch (type)
99  {
100  case IP46_TYPE_ANY:
101  is_ip4 = ip46_address_is_ip4 (ip46);
102  break;
103  case IP46_TYPE_IP4:
104  is_ip4 = 1;
105  break;
106  case IP46_TYPE_IP6:
107  is_ip4 = 0;
108  break;
109  }
110 
111  return is_ip4 ?
112  format (s, "%U", format_ip4_address, &ip46->ip4) :
113  format (s, "%U", format_ip6_address, &ip46->ip6);
114 }
115 
116 u8 *
117 format_api_error (u8 * s, va_list * args)
118 {
119  echo_main_t *em = &echo_main;
120  i32 error = va_arg (*args, u32);
121  uword *p;
122 
123  p = hash_get (em->error_string_by_error_number, -error);
124 
125  if (p)
126  s = format (s, "%s", p[0]);
127  else
128  s = format (s, "%d", error);
129  return s;
130 }
131 
132 void
134 {
135  echo_main_t *em = &echo_main;
136  em->error_string_by_error_number = hash_create (0, sizeof (uword));
137 
138 #define _(n,v,s) hash_set (em->error_string_by_error_number, -v, s);
140 #undef _
141 
142  hash_set (em->error_string_by_error_number, 99, "Misc");
143 }
144 
145 u8 *
146 echo_format_session (u8 * s, va_list * args)
147 {
148  echo_session_t *session = va_arg (*args, echo_session_t *);
149 
150  return format (s, "%U 0x%lx S[%u]", echo_format_session_type,
151  session->session_type, session->vpp_session_handle,
152  session->session_index);
153 }
154 
155 u8 *
156 echo_format_session_type (u8 * s, va_list * args)
157 {
158  u32 session_type = va_arg (*args, u32);
159  switch (session_type)
160  {
162  return format (s, "Qsession");
164  return format (s, "Stream");
166  return format (s, "Lsession");
167  default:
168  break;
169  }
170  return format (s, "BadSession");
171 }
172 
173 u8 *
174 echo_format_session_state (u8 * s, va_list * args)
175 {
176  u32 session_state = va_arg (*args, u32);
177  switch (session_state)
178  {
180  return format (s, "ECHO_SESSION_STATE_INITIAL (%u)", session_state);
182  return format (s, "ECHO_SESSION_STATE_READY (%u)", session_state);
184  return format (s, "ECHO_SESSION_STATE_AWAIT_CLOSING (%u)",
185  session_state);
187  return format (s, "ECHO_SESSION_STATE_AWAIT_DATA (%u)", session_state);
189  return format (s, "ECHO_SESSION_STATE_CLOSING (%u)", session_state);
191  return format (s, "ECHO_SESSION_STATE_CLOSED (%u)", session_state);
192  default:
193  break;
194  }
195  return format (s, "unknown session state (%u)", session_state);
196 }
197 
198 u8 *
199 echo_format_app_state (u8 * s, va_list * args)
200 {
201  u32 state = va_arg (*args, u32);
202  if (state == STATE_START)
203  return format (s, "STATE_START (%u)", state);
204  if (state == STATE_ATTACHED)
205  return format (s, "STATE_ATTACHED (%u)", state);
206  if (state == STATE_ATTACHED_NO_CERT)
207  return format (s, "STATE_ATTACHED_NO_CERT (%u)", state);
208  if (state == STATE_LISTEN)
209  return format (s, "STATE_LISTEN (%u)", state);
210  if (state == STATE_READY)
211  return format (s, "STATE_READY (%u)", state);
212  if (state == STATE_DATA_DONE)
213  return format (s, "STATE_DATA_DONE (%u)", state);
214  if (state == STATE_DISCONNECTED)
215  return format (s, "STATE_DISCONNECTED (%u)", state);
216  if (state == STATE_DETACHED)
217  return format (s, "STATE_DETACHED (%u)", state);
218  else
219  return format (s, "unknown state (%u)", state);
220 }
221 
222 uword
223 echo_unformat_close (unformat_input_t * input, va_list * args)
224 {
225  u8 *a = va_arg (*args, u8 *);
226  if (unformat (input, "Y"))
227  *a = ECHO_CLOSE_F_ACTIVE;
228  else if (unformat (input, "N"))
229  *a = ECHO_CLOSE_F_NONE;
230  else if (unformat (input, "W"))
232  else
233  return 0;
234  return 1;
235 }
236 
237 uword
239 {
240  u8 *a = va_arg (*args, u8 *);
241  if (unformat (input, "start"))
242  *a = ECHO_EVT_START;
243  else if (unformat (input, "qconnected"))
245  else if (unformat (input, "qconnect"))
247  else if (unformat (input, "sconnected"))
249  else if (unformat (input, "sconnect"))
251  else if (unformat (input, "lastbyte"))
252  *a = ECHO_EVT_LAST_BYTE;
253  else if (unformat (input, "exit"))
254  *a = ECHO_EVT_EXIT;
255  else
256  return 0;
257  return 1;
258 }
259 
260 u8 *
261 echo_format_bytes_per_sec (u8 * s, va_list * args)
262 {
263  f64 bps = va_arg (*args, f64) * 8;
264  if (bps > 1e9)
265  return format (s, "%.3f Gb/s", bps / 1e9);
266  else if (bps > 1e6)
267  return format (s, "%.3f Mb/s", bps / 1e6);
268  else if (bps > 1e3)
269  return format (s, "%.3f Kb/s", bps / 1e3);
270  else
271  return format (s, "%.3f b/s", bps);
272 }
273 
274 u8 *
275 echo_format_timing_event (u8 * s, va_list * args)
276 {
277  u32 timing_event = va_arg (*args, u32);
278  if (timing_event == ECHO_EVT_START)
279  return format (s, "start");
280  if (timing_event == ECHO_EVT_FIRST_QCONNECT)
281  return format (s, "qconnect");
282  if (timing_event == ECHO_EVT_LAST_QCONNECTED)
283  return format (s, "qconnected");
284  if (timing_event == ECHO_EVT_FIRST_SCONNECT)
285  return format (s, "sconnect");
286  if (timing_event == ECHO_EVT_LAST_SCONNECTED)
287  return format (s, "sconnected");
288  if (timing_event == ECHO_EVT_LAST_BYTE)
289  return format (s, "lastbyte");
290  if (timing_event == ECHO_EVT_EXIT)
291  return format (s, "exit");
292  else
293  return format (s, "unknown timing event");
294 }
295 
296 uword
298 {
299  u32 *proto = va_arg (*args, u32 *);
300  if (unformat (input, "tcp"))
301  *proto = TRANSPORT_PROTO_TCP;
302  else if (unformat (input, "TCP"))
303  *proto = TRANSPORT_PROTO_TCP;
304  else if (unformat (input, "udp"))
305  *proto = TRANSPORT_PROTO_UDP;
306  else if (unformat (input, "UDP"))
307  *proto = TRANSPORT_PROTO_UDP;
308  else if (unformat (input, "tls"))
309  *proto = TRANSPORT_PROTO_TLS;
310  else if (unformat (input, "TLS"))
311  *proto = TRANSPORT_PROTO_TLS;
312  else if (unformat (input, "quic"))
313  *proto = TRANSPORT_PROTO_QUIC;
314  else if (unformat (input, "QUIC"))
315  *proto = TRANSPORT_PROTO_QUIC;
316  else
317  return 0;
318  return 1;
319 }
320 
321 u8 *
322 format_transport_proto (u8 * s, va_list * args)
323 {
324  u32 transport_proto = va_arg (*args, u32);
325  switch (transport_proto)
326  {
327  case TRANSPORT_PROTO_TCP:
328  s = format (s, "TCP");
329  break;
330  case TRANSPORT_PROTO_UDP:
331  s = format (s, "UDP");
332  break;
333  case TRANSPORT_PROTO_NONE:
334  s = format (s, "NONE");
335  break;
336  case TRANSPORT_PROTO_TLS:
337  s = format (s, "TLS");
338  break;
339  case TRANSPORT_PROTO_QUIC:
340  s = format (s, "QUIC");
341  break;
342  case TRANSPORT_PROTO_DTLS:
343  s = format (s, "DTLS");
344  break;
345  case TRANSPORT_PROTO_SRTP:
346  s = format (s, "SRTP");
347  break;
348  default:
349  s = format (s, "UNKNOWN");
350  break;
351  }
352  return s;
353 }
354 
355 uword
356 unformat_ip4_address (unformat_input_t * input, va_list * args)
357 {
358  u8 *result = va_arg (*args, u8 *);
359  unsigned a[4];
360 
361  if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
362  return 0;
363 
364  if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
365  return 0;
366 
367  result[0] = a[0];
368  result[1] = a[1];
369  result[2] = a[2];
370  result[3] = a[3];
371 
372  return 1;
373 }
374 
375 uword
376 unformat_ip6_address (unformat_input_t * input, va_list * args)
377 {
378  ip6_address_t *result = va_arg (*args, ip6_address_t *);
379  u16 hex_quads[8];
380  uword hex_quad, n_hex_quads, hex_digit, n_hex_digits;
381  uword c, n_colon, double_colon_index;
382 
383  n_hex_quads = hex_quad = n_hex_digits = n_colon = 0;
384  double_colon_index = ARRAY_LEN (hex_quads);
385  while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
386  {
387  hex_digit = 16;
388  if (c >= '0' && c <= '9')
389  hex_digit = c - '0';
390  else if (c >= 'a' && c <= 'f')
391  hex_digit = c + 10 - 'a';
392  else if (c >= 'A' && c <= 'F')
393  hex_digit = c + 10 - 'A';
394  else if (c == ':' && n_colon < 2)
395  n_colon++;
396  else
397  {
398  unformat_put_input (input);
399  break;
400  }
401 
402  /* Too many hex quads. */
403  if (n_hex_quads >= ARRAY_LEN (hex_quads))
404  return 0;
405 
406  if (hex_digit < 16)
407  {
408  hex_quad = (hex_quad << 4) | hex_digit;
409 
410  /* Hex quad must fit in 16 bits. */
411  if (n_hex_digits >= 4)
412  return 0;
413 
414  n_colon = 0;
415  n_hex_digits++;
416  }
417 
418  /* Save position of :: */
419  if (n_colon == 2)
420  {
421  /* More than one :: ? */
422  if (double_colon_index < ARRAY_LEN (hex_quads))
423  return 0;
424  double_colon_index = n_hex_quads;
425  }
426 
427  if (n_colon > 0 && n_hex_digits > 0)
428  {
429  hex_quads[n_hex_quads++] = hex_quad;
430  hex_quad = 0;
431  n_hex_digits = 0;
432  }
433  }
434 
435  if (n_hex_digits > 0)
436  hex_quads[n_hex_quads++] = hex_quad;
437 
438  {
439  word i;
440 
441  /* Expand :: to appropriate number of zero hex quads. */
442  if (double_colon_index < ARRAY_LEN (hex_quads))
443  {
444  word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads;
445 
446  for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--)
447  hex_quads[n_zero + i] = hex_quads[i];
448 
449  for (i = 0; i < n_zero; i++)
450  hex_quads[double_colon_index + i] = 0;
451 
452  n_hex_quads = ARRAY_LEN (hex_quads);
453  }
454 
455  /* Too few hex quads given. */
456  if (n_hex_quads < ARRAY_LEN (hex_quads))
457  return 0;
458 
459  for (i = 0; i < ARRAY_LEN (hex_quads); i++)
460  result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]);
461 
462  return 1;
463  }
464 }
465 
466 uword
467 unformat_ip46_address (unformat_input_t * input, va_list * args)
468 {
469  ip46_address_t *ip = va_arg (*args, ip46_address_t *);
470 
471  if (unformat (input, "%U", unformat_ip4_address, &ip->ip4))
472  ;
473  else if (unformat (input, "%U", unformat_ip6_address, &ip->ip6))
474  ;
475  else
476  return 0;
477  return 1;
478 }
479 
480 u8 *
481 echo_format_crypto_engine (u8 * s, va_list * args)
482 {
483  u32 state = va_arg (*args, u32);
484  if (state == CRYPTO_ENGINE_MBEDTLS)
485  return format (s, "mbedtls");
486  if (state == CRYPTO_ENGINE_OPENSSL)
487  return format (s, "openssl");
488  if (state == CRYPTO_ENGINE_PICOTLS)
489  return format (s, "picotls");
490  if (state == CRYPTO_ENGINE_VPP)
491  return format (s, "vpp");
492  else
493  return format (s, "unknown crypto engine");
494 }
495 
496 uword
498 {
499  u8 *a = va_arg (*args, u8 *);
500  if (unformat (input, "mbedtls"))
502  else if (unformat (input, "openssl"))
504  else if (unformat (input, "picotls"))
506  else if (unformat (input, "vpp"))
507  *a = CRYPTO_ENGINE_VPP;
508  else
509  return 0;
510  return 1;
511 }
512 
513 
514 /*
515  *
516  * End of format functions
517  *
518  */
519 
520 void
522 {
524  if (sid == SESSION_INVALID_INDEX)
525  {
526  ECHO_LOG (3, "hash_unset(0x%lx)", handle);
528  }
529  else
530  {
531  ECHO_LOG (3, "hash_set(0x%lx) S[%d]", handle, sid);
532  hash_set (em->session_index_by_vpp_handles, handle, sid);
533  }
535 }
536 
539 {
540  /* thread safe new prealloced session
541  * see echo_session_prealloc */
542  return pool_elt_at_index (em->sessions,
544  1));
545 }
546 
547 int
548 echo_send_rpc (echo_main_t * em, void *fp, echo_rpc_args_t * args)
549 {
550  svm_msg_q_msg_t msg;
551  echo_rpc_msg_t *evt;
553  {
554  ECHO_FAIL (ECHO_FAIL_RPC_SIZE, "RPC lock failed");
555  return -1;
556  }
558  {
560  ECHO_FAIL (ECHO_FAIL_RPC_SIZE, "RPC ring is full");
561  return -2;
562  }
564  evt = (echo_rpc_msg_t *) svm_msg_q_msg_data (&em->rpc_msq_queue, &msg);
565  evt->fp = fp;
566  clib_memcpy (&evt->args, args, sizeof (evt->args));
567 
569  return 0;
570 }
571 
574 {
575  uword *p;
577  p = hash_get (em->session_index_by_vpp_handles, handle);
579  if (!p)
580  {
581  ECHO_LOG (2, "unknown handle 0x%lx", handle);
582  return 0;
583  }
584  return pool_elt_at_index (em->sessions, p[0]);
585 }
586 
587 int
589  f64 timeout)
590 {
591  f64 end_time = clib_time_now (&em->clib_time) + timeout;
592  while (!timeout || clib_time_now (&em->clib_time) < end_time)
593  {
594  if (em->state == state)
595  return 0;
596  if (em->time_to_stop)
597  return 1;
598  }
599  ECHO_LOG (2, "timeout waiting for %U", echo_format_app_state, state);
600  return -1;
601 }
602 
603 void
605 {
606  if (em->timing.events_sent & e)
607  return;
608  if (em->timing.start_event == e)
610  else if (em->timing.end_event == e)
611  em->timing.end_time = clib_time_now (&em->clib_time);
612  em->timing.events_sent |= e;
613 }
614 
615 void
617 {
618  f64 deltat = clib_time_now (&em->clib_time) - session->start;
619  ECHO_LOG (1, "Session 0x%x done in %.6fs RX[%.4f] TX[%.4f] Gbit/s\n",
620  session->vpp_session_handle, deltat,
621  (session->bytes_received * 8.0) / deltat / 1e9,
622  (session->bytes_sent * 8.0) / deltat / 1e9);
623 }
624 
625 /*
626  * fd.io coding-style-patch-verification: ON
627  *
628  * Local Variables:
629  * eval: (c-set-style "gnu")
630  * End:
631  */
clib_time_t clib_time
#define hash_set(h, key, value)
Definition: hash.h:255
void * svm_msg_q_msg_data(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Get data for message in queue.
static u8 svm_msg_q_ring_is_full(svm_msg_q_t *mq, u32 ring_index)
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
u8 * echo_format_timing_event(u8 *s, va_list *args)
u8 * echo_format_session(u8 *s, va_list *args)
#define hash_unset(h, key)
Definition: hash.h:261
a
Definition: bitmap.h:544
transport_proto
Definition: session.api:22
uword unformat_ip6_address(unformat_input_t *input, va_list *args)
echo_session_t * sessions
u8 * format_ip6_address(u8 *s, va_list *args)
clib_spinlock_t sid_vpp_handles_lock
static uword unformat_get_input(unformat_input_t *input)
Definition: format.h:184
unsigned long u64
Definition: types.h:89
static f64 clib_time_now(clib_time_t *c)
Definition: time.h:230
uword echo_unformat_timing_event(unformat_input_t *input, va_list *args)
uword unformat_ip4_address(unformat_input_t *input, va_list *args)
echo_main_t echo_main
Definition: vpp_echo.c:24
volatile connection_state_t state
char * echo_fail_code_str[]
uword echo_unformat_crypto_engine(unformat_input_t *input, va_list *args)
static u8 ip46_address_is_ip4(const ip46_address_t *ip46)
Definition: ip46_address.h:55
unsigned char u8
Definition: types.h:56
int wait_for_state_change(echo_main_t *em, connection_state_t state, f64 timeout)
foreach_app_session_field u64 vpp_session_handle
double f64
Definition: types.h:142
unsigned int u32
Definition: types.h:88
#define clib_memcpy(d, s, n)
Definition: string.h:197
u8 * echo_format_session_state(u8 *s, va_list *args)
echo_session_t * echo_session_new(echo_main_t *em)
i64 word
Definition: types.h:111
connection_state_t
volatile u64 bytes_received
void echo_session_handle_add_del(echo_main_t *em, u64 handle, u32 sid)
description fragment has unexpected format
Definition: map.api:433
#define ECHO_FAIL(fail, _fmt, _args...)
uword unformat_ip46_address(unformat_input_t *input, va_list *args)
vl_api_fib_path_type_t type
Definition: fib_types.api:123
Definition: cJSON.c:88
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
void init_error_string_table()
vl_api_ip_proto_t proto
Definition: acl_types.api:51
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u8 * echo_format_bytes_per_sec(u8 *s, va_list *args)
#define PREDICT_FALSE(x)
Definition: clib.h:124
u8 * echo_format_app_state(u8 *s, va_list *args)
uword * error_string_by_error_number
static void unformat_put_input(unformat_input_t *input)
Definition: format.h:197
#define SESSION_INVALID_INDEX
Definition: session_types.h:22
u8 * format_ip46_address(u8 *s, va_list *args)
enum echo_test_evt_ echo_test_evt_t
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
svmdb_client_t * c
static void svm_msg_q_unlock(svm_msg_q_t *mq)
Unlock message queue.
u8 * format_ip4_address(u8 *s, va_list *args)
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
struct echo_main_t::@680 timing
#define ECHO_LOG(lvl, _fmt, _args...)
void echo_notify_event(echo_main_t *em, echo_test_evt_t e)
volatile u8 time_to_stop
#define ARRAY_LEN(x)
Definition: clib.h:70
uword unformat_transport_proto(unformat_input_t *input, va_list *args)
#define foreach_vnet_api_error
Definition: api_errno.h:22
int echo_send_rpc(echo_main_t *em, void *fp, echo_rpc_args_t *args)
signed int i32
Definition: types.h:77
#define hash_create(elts, value_bytes)
Definition: hash.h:696
void svm_msg_q_add_and_unlock(svm_msg_q_t *mq, svm_msg_q_msg_t *msg)
Producer enqueue one message to queue with mutex held.
volatile u32 nxt_available_sidx
echo_session_t * echo_get_session_from_handle(echo_main_t *em, u64 handle)
u8 * echo_format_session_type(u8 *s, va_list *args)
#define clib_atomic_fetch_add(a, b)
Definition: atomics.h:23
vl_api_address_t ip
Definition: l2.api:558
u64 uword
Definition: types.h:112
u8 * format_api_error(u8 *s, va_list *args)
uword * session_index_by_vpp_handles
svm_msg_q_t rpc_msq_queue
vl_api_dhcp_client_state_t state
Definition: dhcp.api:201
static int svm_msg_q_lock(svm_msg_q_t *mq)
Lock, or block trying, the message queue.
void echo_session_print_stats(echo_main_t *em, echo_session_t *session)
u8 * echo_format_crypto_engine(u8 *s, va_list *args)
svm_msg_q_msg_t svm_msg_q_alloc_msg_w_ring(svm_msg_q_t *mq, u32 ring_index)
Allocate message buffer on ring.
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
uword echo_unformat_close(unformat_input_t *input, va_list *args)
u8 * format_transport_proto(u8 *s, va_list *args)
ip46_type_t
Definition: ip46_address.h:22
echo_rpc_args_t args