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