FD.io VPP  v20.01-rc1
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 static clib_error_t *
676  unformat_input_t * input, vlib_cli_command_t * cmd)
677 {
678  u32 nitems = 256 << 10;
679  api_main_t *am = vlibapi_get_main ();
681  u8 *filename = 0;
682  u8 *chroot_filename = 0;
683  u32 first = 0;
684  u32 last = (u32) ~ 0;
685  FILE *fp;
686  int rv;
687 
689  {
690  if (unformat (input, "on") || unformat (input, "enable"))
691  {
692  if (unformat (input, "nitems %d", &nitems))
693  ;
694  vl_msg_api_trace_configure (am, which, nitems);
695  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
696  }
697  else if (unformat (input, "off"))
698  {
699  vl_msg_api_trace_onoff (am, which, 0);
700  }
701  else if (unformat (input, "save %s", &filename))
702  {
703  if (strstr ((char *) filename, "..")
704  || index ((char *) filename, '/'))
705  {
706  vlib_cli_output (vm, "illegal characters in filename '%s'",
707  filename);
708  goto out;
709  }
710 
711  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
712 
713  vec_free (filename);
714 
715  fp = fopen ((char *) chroot_filename, "w");
716  if (fp == NULL)
717  {
718  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
719  goto out;
720  }
721  rv = vl_msg_api_trace_save (am, which, fp);
722  fclose (fp);
723  if (rv == -1)
724  vlib_cli_output (vm, "API Trace data not present\n");
725  else if (rv == -2)
726  vlib_cli_output (vm, "File for writing is closed\n");
727  else if (rv == -10)
728  vlib_cli_output (vm, "Error while writing header to file\n");
729  else if (rv == -11)
730  vlib_cli_output (vm, "Error while writing trace to file\n");
731  else if (rv == -12)
732  vlib_cli_output (vm,
733  "Error while writing end of buffer trace to file\n");
734  else if (rv == -13)
735  vlib_cli_output (vm,
736  "Error while writing start of buffer trace to file\n");
737  else if (rv < 0)
738  vlib_cli_output (vm, "Unknown error while saving: %d", rv);
739  else
740  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
741  goto out;
742  }
743  else if (unformat (input, "dump %s", &filename))
744  {
745  vl_msg_api_process_file (vm, filename, first, last, DUMP);
746  }
747  else if (unformat (input, "custom-dump %s", &filename))
748  {
749  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
750  }
751  else if (unformat (input, "replay %s", &filename))
752  {
753  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
754  }
755  else if (unformat (input, "initializers %s", &filename))
756  {
757  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
758  }
759  else if (unformat (input, "tx"))
760  {
761  which = VL_API_TRACE_TX;
762  }
763  else if (unformat (input, "first %d", &first))
764  {
765  ;
766  }
767  else if (unformat (input, "last %d", &last))
768  {
769  ;
770  }
771  else if (unformat (input, "status"))
772  {
774  am, which);
775  }
776  else if (unformat (input, "free"))
777  {
778  vl_msg_api_trace_onoff (am, which, 0);
779  vl_msg_api_trace_free (am, which);
780  }
781  else if (unformat (input, "post-mortem-on"))
783  else if (unformat (input, "post-mortem-off"))
785  else
786  return clib_error_return (0, "unknown input `%U'",
787  format_unformat_error, input);
788  }
789 out:
790  vec_free (filename);
791  vec_free (chroot_filename);
792  return 0;
793 }
794 
795 /*?
796  * Display, replay, or save a binary API trace
797 ?*/
798 
799 /* *INDENT-OFF* */
801 {
802  .path = "api trace",
803  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
804  "[post-mortem-on][dump|custom-dump|save|replay <file>]",
805  .function = api_trace_command_fn,
806 };
807 /* *INDENT-ON* */
808 
809 static clib_error_t *
811  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
812 {
813  u32 nitems = 1024;
815  api_main_t *am = vlibapi_get_main ();
816 
818  {
819  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
820  goto configure;
821  else if (unformat (input, "tx nitems %u", &nitems)
822  || unformat (input, "tx"))
823  {
824  which = VL_API_TRACE_RX;
825  goto configure;
826  }
827  else if (unformat (input, "on rx"))
828  {
830  }
831  else if (unformat (input, "on tx"))
832  {
834  }
835  else if (unformat (input, "on"))
836  {
838  }
839  else if (unformat (input, "off"))
840  {
843  }
844  else if (unformat (input, "free"))
845  {
850  }
851  else if (unformat (input, "debug on"))
852  {
853  am->msg_print_flag = 1;
854  }
855  else if (unformat (input, "debug off"))
856  {
857  am->msg_print_flag = 0;
858  }
859  else
860  return clib_error_return (0, "unknown input `%U'",
861  format_unformat_error, input);
862  }
863  return 0;
864 
865 configure:
866  if (vl_msg_api_trace_configure (am, which, nitems))
867  {
868  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
869  which, nitems);
870  }
871 
872  return 0;
873 }
874 
875 /*?
876  * Control the binary API trace mechanism
877 ?*/
878 /* *INDENT-OFF* */
880 {
881  .path = "set api-trace",
882  .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
883  .function = vl_api_trace_command,
884 };
885 /* *INDENT-ON* */
886 
887 static clib_error_t *
889 {
890  u32 nitems = 256 << 10;
892  api_main_t *am = vlibapi_get_main ();
893 
895  {
896  if (unformat (input, "on") || unformat (input, "enable"))
897  {
898  if (unformat (input, "nitems %d", &nitems))
899  ;
900  vl_msg_api_trace_configure (am, which, nitems);
901  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
903  }
904  else if (unformat (input, "save-api-table %s",
906  ;
907  else
908  return clib_error_return (0, "unknown input `%U'",
909  format_unformat_error, input);
910  }
911  return 0;
912 }
913 
914 /*?
915  * This module has three configuration parameters:
916  * "on" or "enable" - enables binary api tracing
917  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
918  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
919 ?*/
921 
922 static clib_error_t *
924 {
925  api_main_t *am = vlibapi_get_main ();
926  u32 nitems;
927 
929  {
930  if (unformat (input, "length %d", &nitems) ||
931  (unformat (input, "len %d", &nitems)))
932  {
933  if (nitems >= 1024)
934  am->vlib_input_queue_length = nitems;
935  else
936  clib_warning ("vlib input queue length %d too small, ignored",
937  nitems);
938  }
939  else
940  return clib_error_return (0, "unknown input `%U'",
941  format_unformat_error, input);
942  }
943  return 0;
944 }
945 
947 
948 static u8 *
950 {
951  u8 *rv;
952 
953  rv = vec_dup (s);
954 
955  while (vec_len (rv) && rv[vec_len (rv)] != '_')
956  _vec_len (rv)--;
957 
958  rv[vec_len (rv)] = 0;
959 
960  return rv;
961 }
962 
963 static u8 *
965 {
966  int i;
967  u8 *rv;
968 
969  rv = vec_dup (s);
970 
971  for (i = vec_len (rv) - 1; i >= 0; i--)
972  {
973  if (rv[i] == '_')
974  {
975  vec_delete (rv, i + 1, 0);
976  break;
977  }
978  }
979  return rv;
980 }
981 
982 typedef struct
983 {
986  u8 *crc;
988  int which;
990 
991 static int
992 table_id_cmp (void *a1, void *a2)
993 {
994  msg_table_unserialize_t *n1 = a1;
995  msg_table_unserialize_t *n2 = a2;
996 
997  return (n1->msg_index - n2->msg_index);
998 }
999 
1000 static int
1001 table_name_and_crc_cmp (void *a1, void *a2)
1002 {
1003  msg_table_unserialize_t *n1 = a1;
1004  msg_table_unserialize_t *n2 = a2;
1005 
1006  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1007 }
1008 
1009 static clib_error_t *
1011  unformat_input_t * input,
1012  vlib_cli_command_t * cmd)
1013 {
1014  u8 *filename = 0;
1015  api_main_t *am = vlibapi_get_main ();
1016  serialize_main_t _sm, *sm = &_sm;
1017  clib_error_t *error;
1018  u32 nmsgs;
1019  u32 msg_index;
1020  u8 *name_and_crc;
1021  int compare_current = 0;
1022  int numeric_sort = 0;
1023  msg_table_unserialize_t *table = 0, *item;
1024  u32 i;
1025  u32 ndifferences = 0;
1026 
1027  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1028  {
1029  if (unformat (input, "file %s", &filename))
1030  ;
1031  else if (unformat (input, "compare-current")
1032  || unformat (input, "compare"))
1033  compare_current = 1;
1034  else if (unformat (input, "numeric"))
1035  numeric_sort = 1;
1036  else
1037  return clib_error_return (0, "unknown input `%U'",
1038  format_unformat_error, input);
1039  }
1040 
1041  if (numeric_sort && compare_current)
1042  return clib_error_return
1043  (0, "Comparison and numeric sorting are incompatible");
1044 
1045  if (filename == 0)
1046  return clib_error_return (0, "File not specified");
1047 
1048  /* Load the serialized message table from the table dump */
1049 
1050  error = unserialize_open_clib_file (sm, (char *) filename);
1051 
1052  if (error)
1053  return error;
1054 
1055  unserialize_integer (sm, &nmsgs, sizeof (u32));
1056 
1057  for (i = 0; i < nmsgs; i++)
1058  {
1060  unserialize_cstring (sm, (char **) &name_and_crc);
1061  vec_add2 (table, item, 1);
1062  item->msg_index = msg_index;
1063  item->name_and_crc = name_and_crc;
1064  item->name = extract_name (name_and_crc);
1065  item->crc = extract_crc (name_and_crc);
1066  item->which = 0; /* file */
1067  }
1068  unserialize_close (sm);
1069 
1070  /* Compare with the current image? */
1071  if (compare_current)
1072  {
1073  /* Append the current message table */
1074  u8 *tblv = vl_api_serialize_message_table (am, 0);
1075 
1076  serialize_open_vector (sm, tblv);
1077  unserialize_integer (sm, &nmsgs, sizeof (u32));
1078 
1079  for (i = 0; i < nmsgs; i++)
1080  {
1082  unserialize_cstring (sm, (char **) &name_and_crc);
1083 
1084  vec_add2 (table, item, 1);
1085  item->msg_index = msg_index;
1086  item->name_and_crc = name_and_crc;
1087  item->name = extract_name (name_and_crc);
1088  item->crc = extract_crc (name_and_crc);
1089  item->which = 1; /* current_image */
1090  }
1091  vec_free (tblv);
1092  }
1093 
1094  /* Sort the table. */
1095  if (numeric_sort)
1097  else
1099 
1100  if (compare_current)
1101  {
1102  u8 *dashes = 0;
1103  ndifferences = 0;
1104 
1105  /*
1106  * In this case, the recovered table will have two entries per
1107  * API message. So, if entries i and i+1 match, the message definitions
1108  * are identical. Otherwise, the crc is different, or a message is
1109  * present in only one of the tables.
1110  */
1111  vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1112  vec_validate_init_empty (dashes, 60, '-');
1113  vec_terminate_c_string (dashes);
1114  vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1115  vec_free (dashes);
1116  for (i = 0; i < vec_len (table);)
1117  {
1118  /* Last message lonely? */
1119  if (i == vec_len (table) - 1)
1120  {
1121  ndifferences++;
1122  goto last_unique;
1123  }
1124 
1125  /* Identical pair? */
1126  if (!strncmp
1127  ((char *) table[i].name_and_crc,
1128  (char *) table[i + 1].name_and_crc,
1129  vec_len (table[i].name_and_crc)))
1130  {
1131  i += 2;
1132  continue;
1133  }
1134 
1135  ndifferences++;
1136 
1137  /* Only in one of two tables? */
1138  if (i + 1 == vec_len (table)
1139  || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1140  {
1141  last_unique:
1142  vlib_cli_output (vm, "%-60s | only in %s",
1143  table[i].name, table[i].which ?
1144  "image" : "file");
1145  i++;
1146  continue;
1147  }
1148  /* In both tables, but with different signatures */
1149  vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1150  i += 2;
1151  }
1152  if (ndifferences == 0)
1153  vlib_cli_output (vm, "No api message signature differences found.");
1154  else
1155  vlib_cli_output (vm, "\nFound %u api message signature differences",
1156  ndifferences);
1157  goto cleanup;
1158  }
1159 
1160  /* Dump the table, sorted as shown above */
1161  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1162 
1163  for (i = 0; i < vec_len (table); i++)
1164  {
1165  item = table + i;
1166  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1167  item->msg_index, item->crc);
1168  }
1169 
1170 cleanup:
1171  for (i = 0; i < vec_len (table); i++)
1172  {
1173  vec_free (table[i].name_and_crc);
1174  vec_free (table[i].name);
1175  vec_free (table[i].crc);
1176  }
1177 
1178  vec_free (table);
1179 
1180  return 0;
1181 }
1182 
1183 /*?
1184  * Displays a serialized API message decode table, sorted by message name
1185  *
1186  * @cliexpar
1187  * @cliexstart{show api dump file <filename>}
1188  * Message name MsgID CRC
1189  * accept_session 407 8e2a127e
1190  * accept_session_reply 408 67d8c22a
1191  * add_node_next 549 e4202993
1192  * add_node_next_reply 550 e89d6eed
1193  * etc.
1194  * @cliexend
1195 ?*/
1196 
1197 /*?
1198  * Compares a serialized API message decode table with the current image
1199  *
1200  * @cliexpar
1201  * @cliexstart{show api dump file <filename> compare}
1202  * ip_add_del_route definition changed
1203  * ip_table_add_del definition changed
1204  * l2_macs_event only in image
1205  * vnet_ip4_fib_counters only in file
1206  * vnet_ip4_nbr_counters only in file
1207  * @cliexend
1208 ?*/
1209 
1210 /*?
1211  * Display a serialized API message decode table, compare a saved
1212  * decode table with the current image, to establish API differences.
1213  *
1214 ?*/
1215 /* *INDENT-OFF* */
1217 {
1218  .path = "show api dump",
1219  .short_help = "show api dump file <filename> [numeric | compare-current]",
1220  .function = dump_api_table_file_command_fn,
1221 };
1222 
1223 /* *INDENT-ON* */
1224 /*
1225  * fd.io coding-style-patch-verification: ON
1226  *
1227  * Local Variables:
1228  * eval: (c-set-style "gnu")
1229  * End:
1230  */
#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:879
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:964
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 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:675
#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)
Definition: vlib_api_cli.c:992
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:888
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:810
#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:949
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:923
#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
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:800
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