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,
353 format_vl_msg_api_trace_status (u8 * s, va_list * args)
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);
362 case VL_API_TRACE_TX:
364 trace_name = "TX trace";
367 case VL_API_TRACE_RX:
369 trace_name = "RX trace";
378 s = format (s, "%s: not yet configured.\n", trace_name);
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");
388 void vl_msg_api_custom_dump_configure (api_main_t * am)
389 __attribute__ ((weak));
391 vl_msg_api_custom_dump_configure (api_main_t * am)
396 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
397 u32 first_index, u32 last_index,
398 vl_api_replay_t which)
400 vl_api_trace_file_header_t *hp;
405 api_main_t *am = vlibapi_get_main ();
407 u32 nitems, nitems_msgtbl;
408 void **saved_print_handlers = 0;
410 fd = open ((char *) filename, O_RDONLY);
414 vlib_cli_output (vm, "Couldn't open %s\n", filename);
418 if (fstat (fd, &statb) < 0)
420 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
425 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
427 vlib_cli_output (vm, "File not plausible: %s\n", filename);
432 file_size = statb.st_size;
433 file_size = (file_size + 4095) & ~(4095);
435 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
437 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
439 vlib_cli_output (vm, "mmap failed: %s\n", filename);
445 CLIB_MEM_UNPOISON (hp, file_size);
447 nitems = ntohl (hp->nitems);
449 if (last_index == (u32) ~ 0)
451 last_index = nitems - 1;
454 if (first_index >= nitems || last_index >= nitems)
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);
463 "Note: wrapped/incomplete trace, results may vary\n");
465 if (which == CUSTOM_DUMP)
467 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
468 vl_msg_api_custom_dump_configure (am);
471 msg = (u8 *) (hp + 1);
474 serialize_main_t _sm, *sm = &_sm;
475 u32 msgtbl_size = ntohl (hp->msgtbl_size);
478 unserialize_open_data (sm, msg, msgtbl_size);
479 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
481 for (i = 0; i < nitems_msgtbl; i++)
483 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
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;
492 for (i = 0; i < first_index; i++)
498 size = clib_host_to_net_u32 (*(u32 *) msg);
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;
507 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
508 munmap (hp, file_size);
515 am->replay_in_progress = 1;
517 for (; i <= last_index; i++)
524 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
526 size = clib_host_to_net_u32 (*(u32 *) msg);
529 msg_id = ntohs (*((u16 *) msg));
530 if (msg_id < vec_len (msgid_vec))
532 msg_id = msgid_vec[msg_id];
535 cfgp = am->api_trace_cfg + msg_id;
538 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
539 munmap (hp, file_size);
541 am->replay_in_progress = 0;
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));
551 * Endian swap if needed. All msg data is supposed to be in
552 * network byte order.
554 if (((which == DUMP || which == CUSTOM_DUMP)
555 && clib_arch_is_little_endian))
557 void (*endian_fp) (void *);
558 if (msg_id >= vec_len (am->msg_endian_handlers)
559 || (am->msg_endian_handlers[msg_id] == 0))
561 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
562 munmap (hp, file_size);
564 am->replay_in_progress = 0;
567 endian_fp = am->msg_endian_handlers[msg_id];
568 (*endian_fp) (tmpbuf + sizeof (uword));
571 /* msg_id always in network byte order */
572 if (clib_arch_is_little_endian)
574 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
582 if (msg_id < vec_len (am->msg_print_handlers) &&
583 am->msg_print_handlers[msg_id])
585 u8 *(*print_fp) (void *, void *);
587 print_fp = (void *) am->msg_print_handlers[msg_id];
588 (*print_fp) (tmpbuf + sizeof (uword), vm);
592 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
599 if (msg_id < vec_len (am->msg_print_handlers) &&
600 am->msg_print_handlers[msg_id])
604 u8 *(*print_fp) (void *, void *);
606 print_fp = (void *) am->msg_print_handlers[msg_id];
608 vlib_cli_output (vm, "/*");
610 (*print_fp) (tmpbuf + sizeof (uword), vm);
611 vlib_cli_output (vm, "*/\n");
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);
617 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
620 s = format (s, "\n ");
621 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
623 s = format (s, "\n};\n%c", 0);
624 vlib_cli_output (vm, (char *) s);
630 if (msg_id < vec_len (am->msg_print_handlers) &&
631 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
633 void (*handler) (void *, vlib_main_t *);
635 handler = (void *) am->msg_handlers[msg_id];
637 if (!am->is_mp_safe[msg_id])
638 vl_msg_api_barrier_sync ();
639 (*handler) (tmpbuf + sizeof (uword), vm);
640 if (!am->is_mp_safe[msg_id])
641 vl_msg_api_barrier_release ();
645 if (cfgp->replay_enable)
646 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
653 _vec_len (tmpbuf) = 0;
657 if (saved_print_handlers)
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);
664 munmap (hp, file_size);
666 am->replay_in_progress = 0;
669 /** api_trace_command_fn - control the binary API trace / replay feature
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.
679 static clib_error_t *
680 api_trace_command_fn (vlib_main_t * vm,
681 unformat_input_t * input, vlib_cli_command_t * cmd)
683 unformat_input_t _line_input, *line_input = &_line_input;
684 u32 nitems = 256 << 10;
685 api_main_t *am = vlibapi_get_main ();
686 vl_api_trace_which_t which = VL_API_TRACE_RX;
688 u8 *chroot_filename = 0;
690 u32 last = (u32) ~ 0;
694 /* Get a line of input. */
695 if (!unformat_user (input, unformat_line_input, line_input))
698 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
700 if (unformat (line_input, "on") || unformat (line_input, "enable"))
702 if (unformat (line_input, "nitems %d", &nitems))
704 vlib_worker_thread_barrier_sync (vm);
705 vl_msg_api_trace_configure (am, which, nitems);
706 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
707 vlib_worker_thread_barrier_release (vm);
709 else if (unformat (line_input, "off"))
711 vlib_worker_thread_barrier_sync (vm);
712 vl_msg_api_trace_onoff (am, which, 0);
713 vlib_worker_thread_barrier_release (vm);
715 else if (unformat (line_input, "save %s", &filename))
717 if (strstr ((char *) filename, "..")
718 || index ((char *) filename, '/'))
720 vlib_cli_output (vm, "illegal characters in filename '%s'",
725 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
729 fp = fopen ((char *) chroot_filename, "w");
732 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
735 vlib_worker_thread_barrier_sync (vm);
736 rv = vl_msg_api_trace_save (am, which, fp);
737 vlib_worker_thread_barrier_release (vm);
740 vlib_cli_output (vm, "API Trace data not present\n");
742 vlib_cli_output (vm, "File for writing is closed\n");
744 vlib_cli_output (vm, "Error while writing header to file\n");
746 vlib_cli_output (vm, "Error while writing trace to file\n");
749 "Error while writing end of buffer trace to file\n");
752 "Error while writing start of buffer trace to file\n");
754 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
756 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
759 else if (unformat (line_input, "dump %s", &filename))
761 vl_msg_api_process_file (vm, filename, first, last, DUMP);
763 else if (unformat (line_input, "custom-dump %s", &filename))
765 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
767 else if (unformat (line_input, "replay %s", &filename))
769 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
771 else if (unformat (line_input, "initializers %s", &filename))
773 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
775 else if (unformat (line_input, "tx"))
777 which = VL_API_TRACE_TX;
779 else if (unformat (line_input, "first %d", &first))
783 else if (unformat (line_input, "last %d", &last))
787 else if (unformat (line_input, "status"))
789 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
792 else if (unformat (line_input, "free"))
794 vlib_worker_thread_barrier_sync (vm);
795 vl_msg_api_trace_onoff (am, which, 0);
796 vl_msg_api_trace_free (am, which);
797 vlib_worker_thread_barrier_release (vm);
799 else if (unformat (line_input, "post-mortem-on"))
800 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
801 else if (unformat (line_input, "post-mortem-off"))
802 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
804 return clib_error_return (0, "unknown input `%U'",
805 format_unformat_error, input);
809 vec_free (chroot_filename);
810 unformat_free (line_input);
815 * Display, replay, or save a binary API trace
819 VLIB_CLI_COMMAND (api_trace_command, static) =
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,
829 static clib_error_t *
830 vl_api_trace_command (vlib_main_t * vm,
831 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
834 vl_api_trace_which_t which = VL_API_TRACE_RX;
835 api_main_t *am = vlibapi_get_main ();
837 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
839 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
841 else if (unformat (input, "tx nitems %u", &nitems)
842 || unformat (input, "tx"))
844 which = VL_API_TRACE_RX;
847 else if (unformat (input, "on rx"))
849 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
851 else if (unformat (input, "on tx"))
853 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
855 else if (unformat (input, "on"))
857 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
859 else if (unformat (input, "off"))
861 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
862 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
864 else if (unformat (input, "free"))
866 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
867 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
868 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
869 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
871 else if (unformat (input, "debug on"))
873 am->msg_print_flag = 1;
875 else if (unformat (input, "debug off"))
877 am->msg_print_flag = 0;
880 return clib_error_return (0, "unknown input `%U'",
881 format_unformat_error, input);
886 if (vl_msg_api_trace_configure (am, which, nitems))
888 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
896 * Control the binary API trace mechanism
899 VLIB_CLI_COMMAND (trace, static) =
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,
907 static clib_error_t *
908 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
910 u32 nitems = 256 << 10;
911 vl_api_trace_which_t which = VL_API_TRACE_RX;
912 api_main_t *am = vlibapi_get_main ();
914 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
916 if (unformat (input, "on") || unformat (input, "enable"))
918 if (unformat (input, "nitems %d", &nitems))
920 vl_msg_api_trace_configure (am, which, nitems);
921 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
922 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
924 else if (unformat (input, "save-api-table %s",
925 &am->save_msg_table_filename))
928 return clib_error_return (0, "unknown input `%U'",
929 format_unformat_error, input);
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>
940 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
942 static clib_error_t *
943 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
945 api_main_t *am = vlibapi_get_main ();
948 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
950 if (unformat (input, "length %d", &nitems) ||
951 (unformat (input, "len %d", &nitems)))
954 am->vlib_input_queue_length = nitems;
956 clib_warning ("vlib input queue length %d too small, ignored",
960 return clib_error_return (0, "unknown input `%U'",
961 format_unformat_error, input);
966 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
969 extract_name (u8 * s)
975 while (vec_len (rv) && rv[vec_len (rv)] != '_')
978 rv[vec_len (rv)] = 0;
991 for (i = vec_len (rv) - 1; i >= 0; i--)
995 vec_delete (rv, i + 1, 0);
1009 } msg_table_unserialize_t;
1012 table_id_cmp (void *a1, void *a2)
1014 msg_table_unserialize_t *n1 = a1;
1015 msg_table_unserialize_t *n2 = a2;
1017 return (n1->msg_index - n2->msg_index);
1021 table_name_and_crc_cmp (void *a1, void *a2)
1023 msg_table_unserialize_t *n1 = a1;
1024 msg_table_unserialize_t *n2 = a2;
1026 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1029 static clib_error_t *
1030 dump_api_table_file_command_fn (vlib_main_t * vm,
1031 unformat_input_t * input,
1032 vlib_cli_command_t * cmd)
1035 api_main_t *am = vlibapi_get_main ();
1036 serialize_main_t _sm, *sm = &_sm;
1037 clib_error_t *error;
1041 int compare_current = 0;
1042 int numeric_sort = 0;
1043 msg_table_unserialize_t *table = 0, *item;
1045 u32 ndifferences = 0;
1047 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1049 if (unformat (input, "file %s", &filename))
1051 else if (unformat (input, "compare-current")
1052 || unformat (input, "compare"))
1053 compare_current = 1;
1054 else if (unformat (input, "numeric"))
1057 return clib_error_return (0, "unknown input `%U'",
1058 format_unformat_error, input);
1061 if (numeric_sort && compare_current)
1062 return clib_error_return
1063 (0, "Comparison and numeric sorting are incompatible");
1066 return clib_error_return (0, "File not specified");
1068 /* Load the serialized message table from the table dump */
1070 error = unserialize_open_clib_file (sm, (char *) filename);
1075 unserialize_integer (sm, &nmsgs, sizeof (u32));
1077 for (i = 0; i < nmsgs; i++)
1079 msg_index = unserialize_likely_small_unsigned_integer (sm);
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 */
1088 unserialize_close (sm);
1090 /* Compare with the current image? */
1091 if (compare_current)
1093 /* Append the current message table */
1094 u8 *tblv = vl_api_serialize_message_table (am, 0);
1096 serialize_open_vector (sm, tblv);
1097 unserialize_integer (sm, &nmsgs, sizeof (u32));
1099 for (i = 0; i < nmsgs; i++)
1101 msg_index = unserialize_likely_small_unsigned_integer (sm);
1102 unserialize_cstring (sm, (char **) &name_and_crc);
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 */
1114 /* Sort the table. */
1116 vec_sort_with_function (table, table_id_cmp);
1118 vec_sort_with_function (table, table_name_and_crc_cmp);
1120 if (compare_current)
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.
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, "-----------------");
1136 for (i = 0; i < vec_len (table);)
1138 /* Last message lonely? */
1139 if (i == vec_len (table) - 1)
1145 /* Identical pair? */
1147 ((char *) table[i].name_and_crc,
1148 (char *) table[i + 1].name_and_crc,
1149 vec_len (table[i].name_and_crc)))
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))
1162 vlib_cli_output (vm, "%-60s | only in %s",
1163 table[i].name, table[i].which ?
1168 /* In both tables, but with different signatures */
1169 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1172 if (ndifferences == 0)
1173 vlib_cli_output (vm, "No api message signature differences found.");
1175 vlib_cli_output (vm, "\nFound %u api message signature differences",
1180 /* Dump the table, sorted as shown above */
1181 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1183 for (i = 0; i < vec_len (table); i++)
1186 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1187 item->msg_index, item->crc);
1191 for (i = 0; i < vec_len (table); i++)
1193 vec_free (table[i].name_and_crc);
1194 vec_free (table[i].name);
1195 vec_free (table[i].crc);
1204 * Displays a serialized API message decode table, sorted by message name
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
1218 * Compares a serialized API message decode table with the current image
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
1231 * Display a serialized API message decode table, compare a saved
1232 * decode table with the current image, to establish API differences.
1236 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1238 .path = "show api dump",
1239 .short_help = "show api dump file <filename> [numeric | compare-current]",
1240 .function = dump_api_table_file_command_fn,
1245 * fd.io coding-style-patch-verification: ON
1248 * eval: (c-set-style "gnu")