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 u32 nitems = 256 << 10;
684 api_main_t *am = vlibapi_get_main ();
685 vl_api_trace_which_t which = VL_API_TRACE_RX;
687 u8 *chroot_filename = 0;
689 u32 last = (u32) ~ 0;
693 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
695 if (unformat (input, "on") || unformat (input, "enable"))
697 if (unformat (input, "nitems %d", &nitems))
699 vlib_worker_thread_barrier_sync (vm);
700 vl_msg_api_trace_configure (am, which, nitems);
701 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
702 vlib_worker_thread_barrier_release (vm);
704 else if (unformat (input, "off"))
706 vlib_worker_thread_barrier_sync (vm);
707 vl_msg_api_trace_onoff (am, which, 0);
708 vlib_worker_thread_barrier_release (vm);
710 else if (unformat (input, "save %s", &filename))
712 if (strstr ((char *) filename, "..")
713 || index ((char *) filename, '/'))
715 vlib_cli_output (vm, "illegal characters in filename '%s'",
720 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
724 fp = fopen ((char *) chroot_filename, "w");
727 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
730 vlib_worker_thread_barrier_sync (vm);
731 rv = vl_msg_api_trace_save (am, which, fp);
732 vlib_worker_thread_barrier_release (vm);
735 vlib_cli_output (vm, "API Trace data not present\n");
737 vlib_cli_output (vm, "File for writing is closed\n");
739 vlib_cli_output (vm, "Error while writing header to file\n");
741 vlib_cli_output (vm, "Error while writing trace to file\n");
744 "Error while writing end of buffer trace to file\n");
747 "Error while writing start of buffer trace to file\n");
749 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
751 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
754 else if (unformat (input, "dump %s", &filename))
756 vl_msg_api_process_file (vm, filename, first, last, DUMP);
758 else if (unformat (input, "custom-dump %s", &filename))
760 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
762 else if (unformat (input, "replay %s", &filename))
764 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
766 else if (unformat (input, "initializers %s", &filename))
768 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
770 else if (unformat (input, "tx"))
772 which = VL_API_TRACE_TX;
774 else if (unformat (input, "first %d", &first))
778 else if (unformat (input, "last %d", &last))
782 else if (unformat (input, "status"))
784 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
787 else if (unformat (input, "free"))
789 vlib_worker_thread_barrier_sync (vm);
790 vl_msg_api_trace_onoff (am, which, 0);
791 vl_msg_api_trace_free (am, which);
792 vlib_worker_thread_barrier_release (vm);
794 else if (unformat (input, "post-mortem-on"))
795 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
796 else if (unformat (input, "post-mortem-off"))
797 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
799 return clib_error_return (0, "unknown input `%U'",
800 format_unformat_error, input);
804 vec_free (chroot_filename);
809 * Display, replay, or save a binary API trace
813 VLIB_CLI_COMMAND (api_trace_command, static) =
816 .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
817 "[post-mortem-on][dump|custom-dump|save|replay <file>]",
818 .function = api_trace_command_fn,
823 static clib_error_t *
824 vl_api_trace_command (vlib_main_t * vm,
825 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
828 vl_api_trace_which_t which = VL_API_TRACE_RX;
829 api_main_t *am = vlibapi_get_main ();
831 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
833 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
835 else if (unformat (input, "tx nitems %u", &nitems)
836 || unformat (input, "tx"))
838 which = VL_API_TRACE_RX;
841 else if (unformat (input, "on rx"))
843 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
845 else if (unformat (input, "on tx"))
847 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
849 else if (unformat (input, "on"))
851 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
853 else if (unformat (input, "off"))
855 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
856 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
858 else if (unformat (input, "free"))
860 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
861 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
862 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
863 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
865 else if (unformat (input, "debug on"))
867 am->msg_print_flag = 1;
869 else if (unformat (input, "debug off"))
871 am->msg_print_flag = 0;
874 return clib_error_return (0, "unknown input `%U'",
875 format_unformat_error, input);
880 if (vl_msg_api_trace_configure (am, which, nitems))
882 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
890 * Control the binary API trace mechanism
893 VLIB_CLI_COMMAND (trace, static) =
895 .path = "set api-trace",
896 .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
897 .function = vl_api_trace_command,
901 static clib_error_t *
902 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
904 u32 nitems = 256 << 10;
905 vl_api_trace_which_t which = VL_API_TRACE_RX;
906 api_main_t *am = vlibapi_get_main ();
908 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
910 if (unformat (input, "on") || unformat (input, "enable"))
912 if (unformat (input, "nitems %d", &nitems))
914 vl_msg_api_trace_configure (am, which, nitems);
915 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
916 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
918 else if (unformat (input, "save-api-table %s",
919 &am->save_msg_table_filename))
922 return clib_error_return (0, "unknown input `%U'",
923 format_unformat_error, input);
929 * This module has three configuration parameters:
930 * "on" or "enable" - enables binary api tracing
931 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
932 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
934 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
936 static clib_error_t *
937 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
939 api_main_t *am = vlibapi_get_main ();
942 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
944 if (unformat (input, "length %d", &nitems) ||
945 (unformat (input, "len %d", &nitems)))
948 am->vlib_input_queue_length = nitems;
950 clib_warning ("vlib input queue length %d too small, ignored",
954 return clib_error_return (0, "unknown input `%U'",
955 format_unformat_error, input);
960 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
963 extract_name (u8 * s)
969 while (vec_len (rv) && rv[vec_len (rv)] != '_')
972 rv[vec_len (rv)] = 0;
985 for (i = vec_len (rv) - 1; i >= 0; i--)
989 vec_delete (rv, i + 1, 0);
1003 } msg_table_unserialize_t;
1006 table_id_cmp (void *a1, void *a2)
1008 msg_table_unserialize_t *n1 = a1;
1009 msg_table_unserialize_t *n2 = a2;
1011 return (n1->msg_index - n2->msg_index);
1015 table_name_and_crc_cmp (void *a1, void *a2)
1017 msg_table_unserialize_t *n1 = a1;
1018 msg_table_unserialize_t *n2 = a2;
1020 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1023 static clib_error_t *
1024 dump_api_table_file_command_fn (vlib_main_t * vm,
1025 unformat_input_t * input,
1026 vlib_cli_command_t * cmd)
1029 api_main_t *am = vlibapi_get_main ();
1030 serialize_main_t _sm, *sm = &_sm;
1031 clib_error_t *error;
1035 int compare_current = 0;
1036 int numeric_sort = 0;
1037 msg_table_unserialize_t *table = 0, *item;
1039 u32 ndifferences = 0;
1041 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1043 if (unformat (input, "file %s", &filename))
1045 else if (unformat (input, "compare-current")
1046 || unformat (input, "compare"))
1047 compare_current = 1;
1048 else if (unformat (input, "numeric"))
1051 return clib_error_return (0, "unknown input `%U'",
1052 format_unformat_error, input);
1055 if (numeric_sort && compare_current)
1056 return clib_error_return
1057 (0, "Comparison and numeric sorting are incompatible");
1060 return clib_error_return (0, "File not specified");
1062 /* Load the serialized message table from the table dump */
1064 error = unserialize_open_clib_file (sm, (char *) filename);
1069 unserialize_integer (sm, &nmsgs, sizeof (u32));
1071 for (i = 0; i < nmsgs; i++)
1073 msg_index = unserialize_likely_small_unsigned_integer (sm);
1074 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 = 0; /* file */
1082 unserialize_close (sm);
1084 /* Compare with the current image? */
1085 if (compare_current)
1087 /* Append the current message table */
1088 u8 *tblv = vl_api_serialize_message_table (am, 0);
1090 serialize_open_vector (sm, tblv);
1091 unserialize_integer (sm, &nmsgs, sizeof (u32));
1093 for (i = 0; i < nmsgs; i++)
1095 msg_index = unserialize_likely_small_unsigned_integer (sm);
1096 unserialize_cstring (sm, (char **) &name_and_crc);
1098 vec_add2 (table, item, 1);
1099 item->msg_index = msg_index;
1100 item->name_and_crc = name_and_crc;
1101 item->name = extract_name (name_and_crc);
1102 item->crc = extract_crc (name_and_crc);
1103 item->which = 1; /* current_image */
1108 /* Sort the table. */
1110 vec_sort_with_function (table, table_id_cmp);
1112 vec_sort_with_function (table, table_name_and_crc_cmp);
1114 if (compare_current)
1120 * In this case, the recovered table will have two entries per
1121 * API message. So, if entries i and i+1 match, the message definitions
1122 * are identical. Otherwise, the crc is different, or a message is
1123 * present in only one of the tables.
1125 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1126 vec_validate_init_empty (dashes, 60, '-');
1127 vec_terminate_c_string (dashes);
1128 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1130 for (i = 0; i < vec_len (table);)
1132 /* Last message lonely? */
1133 if (i == vec_len (table) - 1)
1139 /* Identical pair? */
1141 ((char *) table[i].name_and_crc,
1142 (char *) table[i + 1].name_and_crc,
1143 vec_len (table[i].name_and_crc)))
1151 /* Only in one of two tables? */
1152 if (i + 1 == vec_len (table)
1153 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1156 vlib_cli_output (vm, "%-60s | only in %s",
1157 table[i].name, table[i].which ?
1162 /* In both tables, but with different signatures */
1163 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1166 if (ndifferences == 0)
1167 vlib_cli_output (vm, "No api message signature differences found.");
1169 vlib_cli_output (vm, "\nFound %u api message signature differences",
1174 /* Dump the table, sorted as shown above */
1175 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1177 for (i = 0; i < vec_len (table); i++)
1180 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1181 item->msg_index, item->crc);
1185 for (i = 0; i < vec_len (table); i++)
1187 vec_free (table[i].name_and_crc);
1188 vec_free (table[i].name);
1189 vec_free (table[i].crc);
1198 * Displays a serialized API message decode table, sorted by message name
1201 * @cliexstart{show api dump file <filename>}
1202 * Message name MsgID CRC
1203 * accept_session 407 8e2a127e
1204 * accept_session_reply 408 67d8c22a
1205 * add_node_next 549 e4202993
1206 * add_node_next_reply 550 e89d6eed
1212 * Compares a serialized API message decode table with the current image
1215 * @cliexstart{show api dump file <filename> compare}
1216 * ip_add_del_route definition changed
1217 * ip_table_add_del definition changed
1218 * l2_macs_event only in image
1219 * vnet_ip4_fib_counters only in file
1220 * vnet_ip4_nbr_counters only in file
1225 * Display a serialized API message decode table, compare a saved
1226 * decode table with the current image, to establish API differences.
1230 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1232 .path = "show api dump",
1233 .short_help = "show api dump file <filename> [numeric | compare-current]",
1234 .function = dump_api_table_file_command_fn,
1239 * fd.io coding-style-patch-verification: ON
1242 * eval: (c-set-style "gnu")