FD.io VPP  v20.01-48-g3e0dafb74
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 = vlibapi_get_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 = vlibapi_get_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 = vlibapi_get_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 = vlibapi_get_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 = vlibapi_get_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  CLIB_MEM_UNPOISON (hp, file_size);
446 
447  nitems = ntohl (hp->nitems);
448 
449  if (last_index == (u32) ~ 0)
450  {
451  last_index = nitems - 1;
452  }
453 
454  if (first_index >= nitems || last_index >= nitems)
455  {
456  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
457  first_index, last_index, nitems - 1);
458  munmap (hp, file_size);
459  CLIB_MEM_POISON (hp, file_size);
460  return;
461  }
462  if (hp->wrapped)
463  vlib_cli_output (vm,
464  "Note: wrapped/incomplete trace, results may vary\n");
465 
466  if (which == CUSTOM_DUMP)
467  {
468  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
470  }
471 
472  msg = (u8 *) (hp + 1);
473 
474  u16 *msgid_vec = 0;
475  serialize_main_t _sm, *sm = &_sm;
476  u32 msgtbl_size = ntohl (hp->msgtbl_size);
477  u8 *name_and_crc;
478 
479  unserialize_open_data (sm, msg, msgtbl_size);
480  unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
481 
482  for (i = 0; i < nitems_msgtbl; i++)
483  {
485  unserialize_cstring (sm, (char **) &name_and_crc);
486  u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
487  vec_validate (msgid_vec, msg_index);
488  msgid_vec[msg_index] = msg_index2;
489  }
490 
491  msg += msgtbl_size;
492 
493  for (i = 0; i < first_index; i++)
494  {
495  trace_cfg_t *cfgp;
496  int size;
497  u16 msg_id;
498 
499  size = clib_host_to_net_u32 (*(u32 *) msg);
500  msg += sizeof (u32);
501 
502  msg_id = ntohs (*((u16 *) msg));
503  if (msg_id < vec_len (msgid_vec))
504  msg_id = msgid_vec[msg_id];
505  cfgp = am->api_trace_cfg + msg_id;
506  if (!cfgp)
507  {
508  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
509  munmap (hp, file_size);
510  CLIB_MEM_POISON (hp, file_size);
511  return;
512  }
513  msg += size;
514  }
515 
516  if (which == REPLAY)
517  am->replay_in_progress = 1;
518 
519  for (; i <= last_index; i++)
520  {
521  trace_cfg_t *cfgp;
522  u16 msg_id;
523  int size;
524 
525  if (which == DUMP)
526  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
527 
528  size = clib_host_to_net_u32 (*(u32 *) msg);
529  msg += sizeof (u32);
530 
531  msg_id = ntohs (*((u16 *) msg));
532  if (msg_id < vec_len (msgid_vec))
533  {
534  msg_id = msgid_vec[msg_id];
535  }
536 
537  cfgp = am->api_trace_cfg + msg_id;
538  if (!cfgp)
539  {
540  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
541  munmap (hp, file_size);
542  CLIB_MEM_POISON (hp, file_size);
543  vec_free (tmpbuf);
544  am->replay_in_progress = 0;
545  return;
546  }
547 
548  /* Copy the buffer (from the read-only mmap'ed file) */
549  vec_validate (tmpbuf, size - 1 + sizeof (uword));
550  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
551  clib_memset (tmpbuf, 0xf, sizeof (uword));
552 
553  /*
554  * Endian swap if needed. All msg data is supposed to be in
555  * network byte order.
556  */
557  if (((which == DUMP || which == CUSTOM_DUMP)
559  {
560  void (*endian_fp) (void *);
561  if (msg_id >= vec_len (am->msg_endian_handlers)
562  || (am->msg_endian_handlers[msg_id] == 0))
563  {
564  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
565  munmap (hp, file_size);
566  CLIB_MEM_POISON (hp, file_size);
567  vec_free (tmpbuf);
568  am->replay_in_progress = 0;
569  return;
570  }
571  endian_fp = am->msg_endian_handlers[msg_id];
572  (*endian_fp) (tmpbuf + sizeof (uword));
573  }
574 
575  /* msg_id always in network byte order */
577  {
578  u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
579  *msg_idp = msg_id;
580  }
581 
582  switch (which)
583  {
584  case CUSTOM_DUMP:
585  case DUMP:
586  if (msg_id < vec_len (am->msg_print_handlers) &&
587  am->msg_print_handlers[msg_id])
588  {
589  u8 *(*print_fp) (void *, void *);
590 
591  print_fp = (void *) am->msg_print_handlers[msg_id];
592  (*print_fp) (tmpbuf + sizeof (uword), vm);
593  }
594  else
595  {
596  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
597  msg_id);
598  break;
599  }
600  break;
601 
602  case INITIALIZERS:
603  if (msg_id < vec_len (am->msg_print_handlers) &&
604  am->msg_print_handlers[msg_id])
605  {
606  u8 *s;
607  int j;
608  u8 *(*print_fp) (void *, void *);
609 
610  print_fp = (void *) am->msg_print_handlers[msg_id];
611 
612  vlib_cli_output (vm, "/*");
613 
614  (*print_fp) (tmpbuf + sizeof (uword), vm);
615  vlib_cli_output (vm, "*/\n");
616 
617  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
618  am->msg_names[msg_id], i,
619  am->api_trace_cfg[msg_id].size);
620 
621  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
622  {
623  if ((j & 7) == 0)
624  s = format (s, "\n ");
625  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
626  }
627  s = format (s, "\n};\n%c", 0);
628  vlib_cli_output (vm, (char *) s);
629  vec_free (s);
630  }
631  break;
632 
633  case REPLAY:
634  if (msg_id < vec_len (am->msg_print_handlers) &&
635  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
636  {
637  void (*handler) (void *, vlib_main_t *);
638 
639  handler = (void *) am->msg_handlers[msg_id];
640 
641  if (!am->is_mp_safe[msg_id])
643  (*handler) (tmpbuf + sizeof (uword), vm);
644  if (!am->is_mp_safe[msg_id])
646  }
647  else
648  {
649  if (cfgp->replay_enable)
650  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
651  msg_id);
652  break;
653  }
654  break;
655  }
656 
657  _vec_len (tmpbuf) = 0;
658  msg += size;
659  }
660 
661  if (saved_print_handlers)
662  {
663  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
664  vec_len (am->msg_print_handlers) * sizeof (void *));
665  vec_free (saved_print_handlers);
666  }
667 
668  munmap (hp, file_size);
669  CLIB_MEM_POISON (hp, file_size);
670  vec_free (tmpbuf);
671  am->replay_in_progress = 0;
672 }
673 
674 /** api_trace_command_fn - control the binary API trace / replay feature
675 
676  Note: this command MUST be marked thread-safe. Replay with
677  multiple worker threads depends in many cases on worker thread
678  graph replica maintenance. If we (implicitly) assert a worker
679  thread barrier at the debug CLI level, all graph replica changes
680  are deferred until the replay operation completes. If an interface
681  is deleted, the wheels fall off.
682  */
683 
684 static clib_error_t *
686  unformat_input_t * input, vlib_cli_command_t * cmd)
687 {
688  u32 nitems = 256 << 10;
689  api_main_t *am = vlibapi_get_main ();
691  u8 *filename = 0;
692  u8 *chroot_filename = 0;
693  u32 first = 0;
694  u32 last = (u32) ~ 0;
695  FILE *fp;
696  int rv;
697 
699  {
700  if (unformat (input, "on") || unformat (input, "enable"))
701  {
702  if (unformat (input, "nitems %d", &nitems))
703  ;
705  vl_msg_api_trace_configure (am, which, nitems);
706  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
708  }
709  else if (unformat (input, "off"))
710  {
712  vl_msg_api_trace_onoff (am, which, 0);
714  }
715  else if (unformat (input, "save %s", &filename))
716  {
717  if (strstr ((char *) filename, "..")
718  || index ((char *) filename, '/'))
719  {
720  vlib_cli_output (vm, "illegal characters in filename '%s'",
721  filename);
722  goto out;
723  }
724 
725  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
726 
727  vec_free (filename);
728 
729  fp = fopen ((char *) chroot_filename, "w");
730  if (fp == NULL)
731  {
732  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
733  goto out;
734  }
736  rv = vl_msg_api_trace_save (am, which, fp);
738  fclose (fp);
739  if (rv == -1)
740  vlib_cli_output (vm, "API Trace data not present\n");
741  else if (rv == -2)
742  vlib_cli_output (vm, "File for writing is closed\n");
743  else if (rv == -10)
744  vlib_cli_output (vm, "Error while writing header to file\n");
745  else if (rv == -11)
746  vlib_cli_output (vm, "Error while writing trace to file\n");
747  else if (rv == -12)
748  vlib_cli_output (vm,
749  "Error while writing end of buffer trace to file\n");
750  else if (rv == -13)
751  vlib_cli_output (vm,
752  "Error while writing start of buffer trace to file\n");
753  else if (rv < 0)
754  vlib_cli_output (vm, "Unknown error while saving: %d", rv);
755  else
756  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
757  goto out;
758  }
759  else if (unformat (input, "dump %s", &filename))
760  {
761  vl_msg_api_process_file (vm, filename, first, last, DUMP);
762  }
763  else if (unformat (input, "custom-dump %s", &filename))
764  {
765  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
766  }
767  else if (unformat (input, "replay %s", &filename))
768  {
769  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
770  }
771  else if (unformat (input, "initializers %s", &filename))
772  {
773  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
774  }
775  else if (unformat (input, "tx"))
776  {
777  which = VL_API_TRACE_TX;
778  }
779  else if (unformat (input, "first %d", &first))
780  {
781  ;
782  }
783  else if (unformat (input, "last %d", &last))
784  {
785  ;
786  }
787  else if (unformat (input, "status"))
788  {
790  am, which);
791  }
792  else if (unformat (input, "free"))
793  {
795  vl_msg_api_trace_onoff (am, which, 0);
796  vl_msg_api_trace_free (am, which);
798  }
799  else if (unformat (input, "post-mortem-on"))
801  else if (unformat (input, "post-mortem-off"))
803  else
804  return clib_error_return (0, "unknown input `%U'",
805  format_unformat_error, input);
806  }
807 out:
808  vec_free (filename);
809  vec_free (chroot_filename);
810  return 0;
811 }
812 
813 /*?
814  * Display, replay, or save a binary API trace
815 ?*/
816 
817 /* *INDENT-OFF* */
819 {
820  .path = "api trace",
821  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
822  "[post-mortem-on][dump|custom-dump|save|replay <file>]",
823  .function = api_trace_command_fn,
824  .is_mp_safe = 1,
825 };
826 /* *INDENT-ON* */
827 
828 static clib_error_t *
830  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
831 {
832  u32 nitems = 1024;
834  api_main_t *am = vlibapi_get_main ();
835 
837  {
838  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
839  goto configure;
840  else if (unformat (input, "tx nitems %u", &nitems)
841  || unformat (input, "tx"))
842  {
843  which = VL_API_TRACE_RX;
844  goto configure;
845  }
846  else if (unformat (input, "on rx"))
847  {
849  }
850  else if (unformat (input, "on tx"))
851  {
853  }
854  else if (unformat (input, "on"))
855  {
857  }
858  else if (unformat (input, "off"))
859  {
862  }
863  else if (unformat (input, "free"))
864  {
869  }
870  else if (unformat (input, "debug on"))
871  {
872  am->msg_print_flag = 1;
873  }
874  else if (unformat (input, "debug off"))
875  {
876  am->msg_print_flag = 0;
877  }
878  else
879  return clib_error_return (0, "unknown input `%U'",
880  format_unformat_error, input);
881  }
882  return 0;
883 
884 configure:
885  if (vl_msg_api_trace_configure (am, which, nitems))
886  {
887  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
888  which, nitems);
889  }
890 
891  return 0;
892 }
893 
894 /*?
895  * Control the binary API trace mechanism
896 ?*/
897 /* *INDENT-OFF* */
899 {
900  .path = "set api-trace",
901  .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
902  .function = vl_api_trace_command,
903 };
904 /* *INDENT-ON* */
905 
906 static clib_error_t *
908 {
909  u32 nitems = 256 << 10;
911  api_main_t *am = vlibapi_get_main ();
912 
914  {
915  if (unformat (input, "on") || unformat (input, "enable"))
916  {
917  if (unformat (input, "nitems %d", &nitems))
918  ;
919  vl_msg_api_trace_configure (am, which, nitems);
920  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
922  }
923  else if (unformat (input, "save-api-table %s",
925  ;
926  else
927  return clib_error_return (0, "unknown input `%U'",
928  format_unformat_error, input);
929  }
930  return 0;
931 }
932 
933 /*?
934  * This module has three configuration parameters:
935  * "on" or "enable" - enables binary api tracing
936  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
937  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
938 ?*/
940 
941 static clib_error_t *
943 {
944  api_main_t *am = vlibapi_get_main ();
945  u32 nitems;
946 
948  {
949  if (unformat (input, "length %d", &nitems) ||
950  (unformat (input, "len %d", &nitems)))
951  {
952  if (nitems >= 1024)
953  am->vlib_input_queue_length = nitems;
954  else
955  clib_warning ("vlib input queue length %d too small, ignored",
956  nitems);
957  }
958  else
959  return clib_error_return (0, "unknown input `%U'",
960  format_unformat_error, input);
961  }
962  return 0;
963 }
964 
966 
967 static u8 *
969 {
970  u8 *rv;
971 
972  rv = vec_dup (s);
973 
974  while (vec_len (rv) && rv[vec_len (rv)] != '_')
975  _vec_len (rv)--;
976 
977  rv[vec_len (rv)] = 0;
978 
979  return rv;
980 }
981 
982 static u8 *
984 {
985  int i;
986  u8 *rv;
987 
988  rv = vec_dup (s);
989 
990  for (i = vec_len (rv) - 1; i >= 0; i--)
991  {
992  if (rv[i] == '_')
993  {
994  vec_delete (rv, i + 1, 0);
995  break;
996  }
997  }
998  return rv;
999 }
1000 
1001 typedef struct
1002 {
1007  int which;
1009 
1010 static int
1011 table_id_cmp (void *a1, void *a2)
1012 {
1013  msg_table_unserialize_t *n1 = a1;
1014  msg_table_unserialize_t *n2 = a2;
1015 
1016  return (n1->msg_index - n2->msg_index);
1017 }
1018 
1019 static int
1020 table_name_and_crc_cmp (void *a1, void *a2)
1021 {
1022  msg_table_unserialize_t *n1 = a1;
1023  msg_table_unserialize_t *n2 = a2;
1024 
1025  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1026 }
1027 
1028 static clib_error_t *
1030  unformat_input_t * input,
1031  vlib_cli_command_t * cmd)
1032 {
1033  u8 *filename = 0;
1034  api_main_t *am = vlibapi_get_main ();
1035  serialize_main_t _sm, *sm = &_sm;
1036  clib_error_t *error;
1037  u32 nmsgs;
1038  u32 msg_index;
1039  u8 *name_and_crc;
1040  int compare_current = 0;
1041  int numeric_sort = 0;
1042  msg_table_unserialize_t *table = 0, *item;
1043  u32 i;
1044  u32 ndifferences = 0;
1045 
1046  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1047  {
1048  if (unformat (input, "file %s", &filename))
1049  ;
1050  else if (unformat (input, "compare-current")
1051  || unformat (input, "compare"))
1052  compare_current = 1;
1053  else if (unformat (input, "numeric"))
1054  numeric_sort = 1;
1055  else
1056  return clib_error_return (0, "unknown input `%U'",
1057  format_unformat_error, input);
1058  }
1059 
1060  if (numeric_sort && compare_current)
1061  return clib_error_return
1062  (0, "Comparison and numeric sorting are incompatible");
1063 
1064  if (filename == 0)
1065  return clib_error_return (0, "File not specified");
1066 
1067  /* Load the serialized message table from the table dump */
1068 
1069  error = unserialize_open_clib_file (sm, (char *) filename);
1070 
1071  if (error)
1072  return error;
1073 
1074  unserialize_integer (sm, &nmsgs, sizeof (u32));
1075 
1076  for (i = 0; i < nmsgs; i++)
1077  {
1079  unserialize_cstring (sm, (char **) &name_and_crc);
1080  vec_add2 (table, item, 1);
1081  item->msg_index = msg_index;
1082  item->name_and_crc = name_and_crc;
1083  item->name = extract_name (name_and_crc);
1084  item->crc = extract_crc (name_and_crc);
1085  item->which = 0; /* file */
1086  }
1087  unserialize_close (sm);
1088 
1089  /* Compare with the current image? */
1090  if (compare_current)
1091  {
1092  /* Append the current message table */
1093  u8 *tblv = vl_api_serialize_message_table (am, 0);
1094 
1095  serialize_open_vector (sm, tblv);
1096  unserialize_integer (sm, &nmsgs, sizeof (u32));
1097 
1098  for (i = 0; i < nmsgs; i++)
1099  {
1101  unserialize_cstring (sm, (char **) &name_and_crc);
1102 
1103  vec_add2 (table, item, 1);
1104  item->msg_index = msg_index;
1105  item->name_and_crc = name_and_crc;
1106  item->name = extract_name (name_and_crc);
1107  item->crc = extract_crc (name_and_crc);
1108  item->which = 1; /* current_image */
1109  }
1110  vec_free (tblv);
1111  }
1112 
1113  /* Sort the table. */
1114  if (numeric_sort)
1116  else
1118 
1119  if (compare_current)
1120  {
1121  u8 *dashes = 0;
1122  ndifferences = 0;
1123 
1124  /*
1125  * In this case, the recovered table will have two entries per
1126  * API message. So, if entries i and i+1 match, the message definitions
1127  * are identical. Otherwise, the crc is different, or a message is
1128  * present in only one of the tables.
1129  */
1130  vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1131  vec_validate_init_empty (dashes, 60, '-');
1132  vec_terminate_c_string (dashes);
1133  vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1134  vec_free (dashes);
1135  for (i = 0; i < vec_len (table);)
1136  {
1137  /* Last message lonely? */
1138  if (i == vec_len (table) - 1)
1139  {
1140  ndifferences++;
1141  goto last_unique;
1142  }
1143 
1144  /* Identical pair? */
1145  if (!strncmp
1146  ((char *) table[i].name_and_crc,
1147  (char *) table[i + 1].name_and_crc,
1148  vec_len (table[i].name_and_crc)))
1149  {
1150  i += 2;
1151  continue;
1152  }
1153 
1154  ndifferences++;
1155 
1156  /* Only in one of two tables? */
1157  if (i + 1 == vec_len (table)
1158  || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1159  {
1160  last_unique:
1161  vlib_cli_output (vm, "%-60s | only in %s",
1162  table[i].name, table[i].which ?
1163  "image" : "file");
1164  i++;
1165  continue;
1166  }
1167  /* In both tables, but with different signatures */
1168  vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1169  i += 2;
1170  }
1171  if (ndifferences == 0)
1172  vlib_cli_output (vm, "No api message signature differences found.");
1173  else
1174  vlib_cli_output (vm, "\nFound %u api message signature differences",
1175  ndifferences);
1176  goto cleanup;
1177  }
1178 
1179  /* Dump the table, sorted as shown above */
1180  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1181 
1182  for (i = 0; i < vec_len (table); i++)
1183  {
1184  item = table + i;
1185  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1186  item->msg_index, item->crc);
1187  }
1188 
1189 cleanup:
1190  for (i = 0; i < vec_len (table); i++)
1191  {
1192  vec_free (table[i].name_and_crc);
1193  vec_free (table[i].name);
1194  vec_free (table[i].crc);
1195  }
1196 
1197  vec_free (table);
1198 
1199  return 0;
1200 }
1201 
1202 /*?
1203  * Displays a serialized API message decode table, sorted by message name
1204  *
1205  * @cliexpar
1206  * @cliexstart{show api dump file <filename>}
1207  * Message name MsgID CRC
1208  * accept_session 407 8e2a127e
1209  * accept_session_reply 408 67d8c22a
1210  * add_node_next 549 e4202993
1211  * add_node_next_reply 550 e89d6eed
1212  * etc.
1213  * @cliexend
1214 ?*/
1215 
1216 /*?
1217  * Compares a serialized API message decode table with the current image
1218  *
1219  * @cliexpar
1220  * @cliexstart{show api dump file <filename> compare}
1221  * ip_add_del_route definition changed
1222  * ip_table_add_del definition changed
1223  * l2_macs_event only in image
1224  * vnet_ip4_fib_counters only in file
1225  * vnet_ip4_nbr_counters only in file
1226  * @cliexend
1227 ?*/
1228 
1229 /*?
1230  * Display a serialized API message decode table, compare a saved
1231  * decode table with the current image, to establish API differences.
1232  *
1233 ?*/
1234 /* *INDENT-OFF* */
1236 {
1237  .path = "show api dump",
1238  .short_help = "show api dump file <filename> [numeric | compare-current]",
1239  .function = dump_api_table_file_command_fn,
1240 };
1241 
1242 /* *INDENT-ON* */
1243 /*
1244  * fd.io coding-style-patch-verification: ON
1245  *
1246  * Local Variables:
1247  * eval: (c-set-style "gnu")
1248  * End:
1249  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
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
#define CLIB_MEM_UNPOISON(a, s)
Definition: sanitizer.h:47
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:898
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
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u8 * message_bounce
Don&#39;t automatically free message buffer vetor.
Definition: api_common.h:245
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1017
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:561
static u8 * extract_crc(u8 *s)
Definition: vlib_api_cli.c:983
int i
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:272
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:204
#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)
api_trace_command_fn - control the binary API trace / replay feature
Definition: vlib_api_cli.c:685
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:263
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:426
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:291
#define foreach_histogram_bucket
Definition: api.h:115
#define clib_arch_is_little_endian
Definition: byte_order.h:54
int replay_in_progress
Replay in progress?
Definition: api_common.h:357
#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:166
u16 last_msg_id
last assigned message ID
Definition: api_common.h:116
char * name
Definition: main.h:140
static int table_id_cmp(void *a1, void *a2)
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:239
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
u64 size
Definition: vhost_user.h:140
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:376
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:907
vlib_main_t * vm
Definition: in2out_ed.c:1810
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:225
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:226
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:124
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:829
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
API trace state.
Definition: api_common.h:90
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:342
vl_api_msg_range_t * msg_ranges
vector of message ranges
Definition: api_common.h:303
static u8 * extract_name(u8 *s)
Definition: vlib_api_cli.c:968
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)
#define clib_warning(format, args...)
Definition: error.h:59
u32 vl_msg_api_get_msg_index(u8 *name_and_crc)
Definition: api_shared.c:1052
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:242
void unserialize_close(serialize_main_t *m)
Definition: serialize.c:877
string name[64]
Definition: ip.api:44
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
u8 * save_msg_table_filename
Dump (msg-name, crc) snapshot here at startup.
Definition: api_common.h:360
vl_api_trace_t * tx_trace
Sent message trace configuration.
Definition: api_common.h:266
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:316
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:942
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:785
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:203
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:236
#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:983
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
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:378
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void(** msg_handlers)(void *)
Message handler vector.
Definition: api_common.h:228
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1496
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:248
int msg_print_flag
Print every received message.
Definition: api_common.h:269
static vlib_cli_command_t api_trace_command
(constructor) VLIB_CLI_COMMAND (api_trace_command)
Definition: vlib_api_cli.c:818
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:487
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:431
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:365
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
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
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:896
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:342
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
#define CLIB_MEM_POISON(a, s)
Definition: sanitizer.h:46
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128