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_data); i++)
247 vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
250 vlib_cli_output (vm, "%-4d %s", i,
251 m->name ? m->name : " [no handler]");
255 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
256 m->name ? m->name : " [no handler]", m->bounce,
265 * Display the current api message decode tables
268 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
270 .path = "show api message-table",
271 .short_help = "Message Table",
272 .function = vl_api_message_table_command,
277 range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
279 int len0, len1, clen;
281 len0 = vec_len (a0->name);
282 len1 = vec_len (a1->name);
283 clen = len0 < len1 ? len0 : len1;
284 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
288 format_api_msg_range (u8 * s, va_list * args)
290 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
293 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
295 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
301 static clib_error_t *
302 vl_api_show_plugin_command (vlib_main_t * vm,
303 unformat_input_t * input,
304 vlib_cli_command_t * cli_cmd)
306 api_main_t *am = vlibapi_get_main ();
307 vl_api_msg_range_t *rp = 0;
310 if (vec_len (am->msg_ranges) == 0)
312 vlib_cli_output (vm, "No plugin API message ranges configured...");
316 rp = vec_dup (am->msg_ranges);
318 vec_sort_with_function (rp, range_compare);
320 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
321 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
323 for (i = 0; i < vec_len (rp); i++)
324 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
332 * Display the plugin binary API message range table
335 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
337 .path = "show api plugin",
338 .short_help = "show api plugin",
339 .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;
398 api_main_t *am = vlibapi_get_main ();
400 u32 nitems, nitems_msgtbl;
402 fd = open ((char *) filename, O_RDONLY);
406 vlib_cli_output (vm, "Couldn't open %s\n", filename);
410 if (fstat (fd, &statb) < 0)
412 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
417 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
419 vlib_cli_output (vm, "File not plausible: %s\n", filename);
424 file_size = statb.st_size;
425 file_size = (file_size + 4095) & ~(4095);
427 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
429 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
431 vlib_cli_output (vm, "mmap failed: %s\n", filename);
437 clib_mem_unpoison (hp, file_size);
439 nitems = ntohl (hp->nitems);
441 if (last_index == (u32) ~ 0)
443 last_index = nitems - 1;
446 if (first_index >= nitems || last_index >= nitems)
448 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
449 first_index, last_index, nitems - 1);
450 munmap (hp, file_size);
455 "Note: wrapped/incomplete trace, results may vary\n");
457 size_t file_size_left = file_size;
459 #define assert_size(size_left, s) \
462 if ((s) >= size_left) \
464 vlib_cli_output (vm, "corrupted file"); \
465 munmap (hp, file_size); \
466 vec_free (msgid_vec); \
473 assert_size (file_size_left, sizeof (hp[0]));
474 msg = (u8 *) (hp + 1);
476 serialize_main_t _sm, *sm = &_sm;
477 u32 msgtbl_size = ntohl (hp->msgtbl_size);
480 assert_size (file_size_left, msgtbl_size);
482 unserialize_open_data (sm, msg, msgtbl_size);
483 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
485 for (i = 0; i < nitems_msgtbl; i++)
487 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
488 unserialize_cstring (sm, (char **) &name_and_crc);
489 u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
490 ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
491 if (~0 == msg_index2)
492 vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
494 vec_validate (msgid_vec, msg_index);
495 msgid_vec[msg_index] = msg_index2;
500 for (i = 0; i < first_index; i++)
505 assert_size (file_size_left, sizeof (u32));
506 size = clib_host_to_net_u32 (*(u32 *) msg);
509 assert_size (file_size_left, clib_max (size, sizeof (u16)));
510 msg_id = ntohs (*((u16 *) msg));
511 if (msg_id >= vec_len (msgid_vec) ||
512 msgid_vec[msg_id] >= vec_len (am->msg_data))
513 vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
520 am->replay_in_progress = 1;
522 for (; i <= last_index; i++)
524 vl_api_msg_data_t *m;
529 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
531 assert_size (file_size_left, sizeof (u32));
532 size = clib_host_to_net_u32 (*(u32 *) msg);
535 assert_size (file_size_left, clib_max (size, sizeof (u16)));
536 msg_id = ntohs (*((u16 *) msg));
538 if (msg_id >= vec_len (msgid_vec) ||
539 msgid_vec[msg_id] >= vec_len (am->msg_data))
542 vm, "warning: unknown msg id %d for msg number %d, skipping\n",
548 msg_id = msgid_vec[msg_id];
549 m = vl_api_get_msg_data (am, msg_id);
551 /* Copy the buffer (from the read-only mmap'ed file) */
552 vec_validate (tmpbuf, size - 1 + sizeof (uword));
553 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
554 clib_memset (tmpbuf, 0xf, sizeof (uword));
557 * Endian swap if needed. All msg data is supposed to be in
558 * network byte order.
560 if (((which == DUMP || which == DUMP_JSON) &&
561 clib_arch_is_little_endian))
563 if (m && m->endian_handler == 0)
565 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
566 munmap (hp, file_size);
568 am->replay_in_progress = 0;
571 m->endian_handler (tmpbuf + sizeof (uword));
574 /* msg_id always in network byte order */
575 if (clib_arch_is_little_endian)
577 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
584 if (m && m->print_json_handler)
586 m->print_json_handler (tmpbuf + sizeof (uword), vm);
590 vlib_cli_output (vm, "Skipping msg id %d: no JSON print fcn\n",
597 if (m && m->print_handler)
599 m->print_handler (tmpbuf + sizeof (uword), vm);
603 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
610 if (m && m->print_handler)
615 vlib_cli_output (vm, "/*");
617 m->print_handler (tmpbuf + sizeof (uword), vm);
618 vlib_cli_output (vm, "*/\n");
620 s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
623 for (j = 0; j < m->trace_size; j++)
626 s = format (s, "\n ");
627 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
629 s = format (s, "\n};\n%c", 0);
630 vlib_cli_output (vm, (char *) s);
636 if (m && m->print_handler && m->replay_allowed)
639 vl_msg_api_barrier_sync ();
640 m->handler (tmpbuf + sizeof (uword));
642 vl_msg_api_barrier_release ();
646 if (m->replay_allowed)
647 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
654 vec_set_len (tmpbuf, 0);
658 munmap (hp, file_size);
660 vec_free (msgid_vec);
661 am->replay_in_progress = 0;
665 file_exists (u8 *fname)
668 fp = fopen ((char *) fname, "r");
684 vl_msg_print_trace (u8 *msg, void *ctx)
686 vl_msg_print_args *a = ctx;
687 api_main_t *am = vlibapi_get_main ();
688 u16 msg_id = ntohs (*((u16 *) msg));
689 vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
690 void (*handler) (void *, void *) = 0;
691 u8 is_json = a->is_json;
696 vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
700 if (clib_arch_is_little_endian)
702 u32 msg_length = vec_len (msg);
703 vec_validate (tmpbuf, msg_length - 1);
704 clib_memcpy_fast (tmpbuf, msg, msg_length);
707 m->endian_handler (tmpbuf);
710 handler = is_json ? m->print_json_handler : m->print_handler;
713 handler (msg, a->vm);
715 vlib_cli_output (a->vm, "Skipping msg id %d: no print fcn\n", msg_id);
722 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
724 api_main_t *am = vlibapi_get_main ();
729 case VL_API_TRACE_TX:
732 case VL_API_TRACE_RX:
739 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
742 vl_msg_print_args args;
743 clib_memset (&args, 0, sizeof (args));
744 args.is_json = is_json;
746 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
752 vl_msg_read_file (FILE *f)
754 const size_t bufsize = 1024;
755 char *buf[bufsize], *v = 0;
758 while ((n = fread (buf, 1, bufsize, f)))
761 /* most callers expect a NULL-terminated C-string */
769 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
772 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
780 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
784 if (!am->msg_id_by_name)
786 vlib_cli_output (vm, "message id table not yet initialized!\n");
790 p = hash_get_mem (am->msg_id_by_name, name);
798 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
800 api_main_t *am = vlibapi_get_main ();
802 int len = 0, rv = -1;
803 vl_api_msg_data_t *m;
806 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
809 vlib_cli_output (vm, "Missing '_msgname' element!\n");
812 char *name = cJSON_GetStringValue (msg_id_obj);
814 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
817 vlib_cli_output (vm, "Missing '_crc' element!\n");
820 char *crc = cJSON_GetStringValue (crc_obj);
823 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
824 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
825 m = vl_api_get_msg_data (am, msg_id);
826 if (msg_id == (u16) ~0)
828 msg_id = vl_msg_find_id_by_name (vm, am, name);
829 if (msg_id == (u16) ~0)
831 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
839 if (m->replay_allowed)
842 vlib_cli_output (vm, "warning: msg %d has different signature\n");
844 if (!m->fromjson_handler)
846 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
851 msg = (u8 *) m->fromjson_handler (o, &len);
854 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
859 if (clib_arch_is_little_endian)
860 m->endian_handler (msg);
864 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
869 vl_msg_api_barrier_sync ();
872 vl_msg_api_barrier_release ();
883 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
885 api_main_t *am = vlibapi_get_main ();
888 FILE *f = fopen ((char *) filename, "r");
892 vlib_cli_output (vm, "failed to open %s!\n", filename);
896 char *buf = vl_msg_read_file (f);
899 o = cJSON_Parse (buf);
903 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
904 cJSON_GetErrorPtr ());
908 if (cJSON_IsArray (o))
910 am->replay_in_progress = 1;
911 size_t size = cJSON_GetArraySize (o);
912 for (int i = 0; i < size; i++)
914 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
917 am->replay_in_progress = 0;
924 rv = vl_msg_exec_json_command (vm, o);
928 vlib_cli_output (vm, "error during replaying API trace");
934 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
936 FILE *f = fopen ((char *) filename, "r");
941 vlib_cli_output (vm, "failed to open %s!\n", filename);
945 buf = vl_msg_read_file (f);
950 vlib_cli_output (vm, "no content in %s!\n", filename);
954 vlib_cli_output (vm, buf);
958 /** api_trace_command_fn - control the binary API trace / replay feature
960 Note: this command MUST be marked thread-safe. Replay with
961 multiple worker threads depends in many cases on worker thread
962 graph replica maintenance. If we (implicitly) assert a worker
963 thread barrier at the debug CLI level, all graph replica changes
964 are deferred until the replay operation completes. If an interface
965 is deleted, the wheels fall off.
968 static clib_error_t *
969 api_trace_command_fn (vlib_main_t * vm,
970 unformat_input_t * input, vlib_cli_command_t * cmd)
972 unformat_input_t _line_input, *line_input = &_line_input;
973 u32 nitems = 256 << 10;
974 api_main_t *am = vlibapi_get_main ();
975 vl_api_trace_which_t which = VL_API_TRACE_RX;
977 u8 *chroot_filename = 0;
979 u32 last = (u32) ~ 0;
983 /* Get a line of input. */
984 if (!unformat_user (input, unformat_line_input, line_input))
987 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
989 if (unformat (line_input, "on") || unformat (line_input, "enable"))
991 if (unformat (line_input, "nitems %d", &nitems))
993 vlib_worker_thread_barrier_sync (vm);
994 vl_msg_api_trace_configure (am, which, nitems);
995 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
996 vlib_worker_thread_barrier_release (vm);
998 else if (unformat (line_input, "off"))
1000 vlib_worker_thread_barrier_sync (vm);
1001 vl_msg_api_trace_onoff (am, which, 0);
1002 vlib_worker_thread_barrier_release (vm);
1004 else if (unformat (line_input, "save-json %s", &filename))
1006 if (strstr ((char *) filename, "..") ||
1007 index ((char *) filename, '/'))
1009 vlib_cli_output (vm, "illegal characters in filename '%s'",
1014 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1016 vec_free (filename);
1018 if (file_exists (chroot_filename))
1020 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1024 fp = fopen ((char *) chroot_filename, "w");
1027 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1030 vlib_worker_thread_barrier_sync (vm);
1031 rv = vl_msg_api_trace_save (am, which, fp, 1);
1033 vlib_cli_output (vm, "API Trace data not present\n");
1035 vlib_cli_output (vm, "failed to save api trace\n");
1037 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1038 vlib_worker_thread_barrier_release (vm);
1041 else if (unformat (line_input, "save %s", &filename))
1043 if (strstr ((char *) filename, "..")
1044 || index ((char *) filename, '/'))
1046 vlib_cli_output (vm, "illegal characters in filename '%s'",
1051 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1053 vec_free (filename);
1055 if (file_exists (chroot_filename))
1057 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1061 fp = fopen ((char *) chroot_filename, "w");
1064 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1067 vlib_worker_thread_barrier_sync (vm);
1068 rv = vl_msg_api_trace_save (am, which, fp, 0);
1069 vlib_worker_thread_barrier_release (vm);
1072 vlib_cli_output (vm, "API Trace data not present\n");
1074 vlib_cli_output (vm, "File for writing is closed\n");
1076 vlib_cli_output (vm, "Error while writing header to file\n");
1078 vlib_cli_output (vm, "Error while writing trace to file\n");
1080 vlib_cli_output (vm,
1081 "Error while writing end of buffer trace to file\n");
1083 vlib_cli_output (vm,
1084 "Error while writing start of buffer trace to file\n");
1086 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1088 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1091 else if (unformat (line_input, "tojson %s", &filename))
1093 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1095 else if (unformat (line_input, "dump-file-json %s", &filename))
1097 vl_msg_dump_file_json (vm, filename);
1099 else if (unformat (line_input, "dump-file %s", &filename))
1101 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1103 else if (unformat (line_input, "dump-json"))
1105 vl_msg_api_dump_trace (vm, which, 1);
1107 else if (unformat (line_input, "dump"))
1109 vl_msg_api_dump_trace (vm, which, 0);
1111 else if (unformat (line_input, "replay-json %s", &filename))
1113 vl_msg_replay_json (vm, filename);
1115 else if (unformat (line_input, "replay %s", &filename))
1117 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1119 else if (unformat (line_input, "initializers %s", &filename))
1121 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1123 else if (unformat (line_input, "tx"))
1125 which = VL_API_TRACE_TX;
1127 else if (unformat (line_input, "first %d", &first))
1131 else if (unformat (line_input, "last %d", &last))
1135 else if (unformat (line_input, "status"))
1137 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1140 else if (unformat (line_input, "free"))
1142 vlib_worker_thread_barrier_sync (vm);
1143 vl_msg_api_trace_onoff (am, which, 0);
1144 vl_msg_api_trace_free (am, which);
1145 vlib_worker_thread_barrier_release (vm);
1147 else if (unformat (line_input, "post-mortem-on"))
1148 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1149 else if (unformat (line_input, "post-mortem-off"))
1150 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1152 return clib_error_return (0, "unknown input `%U'",
1153 format_unformat_error, input);
1156 vec_free (filename);
1157 vec_free (chroot_filename);
1158 unformat_free (line_input);
1163 * Display, replay, or save a binary API trace
1167 VLIB_CLI_COMMAND (api_trace_command, static) = {
1168 .path = "api trace",
1169 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1170 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1171 "json|replay <file>|replay-json <file>][nitems <n>]"
1172 "[initializers <file>]",
1173 .function = api_trace_command_fn,
1178 static clib_error_t *
1179 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1181 u32 nitems = 256 << 10;
1182 vl_api_trace_which_t which = VL_API_TRACE_RX;
1183 api_main_t *am = vlibapi_get_main ();
1185 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1187 if (unformat (input, "on") || unformat (input, "enable"))
1189 if (unformat (input, "nitems %d", &nitems))
1191 vl_msg_api_trace_configure (am, which, nitems);
1192 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1193 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1195 else if (unformat (input, "save-api-table %s",
1196 &am->save_msg_table_filename))
1199 return clib_error_return (0, "unknown input `%U'",
1200 format_unformat_error, input);
1206 * This module has three configuration parameters:
1207 * "on" or "enable" - enables binary api tracing
1208 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1209 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1211 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1213 static clib_error_t *
1214 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1216 api_main_t *am = vlibapi_get_main ();
1219 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1221 if (unformat (input, "length %d", &nitems) ||
1222 (unformat (input, "len %d", &nitems)))
1225 am->vlib_input_queue_length = nitems;
1227 clib_warning ("vlib input queue length %d too small, ignored",
1231 return clib_error_return (0, "unknown input `%U'",
1232 format_unformat_error, input);
1237 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1240 extract_name (u8 * s)
1246 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1247 vec_dec_len (rv, 1);
1249 rv[vec_len (rv)] = 0;
1255 extract_crc (u8 * s)
1262 for (i = vec_len (rv) - 1; i >= 0; i--)
1266 vec_delete (rv, i + 1, 0);
1280 } msg_table_unserialize_t;
1283 table_id_cmp (void *a1, void *a2)
1285 msg_table_unserialize_t *n1 = a1;
1286 msg_table_unserialize_t *n2 = a2;
1288 return (n1->msg_index - n2->msg_index);
1292 table_name_and_crc_cmp (void *a1, void *a2)
1294 msg_table_unserialize_t *n1 = a1;
1295 msg_table_unserialize_t *n2 = a2;
1297 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1300 static clib_error_t *
1301 dump_api_table_file_command_fn (vlib_main_t * vm,
1302 unformat_input_t * input,
1303 vlib_cli_command_t * cmd)
1306 api_main_t *am = vlibapi_get_main ();
1307 serialize_main_t _sm, *sm = &_sm;
1308 clib_error_t *error;
1312 int compare_current = 0;
1313 int numeric_sort = 0;
1314 msg_table_unserialize_t *table = 0, *item;
1316 u32 ndifferences = 0;
1318 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1320 if (unformat (input, "file %s", &filename))
1322 else if (unformat (input, "compare-current")
1323 || unformat (input, "compare"))
1324 compare_current = 1;
1325 else if (unformat (input, "numeric"))
1328 return clib_error_return (0, "unknown input `%U'",
1329 format_unformat_error, input);
1332 if (numeric_sort && compare_current)
1333 return clib_error_return
1334 (0, "Comparison and numeric sorting are incompatible");
1337 return clib_error_return (0, "File not specified");
1339 /* Load the serialized message table from the table dump */
1341 error = unserialize_open_clib_file (sm, (char *) filename);
1346 unserialize_integer (sm, &nmsgs, sizeof (u32));
1348 for (i = 0; i < nmsgs; i++)
1350 msg_index = unserialize_likely_small_unsigned_integer (sm);
1351 unserialize_cstring (sm, (char **) &name_and_crc);
1352 vec_add2 (table, item, 1);
1353 item->msg_index = msg_index;
1354 item->name_and_crc = name_and_crc;
1355 item->name = extract_name (name_and_crc);
1356 item->crc = extract_crc (name_and_crc);
1357 item->which = 0; /* file */
1359 unserialize_close (sm);
1361 /* Compare with the current image? */
1362 if (compare_current)
1364 /* Append the current message table */
1365 u8 *tblv = vl_api_serialize_message_table (am, 0);
1367 serialize_open_vector (sm, tblv);
1368 unserialize_integer (sm, &nmsgs, sizeof (u32));
1370 for (i = 0; i < nmsgs; i++)
1372 msg_index = unserialize_likely_small_unsigned_integer (sm);
1373 unserialize_cstring (sm, (char **) &name_and_crc);
1375 vec_add2 (table, item, 1);
1376 item->msg_index = msg_index;
1377 item->name_and_crc = name_and_crc;
1378 item->name = extract_name (name_and_crc);
1379 item->crc = extract_crc (name_and_crc);
1380 item->which = 1; /* current_image */
1385 /* Sort the table. */
1387 vec_sort_with_function (table, table_id_cmp);
1389 vec_sort_with_function (table, table_name_and_crc_cmp);
1391 if (compare_current)
1397 * In this case, the recovered table will have two entries per
1398 * API message. So, if entries i and i+1 match, the message definitions
1399 * are identical. Otherwise, the crc is different, or a message is
1400 * present in only one of the tables.
1402 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1403 vec_validate_init_empty (dashes, 60, '-');
1404 vec_terminate_c_string (dashes);
1405 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1407 for (i = 0; i < vec_len (table);)
1409 /* Last message lonely? */
1410 if (i == vec_len (table) - 1)
1416 /* Identical pair? */
1418 ((char *) table[i].name_and_crc,
1419 (char *) table[i + 1].name_and_crc,
1420 vec_len (table[i].name_and_crc)))
1428 /* Only in one of two tables? */
1429 if (i + 1 == vec_len (table)
1430 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1433 vlib_cli_output (vm, "%-60s | only in %s",
1434 table[i].name, table[i].which ?
1439 /* In both tables, but with different signatures */
1440 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1443 if (ndifferences == 0)
1444 vlib_cli_output (vm, "No api message signature differences found.");
1446 vlib_cli_output (vm, "\nFound %u api message signature differences",
1451 /* Dump the table, sorted as shown above */
1452 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1454 for (i = 0; i < vec_len (table); i++)
1457 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1458 item->msg_index, item->crc);
1462 for (i = 0; i < vec_len (table); i++)
1464 vec_free (table[i].name_and_crc);
1465 vec_free (table[i].name);
1466 vec_free (table[i].crc);
1475 * Displays a serialized API message decode table, sorted by message name
1478 * @cliexstart{show api dump file <filename>}
1479 * Message name MsgID CRC
1480 * accept_session 407 8e2a127e
1481 * accept_session_reply 408 67d8c22a
1482 * add_node_next 549 e4202993
1483 * add_node_next_reply 550 e89d6eed
1489 * Compares a serialized API message decode table with the current image
1492 * @cliexstart{show api dump file <filename> compare}
1493 * ip_add_del_route definition changed
1494 * ip_table_add_del definition changed
1495 * l2_macs_event only in image
1496 * vnet_ip4_fib_counters only in file
1497 * vnet_ip4_nbr_counters only in file
1502 * Display a serialized API message decode table, compare a saved
1503 * decode table with the current image, to establish API differences.
1507 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1509 .path = "show api dump",
1510 .short_help = "show api dump file <filename> [numeric | compare-current]",
1511 .function = dump_api_table_file_command_fn,
1516 * fd.io coding-style-patch-verification: ON
1519 * eval: (c-set-style "gnu")