FD.io VPP  v19.08-27-gf4dcae4
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  api_main_t *am = &api_main;
406  u8 *tmpbuf = 0;
407  u32 nitems, nitems_msgtbl;
408  void **saved_print_handlers = 0;
409 
410  fd = open ((char *) filename, O_RDONLY);
411 
412  if (fd < 0)
413  {
414  vlib_cli_output (vm, "Couldn't open %s\n", filename);
415  return;
416  }
417 
418  if (fstat (fd, &statb) < 0)
419  {
420  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
421  close (fd);
422  return;
423  }
424 
425  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
426  {
427  vlib_cli_output (vm, "File not plausible: %s\n", filename);
428  close (fd);
429  return;
430  }
431 
432  file_size = statb.st_size;
433  file_size = (file_size + 4095) & ~(4096);
434 
435  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
436 
437  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
438  {
439  vlib_cli_output (vm, "mmap failed: %s\n", filename);
440  close (fd);
441  return;
442  }
443  close (fd);
444 
445  nitems = ntohl (hp->nitems);
446 
447  if (last_index == (u32) ~ 0)
448  {
449  last_index = nitems - 1;
450  }
451 
452  if (first_index >= nitems || last_index >= nitems)
453  {
454  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
455  first_index, last_index, nitems - 1);
456  munmap (hp, file_size);
457  return;
458  }
459  if (hp->wrapped)
460  vlib_cli_output (vm,
461  "Note: wrapped/incomplete trace, results may vary\n");
462 
463  if (which == CUSTOM_DUMP)
464  {
465  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
467  }
468  msg = (u8 *) (hp + 1);
469 
470  u16 *msgid_vec = 0;
471  serialize_main_t _sm, *sm = &_sm;
472  u32 msgtbl_size = ntohl (hp->msgtbl_size);
473  u8 *name_and_crc;
474 
475  unserialize_open_data (sm, msg, msgtbl_size);
476  unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
477 
478  for (i = 0; i < nitems_msgtbl; i++)
479  {
481  unserialize_cstring (sm, (char **) &name_and_crc);
482  u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
483  vec_validate (msgid_vec, msg_index);
484  msgid_vec[msg_index] = msg_index2;
485  }
486 
487  msg += msgtbl_size;
488 
489  for (i = 0; i < first_index; i++)
490  {
491  trace_cfg_t *cfgp;
492  int size;
493  u16 msg_id;
494 
495  size = clib_host_to_net_u32 (*(u32 *) msg);
496  msg += sizeof (u32);
497 
498  msg_id = ntohs (*((u16 *) msg));
499  if (msg_id < vec_len (msgid_vec))
500  msg_id = msgid_vec[msg_id];
501  cfgp = am->api_trace_cfg + msg_id;
502  if (!cfgp)
503  {
504  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
505  munmap (hp, file_size);
506  return;
507  }
508  msg += size;
509  }
510 
511  if (which == REPLAY)
512  am->replay_in_progress = 1;
513 
514  for (; i <= last_index; i++)
515  {
516  trace_cfg_t *cfgp;
517  u16 msg_id;
518  int size;
519 
520  if (which == DUMP)
521  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
522 
523  size = clib_host_to_net_u32 (*(u32 *) msg);
524  msg += sizeof (u32);
525 
526  msg_id = ntohs (*((u16 *) msg));
527  if (msg_id < vec_len (msgid_vec))
528  {
529  msg_id = msgid_vec[msg_id];
530  }
531 
532  cfgp = am->api_trace_cfg + msg_id;
533  if (!cfgp)
534  {
535  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
536  munmap (hp, file_size);
537  vec_free (tmpbuf);
538  am->replay_in_progress = 0;
539  return;
540  }
541 
542  /* Copy the buffer (from the read-only mmap'ed file) */
543  vec_validate (tmpbuf, size - 1 + sizeof (uword));
544  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
545  clib_memset (tmpbuf, 0xf, sizeof (uword));
546 
547  /*
548  * Endian swap if needed. All msg data is supposed to be in
549  * network byte order.
550  */
551  if ((which == DUMP && clib_arch_is_little_endian))
552  {
553  void (*endian_fp) (void *);
554  if (msg_id >= vec_len (am->msg_endian_handlers)
555  || (am->msg_endian_handlers[msg_id] == 0))
556  {
557  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
558  munmap (hp, file_size);
559  vec_free (tmpbuf);
560  am->replay_in_progress = 0;
561  return;
562  }
563  endian_fp = am->msg_endian_handlers[msg_id];
564  (*endian_fp) (tmpbuf + sizeof (uword));
565  }
566 
567  /* msg_id always in network byte order */
569  {
570  u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
571  *msg_idp = msg_id;
572  }
573 
574  switch (which)
575  {
576  case CUSTOM_DUMP:
577  case DUMP:
578  if (msg_id < vec_len (am->msg_print_handlers) &&
579  am->msg_print_handlers[msg_id])
580  {
581  u8 *(*print_fp) (void *, void *);
582 
583  print_fp = (void *) am->msg_print_handlers[msg_id];
584  (*print_fp) (tmpbuf + sizeof (uword), vm);
585  }
586  else
587  {
588  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
589  msg_id);
590  break;
591  }
592  break;
593 
594  case INITIALIZERS:
595  if (msg_id < vec_len (am->msg_print_handlers) &&
596  am->msg_print_handlers[msg_id])
597  {
598  u8 *s;
599  int j;
600  u8 *(*print_fp) (void *, void *);
601 
602  print_fp = (void *) am->msg_print_handlers[msg_id];
603 
604  vlib_cli_output (vm, "/*");
605 
606  (*print_fp) (tmpbuf + sizeof (uword), vm);
607  vlib_cli_output (vm, "*/\n");
608 
609  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
610  am->msg_names[msg_id], i,
611  am->api_trace_cfg[msg_id].size);
612 
613  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
614  {
615  if ((j & 7) == 0)
616  s = format (s, "\n ");
617  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
618  }
619  s = format (s, "\n};\n%c", 0);
620  vlib_cli_output (vm, (char *) s);
621  vec_free (s);
622  }
623  break;
624 
625  case REPLAY:
626  if (msg_id < vec_len (am->msg_print_handlers) &&
627  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
628  {
629  void (*handler) (void *, vlib_main_t *);
630 
631  handler = (void *) am->msg_handlers[msg_id];
632 
633  if (!am->is_mp_safe[msg_id])
635  (*handler) (tmpbuf + sizeof (uword), vm);
636  if (!am->is_mp_safe[msg_id])
638  }
639  else
640  {
641  if (cfgp->replay_enable)
642  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
643  msg_id);
644  break;
645  }
646  break;
647  }
648 
649  _vec_len (tmpbuf) = 0;
650  msg += size;
651  }
652 
653  if (saved_print_handlers)
654  {
655  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
656  vec_len (am->msg_print_handlers) * sizeof (void *));
657  vec_free (saved_print_handlers);
658  }
659 
660  munmap (hp, file_size);
661  vec_free (tmpbuf);
662  am->replay_in_progress = 0;
663 }
664 
665 static clib_error_t *
667  unformat_input_t * input, vlib_cli_command_t * cmd)
668 {
669  u32 nitems = 256 << 10;
670  api_main_t *am = &api_main;
672  u8 *filename = 0;
673  u8 *chroot_filename = 0;
674  u32 first = 0;
675  u32 last = (u32) ~ 0;
676  FILE *fp;
677  int rv;
678 
680  {
681  if (unformat (input, "on") || unformat (input, "enable"))
682  {
683  if (unformat (input, "nitems %d", &nitems))
684  ;
685  vl_msg_api_trace_configure (am, which, nitems);
686  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
687  }
688  else if (unformat (input, "off"))
689  {
690  vl_msg_api_trace_onoff (am, which, 0);
691  }
692  else if (unformat (input, "save %s", &filename))
693  {
694  if (strstr ((char *) filename, "..")
695  || index ((char *) filename, '/'))
696  {
697  vlib_cli_output (vm, "illegal characters in filename '%s'",
698  filename);
699  goto out;
700  }
701 
702  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
703 
704  vec_free (filename);
705 
706  fp = fopen ((char *) chroot_filename, "w");
707  if (fp == NULL)
708  {
709  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
710  goto out;
711  }
712  rv = vl_msg_api_trace_save (am, which, fp);
713  fclose (fp);
714  if (rv == -1)
715  vlib_cli_output (vm, "API Trace data not present\n");
716  else if (rv == -2)
717  vlib_cli_output (vm, "File for writing is closed\n");
718  else if (rv == -10)
719  vlib_cli_output (vm, "Error while writing header to file\n");
720  else if (rv == -11)
721  vlib_cli_output (vm, "Error while writing trace to file\n");
722  else if (rv == -12)
723  vlib_cli_output (vm,
724  "Error while writing end of buffer trace to file\n");
725  else if (rv == -13)
726  vlib_cli_output (vm,
727  "Error while writing start of buffer trace to file\n");
728  else if (rv < 0)
729  vlib_cli_output (vm, "Unknown error while saving: %d", rv);
730  else
731  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
732  goto out;
733  }
734  else if (unformat (input, "dump %s", &filename))
735  {
736  vl_msg_api_process_file (vm, filename, first, last, DUMP);
737  }
738  else if (unformat (input, "custom-dump %s", &filename))
739  {
740  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
741  }
742  else if (unformat (input, "replay %s", &filename))
743  {
744  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
745  }
746  else if (unformat (input, "initializers %s", &filename))
747  {
748  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
749  }
750  else if (unformat (input, "tx"))
751  {
752  which = VL_API_TRACE_TX;
753  }
754  else if (unformat (input, "first %d", &first))
755  {
756  ;
757  }
758  else if (unformat (input, "last %d", &last))
759  {
760  ;
761  }
762  else if (unformat (input, "status"))
763  {
765  am, which);
766  }
767  else if (unformat (input, "free"))
768  {
769  vl_msg_api_trace_onoff (am, which, 0);
770  vl_msg_api_trace_free (am, which);
771  }
772  else if (unformat (input, "post-mortem-on"))
774  else if (unformat (input, "post-mortem-off"))
776  else
777  return clib_error_return (0, "unknown input `%U'",
778  format_unformat_error, input);
779  }
780 out:
781  vec_free (filename);
782  vec_free (chroot_filename);
783  return 0;
784 }
785 
786 /*?
787  * Display, replay, or save a binary API trace
788 ?*/
789 
790 /* *INDENT-OFF* */
792 {
793  .path = "api trace",
794  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
795  "[post-mortem-on][dump|custom-dump|save|replay <file>]",
796  .function = api_trace_command_fn,
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;
806  api_main_t *am = &api_main;
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  {
815  which = VL_API_TRACE_RX;
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;
883  api_main_t *am = &api_main;
884 
886  {
887  if (unformat (input, "on") || unformat (input, "enable"))
888  {
889  if (unformat (input, "nitems %d", &nitems))
890  ;
891  vl_msg_api_trace_configure (am, which, nitems);
892  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
894  }
895  else if (unformat (input, "save-api-table %s",
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 {
916  api_main_t *am = &api_main;
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;
1006  api_main_t *am = &api_main;
1007  serialize_main_t _sm, *sm = &_sm;
1008  clib_error_t *error;
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  */
#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:112
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:870
u64 vector_rate_histogram[]
Definition: vlib_api.c:179
u8 * name
name of the plugin
Definition: api_common.h:114
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
u8 wrapped
trace has wrapped
Definition: api_common.h:94
int size
for sanity checking
Definition: api_common.h:82
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:223
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1014
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:560
static u8 * extract_crc(u8 *s)
Definition: vlib_api_cli.c:955
int i
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
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:250
#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:666
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:241
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:417
void unserialize_open_data(serialize_main_t *m, u8 *data, uword n_data_bytes)
Definition: serialize.c:891
vl_api_registration_t ** vl_clients
vlib/vpp only: vector of client registrations
Definition: api_common.h:269
#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:335
#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
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:156
u16 last_msg_id
last assigned message ID
Definition: api_common.h:116
char * name
Definition: main.h:122
uword size
static int table_id_cmp(void *a1, void *a2)
Definition: vlib_api_cli.c:983
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:217
int replay_enable
This message can be replayed.
Definition: api_common.h:84
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:131
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:182
static clib_error_t * api_trace_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:879
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:203
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:216
u8 enabled
trace is enabled
Definition: api_common.h:93
An API client registration, only in vpp/vlib.
Definition: api_common.h:46
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:114
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
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
API trace state.
Definition: api_common.h:90
vlib_main_t * vm
Definition: buffer.c:312
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:281
static u8 * extract_name(u8 *s)
Definition: vlib_api_cli.c:940
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:992
#define clib_warning(format, args...)
Definition: error.h:59
u32 vl_msg_api_get_msg_index(u8 *name_and_crc)
Definition: api_shared.c:1029
u8 ** traces
Trace ring.
Definition: api_common.h:98
static void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:201
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:220
void unserialize_close(serialize_main_t *m)
Definition: serialize.c:877
#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:338
vl_api_trace_t * tx_trace
Sent message trace configuration.
Definition: api_common.h:244
#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:914
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:784
vl_api_trace_which_t
Trace RX / TX enum.
Definition: api_common.h:102
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: api_shared.c:193
static clib_error_t * dump_api_table_file_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
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:115
void(** msg_endian_handlers)(void *)
Message endian handler vector.
Definition: api_common.h:214
#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:980
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:206
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:226
int msg_print_flag
Print every received message.
Definition: api_common.h:247
static vlib_cli_command_t api_trace_command
(constructor) VLIB_CLI_COMMAND (api_trace_command)
Definition: vlib_api_cli.c:791
Trace configuration for a single message.
Definition: api_common.h:80
void vl_msg_api_custom_dump_configure(api_main_t *am)
Definition: vlib_api_cli.c:391
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:422
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:356
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:768
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:873
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:96
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
u32 vlib_input_queue_length
vpp/vlib input queue length
Definition: api_common.h:320
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:171
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128