FD.io VPP  v21.06
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:
155  vl_sock_api_dump_clients (vm, am);
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* */
195 VLIB_CLI_COMMAND (cli_show_api_command, static) =
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* */
206 VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
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* */
218 VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
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* */
269 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
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* */
336 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
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 *);
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,
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) & ~(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  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  return;
460  }
461  if (hp->wrapped)
462  vlib_cli_output (vm,
463  "Note: wrapped/incomplete trace, results may vary\n");
464 
465  if (which == CUSTOM_DUMP)
466  {
467  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
469  }
470 
471  msg = (u8 *) (hp + 1);
472 
473  u16 *msgid_vec = 0;
474  serialize_main_t _sm, *sm = &_sm;
475  u32 msgtbl_size = ntohl (hp->msgtbl_size);
476  u8 *name_and_crc;
477 
478  unserialize_open_data (sm, msg, msgtbl_size);
479  unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
480 
481  for (i = 0; i < nitems_msgtbl; i++)
482  {
484  unserialize_cstring (sm, (char **) &name_and_crc);
485  u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
486  vec_validate (msgid_vec, msg_index);
487  msgid_vec[msg_index] = msg_index2;
488  }
489 
490  msg += msgtbl_size;
491 
492  for (i = 0; i < first_index; i++)
493  {
494  trace_cfg_t *cfgp;
495  int size;
496  u16 msg_id;
497 
498  size = clib_host_to_net_u32 (*(u32 *) msg);
499  msg += sizeof (u32);
500 
501  msg_id = ntohs (*((u16 *) msg));
502  if (msg_id < vec_len (msgid_vec))
503  msg_id = msgid_vec[msg_id];
504  cfgp = am->api_trace_cfg + msg_id;
505  if (!cfgp)
506  {
507  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
508  munmap (hp, file_size);
509  return;
510  }
511  msg += size;
512  }
513 
514  if (which == REPLAY)
515  am->replay_in_progress = 1;
516 
517  for (; i <= last_index; i++)
518  {
519  trace_cfg_t *cfgp;
520  u16 msg_id;
521  int size;
522 
523  if (which == DUMP)
524  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
525 
526  size = clib_host_to_net_u32 (*(u32 *) msg);
527  msg += sizeof (u32);
528 
529  msg_id = ntohs (*((u16 *) msg));
530  if (msg_id < vec_len (msgid_vec))
531  {
532  msg_id = msgid_vec[msg_id];
533  }
534 
535  cfgp = am->api_trace_cfg + msg_id;
536  if (!cfgp)
537  {
538  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
539  munmap (hp, file_size);
540  vec_free (tmpbuf);
541  am->replay_in_progress = 0;
542  return;
543  }
544 
545  /* Copy the buffer (from the read-only mmap'ed file) */
546  vec_validate (tmpbuf, size - 1 + sizeof (uword));
547  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
548  clib_memset (tmpbuf, 0xf, sizeof (uword));
549 
550  /*
551  * Endian swap if needed. All msg data is supposed to be in
552  * network byte order.
553  */
554  if (((which == DUMP || which == CUSTOM_DUMP)
556  {
557  void (*endian_fp) (void *);
558  if (msg_id >= vec_len (am->msg_endian_handlers)
559  || (am->msg_endian_handlers[msg_id] == 0))
560  {
561  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
562  munmap (hp, file_size);
563  vec_free (tmpbuf);
564  am->replay_in_progress = 0;
565  return;
566  }
567  endian_fp = am->msg_endian_handlers[msg_id];
568  (*endian_fp) (tmpbuf + sizeof (uword));
569  }
570 
571  /* msg_id always in network byte order */
573  {
574  u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
575  *msg_idp = msg_id;
576  }
577 
578  switch (which)
579  {
580  case CUSTOM_DUMP:
581  case DUMP:
582  if (msg_id < vec_len (am->msg_print_handlers) &&
583  am->msg_print_handlers[msg_id])
584  {
585  u8 *(*print_fp) (void *, void *);
586 
587  print_fp = (void *) am->msg_print_handlers[msg_id];
588  (*print_fp) (tmpbuf + sizeof (uword), vm);
589  }
590  else
591  {
592  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
593  msg_id);
594  break;
595  }
596  break;
597 
598  case INITIALIZERS:
599  if (msg_id < vec_len (am->msg_print_handlers) &&
600  am->msg_print_handlers[msg_id])
601  {
602  u8 *s;
603  int j;
604  u8 *(*print_fp) (void *, void *);
605 
606  print_fp = (void *) am->msg_print_handlers[msg_id];
607 
608  vlib_cli_output (vm, "/*");
609 
610  (*print_fp) (tmpbuf + sizeof (uword), vm);
611  vlib_cli_output (vm, "*/\n");
612 
613  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
614  am->msg_names[msg_id], i,
615  am->api_trace_cfg[msg_id].size);
616 
617  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
618  {
619  if ((j & 7) == 0)
620  s = format (s, "\n ");
621  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
622  }
623  s = format (s, "\n};\n%c", 0);
624  vlib_cli_output (vm, (char *) s);
625  vec_free (s);
626  }
627  break;
628 
629  case REPLAY:
630  if (msg_id < vec_len (am->msg_print_handlers) &&
631  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
632  {
633  void (*handler) (void *, vlib_main_t *);
634 
635  handler = (void *) am->msg_handlers[msg_id];
636 
637  if (!am->is_mp_safe[msg_id])
639  (*handler) (tmpbuf + sizeof (uword), vm);
640  if (!am->is_mp_safe[msg_id])
642  }
643  else
644  {
645  if (cfgp->replay_enable)
646  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
647  msg_id);
648  break;
649  }
650  break;
651  }
652 
653  _vec_len (tmpbuf) = 0;
654  msg += size;
655  }
656 
657  if (saved_print_handlers)
658  {
659  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
660  vec_len (am->msg_print_handlers) * sizeof (void *));
661  vec_free (saved_print_handlers);
662  }
663 
664  munmap (hp, file_size);
665  vec_free (tmpbuf);
666  am->replay_in_progress = 0;
667 }
668 
669 /** api_trace_command_fn - control the binary API trace / replay feature
670 
671  Note: this command MUST be marked thread-safe. Replay with
672  multiple worker threads depends in many cases on worker thread
673  graph replica maintenance. If we (implicitly) assert a worker
674  thread barrier at the debug CLI level, all graph replica changes
675  are deferred until the replay operation completes. If an interface
676  is deleted, the wheels fall off.
677  */
678 
679 static clib_error_t *
681  unformat_input_t * input, vlib_cli_command_t * cmd)
682 {
683  unformat_input_t _line_input, *line_input = &_line_input;
684  u32 nitems = 256 << 10;
685  api_main_t *am = vlibapi_get_main ();
687  u8 *filename = 0;
688  u8 *chroot_filename = 0;
689  u32 first = 0;
690  u32 last = (u32) ~ 0;
691  FILE *fp;
692  int rv;
693 
694  /* Get a line of input. */
695  if (!unformat_user (input, unformat_line_input, line_input))
696  return 0;
697 
698  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
699  {
700  if (unformat (line_input, "on") || unformat (line_input, "enable"))
701  {
702  if (unformat (line_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 (line_input, "off"))
710  {
712  vl_msg_api_trace_onoff (am, which, 0);
714  }
715  else if (unformat (line_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 (line_input, "dump %s", &filename))
760  {
761  vl_msg_api_process_file (vm, filename, first, last, DUMP);
762  }
763  else if (unformat (line_input, "custom-dump %s", &filename))
764  {
765  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
766  }
767  else if (unformat (line_input, "replay %s", &filename))
768  {
769  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
770  }
771  else if (unformat (line_input, "initializers %s", &filename))
772  {
773  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
774  }
775  else if (unformat (line_input, "tx"))
776  {
777  which = VL_API_TRACE_TX;
778  }
779  else if (unformat (line_input, "first %d", &first))
780  {
781  ;
782  }
783  else if (unformat (line_input, "last %d", &last))
784  {
785  ;
786  }
787  else if (unformat (line_input, "status"))
788  {
790  am, which);
791  }
792  else if (unformat (line_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 (line_input, "post-mortem-on"))
801  else if (unformat (line_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  unformat_free (line_input);
811  return 0;
812 }
813 
814 /*?
815  * Display, replay, or save a binary API trace
816 ?*/
817 
818 /* *INDENT-OFF* */
819 VLIB_CLI_COMMAND (api_trace_command, static) =
820 {
821  .path = "api trace",
822  .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
823  "[post-mortem-on][dump|custom-dump|save|replay <file>]",
824  .function = api_trace_command_fn,
825  .is_mp_safe = 1,
826 };
827 /* *INDENT-ON* */
828 
829 static clib_error_t *
831  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
832 {
833  u32 nitems = 1024;
835  api_main_t *am = vlibapi_get_main ();
836 
838  {
839  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
840  goto configure;
841  else if (unformat (input, "tx nitems %u", &nitems)
842  || unformat (input, "tx"))
843  {
844  which = VL_API_TRACE_RX;
845  goto configure;
846  }
847  else if (unformat (input, "on rx"))
848  {
850  }
851  else if (unformat (input, "on tx"))
852  {
854  }
855  else if (unformat (input, "on"))
856  {
858  }
859  else if (unformat (input, "off"))
860  {
863  }
864  else if (unformat (input, "free"))
865  {
870  }
871  else if (unformat (input, "debug on"))
872  {
873  am->msg_print_flag = 1;
874  }
875  else if (unformat (input, "debug off"))
876  {
877  am->msg_print_flag = 0;
878  }
879  else
880  return clib_error_return (0, "unknown input `%U'",
881  format_unformat_error, input);
882  }
883  return 0;
884 
885 configure:
886  if (vl_msg_api_trace_configure (am, which, nitems))
887  {
888  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
889  which, nitems);
890  }
891 
892  return 0;
893 }
894 
895 /*?
896  * Control the binary API trace mechanism
897 ?*/
898 /* *INDENT-OFF* */
899 VLIB_CLI_COMMAND (trace, static) =
900 {
901  .path = "set api-trace",
902  .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
903  .function = vl_api_trace_command,
904 };
905 /* *INDENT-ON* */
906 
907 static clib_error_t *
909 {
910  u32 nitems = 256 << 10;
912  api_main_t *am = vlibapi_get_main ();
913 
915  {
916  if (unformat (input, "on") || unformat (input, "enable"))
917  {
918  if (unformat (input, "nitems %d", &nitems))
919  ;
920  vl_msg_api_trace_configure (am, which, nitems);
921  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
923  }
924  else if (unformat (input, "save-api-table %s",
926  ;
927  else
928  return clib_error_return (0, "unknown input `%U'",
929  format_unformat_error, input);
930  }
931  return 0;
932 }
933 
934 /*?
935  * This module has three configuration parameters:
936  * "on" or "enable" - enables binary api tracing
937  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
938  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
939 ?*/
941 
942 static clib_error_t *
944 {
945  api_main_t *am = vlibapi_get_main ();
946  u32 nitems;
947 
949  {
950  if (unformat (input, "length %d", &nitems) ||
951  (unformat (input, "len %d", &nitems)))
952  {
953  if (nitems >= 1024)
954  am->vlib_input_queue_length = nitems;
955  else
956  clib_warning ("vlib input queue length %d too small, ignored",
957  nitems);
958  }
959  else
960  return clib_error_return (0, "unknown input `%U'",
961  format_unformat_error, input);
962  }
963  return 0;
964 }
965 
967 
968 static u8 *
970 {
971  u8 *rv;
972 
973  rv = vec_dup (s);
974 
975  while (vec_len (rv) && rv[vec_len (rv)] != '_')
976  _vec_len (rv)--;
977 
978  rv[vec_len (rv)] = 0;
979 
980  return rv;
981 }
982 
983 static u8 *
985 {
986  int i;
987  u8 *rv;
988 
989  rv = vec_dup (s);
990 
991  for (i = vec_len (rv) - 1; i >= 0; i--)
992  {
993  if (rv[i] == '_')
994  {
995  vec_delete (rv, i + 1, 0);
996  break;
997  }
998  }
999  return rv;
1000 }
1001 
1002 typedef struct
1003 {
1008  int which;
1010 
1011 static int
1012 table_id_cmp (void *a1, void *a2)
1013 {
1014  msg_table_unserialize_t *n1 = a1;
1015  msg_table_unserialize_t *n2 = a2;
1016 
1017  return (n1->msg_index - n2->msg_index);
1018 }
1019 
1020 static int
1021 table_name_and_crc_cmp (void *a1, void *a2)
1022 {
1023  msg_table_unserialize_t *n1 = a1;
1024  msg_table_unserialize_t *n2 = a2;
1025 
1026  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1027 }
1028 
1029 static clib_error_t *
1031  unformat_input_t * input,
1032  vlib_cli_command_t * cmd)
1033 {
1034  u8 *filename = 0;
1035  api_main_t *am = vlibapi_get_main ();
1036  serialize_main_t _sm, *sm = &_sm;
1038  u32 nmsgs;
1039  u32 msg_index;
1040  u8 *name_and_crc;
1041  int compare_current = 0;
1042  int numeric_sort = 0;
1043  msg_table_unserialize_t *table = 0, *item;
1044  u32 i;
1045  u32 ndifferences = 0;
1046 
1047  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1048  {
1049  if (unformat (input, "file %s", &filename))
1050  ;
1051  else if (unformat (input, "compare-current")
1052  || unformat (input, "compare"))
1053  compare_current = 1;
1054  else if (unformat (input, "numeric"))
1055  numeric_sort = 1;
1056  else
1057  return clib_error_return (0, "unknown input `%U'",
1058  format_unformat_error, input);
1059  }
1060 
1061  if (numeric_sort && compare_current)
1062  return clib_error_return
1063  (0, "Comparison and numeric sorting are incompatible");
1064 
1065  if (filename == 0)
1066  return clib_error_return (0, "File not specified");
1067 
1068  /* Load the serialized message table from the table dump */
1069 
1070  error = unserialize_open_clib_file (sm, (char *) filename);
1071 
1072  if (error)
1073  return error;
1074 
1075  unserialize_integer (sm, &nmsgs, sizeof (u32));
1076 
1077  for (i = 0; i < nmsgs; i++)
1078  {
1080  unserialize_cstring (sm, (char **) &name_and_crc);
1081  vec_add2 (table, item, 1);
1082  item->msg_index = msg_index;
1083  item->name_and_crc = name_and_crc;
1084  item->name = extract_name (name_and_crc);
1085  item->crc = extract_crc (name_and_crc);
1086  item->which = 0; /* file */
1087  }
1088  unserialize_close (sm);
1089 
1090  /* Compare with the current image? */
1091  if (compare_current)
1092  {
1093  /* Append the current message table */
1094  u8 *tblv = vl_api_serialize_message_table (am, 0);
1095 
1096  serialize_open_vector (sm, tblv);
1097  unserialize_integer (sm, &nmsgs, sizeof (u32));
1098 
1099  for (i = 0; i < nmsgs; i++)
1100  {
1102  unserialize_cstring (sm, (char **) &name_and_crc);
1103 
1104  vec_add2 (table, item, 1);
1105  item->msg_index = msg_index;
1106  item->name_and_crc = name_and_crc;
1107  item->name = extract_name (name_and_crc);
1108  item->crc = extract_crc (name_and_crc);
1109  item->which = 1; /* current_image */
1110  }
1111  vec_free (tblv);
1112  }
1113 
1114  /* Sort the table. */
1115  if (numeric_sort)
1117  else
1119 
1120  if (compare_current)
1121  {
1122  u8 *dashes = 0;
1123  ndifferences = 0;
1124 
1125  /*
1126  * In this case, the recovered table will have two entries per
1127  * API message. So, if entries i and i+1 match, the message definitions
1128  * are identical. Otherwise, the crc is different, or a message is
1129  * present in only one of the tables.
1130  */
1131  vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1132  vec_validate_init_empty (dashes, 60, '-');
1133  vec_terminate_c_string (dashes);
1134  vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1135  vec_free (dashes);
1136  for (i = 0; i < vec_len (table);)
1137  {
1138  /* Last message lonely? */
1139  if (i == vec_len (table) - 1)
1140  {
1141  ndifferences++;
1142  goto last_unique;
1143  }
1144 
1145  /* Identical pair? */
1146  if (!strncmp
1147  ((char *) table[i].name_and_crc,
1148  (char *) table[i + 1].name_and_crc,
1149  vec_len (table[i].name_and_crc)))
1150  {
1151  i += 2;
1152  continue;
1153  }
1154 
1155  ndifferences++;
1156 
1157  /* Only in one of two tables? */
1158  if (i + 1 == vec_len (table)
1159  || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1160  {
1161  last_unique:
1162  vlib_cli_output (vm, "%-60s | only in %s",
1163  table[i].name, table[i].which ?
1164  "image" : "file");
1165  i++;
1166  continue;
1167  }
1168  /* In both tables, but with different signatures */
1169  vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1170  i += 2;
1171  }
1172  if (ndifferences == 0)
1173  vlib_cli_output (vm, "No api message signature differences found.");
1174  else
1175  vlib_cli_output (vm, "\nFound %u api message signature differences",
1176  ndifferences);
1177  goto cleanup;
1178  }
1179 
1180  /* Dump the table, sorted as shown above */
1181  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1182 
1183  for (i = 0; i < vec_len (table); i++)
1184  {
1185  item = table + i;
1186  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1187  item->msg_index, item->crc);
1188  }
1189 
1190 cleanup:
1191  for (i = 0; i < vec_len (table); i++)
1192  {
1193  vec_free (table[i].name_and_crc);
1194  vec_free (table[i].name);
1195  vec_free (table[i].crc);
1196  }
1197 
1198  vec_free (table);
1199 
1200  return 0;
1201 }
1202 
1203 /*?
1204  * Displays a serialized API message decode table, sorted by message name
1205  *
1206  * @cliexpar
1207  * @cliexstart{show api dump file <filename>}
1208  * Message name MsgID CRC
1209  * accept_session 407 8e2a127e
1210  * accept_session_reply 408 67d8c22a
1211  * add_node_next 549 e4202993
1212  * add_node_next_reply 550 e89d6eed
1213  * etc.
1214  * @cliexend
1215 ?*/
1216 
1217 /*?
1218  * Compares a serialized API message decode table with the current image
1219  *
1220  * @cliexpar
1221  * @cliexstart{show api dump file <filename> compare}
1222  * ip_add_del_route definition changed
1223  * ip_table_add_del definition changed
1224  * l2_macs_event only in image
1225  * vnet_ip4_fib_counters only in file
1226  * vnet_ip4_nbr_counters only in file
1227  * @cliexend
1228 ?*/
1229 
1230 /*?
1231  * Display a serialized API message decode table, compare a saved
1232  * decode table with the current image, to establish API differences.
1233  *
1234 ?*/
1235 /* *INDENT-OFF* */
1236 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1237 {
1238  .path = "show api dump",
1239  .short_help = "show api dump file <filename> [numeric | compare-current]",
1240  .function = dump_api_table_file_command_fn,
1241 };
1242 
1243 /* *INDENT-ON* */
1244 /*
1245  * fd.io coding-style-patch-verification: ON
1246  *
1247  * Local Variables:
1248  * eval: (c-set-style "gnu")
1249  * End:
1250  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
Message range (belonging to a plugin)
Definition: api_common.h:114
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
u8 * name
Client name.
Definition: api_common.h:54
#define CLIB_MEM_UNPOISON(a, s)
Definition: sanitizer.h:47
u64 vector_rate_histogram[]
Definition: vlib_api.c:179
u8 * name
name of the plugin
Definition: api_common.h:116
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
#define ntohs(x)
Definition: af_xdp.bpf.c:29
u8 wrapped
trace has wrapped
Definition: api_common.h:96
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
int size
for sanity checking
Definition: api_common.h:84
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:248
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
Definition: vec.h:1133
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
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:645
static u8 * extract_crc(u8 *s)
Definition: vlib_api_cli.c:984
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
string name[64]
Definition: fib.api:25
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:278
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:194
unsigned int u32
Definition: types.h:88
#define clib_memcpy(d, s, n)
Definition: string.h:197
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:680
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:269
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:427
int which
Definition: cJSON.h:234
vl_api_registration_t ** vl_clients
vlib/vpp only: vector of client registrations
Definition: api_common.h:297
#define foreach_histogram_bucket
Definition: api.h:137
description fragment has unexpected format
Definition: map.api:433
#define clib_arch_is_little_endian
Definition: byte_order.h:54
int replay_in_progress
Replay in progress?
Definition: api_common.h:363
#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
int __clib_unused rv
Definition: application.c:491
unformat_function_t unformat_line_input
Definition: format.h:275
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:167
u16 last_msg_id
last assigned message ID
Definition: api_common.h:118
Definition: cJSON.c:88
static int table_id_cmp(void *a1, void *a2)
svm_queue_t * vl_input_queue
shared memory only: pointer to client input queue
Definition: api_common.h:63
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:242
int replay_enable
This message can be replayed.
Definition: api_common.h:86
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u32 size
Definition: vhost_user.h:125
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
static void cleanup(void)
Definition: client.c:98
#define PREDICT_FALSE(x)
Definition: clib.h:124
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:181
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
static clib_error_t * api_trace_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: vlib_api_cli.c:908
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:227
u8 enabled
trace is enabled
Definition: api_common.h:95
An API client registration, only in vpp/vlib.
Definition: api_common.h:47
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:125
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:830
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
API trace state.
Definition: api_common.h:92
__clib_export void unserialize_close(serialize_main_t *m)
Definition: serialize.c:877
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
u32 index
Definition: flow_types.api:221
vl_api_msg_range_t * msg_ranges
vector of message ranges
Definition: api_common.h:309
static u8 * extract_name(u8 *s)
Definition: vlib_api_cli.c:969
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:1119
__clib_export clib_error_t * unserialize_open_clib_file(serialize_main_t *m, char *file)
Definition: serialize.c:1242
u8 ** traces
Trace ring.
Definition: api_common.h:100
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:245
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
cJSON * item
Definition: cJSON.h:222
u8 * save_msg_table_filename
Dump (msg-name, crc) snapshot here at startup.
Definition: api_common.h:366
vl_api_trace_t * tx_trace
Sent message trace configuration.
Definition: api_common.h:272
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
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:943
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:876
vl_api_trace_which_t
Trace RX / TX enum.
Definition: api_common.h:104
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: api_shared.c:204
static clib_error_t * dump_api_table_file_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 missing_clients
Number of missing clients / failed message sends.
Definition: api_common.h:266
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:117
__clib_export void unserialize_open_data(serialize_main_t *m, u8 *data, uword n_data_bytes)
Definition: serialize.c:891
void(** msg_endian_handlers)(void *)
Message endian handler vector.
Definition: api_common.h:239
#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:1098
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
__clib_export void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
struct _svm_queue svm_queue_t
__clib_export void serialize_open_vector(serialize_main_t *m, u8 *vector)
Definition: serialize.c:909
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void(** msg_handlers)(void *)
Message handler vector.
Definition: api_common.h:231
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1386
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:251
int msg_print_flag
Print every received message.
Definition: api_common.h:275
Trace configuration for a single message.
Definition: api_common.h:82
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:571
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:432
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:366
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 vl_msg_api_post_mortem_dump_enable_disable(int enable)
Definition: api_shared.c:963
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:98
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:348
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:163
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127