FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
vlib_api_cli.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
25 
26 static clib_error_t *
28  unformat_input_t * input,
29  vlib_cli_command_t * cli_cmd)
30 {
31  u64 total_counts = 0;
32  int i;
33 
34  for (i = 0; i < SLEEP_N_BUCKETS; i++)
35  {
36  total_counts += vector_rate_histogram[i];
37  }
38 
39  if (total_counts == 0)
40  {
41  vlib_cli_output (vm, "No control-plane activity.");
42  return 0;
43  }
44 
45 #define _(n) \
46  do { \
47  f64 percent; \
48  percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
49  / (f64) total_counts; \
50  percent *= 100.0; \
51  vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
52  vector_rate_histogram[SLEEP_##n##_US], \
53  percent); \
54  } while (0);
56 #undef _
57 
58  return 0;
59 }
60 
61 /*?
62  * Display the binary api sleep-time histogram
63 ?*/
64 /* *INDENT-OFF* */
66 {
67  .path = "show api histogram",
68  .short_help = "show api histogram",
70 };
71 /* *INDENT-ON* */
72 
73 static clib_error_t *
75  unformat_input_t * input,
76  vlib_cli_command_t * cli_cmd)
77 {
78  int i;
79 
80  for (i = 0; i < SLEEP_N_BUCKETS; i++)
82  return 0;
83 }
84 
85 /*?
86  * Clear the binary api sleep-time histogram
87 ?*/
88 /* *INDENT-OFF* */
90 {
91  .path = "clear api histogram",
92  .short_help = "clear api histogram",
94 };
95 /* *INDENT-ON* */
96 
97 static clib_error_t *
99  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
100 {
101  vl_api_registration_t **regpp, *regp;
102  svm_queue_t *q;
103  char *health;
105  u32 *confused_indices = 0;
106 
107  if (!pool_elts (am->vl_clients))
108  goto socket_clients;
109  vlib_cli_output (vm, "Shared memory clients");
110  vlib_cli_output (vm, "%20s %8s %14s %18s %s",
111  "Name", "PID", "Queue Length", "Queue VA", "Health");
112 
113  /* *INDENT-OFF* */
114  pool_foreach (regpp, am->vl_clients)
115  {
116  regp = *regpp;
117 
118  if (regp)
119  {
120  if (regp->unanswered_pings > 0)
121  health = "questionable";
122  else
123  health = "OK";
124 
125  q = regp->vl_input_queue;
126 
127  vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
128  regp->name, q->consumer_pid, q->cursize,
129  q, health);
130  }
131  else
132  {
133  clib_warning ("NULL client registration index %d",
134  regpp - am->vl_clients);
135  vec_add1 (confused_indices, regpp - am->vl_clients);
136  }
137  }
138  /* *INDENT-ON* */
139 
140  /* This should "never happen," but if it does, fix it... */
141  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
142  {
143  int i;
144  for (i = 0; i < vec_len (confused_indices); i++)
145  {
146  pool_put_index (am->vl_clients, confused_indices[i]);
147  }
148  }
149  vec_free (confused_indices);
150 
151  if (am->missing_clients)
152  vlib_cli_output (vm, "%u messages with missing clients",
153  am->missing_clients);
154 socket_clients:
156 
157  return 0;
158 }
159 
160 static clib_error_t *
162  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
163 {
165 
166  /* check if rx_trace and tx_trace are not null pointers */
167  if (am->rx_trace == 0)
168  {
169  vlib_cli_output (vm, "RX Trace disabled\n");
170  }
171  else
172  {
173  if (am->rx_trace->enabled == 0)
174  vlib_cli_output (vm, "RX Trace disabled\n");
175  else
176  vlib_cli_output (vm, "RX Trace enabled\n");
177  }
178 
179  if (am->tx_trace == 0)
180  {
181  vlib_cli_output (vm, "TX Trace disabled\n");
182  }
183  else
184  {
185  if (am->tx_trace->enabled == 0)
186  vlib_cli_output (vm, "TX Trace disabled\n");
187  else
188  vlib_cli_output (vm, "TX Trace enabled\n");
189  }
190 
191  return 0;
192 }
193 
194 /* *INDENT-OFF* */
196 {
197  .path = "show api",
198  .short_help = "Show API information",
199 };
200 /* *INDENT-ON* */
201 
202 /*?
203  * Display current api client connections
204 ?*/
205 /* *INDENT-OFF* */
207 {
208  .path = "show api clients",
209  .short_help = "Client information",
210  .function = vl_api_client_command,
211 };
212 /* *INDENT-ON* */
213 
214 /*?
215  * Display the current api message tracing status
216 ?*/
217 /* *INDENT-OFF* */
219 {
220  .path = "show api trace-status",
221  .short_help = "Display API trace status",
222  .function = vl_api_status_command,
223 };
224 /* *INDENT-ON* */
225 
226 static clib_error_t *
228  unformat_input_t * input,
229  vlib_cli_command_t * cli_cmd)
230 {
232  int i;
233  int verbose = 0;
234 
235  if (unformat (input, "verbose"))
236  verbose = 1;
237 
238 
239  if (verbose == 0)
240  vlib_cli_output (vm, "%-4s %s", "ID", "Name");
241  else
242  vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
243  "MP-safe");
244 
245  for (i = 1; i < vec_len (am->msg_names); i++)
246  {
247  if (verbose == 0)
248  {
249  vlib_cli_output (vm, "%-4d %s", i,
250  am->msg_names[i] ? am->msg_names[i] :
251  " [no handler]");
252  }
253  else
254  {
255  vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
256  am->msg_names[i] ? am->msg_names[i] :
257  " [no handler]", am->message_bounce[i],
258  am->is_mp_safe[i]);
259  }
260  }
261 
262  return 0;
263 }
264 
265 /*?
266  * Display the current api message decode tables
267 ?*/
268 /* *INDENT-OFF* */
270 {
271  .path = "show api message-table",
272  .short_help = "Message Table",
273  .function = vl_api_message_table_command,
274 };
275 /* *INDENT-ON* */
276 
277 static int
279 {
280  int len0, len1, clen;
281 
282  len0 = vec_len (a0->name);
283  len1 = vec_len (a1->name);
284  clen = len0 < len1 ? len0 : len1;
285  return (strncmp ((char *) a0->name, (char *) a1->name, clen));
286 }
287 
288 static u8 *
289 format_api_msg_range (u8 * s, va_list * args)
290 {
291  vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
292 
293  if (rp == 0)
294  s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
295  else
296  s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
297  rp->last_msg_id);
298 
299  return s;
300 }
301 
302 static clib_error_t *
304  unformat_input_t * input,
305  vlib_cli_command_t * cli_cmd)
306 {
308  vl_api_msg_range_t *rp = 0;
309  int i;
310 
311  if (vec_len (am->msg_ranges) == 0)
312  {
313  vlib_cli_output (vm, "No plugin API message ranges configured...");
314  return 0;
315  }
316 
317  rp = vec_dup (am->msg_ranges);
318 
320 
321  vlib_cli_output (vm, "Plugin API message ID ranges...\n");
322  vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
323 
324  for (i = 0; i < vec_len (rp); i++)
325  vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
326 
327  vec_free (rp);
328 
329  return 0;
330 }
331 
332 /*?
333  * Display the plugin binary API message range table
334 ?*/
335 /* *INDENT-OFF* */
337 {
338  .path = "show api plugin",
339  .short_help = "show api plugin",
340  .function = vl_api_show_plugin_command,
341 };
342 /* *INDENT-ON* */
343 
344 typedef enum
345 {
350 
351 u8 *
352 format_vl_msg_api_trace_status (u8 * s, va_list * args)
353 {
354  api_main_t *am = va_arg (*args, api_main_t *);
356  vl_api_trace_t *tp;
357  char *trace_name;
358 
359  switch (which)
360  {
361  case VL_API_TRACE_TX:
362  tp = am->tx_trace;
363  trace_name = "TX trace";
364  break;
365 
366  case VL_API_TRACE_RX:
367  tp = am->rx_trace;
368  trace_name = "RX trace";
369  break;
370 
371  default:
372  abort ();
373  }
374 
375  if (tp == 0)
376  {
377  s = format (s, "%s: not yet configured.\n", trace_name);
378  return s;
379  }
380 
381  s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
382  trace_name, vec_len (tp->traces), tp->nitems,
383  tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
384  return s;
385 }
386 
387 static void
389  u32 first_index, u32 last_index,
391 {
392  vl_api_trace_file_header_t *hp;
393  int i, fd;
394  struct stat statb;
395  size_t file_size;
396  u8 *msg;
398  u8 *tmpbuf = 0;
399  u32 nitems, nitems_msgtbl;
400 
401  fd = open ((char *) filename, O_RDONLY);
402 
403  if (fd < 0)
404  {
405  vlib_cli_output (vm, "Couldn't open %s\n", filename);
406  return;
407  }
408 
409  if (fstat (fd, &statb) < 0)
410  {
411  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
412  close (fd);
413  return;
414  }
415 
416  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
417  {
418  vlib_cli_output (vm, "File not plausible: %s\n", filename);
419  close (fd);
420  return;
421  }
422 
423  file_size = statb.st_size;
424  file_size = (file_size + 4095) & ~(4095);
425 
426  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
427 
428  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
429  {
430  vlib_cli_output (vm, "mmap failed: %s\n", filename);
431  close (fd);
432  return;
433  }
434  close (fd);
435 
436  CLIB_MEM_UNPOISON (hp, file_size);
437 
438  nitems = ntohl (hp->nitems);
439 
440  if (last_index == (u32) ~ 0)
441  {
442  last_index = nitems - 1;
443  }
444 
445  if (first_index >= nitems || last_index >= nitems)
446  {
447  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
448  first_index, last_index, nitems - 1);
449  munmap (hp, file_size);
450  return;
451  }
452  if (hp->wrapped)
454  "Note: wrapped/incomplete trace, results may vary\n");
455 
456  msg = (u8 *) (hp + 1);
457 
458  u16 *msgid_vec = 0;
459  serialize_main_t _sm, *sm = &_sm;
460  u32 msgtbl_size = ntohl (hp->msgtbl_size);
461  u8 *name_and_crc;
462 
463  unserialize_open_data (sm, msg, msgtbl_size);
464  unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
465 
466  for (i = 0; i < nitems_msgtbl; i++)
467  {
469  unserialize_cstring (sm, (char **) &name_and_crc);
470  u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
471  vec_validate (msgid_vec, msg_index);
472  msgid_vec[msg_index] = msg_index2;
473  }
474 
475  msg += msgtbl_size;
476 
477  for (i = 0; i < first_index; i++)
478  {
479  trace_cfg_t *cfgp;
480  int size;
481  u16 msg_id;
482 
483  size = clib_host_to_net_u32 (*(u32 *) msg);
484  msg += sizeof (u32);
485 
486  msg_id = ntohs (*((u16 *) msg));
487  if (msg_id < vec_len (msgid_vec))
488  msg_id = msgid_vec[msg_id];
489  cfgp = am->api_trace_cfg + msg_id;
490  if (!cfgp)
491  {
492  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
493  munmap (hp, file_size);
494  return;
495  }
496  msg += size;
497  }
498 
499  if (which == REPLAY)
500  am->replay_in_progress = 1;
501 
502  for (; i <= last_index; i++)
503  {
504  trace_cfg_t *cfgp;
505  u16 msg_id;
506  int size;
507 
508  if (which == DUMP)
509  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
510 
511  size = clib_host_to_net_u32 (*(u32 *) msg);
512  msg += sizeof (u32);
513 
514  msg_id = ntohs (*((u16 *) msg));
515  if (msg_id < vec_len (msgid_vec))
516  {
517  msg_id = msgid_vec[msg_id];
518  }
519 
520  cfgp = am->api_trace_cfg + msg_id;
521  if (!cfgp)
522  {
523  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
524  munmap (hp, file_size);
525  vec_free (tmpbuf);
526  am->replay_in_progress = 0;
527  return;
528  }
529 
530  /* Copy the buffer (from the read-only mmap'ed file) */
531  vec_validate (tmpbuf, size - 1 + sizeof (uword));
532  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
533  clib_memset (tmpbuf, 0xf, sizeof (uword));
534 
535  /*
536  * Endian swap if needed. All msg data is supposed to be in
537  * network byte order.
538  */
539  if (((which == DUMP) && clib_arch_is_little_endian))
540  {
541  void (*endian_fp) (void *);
542  if (msg_id >= vec_len (am->msg_endian_handlers)
543  || (am->msg_endian_handlers[msg_id] == 0))
544  {
545  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
546  munmap (hp, file_size);
547  vec_free (tmpbuf);
548  am->replay_in_progress = 0;
549  return;
550  }
551  endian_fp = am->msg_endian_handlers[msg_id];
552  (*endian_fp) (tmpbuf + sizeof (uword));
553  }
554 
555  /* msg_id always in network byte order */
557  {
558  u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
559  *msg_idp = msg_id;
560  }
561 
562  switch (which)
563  {
564  case DUMP:
565  if (msg_id < vec_len (am->msg_print_handlers) &&
566  am->msg_print_handlers[msg_id])
567  {
568  u8 *(*print_fp) (void *, void *);
569 
570  print_fp = (void *) am->msg_print_handlers[msg_id];
571  (*print_fp) (tmpbuf + sizeof (uword), vm);
572  }
573  else
574  {
575  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
576  msg_id);
577  break;
578  }
579  break;
580 
581  case INITIALIZERS:
582  if (msg_id < vec_len (am->msg_print_handlers) &&
583  am->msg_print_handlers[msg_id])
584  {
585  u8 *s;
586  int j;
587  u8 *(*print_fp) (void *, void *);
588 
589  print_fp = (void *) am->msg_print_handlers[msg_id];
590 
591  vlib_cli_output (vm, "/*");
592 
593  (*print_fp) (tmpbuf + sizeof (uword), vm);
594  vlib_cli_output (vm, "*/\n");
595 
596  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
597  am->msg_names[msg_id], i,
598  am->api_trace_cfg[msg_id].size);
599 
600  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
601  {
602  if ((j & 7) == 0)
603  s = format (s, "\n ");
604  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
605  }
606  s = format (s, "\n};\n%c", 0);
607  vlib_cli_output (vm, (char *) s);
608  vec_free (s);
609  }
610  break;
611 
612  case REPLAY:
613  if (msg_id < vec_len (am->msg_print_handlers) &&
614  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
615  {
616  void (*handler) (void *, vlib_main_t *);
617 
618  handler = (void *) am->msg_handlers[msg_id];
619 
620  if (!am->is_mp_safe[msg_id])
622  (*handler) (tmpbuf + sizeof (uword), vm);
623  if (!am->is_mp_safe[msg_id])
625  }
626  else
627  {
628  if (cfgp->replay_enable)
629  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
630  msg_id);
631  break;
632  }
633  break;
634  }
635 
636  _vec_len (tmpbuf) = 0;
637  msg += size;
638  }
639 
640  munmap (hp, file_size);
641  vec_free (tmpbuf);
642  am->replay_in_progress = 0;
643 }
644 
645 /** api_trace_command_fn - control the binary API trace / replay feature
646 
647  Note: this command MUST be marked thread-safe. Replay with
648  multiple worker threads depends in many cases on worker thread
649  graph replica maintenance. If we (implicitly) assert a worker
650  thread barrier at the debug CLI level, all graph replica changes
651  are deferred until the replay operation completes. If an interface
652  is deleted, the wheels fall off.
653  */
654 
655 static clib_error_t *
657  unformat_input_t * input, vlib_cli_command_t * cmd)
658 {
659  unformat_input_t _line_input, *line_input = &_line_input;
660  u32 nitems = 256 << 10;
663  u8 *filename = 0;
664  u8 *chroot_filename = 0;
665  u32 first = 0;
666  u32 last = (u32) ~ 0;
667  FILE *fp;
668  int rv;
669 
670  /* Get a line of input. */
671  if (!unformat_user (input, unformat_line_input, line_input))
672  return 0;
673 
674  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
675  {
676  if (unformat (line_input, "on") || unformat (line_input, "enable"))
677  {
678  if (unformat (line_input, "nitems %d", &nitems))
679  ;
682  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
684  }
685  else if (unformat (line_input, "off"))
686  {
690  }
691  else if (unformat (line_input, "save %s", &filename))
692  {
693  if (strstr ((char *) filename, "..")
694  || index ((char *) filename, '/'))
695  {
696  vlib_cli_output (vm, "illegal characters in filename '%s'",
697  filename);
698  goto out;
699  }
700 
701  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
702 
703  vec_free (filename);
704 
705  fp = fopen ((char *) chroot_filename, "w");
706  if (fp == NULL)
707  {
708  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
709  goto out;
710  }
712  rv = vl_msg_api_trace_save (am, which, fp);
714  fclose (fp);
715  if (rv == -1)
716  vlib_cli_output (vm, "API Trace data not present\n");
717  else if (rv == -2)
718  vlib_cli_output (vm, "File for writing is closed\n");
719  else if (rv == -10)
720  vlib_cli_output (vm, "Error while writing header to file\n");
721  else if (rv == -11)
722  vlib_cli_output (vm, "Error while writing trace to file\n");
723  else if (rv == -12)
725  "Error while writing end of buffer trace to file\n");
726  else if (rv == -13)
728  "Error while writing start of buffer trace to file\n");
729  else if (rv < 0)
730  vlib_cli_output (vm, "Unknown error while saving: %d", rv);
731  else
732  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
733  goto out;
734  }
735  else if (unformat (line_input, "dump %s", &filename))
736  {
737  vl_msg_api_process_file (vm, filename, first, last, DUMP);
738  }
739  else if (unformat (line_input, "replay %s", &filename))
740  {
741  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
742  }
743  else if (unformat (line_input, "initializers %s", &filename))
744  {
746  }
747  else if (unformat (line_input, "tx"))
748  {
750  }
751  else if (unformat (line_input, "first %d", &first))
752  {
753  ;
754  }
755  else if (unformat (line_input, "last %d", &last))
756  {
757  ;
758  }
759  else if (unformat (line_input, "status"))
760  {
762  am, which);
763  }
764  else if (unformat (line_input, "free"))
765  {
770  }
771  else if (unformat (line_input, "post-mortem-on"))
773  else if (unformat (line_input, "post-mortem-off"))
775  else
776  return clib_error_return (0, "unknown input `%U'",
777  format_unformat_error, input);
778  }
779 out:
780  vec_free (filename);
781  vec_free (chroot_filename);
782  unformat_free (line_input);
783  return 0;
784 }
785 
786 /*?
787  * Display, replay, or save a binary API trace
788 ?*/
789 
790 /* *INDENT-OFF* */
792  .path = "api trace",
793  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
794  "[post-mortem-on][dump|save|replay <file>]",
795  .function = api_trace_command_fn,
796  .is_mp_safe = 1,
797 };
798 /* *INDENT-ON* */
799 
800 static clib_error_t *
802  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
803 {
804  u32 nitems = 1024;
807 
809  {
810  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
811  goto configure;
812  else if (unformat (input, "tx nitems %u", &nitems)
813  || unformat (input, "tx"))
814  {
816  goto configure;
817  }
818  else if (unformat (input, "on rx"))
819  {
821  }
822  else if (unformat (input, "on tx"))
823  {
825  }
826  else if (unformat (input, "on"))
827  {
829  }
830  else if (unformat (input, "off"))
831  {
834  }
835  else if (unformat (input, "free"))
836  {
841  }
842  else if (unformat (input, "debug on"))
843  {
844  am->msg_print_flag = 1;
845  }
846  else if (unformat (input, "debug off"))
847  {
848  am->msg_print_flag = 0;
849  }
850  else
851  return clib_error_return (0, "unknown input `%U'",
852  format_unformat_error, input);
853  }
854  return 0;
855 
856 configure:
857  if (vl_msg_api_trace_configure (am, which, nitems))
858  {
859  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
860  which, nitems);
861  }
862 
863  return 0;
864 }
865 
866 /*?
867  * Control the binary API trace mechanism
868 ?*/
869 /* *INDENT-OFF* */
871 {
872  .path = "set api-trace",
873  .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
874  .function = vl_api_trace_command,
875 };
876 /* *INDENT-ON* */
877 
878 static clib_error_t *
880 {
881  u32 nitems = 256 << 10;
884 
886  {
887  if (unformat (input, "on") || unformat (input, "enable"))
888  {
889  if (unformat (input, "nitems %d", &nitems))
890  ;
892  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
894  }
895  else if (unformat (input, "save-api-table %s",
896  &am->save_msg_table_filename))
897  ;
898  else
899  return clib_error_return (0, "unknown input `%U'",
900  format_unformat_error, input);
901  }
902  return 0;
903 }
904 
905 /*?
906  * This module has three configuration parameters:
907  * "on" or "enable" - enables binary api tracing
908  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
909  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
910 ?*/
912 
913 static clib_error_t *
915 {
917  u32 nitems;
918 
920  {
921  if (unformat (input, "length %d", &nitems) ||
922  (unformat (input, "len %d", &nitems)))
923  {
924  if (nitems >= 1024)
925  am->vlib_input_queue_length = nitems;
926  else
927  clib_warning ("vlib input queue length %d too small, ignored",
928  nitems);
929  }
930  else
931  return clib_error_return (0, "unknown input `%U'",
932  format_unformat_error, input);
933  }
934  return 0;
935 }
936 
938 
939 static u8 *
941 {
942  u8 *rv;
943 
944  rv = vec_dup (s);
945 
946  while (vec_len (rv) && rv[vec_len (rv)] != '_')
947  _vec_len (rv)--;
948 
949  rv[vec_len (rv)] = 0;
950 
951  return rv;
952 }
953 
954 static u8 *
956 {
957  int i;
958  u8 *rv;
959 
960  rv = vec_dup (s);
961 
962  for (i = vec_len (rv) - 1; i >= 0; i--)
963  {
964  if (rv[i] == '_')
965  {
966  vec_delete (rv, i + 1, 0);
967  break;
968  }
969  }
970  return rv;
971 }
972 
973 typedef struct
974 {
977  u8 *crc;
979  int which;
981 
982 static int
983 table_id_cmp (void *a1, void *a2)
984 {
985  msg_table_unserialize_t *n1 = a1;
986  msg_table_unserialize_t *n2 = a2;
987 
988  return (n1->msg_index - n2->msg_index);
989 }
990 
991 static int
992 table_name_and_crc_cmp (void *a1, void *a2)
993 {
994  msg_table_unserialize_t *n1 = a1;
995  msg_table_unserialize_t *n2 = a2;
996 
997  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
998 }
999 
1000 static clib_error_t *
1002  unformat_input_t * input,
1003  vlib_cli_command_t * cmd)
1004 {
1005  u8 *filename = 0;
1007  serialize_main_t _sm, *sm = &_sm;
1009  u32 nmsgs;
1010  u32 msg_index;
1011  u8 *name_and_crc;
1012  int compare_current = 0;
1013  int numeric_sort = 0;
1014  msg_table_unserialize_t *table = 0, *item;
1015  u32 i;
1016  u32 ndifferences = 0;
1017 
1018  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1019  {
1020  if (unformat (input, "file %s", &filename))
1021  ;
1022  else if (unformat (input, "compare-current")
1023  || unformat (input, "compare"))
1024  compare_current = 1;
1025  else if (unformat (input, "numeric"))
1026  numeric_sort = 1;
1027  else
1028  return clib_error_return (0, "unknown input `%U'",
1029  format_unformat_error, input);
1030  }
1031 
1032  if (numeric_sort && compare_current)
1033  return clib_error_return
1034  (0, "Comparison and numeric sorting are incompatible");
1035 
1036  if (filename == 0)
1037  return clib_error_return (0, "File not specified");
1038 
1039  /* Load the serialized message table from the table dump */
1040 
1041  error = unserialize_open_clib_file (sm, (char *) filename);
1042 
1043  if (error)
1044  return error;
1045 
1046  unserialize_integer (sm, &nmsgs, sizeof (u32));
1047 
1048  for (i = 0; i < nmsgs; i++)
1049  {
1051  unserialize_cstring (sm, (char **) &name_and_crc);
1052  vec_add2 (table, item, 1);
1053  item->msg_index = msg_index;
1054  item->name_and_crc = name_and_crc;
1055  item->name = extract_name (name_and_crc);
1056  item->crc = extract_crc (name_and_crc);
1057  item->which = 0; /* file */
1058  }
1059  unserialize_close (sm);
1060 
1061  /* Compare with the current image? */
1062  if (compare_current)
1063  {
1064  /* Append the current message table */
1065  u8 *tblv = vl_api_serialize_message_table (am, 0);
1066 
1067  serialize_open_vector (sm, tblv);
1068  unserialize_integer (sm, &nmsgs, sizeof (u32));
1069 
1070  for (i = 0; i < nmsgs; i++)
1071  {
1073  unserialize_cstring (sm, (char **) &name_and_crc);
1074 
1075  vec_add2 (table, item, 1);
1076  item->msg_index = msg_index;
1077  item->name_and_crc = name_and_crc;
1078  item->name = extract_name (name_and_crc);
1079  item->crc = extract_crc (name_and_crc);
1080  item->which = 1; /* current_image */
1081  }
1082  vec_free (tblv);
1083  }
1084 
1085  /* Sort the table. */
1086  if (numeric_sort)
1088  else
1090 
1091  if (compare_current)
1092  {
1093  u8 *dashes = 0;
1094  ndifferences = 0;
1095 
1096  /*
1097  * In this case, the recovered table will have two entries per
1098  * API message. So, if entries i and i+1 match, the message definitions
1099  * are identical. Otherwise, the crc is different, or a message is
1100  * present in only one of the tables.
1101  */
1102  vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1103  vec_validate_init_empty (dashes, 60, '-');
1104  vec_terminate_c_string (dashes);
1105  vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1106  vec_free (dashes);
1107  for (i = 0; i < vec_len (table);)
1108  {
1109  /* Last message lonely? */
1110  if (i == vec_len (table) - 1)
1111  {
1112  ndifferences++;
1113  goto last_unique;
1114  }
1115 
1116  /* Identical pair? */
1117  if (!strncmp
1118  ((char *) table[i].name_and_crc,
1119  (char *) table[i + 1].name_and_crc,
1120  vec_len (table[i].name_and_crc)))
1121  {
1122  i += 2;
1123  continue;
1124  }
1125 
1126  ndifferences++;
1127 
1128  /* Only in one of two tables? */
1129  if (i + 1 == vec_len (table)
1130  || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1131  {
1132  last_unique:
1133  vlib_cli_output (vm, "%-60s | only in %s",
1134  table[i].name, table[i].which ?
1135  "image" : "file");
1136  i++;
1137  continue;
1138  }
1139  /* In both tables, but with different signatures */
1140  vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1141  i += 2;
1142  }
1143  if (ndifferences == 0)
1144  vlib_cli_output (vm, "No api message signature differences found.");
1145  else
1146  vlib_cli_output (vm, "\nFound %u api message signature differences",
1147  ndifferences);
1148  goto cleanup;
1149  }
1150 
1151  /* Dump the table, sorted as shown above */
1152  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1153 
1154  for (i = 0; i < vec_len (table); i++)
1155  {
1156  item = table + i;
1157  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1158  item->msg_index, item->crc);
1159  }
1160 
1161 cleanup:
1162  for (i = 0; i < vec_len (table); i++)
1163  {
1164  vec_free (table[i].name_and_crc);
1165  vec_free (table[i].name);
1166  vec_free (table[i].crc);
1167  }
1168 
1169  vec_free (table);
1170 
1171  return 0;
1172 }
1173 
1174 /*?
1175  * Displays a serialized API message decode table, sorted by message name
1176  *
1177  * @cliexpar
1178  * @cliexstart{show api dump file <filename>}
1179  * Message name MsgID CRC
1180  * accept_session 407 8e2a127e
1181  * accept_session_reply 408 67d8c22a
1182  * add_node_next 549 e4202993
1183  * add_node_next_reply 550 e89d6eed
1184  * etc.
1185  * @cliexend
1186 ?*/
1187 
1188 /*?
1189  * Compares a serialized API message decode table with the current image
1190  *
1191  * @cliexpar
1192  * @cliexstart{show api dump file <filename> compare}
1193  * ip_add_del_route definition changed
1194  * ip_table_add_del definition changed
1195  * l2_macs_event only in image
1196  * vnet_ip4_fib_counters only in file
1197  * vnet_ip4_nbr_counters only in file
1198  * @cliexend
1199 ?*/
1200 
1201 /*?
1202  * Display a serialized API message decode table, compare a saved
1203  * decode table with the current image, to establish API differences.
1204  *
1205 ?*/
1206 /* *INDENT-OFF* */
1208 {
1209  .path = "show api dump",
1210  .short_help = "show api dump file <filename> [numeric | compare-current]",
1211  .function = dump_api_table_file_command_fn,
1212 };
1213 
1214 /* *INDENT-ON* */
1215 /*
1216  * fd.io coding-style-patch-verification: ON
1217  *
1218  * Local Variables:
1219  * eval: (c-set-style "gnu")
1220  * End:
1221  */
extract_name
static u8 * extract_name(u8 *s)
Definition: vlib_api_cli.c:940
vl_api_status_command
static clib_error_t * vl_api_status_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:161
vl_msg_api_barrier_release
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:432
msg_table_unserialize_t::msg_index
u32 msg_index
Definition: vlib_api_cli.c:978
trace
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:870
api.h
vlib_worker_thread_barrier_release
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1375
unformat_user
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
ntohs
#define ntohs(x)
Definition: af_xdp.bpf.c:29
cli_show_api_histogram_command
static vlib_cli_command_t cli_show_api_histogram_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_histogram_command)
Definition: vlib_api_cli.c:65
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
vl_api_replay_t
vl_api_replay_t
Definition: vlib_api_cli.c:344
vl_api_msg_range_t::name
u8 * name
name of the plugin
Definition: api_common.h:116
cli_show_api_status_command
static vlib_cli_command_t cli_show_api_status_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_status_command)
Definition: vlib_api_cli.c:218
cli_show_api_command
static vlib_cli_command_t cli_show_api_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_command)
Definition: vlib_api_cli.c:195
unformat_line_input
unformat_function_t unformat_line_input
Definition: format.h:275
name
string name[64]
Definition: fib.api:25
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
vlib_cli_command_t::path
char * path
Definition: cli.h:96
foreach_histogram_bucket
#define foreach_histogram_bucket
Definition: api.h:137
svm_queue_t
struct _svm_queue svm_queue_t
VL_API_TRACE_RX
@ VL_API_TRACE_RX
Definition: api_common.h:107
u16
unsigned short u16
Definition: types.h:57
vl_api_trace_t::traces
u8 ** traces
Trace ring.
Definition: api_common.h:100
first
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
am
app_main_t * am
Definition: application.c:489
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
api.h
vl_api_registration_::vl_input_queue
svm_queue_t * vl_input_queue
shared memory only: pointer to client input queue
Definition: api_common.h:63
vec_delete
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:875
vl_api_trace_which_t
vl_api_trace_which_t
Trace RX / TX enum.
Definition: api_common.h:104
vl_api_msg_range_t::last_msg_id
u16 last_msg_id
last assigned message ID
Definition: api_common.h:118
VL_API_TRACE_TX
@ VL_API_TRACE_TX
Definition: api_common.h:106
unformat_input_t
struct _unformat_input_t unformat_input_t
serialize_open_vector
__clib_export void serialize_open_vector(serialize_main_t *m, u8 *vector)
Definition: serialize.c:909
serialize_main_t
Definition: serialize.h:144
api_trace_command_fn
static clib_error_t * api_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
api_trace_command_fn - control the binary API trace / replay feature
Definition: vlib_api_cli.c:656
pool_put_index
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
error
Definition: cJSON.c:88
msg_table_unserialize_t::which
int which
Definition: vlib_api_cli.c:979
api_trace_command
static vlib_cli_command_t api_trace_command
(constructor) VLIB_CLI_COMMAND (api_trace_command)
Definition: vlib_api_cli.c:791
table_name_and_crc_cmp
static int table_name_and_crc_cmp(void *a1, void *a2)
Definition: vlib_api_cli.c:992
VLIB_CONFIG_FUNCTION
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:181
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
vl_api_trace_t::enabled
u8 enabled
trace is enabled
Definition: api_common.h:95
vl_api_show_plugin_command
static clib_error_t * vl_api_show_plugin_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:303
pool_foreach
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
vl_msg_api_trace_save
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:227
dump_api_table_file
static vlib_cli_command_t dump_api_table_file
(constructor) VLIB_CLI_COMMAND (dump_api_table_file)
Definition: vlib_api_cli.c:1207
which
int which
Definition: cJSON.h:234
msg_table_unserialize_t
Definition: vlib_api_cli.c:973
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
trace_cfg_t
Trace configuration for a single message.
Definition: api_common.h:82
unformat_free
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
vl_msg_api_trace_configure
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:366
vl_api_registration_::unanswered_pings
int unanswered_pings
Definition: api_common.h:59
vec_add2
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:644
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
unserialize_open_clib_file
__clib_export clib_error_t * unserialize_open_clib_file(serialize_main_t *m, char *file)
Definition: serialize.c:1242
vec_dup
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
dump_api_table_file_command_fn
static clib_error_t * dump_api_table_file_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vlib_api_cli.c:1001
vlib_worker_thread_barrier_sync
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:173
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
vl_api_registration_
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
unformat_check_input
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
vlib_config_function_runtime_t
Definition: init.h:68
api_trace_config_fn
static clib_error_t * api_trace_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:879
cli_show_api_plugin_command
static vlib_cli_command_t cli_show_api_plugin_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_plugin_command)
Definition: vlib_api_cli.c:336
unserialize_integer
static void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:201
uword
u64 uword
Definition: types.h:112
last
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
if
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
DUMP
@ DUMP
Definition: vlib_api_cli.c:346
vlibapi_get_main
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
vl_msg_api_get_msg_index
u32 vl_msg_api_get_msg_index(u8 *name_and_crc)
Definition: api_shared.c:1119
vl_sock_api_dump_clients
void vl_sock_api_dump_clients(vlib_main_t *vm, api_main_t *am)
Definition: socket_api.c:72
vl_api_serialize_message_table
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: api_shared.c:204
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
REPLAY
@ REPLAY
Definition: vlib_api_cli.c:347
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
VLIB_CLI_COMMAND
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
cli_clear_api_histogram_command
static vlib_cli_command_t cli_clear_api_histogram_command
(constructor) VLIB_CLI_COMMAND (cli_clear_api_histogram_command)
Definition: vlib_api_cli.c:89
msg_table_unserialize_t::name_and_crc
u8 * name_and_crc
Definition: vlib_api_cli.c:975
vl_api_trace_command
static clib_error_t * vl_api_trace_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:801
vl_api_show_histogram_command
static clib_error_t * vl_api_show_histogram_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:27
vlib_cli_output
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
unserialize_open_data
__clib_export void unserialize_open_data(serialize_main_t *m, u8 *data, uword n_data_bytes)
Definition: serialize.c:891
vl_api_trace_t
API trace state.
Definition: api_common.h:92
api_main_t
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
vl_api_clear_histogram_command
static clib_error_t * vl_api_clear_histogram_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:74
unserialize_cstring
__clib_export void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
size
u32 size
Definition: vhost_user.h:125
index
u32 index
Definition: flow_types.api:221
format_api_msg_range
static u8 * format_api_msg_range(u8 *s, va_list *args)
Definition: vlib_api_cli.c:289
range_compare
static int range_compare(vl_api_msg_range_t *a0, vl_api_msg_range_t *a1)
Definition: vlib_api_cli.c:278
vl_api_trace_t::nitems
u32 nitems
Number of trace records.
Definition: api_common.h:98
vl_api_trace_t::wrapped
u8 wrapped
trace has wrapped
Definition: api_common.h:96
u64
unsigned long u64
Definition: types.h:89
vl_msg_api_trace_free
int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
Definition: api_shared.c:167
format
description fragment has unexpected format
Definition: map.api:433
vec_validate_init_empty
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header,...
Definition: vec.h:570
vl_api_msg_range_t
Message range (belonging to a plugin)
Definition: api_common.h:114
u32
unsigned int u32
Definition: types.h:88
format_vl_msg_api_trace_status
u8 * format_vl_msg_api_trace_status(u8 *s, va_list *args)
Definition: vlib_api_cli.c:352
vector_rate_histogram
u64 vector_rate_histogram[]
Definition: vlib_api.c:179
CLIB_MEM_UNPOISON
#define CLIB_MEM_UNPOISON(a, s)
Definition: sanitizer.h:114
vl_api_client_command
static clib_error_t * vl_api_client_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:98
vl_api_message_table_command
static clib_error_t * vl_api_message_table_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: vlib_api_cli.c:227
table_id_cmp
static int table_id_cmp(void *a1, void *a2)
Definition: vlib_api_cli.c:983
vl_api_msg_range_t::first_msg_id
u16 first_msg_id
first assigned message ID
Definition: api_common.h:117
cli_show_api_clients_command
static vlib_cli_command_t cli_show_api_clients_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_clients_command)
Definition: vlib_api_cli.c:206
pool_elts
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127
trace_cfg_t::replay_enable
int replay_enable
This message can be replayed
Definition: api_common.h:86
vl_msg_api_post_mortem_dump_enable_disable
void vl_msg_api_post_mortem_dump_enable_disable(int enable)
Definition: api_shared.c:963
clib_arch_is_little_endian
#define clib_arch_is_little_endian
Definition: byte_order.h:54
vec_sort_with_function
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:1097
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
vlib_main_t
Definition: main.h:102
item
cJSON * item
Definition: cJSON.h:222
SLEEP_N_BUCKETS
@ SLEEP_N_BUCKETS
Definition: api.h:148
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
unserialize_close
__clib_export void unserialize_close(serialize_main_t *m)
Definition: serialize.c:877
vec_terminate_c_string
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1132
i
int i
Definition: flowhash_template.h:376
msg_table_unserialize_t::crc
u8 * crc
Definition: vlib_api_cli.c:977
clib_warning
#define clib_warning(format, args...)
Definition: error.h:59
unserialize_likely_small_unsigned_integer
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
rv
int __clib_unused rv
Definition: application.c:491
cleanup
static void cleanup(void)
Definition: client.c:98
vl_api_registration_::name
u8 * name
Client name.
Definition: api_common.h:54
vl_msg_api_process_file
static void vl_msg_api_process_file(vlib_main_t *vm, u8 *filename, u32 first_index, u32 last_index, vl_api_replay_t which)
Definition: vlib_api_cli.c:388
vl_msg_api_trace_onoff
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:125
msg_table_unserialize_t::name
u8 * name
Definition: vlib_api_cli.c:976
vlib_cli_command_t
Definition: cli.h:92
api_queue_config_fn
static clib_error_t * api_queue_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:914
vl_msg_api_barrier_sync
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:427
extract_crc
static u8 * extract_crc(u8 *s)
Definition: vlib_api_cli.c:955
UNFORMAT_END_OF_INPUT
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
cli_show_api_message_table_command
static vlib_cli_command_t cli_show_api_message_table_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_message_table_command)
Definition: vlib_api_cli.c:269
INITIALIZERS
@ INITIALIZERS
Definition: vlib_api_cli.c:348