FD.io VPP  v19.01.2-3-gf61a1a8
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* */
65 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
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++)
81  vector_rate_histogram[i] = 0;
82  return 0;
83 }
84 
85 /*?
86  * Clear the binary api sleep-time histogram
87 ?*/
88 /* *INDENT-OFF* */
89 VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
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;
104  api_main_t *am = &api_main;
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 {
164  api_main_t *am = &api_main;
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 {
231  api_main_t *am = &api_main;
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 {
307  api_main_t *am = &api_main;
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 {
351 
352 u8 *
353 format_vl_msg_api_trace_status (u8 * s, va_list * args)
354 {
355  api_main_t *am = va_arg (*args, api_main_t *);
356  vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
357  vl_api_trace_t *tp;
358  char *trace_name;
359 
360  switch (which)
361  {
362  case VL_API_TRACE_TX:
363  tp = am->tx_trace;
364  trace_name = "TX trace";
365  break;
366 
367  case VL_API_TRACE_RX:
368  tp = am->rx_trace;
369  trace_name = "RX trace";
370  break;
371 
372  default:
373  abort ();
374  }
375 
376  if (tp == 0)
377  {
378  s = format (s, "%s: not yet configured.\n", trace_name);
379  return s;
380  }
381 
382  s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
383  trace_name, vec_len (tp->traces), tp->nitems,
384  tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
385  return s;
386 }
387 
389  __attribute__ ((weak));
390 void
392 {
393 }
394 
395 static void
397  u32 first_index, u32 last_index,
398  vl_api_replay_t which)
399 {
400  vl_api_trace_file_header_t *hp;
401  int i, fd;
402  struct stat statb;
403  size_t file_size;
404  u8 *msg;
405  u8 endian_swap_needed = 0;
406  api_main_t *am = &api_main;
407  u8 *tmpbuf = 0;
408  u32 nitems;
409  void **saved_print_handlers = 0;
410 
411  fd = open ((char *) filename, O_RDONLY);
412 
413  if (fd < 0)
414  {
415  vlib_cli_output (vm, "Couldn't open %s\n", filename);
416  return;
417  }
418 
419  if (fstat (fd, &statb) < 0)
420  {
421  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
422  close (fd);
423  return;
424  }
425 
426  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
427  {
428  vlib_cli_output (vm, "File not plausible: %s\n", filename);
429  close (fd);
430  return;
431  }
432 
433  file_size = statb.st_size;
434  file_size = (file_size + 4095) & ~(4096);
435 
436  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
437 
438  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
439  {
440  vlib_cli_output (vm, "mmap failed: %s\n", filename);
441  close (fd);
442  return;
443  }
444  close (fd);
445 
446  if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
447  || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
448  endian_swap_needed = 1;
449 
450  if (endian_swap_needed)
451  nitems = ntohl (hp->nitems);
452  else
453  nitems = hp->nitems;
454 
455  if (last_index == (u32) ~ 0)
456  {
457  last_index = nitems - 1;
458  }
459 
460  if (first_index >= nitems || last_index >= nitems)
461  {
462  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
463  first_index, last_index, nitems - 1);
464  munmap (hp, file_size);
465  return;
466  }
467  if (hp->wrapped)
468  vlib_cli_output (vm,
469  "Note: wrapped/incomplete trace, results may vary\n");
470 
471  if (which == CUSTOM_DUMP)
472  {
473  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
475  }
476 
477 
478  msg = (u8 *) (hp + 1);
479 
480  for (i = 0; i < first_index; i++)
481  {
482  trace_cfg_t *cfgp;
483  int size;
484  u16 msg_id;
485 
486  size = clib_host_to_net_u32 (*(u32 *) msg);
487  msg += sizeof (u32);
488 
490  msg_id = ntohs (*((u16 *) msg));
491  else
492  msg_id = *((u16 *) msg);
493 
494  cfgp = am->api_trace_cfg + msg_id;
495  if (!cfgp)
496  {
497  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
498  munmap (hp, file_size);
499  return;
500  }
501  msg += size;
502  }
503 
504  if (which == REPLAY)
505  am->replay_in_progress = 1;
506 
507  for (; i <= last_index; i++)
508  {
509  trace_cfg_t *cfgp;
510  u16 *msg_idp;
511  u16 msg_id;
512  int size;
513 
514  if (which == DUMP)
515  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
516 
517  size = clib_host_to_net_u32 (*(u32 *) msg);
518  msg += sizeof (u32);
519 
521  msg_id = ntohs (*((u16 *) msg));
522  else
523  msg_id = *((u16 *) msg);
524 
525  cfgp = am->api_trace_cfg + msg_id;
526  if (!cfgp)
527  {
528  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
529  munmap (hp, file_size);
530  vec_free (tmpbuf);
531  am->replay_in_progress = 0;
532  return;
533  }
534 
535  /* Copy the buffer (from the read-only mmap'ed file) */
536  vec_validate (tmpbuf, size - 1 + sizeof (uword));
537  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
538  clib_memset (tmpbuf, 0xf, sizeof (uword));
539 
540  /*
541  * Endian swap if needed. All msg data is supposed to be
542  * in network byte order. All msg handlers are supposed to
543  * know that. The generic message dumpers don't know that.
544  * One could fix apigen, I suppose.
545  */
546  if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
547  {
548  void (*endian_fp) (void *);
549  if (msg_id >= vec_len (am->msg_endian_handlers)
550  || (am->msg_endian_handlers[msg_id] == 0))
551  {
552  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
553  munmap (hp, file_size);
554  vec_free (tmpbuf);
555  am->replay_in_progress = 0;
556  return;
557  }
558  endian_fp = am->msg_endian_handlers[msg_id];
559  (*endian_fp) (tmpbuf + sizeof (uword));
560  }
561 
562  /* msg_id always in network byte order */
564  {
565  msg_idp = (u16 *) (tmpbuf + sizeof (uword));
566  *msg_idp = msg_id;
567  }
568 
569  switch (which)
570  {
571  case CUSTOM_DUMP:
572  case DUMP:
573  if (msg_id < vec_len (am->msg_print_handlers) &&
574  am->msg_print_handlers[msg_id])
575  {
576  u8 *(*print_fp) (void *, void *);
577 
578  print_fp = (void *) am->msg_print_handlers[msg_id];
579  (*print_fp) (tmpbuf + sizeof (uword), vm);
580  }
581  else
582  {
583  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
584  msg_id);
585  break;
586  }
587  break;
588 
589  case INITIALIZERS:
590  if (msg_id < vec_len (am->msg_print_handlers) &&
591  am->msg_print_handlers[msg_id])
592  {
593  u8 *s;
594  int j;
595  u8 *(*print_fp) (void *, void *);
596 
597  print_fp = (void *) am->msg_print_handlers[msg_id];
598 
599  vlib_cli_output (vm, "/*");
600 
601  (*print_fp) (tmpbuf + sizeof (uword), vm);
602  vlib_cli_output (vm, "*/\n");
603 
604  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
605  am->msg_names[msg_id], i,
606  am->api_trace_cfg[msg_id].size);
607 
608  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
609  {
610  if ((j & 7) == 0)
611  s = format (s, "\n ");
612  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
613  }
614  s = format (s, "\n};\n%c", 0);
615  vlib_cli_output (vm, (char *) s);
616  vec_free (s);
617  }
618  break;
619 
620  case REPLAY:
621  if (msg_id < vec_len (am->msg_print_handlers) &&
622  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
623  {
624  void (*handler) (void *, vlib_main_t *);
625 
626  handler = (void *) am->msg_handlers[msg_id];
627 
628  if (!am->is_mp_safe[msg_id])
630  (*handler) (tmpbuf + sizeof (uword), vm);
631  if (!am->is_mp_safe[msg_id])
633  }
634  else
635  {
636  if (cfgp->replay_enable)
637  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
638  msg_id);
639  break;
640  }
641  break;
642  }
643 
644  _vec_len (tmpbuf) = 0;
645  msg += size;
646  }
647 
648  if (saved_print_handlers)
649  {
650  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
651  vec_len (am->msg_print_handlers) * sizeof (void *));
652  vec_free (saved_print_handlers);
653  }
654 
655  munmap (hp, file_size);
656  vec_free (tmpbuf);
657  am->replay_in_progress = 0;
658 }
659 
660 static clib_error_t *
662  unformat_input_t * input, vlib_cli_command_t * cmd)
663 {
664  u32 nitems = 256 << 10;
665  api_main_t *am = &api_main;
667  u8 *filename;
668  u32 first = 0;
669  u32 last = (u32) ~ 0;
670  FILE *fp;
671  int rv;
672 
674  {
675  if (unformat (input, "on") || unformat (input, "enable"))
676  {
677  if (unformat (input, "nitems %d", &nitems))
678  ;
679  vl_msg_api_trace_configure (am, which, nitems);
680  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
681  }
682  else if (unformat (input, "off"))
683  {
684  vl_msg_api_trace_onoff (am, which, 0);
685  }
686  else if (unformat (input, "save %s", &filename))
687  {
688  u8 *chroot_filename;
689  if (strstr ((char *) filename, "..")
690  || index ((char *) filename, '/'))
691  {
692  vlib_cli_output (vm, "illegal characters in filename '%s'",
693  filename);
694  return 0;
695  }
696 
697  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
698 
699  vec_free (filename);
700 
701  fp = fopen ((char *) chroot_filename, "w");
702  if (fp == NULL)
703  {
704  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
705  return 0;
706  }
707  rv = vl_msg_api_trace_save (am, which, fp);
708  fclose (fp);
709  if (rv == -1)
710  vlib_cli_output (vm, "API Trace data not present\n");
711  else if (rv == -2)
712  vlib_cli_output (vm, "File for writing is closed\n");
713  else if (rv == -10)
714  vlib_cli_output (vm, "Error while writing header to file\n");
715  else if (rv == -11)
716  vlib_cli_output (vm, "Error while writing trace to file\n");
717  else if (rv == -12)
718  vlib_cli_output (vm,
719  "Error while writing end of buffer trace to file\n");
720  else if (rv == -13)
721  vlib_cli_output (vm,
722  "Error while writing start of buffer trace to file\n");
723  else if (rv < 0)
724  vlib_cli_output (vm, "Unknown error while saving: %d", rv);
725  else
726  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
727  vec_free (chroot_filename);
728  }
729  else if (unformat (input, "dump %s", &filename))
730  {
731  vl_msg_api_process_file (vm, filename, first, last, DUMP);
732  }
733  else if (unformat (input, "custom-dump %s", &filename))
734  {
735  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
736  }
737  else if (unformat (input, "replay %s", &filename))
738  {
739  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
740  }
741  else if (unformat (input, "initializers %s", &filename))
742  {
743  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
744  }
745  else if (unformat (input, "tx"))
746  {
747  which = VL_API_TRACE_TX;
748  }
749  else if (unformat (input, "first %d", &first))
750  {
751  ;
752  }
753  else if (unformat (input, "last %d", &last))
754  {
755  ;
756  }
757  else if (unformat (input, "status"))
758  {
760  am, which);
761  }
762  else if (unformat (input, "free"))
763  {
764  vl_msg_api_trace_onoff (am, which, 0);
765  vl_msg_api_trace_free (am, which);
766  }
767  else if (unformat (input, "post-mortem-on"))
769  else if (unformat (input, "post-mortem-off"))
771  else
772  return clib_error_return (0, "unknown input `%U'",
773  format_unformat_error, input);
774  }
775  return 0;
776 }
777 
778 /*?
779  * Display, replay, or save a binary API trace
780 ?*/
781 
782 /* *INDENT-OFF* */
784 {
785  .path = "api trace",
786  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
787  "[post-mortem-on][dump|custom-dump|save|replay <file>]",
788  .function = api_trace_command_fn,
789 };
790 /* *INDENT-ON* */
791 
792 static clib_error_t *
794  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
795 {
796  u32 nitems = 1024;
798  api_main_t *am = &api_main;
799 
801  {
802  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
803  goto configure;
804  else if (unformat (input, "tx nitems %u", &nitems)
805  || unformat (input, "tx"))
806  {
807  which = VL_API_TRACE_RX;
808  goto configure;
809  }
810  else if (unformat (input, "on rx"))
811  {
813  }
814  else if (unformat (input, "on tx"))
815  {
817  }
818  else if (unformat (input, "on"))
819  {
821  }
822  else if (unformat (input, "off"))
823  {
826  }
827  else if (unformat (input, "free"))
828  {
833  }
834  else if (unformat (input, "debug on"))
835  {
836  am->msg_print_flag = 1;
837  }
838  else if (unformat (input, "debug off"))
839  {
840  am->msg_print_flag = 0;
841  }
842  else
843  return clib_error_return (0, "unknown input `%U'",
844  format_unformat_error, input);
845  }
846  return 0;
847 
848 configure:
849  if (vl_msg_api_trace_configure (am, which, nitems))
850  {
851  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
852  which, nitems);
853  }
854 
855  return 0;
856 }
857 
858 /*?
859  * Control the binary API trace mechanism
860 ?*/
861 /* *INDENT-OFF* */
863 {
864  .path = "set api-trace [on][on tx][on rx][off][free][debug on][debug off]",
865  .short_help = "API trace",
866  .function = vl_api_trace_command,
867 };
868 /* *INDENT-ON* */
869 
870 static clib_error_t *
872 {
873  u32 nitems = 256 << 10;
875  api_main_t *am = &api_main;
876 
878  {
879  if (unformat (input, "on") || unformat (input, "enable"))
880  {
881  if (unformat (input, "nitems %d", &nitems))
882  ;
883  vl_msg_api_trace_configure (am, which, nitems);
884  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
886  }
887  else if (unformat (input, "save-api-table %s",
889  ;
890  else
891  return clib_error_return (0, "unknown input `%U'",
892  format_unformat_error, input);
893  }
894  return 0;
895 }
896 
897 /*?
898  * This module has three configuration parameters:
899  * "on" or "enable" - enables binary api tracing
900  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
901  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
902 ?*/
904 
905 static clib_error_t *
907 {
908  api_main_t *am = &api_main;
909  u32 nitems;
910 
912  {
913  if (unformat (input, "length %d", &nitems) ||
914  (unformat (input, "len %d", &nitems)))
915  {
916  if (nitems >= 1024)
917  am->vlib_input_queue_length = nitems;
918  else
919  clib_warning ("vlib input queue length %d too small, ignored",
920  nitems);
921  }
922  else
923  return clib_error_return (0, "unknown input `%U'",
924  format_unformat_error, input);
925  }
926  return 0;
927 }
928 
930 
931 static u8 *
933 {
934  u8 *rv;
935 
936  rv = vec_dup (s);
937 
938  while (vec_len (rv) && rv[vec_len (rv)] != '_')
939  _vec_len (rv)--;
940 
941  rv[vec_len (rv)] = 0;
942 
943  return rv;
944 }
945 
946 static u8 *
948 {
949  int i;
950  u8 *rv;
951 
952  rv = vec_dup (s);
953 
954  for (i = vec_len (rv) - 1; i >= 0; i--)
955  {
956  if (rv[i] == '_')
957  {
958  vec_delete (rv, i + 1, 0);
959  break;
960  }
961  }
962  return rv;
963 }
964 
965 typedef struct
966 {
969  u8 *crc;
971  int which;
973 
974 static int
975 table_id_cmp (void *a1, void *a2)
976 {
977  msg_table_unserialize_t *n1 = a1;
978  msg_table_unserialize_t *n2 = a2;
979 
980  return (n1->msg_index - n2->msg_index);
981 }
982 
983 static int
984 table_name_and_crc_cmp (void *a1, void *a2)
985 {
986  msg_table_unserialize_t *n1 = a1;
987  msg_table_unserialize_t *n2 = a2;
988 
989  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
990 }
991 
992 static clib_error_t *
994  unformat_input_t * input,
995  vlib_cli_command_t * cmd)
996 {
997  u8 *filename = 0;
998  api_main_t *am = &api_main;
999  serialize_main_t _sm, *sm = &_sm;
1000  clib_error_t *error;
1001  u32 nmsgs;
1002  u32 msg_index;
1003  u8 *name_and_crc;
1004  int compare_current = 0;
1005  int numeric_sort = 0;
1006  msg_table_unserialize_t *table = 0, *item;
1007  u32 i;
1008  u32 ndifferences = 0;
1009 
1010  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1011  {
1012  if (unformat (input, "file %s", &filename))
1013  ;
1014  else if (unformat (input, "compare-current")
1015  || unformat (input, "compare"))
1016  compare_current = 1;
1017  else if (unformat (input, "numeric"))
1018  numeric_sort = 1;
1019  else
1020  return clib_error_return (0, "unknown input `%U'",
1021  format_unformat_error, input);
1022  }
1023 
1024  if (numeric_sort && compare_current)
1025  return clib_error_return
1026  (0, "Comparison and numeric sorting are incompatible");
1027 
1028  if (filename == 0)
1029  return clib_error_return (0, "File not specified");
1030 
1031  /* Load the serialized message table from the table dump */
1032 
1033  error = unserialize_open_clib_file (sm, (char *) filename);
1034 
1035  if (error)
1036  return error;
1037 
1038  unserialize_integer (sm, &nmsgs, sizeof (u32));
1039 
1040  for (i = 0; i < nmsgs; i++)
1041  {
1043  unserialize_cstring (sm, (char **) &name_and_crc);
1044  vec_add2 (table, item, 1);
1045  item->msg_index = msg_index;
1046  item->name_and_crc = name_and_crc;
1047  item->name = extract_name (name_and_crc);
1048  item->crc = extract_crc (name_and_crc);
1049  item->which = 0; /* file */
1050  }
1051  serialize_close (sm);
1052 
1053  /* Compare with the current image? */
1054  if (compare_current)
1055  {
1056  /* Append the current message table */
1057  u8 *tblv = vl_api_serialize_message_table (am, 0);
1058 
1059  serialize_open_vector (sm, tblv);
1060  unserialize_integer (sm, &nmsgs, sizeof (u32));
1061 
1062  for (i = 0; i < nmsgs; i++)
1063  {
1065  unserialize_cstring (sm, (char **) &name_and_crc);
1066 
1067  vec_add2 (table, item, 1);
1068  item->msg_index = msg_index;
1069  item->name_and_crc = name_and_crc;
1070  item->name = extract_name (name_and_crc);
1071  item->crc = extract_crc (name_and_crc);
1072  item->which = 1; /* current_image */
1073  }
1074  vec_free (tblv);
1075  }
1076 
1077  /* Sort the table. */
1078  if (numeric_sort)
1080  else
1082 
1083  if (compare_current)
1084  {
1085  ndifferences = 0;
1086 
1087  /*
1088  * In this case, the recovered table will have two entries per
1089  * API message. So, if entries i and i+1 match, the message definitions
1090  * are identical. Otherwise, the crc is different, or a message is
1091  * present in only one of the tables.
1092  */
1093  vlib_cli_output (vm, "%=60s %s", "Message Name", "Result");
1094 
1095  for (i = 0; i < vec_len (table);)
1096  {
1097  /* Last message lonely? */
1098  if (i == vec_len (table) - 1)
1099  {
1100  ndifferences++;
1101  goto last_unique;
1102  }
1103 
1104  /* Identical pair? */
1105  if (!strncmp
1106  ((char *) table[i].name_and_crc,
1107  (char *) table[i + 1].name_and_crc,
1108  vec_len (table[i].name_and_crc)))
1109  {
1110  i += 2;
1111  continue;
1112  }
1113 
1114  ndifferences++;
1115 
1116  /* Only in one of two tables? */
1117  if (strncmp ((char *) table[i].name, (char *) table[i + 1].name,
1118  vec_len (table[i].name)))
1119  {
1120  last_unique:
1121  vlib_cli_output (vm, "%-60s only in %s",
1122  table[i].name, table[i].which ?
1123  "image" : "file");
1124  i++;
1125  continue;
1126  }
1127  /* In both tables, but with different signatures */
1128  vlib_cli_output (vm, "%-60s definition changed", table[i].name);
1129  i += 2;
1130  }
1131  if (ndifferences == 0)
1132  vlib_cli_output (vm, "No api message signature differences found.");
1133  else
1134  vlib_cli_output (vm, "Found %u api message signature differences",
1135  ndifferences);
1136  goto cleanup;
1137  }
1138 
1139  /* Dump the table, sorted as shown above */
1140  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1141 
1142  for (i = 0; i < vec_len (table); i++)
1143  {
1144  item = table + i;
1145  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1146  item->msg_index, item->crc);
1147  }
1148 
1149 cleanup:
1150  for (i = 0; i < vec_len (table); i++)
1151  {
1152  vec_free (table[i].name_and_crc);
1153  vec_free (table[i].name);
1154  vec_free (table[i].crc);
1155  }
1156 
1157  vec_free (table);
1158 
1159  return 0;
1160 }
1161 
1162 /*?
1163  * Displays a serialized API message decode table, sorted by message name
1164  *
1165  * @cliexpar
1166  * @cliexstart{show api dump file <filename>}
1167  * Message name MsgID CRC
1168  * accept_session 407 8e2a127e
1169  * accept_session_reply 408 67d8c22a
1170  * add_node_next 549 e4202993
1171  * add_node_next_reply 550 e89d6eed
1172  * etc.
1173  * @cliexend
1174 ?*/
1175 
1176 /*?
1177  * Compares a serialized API message decode table with the current image
1178  *
1179  * @cliexpar
1180  * @cliexstart{show api dump file <filename> compare}
1181  * ip_add_del_route definition changed
1182  * ip_table_add_del definition changed
1183  * l2_macs_event only in image
1184  * vnet_ip4_fib_counters only in file
1185  * vnet_ip4_nbr_counters only in file
1186  * @cliexend
1187 ?*/
1188 
1189 /*?
1190  * Display a serialized API message decode table, compare a saved
1191  * decode table with the current image, to establish API differences.
1192  *
1193 ?*/
1194 /* *INDENT-OFF* */
1196 {
1197  .path = "show api dump",
1198  .short_help = "show api dump file <filename> [numeric | compare-current]",
1199  .function = dump_api_table_file_command_fn,
1200 };
1201 
1202 /* *INDENT-ON* */
1203 /*
1204  * fd.io coding-style-patch-verification: ON
1205  *
1206  * Local Variables:
1207  * eval: (c-set-style "gnu")
1208  * End:
1209  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
Message range (belonging to a plugin)
Definition: api_common.h:111
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
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
u64 vector_rate_histogram[]
Definition: vlib_api.c:202
u8 * name
name of the plugin
Definition: api_common.h:113
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
u8 wrapped
trace has wrapped
Definition: api_common.h:93
int size
for sanity checking
Definition: api_common.h:81
unsigned long u64
Definition: types.h:89
#define NULL
Definition: clib.h:58
u8 * message_bounce
Don&#39;t automatically free message buffer vetor.
Definition: api_common.h:222
void vl_sock_api_dump_clients(vlib_main_t *vm, api_main_t *am)
Definition: socket_api.c:72
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:564
static u8 * extract_crc(u8 *s)
Definition: vlib_api_cli.c:947
int i
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
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
static int range_compare(vl_api_msg_range_t *a0, vl_api_msg_range_t *a1)
Definition: vlib_api_cli.c:278
unsigned char u8
Definition: types.h:56
trace_cfg_t * api_trace_cfg
Current trace configuration.
Definition: api_common.h:249
#define clib_memcpy(d, s, n)
Definition: string.h:180
static clib_error_t * api_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: vlib_api_cli.c:661
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:490
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:240
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:383
vl_api_registration_t ** vl_clients
vlib/vpp only: vector of client registrations
Definition: api_common.h:268
#define foreach_histogram_bucket
Definition: api.h:114
#define clib_arch_is_little_endian
Definition: byte_order.h:54
int replay_in_progress
Replay in progress?
Definition: api_common.h:334
#define clib_error_return(e, args...)
Definition: error.h:99
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
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
unsigned int u32
Definition: types.h:88
#define VL_API_BIG_ENDIAN
Definition: api_common.h:108
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
Definition: api_shared.c:154
u16 last_msg_id
last assigned message ID
Definition: api_common.h:115
char * name
Definition: main.h:111
uword size
static int table_id_cmp(void *a1, void *a2)
Definition: vlib_api_cli.c:975
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:216
int replay_enable
This message can be replayed.
Definition: api_common.h:83
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
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:375
static void cleanup(void)
Definition: client.c:130
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:172
static clib_error_t * api_trace_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:871
u8 name[64]
Definition: memclnt.api:152
void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
static vlib_cli_command_t cli_show_api_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_command)
Definition: vlib_api_cli.c:195
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:202
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:191
u8 enabled
trace is enabled
Definition: api_common.h:92
An API client registration, only in vpp/vlib.
Definition: api_common.h:45
#define clib_arch_is_big_endian
Definition: byte_order.h:53
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:112
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:793
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
API trace state.
Definition: api_common.h:89
vlib_main_t * vm
Definition: buffer.c:301
void serialize_open_vector(serialize_main_t *m, u8 *vector)
Definition: serialize.c:909
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
vl_api_msg_range_t * msg_ranges
vector of message ranges
Definition: api_common.h:280
static u8 * extract_name(u8 *s)
Definition: vlib_api_cli.c:932
clib_error_t * unserialize_open_clib_file(serialize_main_t *m, char *file)
Definition: serialize.c:1242
static int table_name_and_crc_cmp(void *a1, void *a2)
Definition: vlib_api_cli.c:984
#define clib_warning(format, args...)
Definition: error.h:59
u8 ** traces
Trace ring.
Definition: api_common.h:97
static void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:201
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: vlib_api.c:72
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:396
const char ** msg_names
Message name vector.
Definition: api_common.h:219
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
u8 * save_msg_table_filename
Dump (msg-name, crc) snapshot here at startup.
Definition: api_common.h:337
vl_api_trace_t * tx_trace
Sent message trace configuration.
Definition: api_common.h:243
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:311
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
static clib_error_t * api_queue_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:906
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:788
void serialize_close(serialize_main_t *m)
Definition: serialize.c:870
vl_api_trace_which_t
Trace RX / TX enum.
Definition: api_common.h:101
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:993
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
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_api_replay_t
Definition: vlib_api_cli.c:344
u16 first_msg_id
first assigned message ID
Definition: api_common.h:114
void(** msg_endian_handlers)(void *)
Message endian handler vector.
Definition: api_common.h:213
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:984
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
struct _svm_queue svm_queue_t
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void(** msg_handlers)(void *)
Message handler vector.
Definition: api_common.h:205
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:225
int msg_print_flag
Print every received message.
Definition: api_common.h:246
static vlib_cli_command_t api_trace_command
(constructor) VLIB_CLI_COMMAND (api_trace_command)
Definition: vlib_api_cli.c:783
Trace configuration for a single message.
Definition: api_common.h:79
#define VL_API_LITTLE_ENDIAN
Definition: api_common.h:107
void vl_msg_api_custom_dump_configure(api_main_t *am)
Definition: vlib_api_cli.c:391
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:388
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:322
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
api_main_t api_main
Definition: api_shared.c:35
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:725
static vlib_cli_command_t dump_api_table_file
(constructor) VLIB_CLI_COMMAND (dump_api_table_file)
void vl_msg_api_post_mortem_dump_enable_disable(int enable)
Definition: api_shared.c:781
static u8 * format_api_msg_range(u8 *s, va_list *args)
Definition: vlib_api_cli.c:289
u32 nitems
Number of trace records.
Definition: api_common.h:95
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u32 vlib_input_queue_length
vpp/vlib input queue length
Definition: api_common.h:319
u8 * format_vl_msg_api_trace_status(u8 *s, va_list *args)
Definition: vlib_api_cli.c:353
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128