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);
459 CLIB_MEM_POISON (hp, file_size);
464 "Note: wrapped/incomplete trace, results may vary\n");
466 if (which == CUSTOM_DUMP)
468 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
469 vl_msg_api_custom_dump_configure (am);
472 msg = (u8 *) (hp + 1);
475 serialize_main_t _sm, *sm = &_sm;
476 u32 msgtbl_size = ntohl (hp->msgtbl_size);
479 unserialize_open_data (sm, msg, msgtbl_size);
480 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
482 for (i = 0; i < nitems_msgtbl; i++)
484 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
485 unserialize_cstring (sm, (char **) &name_and_crc);
486 u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
487 vec_validate (msgid_vec, msg_index);
488 msgid_vec[msg_index] = msg_index2;
493 for (i = 0; i < first_index; i++)
499 size = clib_host_to_net_u32 (*(u32 *) msg);
502 msg_id = ntohs (*((u16 *) msg));
503 if (msg_id < vec_len (msgid_vec))
504 msg_id = msgid_vec[msg_id];
505 cfgp = am->api_trace_cfg + msg_id;
508 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
509 munmap (hp, file_size);
510 CLIB_MEM_POISON (hp, file_size);
517 am->replay_in_progress = 1;
519 for (; i <= last_index; i++)
526 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
528 size = clib_host_to_net_u32 (*(u32 *) msg);
531 msg_id = ntohs (*((u16 *) msg));
532 if (msg_id < vec_len (msgid_vec))
534 msg_id = msgid_vec[msg_id];
537 cfgp = am->api_trace_cfg + msg_id;
540 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
541 munmap (hp, file_size);
542 CLIB_MEM_POISON (hp, file_size);
544 am->replay_in_progress = 0;
548 /* Copy the buffer (from the read-only mmap'ed file) */
549 vec_validate (tmpbuf, size - 1 + sizeof (uword));
550 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
551 clib_memset (tmpbuf, 0xf, sizeof (uword));
554 * Endian swap if needed. All msg data is supposed to be in
555 * network byte order.
557 if (((which == DUMP || which == CUSTOM_DUMP)
558 && clib_arch_is_little_endian))
560 void (*endian_fp) (void *);
561 if (msg_id >= vec_len (am->msg_endian_handlers)
562 || (am->msg_endian_handlers[msg_id] == 0))
564 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
565 munmap (hp, file_size);
566 CLIB_MEM_POISON (hp, file_size);
568 am->replay_in_progress = 0;
571 endian_fp = am->msg_endian_handlers[msg_id];
572 (*endian_fp) (tmpbuf + sizeof (uword));
575 /* msg_id always in network byte order */
576 if (clib_arch_is_little_endian)
578 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
586 if (msg_id < vec_len (am->msg_print_handlers) &&
587 am->msg_print_handlers[msg_id])
589 u8 *(*print_fp) (void *, void *);
591 print_fp = (void *) am->msg_print_handlers[msg_id];
592 (*print_fp) (tmpbuf + sizeof (uword), vm);
596 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
603 if (msg_id < vec_len (am->msg_print_handlers) &&
604 am->msg_print_handlers[msg_id])
608 u8 *(*print_fp) (void *, void *);
610 print_fp = (void *) am->msg_print_handlers[msg_id];
612 vlib_cli_output (vm, "/*");
614 (*print_fp) (tmpbuf + sizeof (uword), vm);
615 vlib_cli_output (vm, "*/\n");
617 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
618 am->msg_names[msg_id], i,
619 am->api_trace_cfg[msg_id].size);
621 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
624 s = format (s, "\n ");
625 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
627 s = format (s, "\n};\n%c", 0);
628 vlib_cli_output (vm, (char *) s);
634 if (msg_id < vec_len (am->msg_print_handlers) &&
635 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
637 void (*handler) (void *, vlib_main_t *);
639 handler = (void *) am->msg_handlers[msg_id];
641 if (!am->is_mp_safe[msg_id])
642 vl_msg_api_barrier_sync ();
643 (*handler) (tmpbuf + sizeof (uword), vm);
644 if (!am->is_mp_safe[msg_id])
645 vl_msg_api_barrier_release ();
649 if (cfgp->replay_enable)
650 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
657 _vec_len (tmpbuf) = 0;
661 if (saved_print_handlers)
663 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
664 vec_len (am->msg_print_handlers) * sizeof (void *));
665 vec_free (saved_print_handlers);
668 munmap (hp, file_size);
669 CLIB_MEM_POISON (hp, file_size);
671 am->replay_in_progress = 0;
674 /** api_trace_command_fn - control the binary API trace / replay feature
676 Note: this command MUST be marked thread-safe. Replay with
677 multiple worker threads depends in many cases on worker thread
678 graph replica maintenance. If we (implicitly) assert a worker
679 thread barrier at the debug CLI level, all graph replica changes
680 are deferred until the replay operation completes. If an interface
681 is deleted, the wheels fall off.
684 static clib_error_t *
685 api_trace_command_fn (vlib_main_t * vm,
686 unformat_input_t * input, vlib_cli_command_t * cmd)
688 u32 nitems = 256 << 10;
689 api_main_t *am = vlibapi_get_main ();
690 vl_api_trace_which_t which = VL_API_TRACE_RX;
692 u8 *chroot_filename = 0;
694 u32 last = (u32) ~ 0;
698 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
700 if (unformat (input, "on") || unformat (input, "enable"))
702 if (unformat (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 (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 (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 (input, "dump %s", &filename))
761 vl_msg_api_process_file (vm, filename, first, last, DUMP);
763 else if (unformat (input, "custom-dump %s", &filename))
765 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
767 else if (unformat (input, "replay %s", &filename))
769 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
771 else if (unformat (input, "initializers %s", &filename))
773 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
775 else if (unformat (input, "tx"))
777 which = VL_API_TRACE_TX;
779 else if (unformat (input, "first %d", &first))
783 else if (unformat (input, "last %d", &last))
787 else if (unformat (input, "status"))
789 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
792 else if (unformat (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 (input, "post-mortem-on"))
800 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
801 else if (unformat (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);
814 * Display, replay, or save a binary API trace
818 VLIB_CLI_COMMAND (api_trace_command, static) =
821 .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
822 "[post-mortem-on][dump|custom-dump|save|replay <file>]",
823 .function = api_trace_command_fn,
828 static clib_error_t *
829 vl_api_trace_command (vlib_main_t * vm,
830 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
833 vl_api_trace_which_t which = VL_API_TRACE_RX;
834 api_main_t *am = vlibapi_get_main ();
836 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
838 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
840 else if (unformat (input, "tx nitems %u", &nitems)
841 || unformat (input, "tx"))
843 which = VL_API_TRACE_RX;
846 else if (unformat (input, "on rx"))
848 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
850 else if (unformat (input, "on tx"))
852 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
854 else if (unformat (input, "on"))
856 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
858 else if (unformat (input, "off"))
860 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
861 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
863 else if (unformat (input, "free"))
865 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
866 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
867 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
868 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
870 else if (unformat (input, "debug on"))
872 am->msg_print_flag = 1;
874 else if (unformat (input, "debug off"))
876 am->msg_print_flag = 0;
879 return clib_error_return (0, "unknown input `%U'",
880 format_unformat_error, input);
885 if (vl_msg_api_trace_configure (am, which, nitems))
887 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
895 * Control the binary API trace mechanism
898 VLIB_CLI_COMMAND (trace, static) =
900 .path = "set api-trace",
901 .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
902 .function = vl_api_trace_command,
906 static clib_error_t *
907 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
909 u32 nitems = 256 << 10;
910 vl_api_trace_which_t which = VL_API_TRACE_RX;
911 api_main_t *am = vlibapi_get_main ();
913 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
915 if (unformat (input, "on") || unformat (input, "enable"))
917 if (unformat (input, "nitems %d", &nitems))
919 vl_msg_api_trace_configure (am, which, nitems);
920 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
921 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
923 else if (unformat (input, "save-api-table %s",
924 &am->save_msg_table_filename))
927 return clib_error_return (0, "unknown input `%U'",
928 format_unformat_error, input);
934 * This module has three configuration parameters:
935 * "on" or "enable" - enables binary api tracing
936 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
937 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
939 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
941 static clib_error_t *
942 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
944 api_main_t *am = vlibapi_get_main ();
947 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
949 if (unformat (input, "length %d", &nitems) ||
950 (unformat (input, "len %d", &nitems)))
953 am->vlib_input_queue_length = nitems;
955 clib_warning ("vlib input queue length %d too small, ignored",
959 return clib_error_return (0, "unknown input `%U'",
960 format_unformat_error, input);
965 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
968 extract_name (u8 * s)
974 while (vec_len (rv) && rv[vec_len (rv)] != '_')
977 rv[vec_len (rv)] = 0;
990 for (i = vec_len (rv) - 1; i >= 0; i--)
994 vec_delete (rv, i + 1, 0);
1008 } msg_table_unserialize_t;
1011 table_id_cmp (void *a1, void *a2)
1013 msg_table_unserialize_t *n1 = a1;
1014 msg_table_unserialize_t *n2 = a2;
1016 return (n1->msg_index - n2->msg_index);
1020 table_name_and_crc_cmp (void *a1, void *a2)
1022 msg_table_unserialize_t *n1 = a1;
1023 msg_table_unserialize_t *n2 = a2;
1025 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1028 static clib_error_t *
1029 dump_api_table_file_command_fn (vlib_main_t * vm,
1030 unformat_input_t * input,
1031 vlib_cli_command_t * cmd)
1034 api_main_t *am = vlibapi_get_main ();
1035 serialize_main_t _sm, *sm = &_sm;
1036 clib_error_t *error;
1040 int compare_current = 0;
1041 int numeric_sort = 0;
1042 msg_table_unserialize_t *table = 0, *item;
1044 u32 ndifferences = 0;
1046 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1048 if (unformat (input, "file %s", &filename))
1050 else if (unformat (input, "compare-current")
1051 || unformat (input, "compare"))
1052 compare_current = 1;
1053 else if (unformat (input, "numeric"))
1056 return clib_error_return (0, "unknown input `%U'",
1057 format_unformat_error, input);
1060 if (numeric_sort && compare_current)
1061 return clib_error_return
1062 (0, "Comparison and numeric sorting are incompatible");
1065 return clib_error_return (0, "File not specified");
1067 /* Load the serialized message table from the table dump */
1069 error = unserialize_open_clib_file (sm, (char *) filename);
1074 unserialize_integer (sm, &nmsgs, sizeof (u32));
1076 for (i = 0; i < nmsgs; i++)
1078 msg_index = unserialize_likely_small_unsigned_integer (sm);
1079 unserialize_cstring (sm, (char **) &name_and_crc);
1080 vec_add2 (table, item, 1);
1081 item->msg_index = msg_index;
1082 item->name_and_crc = name_and_crc;
1083 item->name = extract_name (name_and_crc);
1084 item->crc = extract_crc (name_and_crc);
1085 item->which = 0; /* file */
1087 unserialize_close (sm);
1089 /* Compare with the current image? */
1090 if (compare_current)
1092 /* Append the current message table */
1093 u8 *tblv = vl_api_serialize_message_table (am, 0);
1095 serialize_open_vector (sm, tblv);
1096 unserialize_integer (sm, &nmsgs, sizeof (u32));
1098 for (i = 0; i < nmsgs; i++)
1100 msg_index = unserialize_likely_small_unsigned_integer (sm);
1101 unserialize_cstring (sm, (char **) &name_and_crc);
1103 vec_add2 (table, item, 1);
1104 item->msg_index = msg_index;
1105 item->name_and_crc = name_and_crc;
1106 item->name = extract_name (name_and_crc);
1107 item->crc = extract_crc (name_and_crc);
1108 item->which = 1; /* current_image */
1113 /* Sort the table. */
1115 vec_sort_with_function (table, table_id_cmp);
1117 vec_sort_with_function (table, table_name_and_crc_cmp);
1119 if (compare_current)
1125 * In this case, the recovered table will have two entries per
1126 * API message. So, if entries i and i+1 match, the message definitions
1127 * are identical. Otherwise, the crc is different, or a message is
1128 * present in only one of the tables.
1130 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1131 vec_validate_init_empty (dashes, 60, '-');
1132 vec_terminate_c_string (dashes);
1133 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1135 for (i = 0; i < vec_len (table);)
1137 /* Last message lonely? */
1138 if (i == vec_len (table) - 1)
1144 /* Identical pair? */
1146 ((char *) table[i].name_and_crc,
1147 (char *) table[i + 1].name_and_crc,
1148 vec_len (table[i].name_and_crc)))
1156 /* Only in one of two tables? */
1157 if (i + 1 == vec_len (table)
1158 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1161 vlib_cli_output (vm, "%-60s | only in %s",
1162 table[i].name, table[i].which ?
1167 /* In both tables, but with different signatures */
1168 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1171 if (ndifferences == 0)
1172 vlib_cli_output (vm, "No api message signature differences found.");
1174 vlib_cli_output (vm, "\nFound %u api message signature differences",
1179 /* Dump the table, sorted as shown above */
1180 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1182 for (i = 0; i < vec_len (table); i++)
1185 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1186 item->msg_index, item->crc);
1190 for (i = 0; i < vec_len (table); i++)
1192 vec_free (table[i].name_and_crc);
1193 vec_free (table[i].name);
1194 vec_free (table[i].crc);
1203 * Displays a serialized API message decode table, sorted by message name
1206 * @cliexstart{show api dump file <filename>}
1207 * Message name MsgID CRC
1208 * accept_session 407 8e2a127e
1209 * accept_session_reply 408 67d8c22a
1210 * add_node_next 549 e4202993
1211 * add_node_next_reply 550 e89d6eed
1217 * Compares a serialized API message decode table with the current image
1220 * @cliexstart{show api dump file <filename> compare}
1221 * ip_add_del_route definition changed
1222 * ip_table_add_del definition changed
1223 * l2_macs_event only in image
1224 * vnet_ip4_fib_counters only in file
1225 * vnet_ip4_nbr_counters only in file
1230 * Display a serialized API message decode table, compare a saved
1231 * decode table with the current image, to establish API differences.
1235 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1237 .path = "show api dump",
1238 .short_help = "show api dump file <filename> [numeric | compare-current]",
1239 .function = dump_api_table_file_command_fn,
1244 * fd.io coding-style-patch-verification: ON
1247 * eval: (c-set-style "gnu")