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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
20 #include <sys/types.h>
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
27 vl_api_show_histogram_command (vlib_main_t * vm,
28 unformat_input_t * input,
29 vlib_cli_command_t * cli_cmd)
34 for (i = 0; i < SLEEP_N_BUCKETS; i++)
36 total_counts += vector_rate_histogram[i];
39 if (total_counts == 0)
41 vlib_cli_output (vm, "No control-plane activity.");
48 percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
49 / (f64) total_counts; \
51 vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
52 vector_rate_histogram[SLEEP_##n##_US], \
55 foreach_histogram_bucket;
62 * Display the binary api sleep-time histogram
65 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
67 .path = "show api histogram",
68 .short_help = "show api histogram",
69 .function = vl_api_show_histogram_command,
74 vl_api_clear_histogram_command (vlib_main_t * vm,
75 unformat_input_t * input,
76 vlib_cli_command_t * cli_cmd)
80 for (i = 0; i < SLEEP_N_BUCKETS; i++)
81 vector_rate_histogram[i] = 0;
86 * Clear the binary api sleep-time histogram
89 VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
91 .path = "clear api histogram",
92 .short_help = "clear api histogram",
93 .function = vl_api_clear_histogram_command,
98 vl_api_client_command (vlib_main_t * vm,
99 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
101 vl_api_registration_t **regpp, *regp;
104 api_main_t *am = vlibapi_get_main ();
105 u32 *confused_indices = 0;
107 if (!pool_elts (am->vl_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");
114 pool_foreach (regpp, am->vl_clients)
120 if (regp->unanswered_pings > 0)
121 health = "questionable";
125 q = regp->vl_input_queue;
127 vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
128 regp->name, q->consumer_pid, q->cursize,
133 clib_warning ("NULL client registration index %d",
134 regpp - am->vl_clients);
135 vec_add1 (confused_indices, regpp - am->vl_clients);
140 /* This should "never happen," but if it does, fix it... */
141 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
144 for (i = 0; i < vec_len (confused_indices); i++)
146 pool_put_index (am->vl_clients, confused_indices[i]);
149 vec_free (confused_indices);
151 if (am->missing_clients)
152 vlib_cli_output (vm, "%u messages with missing clients",
153 am->missing_clients);
155 vl_sock_api_dump_clients (vm, am);
160 static clib_error_t *
161 vl_api_status_command (vlib_main_t * vm,
162 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
164 api_main_t *am = vlibapi_get_main ();
166 /* check if rx_trace and tx_trace are not null pointers */
167 if (am->rx_trace == 0)
169 vlib_cli_output (vm, "RX Trace disabled\n");
173 if (am->rx_trace->enabled == 0)
174 vlib_cli_output (vm, "RX Trace disabled\n");
176 vlib_cli_output (vm, "RX Trace enabled\n");
179 if (am->tx_trace == 0)
181 vlib_cli_output (vm, "TX Trace disabled\n");
185 if (am->tx_trace->enabled == 0)
186 vlib_cli_output (vm, "TX Trace disabled\n");
188 vlib_cli_output (vm, "TX Trace enabled\n");
195 VLIB_CLI_COMMAND (cli_show_api_command, static) =
198 .short_help = "Show API information",
203 * Display current api client connections
206 VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
208 .path = "show api clients",
209 .short_help = "Client information",
210 .function = vl_api_client_command,
215 * Display the current api message tracing status
218 VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
220 .path = "show api trace-status",
221 .short_help = "Display API trace status",
222 .function = vl_api_status_command,
226 static clib_error_t *
227 vl_api_message_table_command (vlib_main_t * vm,
228 unformat_input_t * input,
229 vlib_cli_command_t * cli_cmd)
231 api_main_t *am = vlibapi_get_main ();
235 if (unformat (input, "verbose"))
240 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
242 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
245 for (i = 1; i < vec_len (am->msg_names); i++)
249 vlib_cli_output (vm, "%-4d %s", i,
250 am->msg_names[i] ? am->msg_names[i] :
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],
266 * Display the current api message decode tables
269 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
271 .path = "show api message-table",
272 .short_help = "Message Table",
273 .function = vl_api_message_table_command,
278 range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
280 int len0, len1, clen;
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));
289 format_api_msg_range (u8 * s, va_list * args)
291 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
294 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
296 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
302 static clib_error_t *
303 vl_api_show_plugin_command (vlib_main_t * vm,
304 unformat_input_t * input,
305 vlib_cli_command_t * cli_cmd)
307 api_main_t *am = vlibapi_get_main ();
308 vl_api_msg_range_t *rp = 0;
311 if (vec_len (am->msg_ranges) == 0)
313 vlib_cli_output (vm, "No plugin API message ranges configured...");
317 rp = vec_dup (am->msg_ranges);
319 vec_sort_with_function (rp, range_compare);
321 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
322 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
324 for (i = 0; i < vec_len (rp); i++)
325 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
333 * Display the plugin binary API message range table
336 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
338 .path = "show api plugin",
339 .short_help = "show api plugin",
340 .function = vl_api_show_plugin_command,
352 format_vl_msg_api_trace_status (u8 * s, va_list * args)
354 api_main_t *am = va_arg (*args, api_main_t *);
355 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
361 case VL_API_TRACE_TX:
363 trace_name = "TX trace";
366 case VL_API_TRACE_RX:
368 trace_name = "RX trace";
377 s = format (s, "%s: not yet configured.\n", trace_name);
381 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
382 trace_name, vec_len (tp->traces), tp->nitems,
383 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
388 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
389 u32 first_index, u32 last_index,
390 vl_api_replay_t which)
392 vl_api_trace_file_header_t *hp;
397 api_main_t *am = vlibapi_get_main ();
399 u32 nitems, nitems_msgtbl;
401 fd = open ((char *) filename, O_RDONLY);
405 vlib_cli_output (vm, "Couldn't open %s\n", filename);
409 if (fstat (fd, &statb) < 0)
411 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
416 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
418 vlib_cli_output (vm, "File not plausible: %s\n", filename);
423 file_size = statb.st_size;
424 file_size = (file_size + 4095) & ~(4095);
426 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
428 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
430 vlib_cli_output (vm, "mmap failed: %s\n", filename);
436 CLIB_MEM_UNPOISON (hp, file_size);
438 nitems = ntohl (hp->nitems);
440 if (last_index == (u32) ~ 0)
442 last_index = nitems - 1;
445 if (first_index >= nitems || last_index >= nitems)
447 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
448 first_index, last_index, nitems - 1);
449 munmap (hp, file_size);
454 "Note: wrapped/incomplete trace, results may vary\n");
456 msg = (u8 *) (hp + 1);
459 serialize_main_t _sm, *sm = &_sm;
460 u32 msgtbl_size = ntohl (hp->msgtbl_size);
463 unserialize_open_data (sm, msg, msgtbl_size);
464 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
466 for (i = 0; i < nitems_msgtbl; i++)
468 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
469 unserialize_cstring (sm, (char **) &name_and_crc);
470 u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
471 vec_validate (msgid_vec, msg_index);
472 msgid_vec[msg_index] = msg_index2;
477 for (i = 0; i < first_index; i++)
483 size = clib_host_to_net_u32 (*(u32 *) msg);
486 msg_id = ntohs (*((u16 *) msg));
487 if (msg_id < vec_len (msgid_vec))
488 msg_id = msgid_vec[msg_id];
489 cfgp = am->api_trace_cfg + msg_id;
492 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
493 munmap (hp, file_size);
500 am->replay_in_progress = 1;
502 for (; i <= last_index; i++)
509 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
511 size = clib_host_to_net_u32 (*(u32 *) msg);
514 msg_id = ntohs (*((u16 *) msg));
515 if (msg_id < vec_len (msgid_vec))
517 msg_id = msgid_vec[msg_id];
520 cfgp = am->api_trace_cfg + msg_id;
523 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
524 munmap (hp, file_size);
526 am->replay_in_progress = 0;
530 /* Copy the buffer (from the read-only mmap'ed file) */
531 vec_validate (tmpbuf, size - 1 + sizeof (uword));
532 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
533 clib_memset (tmpbuf, 0xf, sizeof (uword));
536 * Endian swap if needed. All msg data is supposed to be in
537 * network byte order.
539 if (((which == DUMP) && clib_arch_is_little_endian))
541 void (*endian_fp) (void *);
542 if (msg_id >= vec_len (am->msg_endian_handlers)
543 || (am->msg_endian_handlers[msg_id] == 0))
545 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
546 munmap (hp, file_size);
548 am->replay_in_progress = 0;
551 endian_fp = am->msg_endian_handlers[msg_id];
552 (*endian_fp) (tmpbuf + sizeof (uword));
555 /* msg_id always in network byte order */
556 if (clib_arch_is_little_endian)
558 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
565 if (msg_id < vec_len (am->msg_print_handlers) &&
566 am->msg_print_handlers[msg_id])
568 u8 *(*print_fp) (void *, void *);
570 print_fp = (void *) am->msg_print_handlers[msg_id];
571 (*print_fp) (tmpbuf + sizeof (uword), vm);
575 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
582 if (msg_id < vec_len (am->msg_print_handlers) &&
583 am->msg_print_handlers[msg_id])
587 u8 *(*print_fp) (void *, void *);
589 print_fp = (void *) am->msg_print_handlers[msg_id];
591 vlib_cli_output (vm, "/*");
593 (*print_fp) (tmpbuf + sizeof (uword), vm);
594 vlib_cli_output (vm, "*/\n");
596 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
597 am->msg_names[msg_id], i,
598 am->api_trace_cfg[msg_id].size);
600 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
603 s = format (s, "\n ");
604 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
606 s = format (s, "\n};\n%c", 0);
607 vlib_cli_output (vm, (char *) s);
613 if (msg_id < vec_len (am->msg_print_handlers) &&
614 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
616 void (*handler) (void *, vlib_main_t *);
618 handler = (void *) am->msg_handlers[msg_id];
620 if (!am->is_mp_safe[msg_id])
621 vl_msg_api_barrier_sync ();
622 (*handler) (tmpbuf + sizeof (uword), vm);
623 if (!am->is_mp_safe[msg_id])
624 vl_msg_api_barrier_release ();
628 if (cfgp->replay_enable)
629 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
636 _vec_len (tmpbuf) = 0;
640 munmap (hp, file_size);
642 am->replay_in_progress = 0;
645 /** api_trace_command_fn - control the binary API trace / replay feature
647 Note: this command MUST be marked thread-safe. Replay with
648 multiple worker threads depends in many cases on worker thread
649 graph replica maintenance. If we (implicitly) assert a worker
650 thread barrier at the debug CLI level, all graph replica changes
651 are deferred until the replay operation completes. If an interface
652 is deleted, the wheels fall off.
655 static clib_error_t *
656 api_trace_command_fn (vlib_main_t * vm,
657 unformat_input_t * input, vlib_cli_command_t * cmd)
659 unformat_input_t _line_input, *line_input = &_line_input;
660 u32 nitems = 256 << 10;
661 api_main_t *am = vlibapi_get_main ();
662 vl_api_trace_which_t which = VL_API_TRACE_RX;
664 u8 *chroot_filename = 0;
666 u32 last = (u32) ~ 0;
670 /* Get a line of input. */
671 if (!unformat_user (input, unformat_line_input, line_input))
674 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
676 if (unformat (line_input, "on") || unformat (line_input, "enable"))
678 if (unformat (line_input, "nitems %d", &nitems))
680 vlib_worker_thread_barrier_sync (vm);
681 vl_msg_api_trace_configure (am, which, nitems);
682 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
683 vlib_worker_thread_barrier_release (vm);
685 else if (unformat (line_input, "off"))
687 vlib_worker_thread_barrier_sync (vm);
688 vl_msg_api_trace_onoff (am, which, 0);
689 vlib_worker_thread_barrier_release (vm);
691 else if (unformat (line_input, "save %s", &filename))
693 if (strstr ((char *) filename, "..")
694 || index ((char *) filename, '/'))
696 vlib_cli_output (vm, "illegal characters in filename '%s'",
701 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
705 fp = fopen ((char *) chroot_filename, "w");
708 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
711 vlib_worker_thread_barrier_sync (vm);
712 rv = vl_msg_api_trace_save (am, which, fp);
713 vlib_worker_thread_barrier_release (vm);
716 vlib_cli_output (vm, "API Trace data not present\n");
718 vlib_cli_output (vm, "File for writing is closed\n");
720 vlib_cli_output (vm, "Error while writing header to file\n");
722 vlib_cli_output (vm, "Error while writing trace to file\n");
725 "Error while writing end of buffer trace to file\n");
728 "Error while writing start of buffer trace to file\n");
730 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
732 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
735 else if (unformat (line_input, "dump %s", &filename))
737 vl_msg_api_process_file (vm, filename, first, last, DUMP);
739 else if (unformat (line_input, "replay %s", &filename))
741 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
743 else if (unformat (line_input, "initializers %s", &filename))
745 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
747 else if (unformat (line_input, "tx"))
749 which = VL_API_TRACE_TX;
751 else if (unformat (line_input, "first %d", &first))
755 else if (unformat (line_input, "last %d", &last))
759 else if (unformat (line_input, "status"))
761 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
764 else if (unformat (line_input, "free"))
766 vlib_worker_thread_barrier_sync (vm);
767 vl_msg_api_trace_onoff (am, which, 0);
768 vl_msg_api_trace_free (am, which);
769 vlib_worker_thread_barrier_release (vm);
771 else if (unformat (line_input, "post-mortem-on"))
772 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
773 else if (unformat (line_input, "post-mortem-off"))
774 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
776 return clib_error_return (0, "unknown input `%U'",
777 format_unformat_error, input);
781 vec_free (chroot_filename);
782 unformat_free (line_input);
787 * Display, replay, or save a binary API trace
791 VLIB_CLI_COMMAND (api_trace_command, static) = {
793 .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
794 "[post-mortem-on][dump|save|replay <file>]",
795 .function = api_trace_command_fn,
800 static clib_error_t *
801 vl_api_trace_command (vlib_main_t * vm,
802 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
805 vl_api_trace_which_t which = VL_API_TRACE_RX;
806 api_main_t *am = vlibapi_get_main ();
808 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
810 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
812 else if (unformat (input, "tx nitems %u", &nitems)
813 || unformat (input, "tx"))
815 which = VL_API_TRACE_RX;
818 else if (unformat (input, "on rx"))
820 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
822 else if (unformat (input, "on tx"))
824 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
826 else if (unformat (input, "on"))
828 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
830 else if (unformat (input, "off"))
832 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
833 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
835 else if (unformat (input, "free"))
837 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
838 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
839 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
840 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
842 else if (unformat (input, "debug on"))
844 am->msg_print_flag = 1;
846 else if (unformat (input, "debug off"))
848 am->msg_print_flag = 0;
851 return clib_error_return (0, "unknown input `%U'",
852 format_unformat_error, input);
857 if (vl_msg_api_trace_configure (am, which, nitems))
859 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
867 * Control the binary API trace mechanism
870 VLIB_CLI_COMMAND (trace, static) =
872 .path = "set api-trace",
873 .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
874 .function = vl_api_trace_command,
878 static clib_error_t *
879 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
881 u32 nitems = 256 << 10;
882 vl_api_trace_which_t which = VL_API_TRACE_RX;
883 api_main_t *am = vlibapi_get_main ();
885 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
887 if (unformat (input, "on") || unformat (input, "enable"))
889 if (unformat (input, "nitems %d", &nitems))
891 vl_msg_api_trace_configure (am, which, nitems);
892 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
893 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
895 else if (unformat (input, "save-api-table %s",
896 &am->save_msg_table_filename))
899 return clib_error_return (0, "unknown input `%U'",
900 format_unformat_error, input);
906 * This module has three configuration parameters:
907 * "on" or "enable" - enables binary api tracing
908 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
909 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
911 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
913 static clib_error_t *
914 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
916 api_main_t *am = vlibapi_get_main ();
919 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
921 if (unformat (input, "length %d", &nitems) ||
922 (unformat (input, "len %d", &nitems)))
925 am->vlib_input_queue_length = nitems;
927 clib_warning ("vlib input queue length %d too small, ignored",
931 return clib_error_return (0, "unknown input `%U'",
932 format_unformat_error, input);
937 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
940 extract_name (u8 * s)
946 while (vec_len (rv) && rv[vec_len (rv)] != '_')
949 rv[vec_len (rv)] = 0;
962 for (i = vec_len (rv) - 1; i >= 0; i--)
966 vec_delete (rv, i + 1, 0);
980 } msg_table_unserialize_t;
983 table_id_cmp (void *a1, void *a2)
985 msg_table_unserialize_t *n1 = a1;
986 msg_table_unserialize_t *n2 = a2;
988 return (n1->msg_index - n2->msg_index);
992 table_name_and_crc_cmp (void *a1, void *a2)
994 msg_table_unserialize_t *n1 = a1;
995 msg_table_unserialize_t *n2 = a2;
997 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1000 static clib_error_t *
1001 dump_api_table_file_command_fn (vlib_main_t * vm,
1002 unformat_input_t * input,
1003 vlib_cli_command_t * cmd)
1006 api_main_t *am = vlibapi_get_main ();
1007 serialize_main_t _sm, *sm = &_sm;
1008 clib_error_t *error;
1012 int compare_current = 0;
1013 int numeric_sort = 0;
1014 msg_table_unserialize_t *table = 0, *item;
1016 u32 ndifferences = 0;
1018 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1020 if (unformat (input, "file %s", &filename))
1022 else if (unformat (input, "compare-current")
1023 || unformat (input, "compare"))
1024 compare_current = 1;
1025 else if (unformat (input, "numeric"))
1028 return clib_error_return (0, "unknown input `%U'",
1029 format_unformat_error, input);
1032 if (numeric_sort && compare_current)
1033 return clib_error_return
1034 (0, "Comparison and numeric sorting are incompatible");
1037 return clib_error_return (0, "File not specified");
1039 /* Load the serialized message table from the table dump */
1041 error = unserialize_open_clib_file (sm, (char *) filename);
1046 unserialize_integer (sm, &nmsgs, sizeof (u32));
1048 for (i = 0; i < nmsgs; i++)
1050 msg_index = unserialize_likely_small_unsigned_integer (sm);
1051 unserialize_cstring (sm, (char **) &name_and_crc);
1052 vec_add2 (table, item, 1);
1053 item->msg_index = msg_index;
1054 item->name_and_crc = name_and_crc;
1055 item->name = extract_name (name_and_crc);
1056 item->crc = extract_crc (name_and_crc);
1057 item->which = 0; /* file */
1059 unserialize_close (sm);
1061 /* Compare with the current image? */
1062 if (compare_current)
1064 /* Append the current message table */
1065 u8 *tblv = vl_api_serialize_message_table (am, 0);
1067 serialize_open_vector (sm, tblv);
1068 unserialize_integer (sm, &nmsgs, sizeof (u32));
1070 for (i = 0; i < nmsgs; i++)
1072 msg_index = unserialize_likely_small_unsigned_integer (sm);
1073 unserialize_cstring (sm, (char **) &name_and_crc);
1075 vec_add2 (table, item, 1);
1076 item->msg_index = msg_index;
1077 item->name_and_crc = name_and_crc;
1078 item->name = extract_name (name_and_crc);
1079 item->crc = extract_crc (name_and_crc);
1080 item->which = 1; /* current_image */
1085 /* Sort the table. */
1087 vec_sort_with_function (table, table_id_cmp);
1089 vec_sort_with_function (table, table_name_and_crc_cmp);
1091 if (compare_current)
1097 * In this case, the recovered table will have two entries per
1098 * API message. So, if entries i and i+1 match, the message definitions
1099 * are identical. Otherwise, the crc is different, or a message is
1100 * present in only one of the tables.
1102 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1103 vec_validate_init_empty (dashes, 60, '-');
1104 vec_terminate_c_string (dashes);
1105 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1107 for (i = 0; i < vec_len (table);)
1109 /* Last message lonely? */
1110 if (i == vec_len (table) - 1)
1116 /* Identical pair? */
1118 ((char *) table[i].name_and_crc,
1119 (char *) table[i + 1].name_and_crc,
1120 vec_len (table[i].name_and_crc)))
1128 /* Only in one of two tables? */
1129 if (i + 1 == vec_len (table)
1130 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1133 vlib_cli_output (vm, "%-60s | only in %s",
1134 table[i].name, table[i].which ?
1139 /* In both tables, but with different signatures */
1140 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1143 if (ndifferences == 0)
1144 vlib_cli_output (vm, "No api message signature differences found.");
1146 vlib_cli_output (vm, "\nFound %u api message signature differences",
1151 /* Dump the table, sorted as shown above */
1152 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1154 for (i = 0; i < vec_len (table); i++)
1157 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1158 item->msg_index, item->crc);
1162 for (i = 0; i < vec_len (table); i++)
1164 vec_free (table[i].name_and_crc);
1165 vec_free (table[i].name);
1166 vec_free (table[i].crc);
1175 * Displays a serialized API message decode table, sorted by message name
1178 * @cliexstart{show api dump file <filename>}
1179 * Message name MsgID CRC
1180 * accept_session 407 8e2a127e
1181 * accept_session_reply 408 67d8c22a
1182 * add_node_next 549 e4202993
1183 * add_node_next_reply 550 e89d6eed
1189 * Compares a serialized API message decode table with the current image
1192 * @cliexstart{show api dump file <filename> compare}
1193 * ip_add_del_route definition changed
1194 * ip_table_add_del definition changed
1195 * l2_macs_event only in image
1196 * vnet_ip4_fib_counters only in file
1197 * vnet_ip4_nbr_counters only in file
1202 * Display a serialized API message decode table, compare a saved
1203 * decode table with the current image, to establish API differences.
1207 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1209 .path = "show api dump",
1210 .short_help = "show api dump file <filename> [numeric | compare-current]",
1211 .function = dump_api_table_file_command_fn,
1216 * fd.io coding-style-patch-verification: ON
1219 * eval: (c-set-style "gnu")