FD.io VPP  v20.05-21-gb1500e9ff
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  default:
343  s = format (s, "UNKNOWN");
344  break;
345  }
346  return s;
347 }
348 
349 uword
350 unformat_ip4_address (unformat_input_t * input, va_list * args)
351 {
352  u8 *result = va_arg (*args, u8 *);
353  unsigned a[4];
354 
355  if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]))
356  return 0;
357 
358  if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256)
359  return 0;
360 
361  result[0] = a[0];
362  result[1] = a[1];
363  result[2] = a[2];
364  result[3] = a[3];
365 
366  return 1;
367 }
368 
369 uword
370 unformat_ip6_address (unformat_input_t * input, va_list * args)
371 {
372  ip6_address_t *result = va_arg (*args, ip6_address_t *);
373  u16 hex_quads[8];
374  uword hex_quad, n_hex_quads, hex_digit, n_hex_digits;
375  uword c, n_colon, double_colon_index;
376 
377  n_hex_quads = hex_quad = n_hex_digits = n_colon = 0;
378  double_colon_index = ARRAY_LEN (hex_quads);
379  while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
380  {
381  hex_digit = 16;
382  if (c >= '0' && c <= '9')
383  hex_digit = c - '0';
384  else if (c >= 'a' && c <= 'f')
385  hex_digit = c + 10 - 'a';
386  else if (c >= 'A' && c <= 'F')
387  hex_digit = c + 10 - 'A';
388  else if (c == ':' && n_colon < 2)
389  n_colon++;
390  else
391  {
392  unformat_put_input (input);
393  break;
394  }
395 
396  /* Too many hex quads. */
397  if (n_hex_quads >= ARRAY_LEN (hex_quads))
398  return 0;
399 
400  if (hex_digit < 16)
401  {
402  hex_quad = (hex_quad << 4) | hex_digit;
403 
404  /* Hex quad must fit in 16 bits. */
405  if (n_hex_digits >= 4)
406  return 0;
407 
408  n_colon = 0;
409  n_hex_digits++;
410  }
411 
412  /* Save position of :: */
413  if (n_colon == 2)
414  {
415  /* More than one :: ? */
416  if (double_colon_index < ARRAY_LEN (hex_quads))
417  return 0;
418  double_colon_index = n_hex_quads;
419  }
420 
421  if (n_colon > 0 && n_hex_digits > 0)
422  {
423  hex_quads[n_hex_quads++] = hex_quad;
424  hex_quad = 0;
425  n_hex_digits = 0;
426  }
427  }
428 
429  if (n_hex_digits > 0)
430  hex_quads[n_hex_quads++] = hex_quad;
431 
432  {
433  word i;
434 
435  /* Expand :: to appropriate number of zero hex quads. */
436  if (double_colon_index < ARRAY_LEN (hex_quads))
437  {
438  word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads;
439 
440  for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--)
441  hex_quads[n_zero + i] = hex_quads[i];
442 
443  for (i = 0; i < n_zero; i++)
444  hex_quads[double_colon_index + i] = 0;
445 
446  n_hex_quads = ARRAY_LEN (hex_quads);
447  }
448 
449  /* Too few hex quads given. */
450  if (n_hex_quads < ARRAY_LEN (hex_quads))
451  return 0;
452 
453  for (i = 0; i < ARRAY_LEN (hex_quads); i++)
454  result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]);
455 
456  return 1;
457  }
458 }
459 
460 uword
461 unformat_ip46_address (unformat_input_t * input, va_list * args)
462 {
463  ip46_address_t *ip = va_arg (*args, ip46_address_t *);
464 
465  if (unformat (input, "%U", unformat_ip4_address, &ip->ip4))
466  ;
467  else if (unformat (input, "%U", unformat_ip6_address, &ip->ip6))
468  ;
469  else
470  return 0;
471  return 1;
472 }
473 
474 u8 *
475 echo_format_crypto_engine (u8 * s, va_list * args)
476 {
477  u32 state = va_arg (*args, u32);
478  if (state == CRYPTO_ENGINE_MBEDTLS)
479  return format (s, "mbedtls");
480  if (state == CRYPTO_ENGINE_OPENSSL)
481  return format (s, "openssl");
482  if (state == CRYPTO_ENGINE_PICOTLS)
483  return format (s, "picotls");
484  if (state == CRYPTO_ENGINE_VPP)
485  return format (s, "vpp");
486  else
487  return format (s, "unknown crypto engine");
488 }
489 
490 uword
492 {
493  u8 *a = va_arg (*args, u8 *);
494  if (unformat (input, "mbedtls"))
496  else if (unformat (input, "openssl"))
498  else if (unformat (input, "picotls"))
500  else if (unformat (input, "vpp"))
501  *a = CRYPTO_ENGINE_VPP;
502  else
503  return 0;
504  return 1;
505 }
506 
507 
508 /*
509  *
510  * End of format functions
511  *
512  */
513 
514 void
516 {
518  if (sid == SESSION_INVALID_INDEX)
519  {
520  ECHO_LOG (3, "hash_unset(0x%lx)", handle);
522  }
523  else
524  {
525  ECHO_LOG (3, "hash_set(0x%lx) S[%d]", handle, sid);
526  hash_set (em->session_index_by_vpp_handles, handle, sid);
527  }
529 }
530 
533 {
534  /* thread safe new prealloced session
535  * see echo_session_prealloc */
536  return pool_elt_at_index (em->sessions,
538  1));
539 }
540 
541 int
542 echo_send_rpc (echo_main_t * em, void *fp, echo_rpc_args_t * args)
543 {
544  svm_msg_q_msg_t msg;
545  echo_rpc_msg_t *evt;
547  {
548  ECHO_FAIL (ECHO_FAIL_RPC_SIZE, "RPC lock failed");
549  return -1;
550  }
552  {
554  ECHO_FAIL (ECHO_FAIL_RPC_SIZE, "RPC ring is full");
555  return -2;
556  }
558  evt = (echo_rpc_msg_t *) svm_msg_q_msg_data (em->rpc_msq_queue, &msg);
559  evt->fp = fp;
560  clib_memcpy (&evt->args, args, sizeof (evt->args));
561 
563  return 0;
564 }
565 
568 {
569  uword *p;
571  p = hash_get (em->session_index_by_vpp_handles, handle);
573  if (!p)
574  {
575  ECHO_LOG (2, "unknown handle 0x%lx", handle);
576  return 0;
577  }
578  return pool_elt_at_index (em->sessions, p[0]);
579 }
580 
581 int
583  f64 timeout)
584 {
585  f64 end_time = clib_time_now (&em->clib_time) + timeout;
586  while (!timeout || clib_time_now (&em->clib_time) < end_time)
587  {
588  if (em->state == state)
589  return 0;
590  if (em->time_to_stop)
591  return 1;
592  }
593  ECHO_LOG (2, "timeout waiting for %U", echo_format_app_state, state);
594  return -1;
595 }
596 
597 void
599 {
600  if (em->timing.events_sent & e)
601  return;
602  if (em->timing.start_event == e)
604  else if (em->timing.end_event == e)
605  em->timing.end_time = clib_time_now (&em->clib_time);
606  em->timing.events_sent |= e;
607 }
608 
609 void
611 {
612  f64 deltat = clib_time_now (&em->clib_time) - session->start;
613  ECHO_LOG (1, "Session 0x%x done in %.6fs RX[%.4f] TX[%.4f] Gbit/s\n",
614  session->vpp_session_handle, deltat,
615  (session->bytes_received * 8.0) / deltat / 1e9,
616  (session->bytes_sent * 8.0) / deltat / 1e9);
617 }
618 
619 /*
620  * fd.io coding-style-patch-verification: ON
621  *
622  * Local Variables:
623  * eval: (c-set-style "gnu")
624  * End:
625  */
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:102
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:80
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:538
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:192
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
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
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
#define clib_memcpy(d, s, n)
Definition: string.h:180
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)
#define ECHO_FAIL(fail, _fmt, _args...)
unsigned int u32
Definition: types.h:88
uword unformat_ip46_address(unformat_input_t *input, va_list *args)
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#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:534
void init_error_string_table()
vl_api_ip_proto_t proto
Definition: acl_types.api:50
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:118
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:205
#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:145
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:317
#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:66
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:501
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)
struct echo_main_t::@629 timing
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