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;
573 m->endian_handler (tmpbuf + sizeof (uword));
577 /* msg_id always in network byte order */
578 if (clib_arch_is_little_endian)
580 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
587 vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
588 tmpbuf + sizeof (uword));
592 vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
593 tmpbuf + sizeof (uword));
602 vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
603 msg_id, tmpbuf + sizeof (uword));
605 vlib_cli_output (vm, "*/\n");
607 s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
610 for (j = 0; j < m->trace_size; j++)
613 s = format (s, "\n ");
614 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
616 s = format (s, "\n};\n%c", 0);
617 vlib_cli_output (vm, (char *) s);
623 if (m && m->handler && m->replay_allowed)
626 vl_msg_api_barrier_sync ();
627 m->handler (tmpbuf + sizeof (uword));
629 vl_msg_api_barrier_release ();
633 if (m && m->replay_allowed)
634 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
641 vec_set_len (tmpbuf, 0);
645 munmap (hp, file_size);
647 vec_free (msgid_vec);
648 am->replay_in_progress = 0;
652 file_exists (u8 *fname)
655 fp = fopen ((char *) fname, "r");
671 vl_msg_print_trace (u8 *msg, void *ctx)
673 vl_msg_print_args *a = ctx;
674 api_main_t *am = vlibapi_get_main ();
675 u16 msg_id = ntohs (*((u16 *) msg));
676 vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
677 u8 is_json = a->is_json;
682 vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
686 if (clib_arch_is_little_endian)
688 u32 msg_length = vec_len (msg);
689 vec_validate (tmpbuf, msg_length - 1);
690 clib_memcpy_fast (tmpbuf, msg, msg_length);
693 m->endian_handler (tmpbuf);
696 vlib_cli_output (a->vm, "%U\n",
697 is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
705 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
707 api_main_t *am = vlibapi_get_main ();
712 case VL_API_TRACE_TX:
715 case VL_API_TRACE_RX:
722 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
725 vl_msg_print_args args;
726 clib_memset (&args, 0, sizeof (args));
727 args.is_json = is_json;
729 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
735 vl_msg_read_file (FILE *f)
737 const size_t bufsize = 1024;
738 char *buf[bufsize], *v = 0;
741 while ((n = fread (buf, 1, bufsize, f)))
744 /* most callers expect a NULL-terminated C-string */
752 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
755 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
763 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
767 if (!am->msg_id_by_name)
769 vlib_cli_output (vm, "message id table not yet initialized!\n");
773 p = hash_get_mem (am->msg_id_by_name, name);
781 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
783 api_main_t *am = vlibapi_get_main ();
785 int len = 0, rv = -1;
786 vl_api_msg_data_t *m;
789 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
792 vlib_cli_output (vm, "Missing '_msgname' element!\n");
795 char *name = cJSON_GetStringValue (msg_id_obj);
797 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
800 vlib_cli_output (vm, "Missing '_crc' element!\n");
803 char *crc = cJSON_GetStringValue (crc_obj);
806 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
807 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
808 m = vl_api_get_msg_data (am, msg_id);
809 if (msg_id == (u16) ~0)
811 msg_id = vl_msg_find_id_by_name (vm, am, name);
812 if (msg_id == (u16) ~0)
814 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
822 if (m->replay_allowed)
825 vlib_cli_output (vm, "warning: msg %d has different signature\n");
827 if (!m->fromjson_handler)
829 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
834 msg = (u8 *) m->fromjson_handler (o, &len);
837 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
842 if (clib_arch_is_little_endian)
843 m->endian_handler (msg);
847 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
854 vl_msg_api_barrier_sync ();
857 vl_msg_api_barrier_release ();
869 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
871 api_main_t *am = vlibapi_get_main ();
874 FILE *f = fopen ((char *) filename, "r");
878 vlib_cli_output (vm, "failed to open %s!\n", filename);
882 char *buf = vl_msg_read_file (f);
885 o = cJSON_Parse (buf);
889 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
890 cJSON_GetErrorPtr ());
894 if (cJSON_IsArray (o))
896 am->replay_in_progress = 1;
897 size_t size = cJSON_GetArraySize (o);
898 for (int i = 0; i < size; i++)
900 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
903 am->replay_in_progress = 0;
910 rv = vl_msg_exec_json_command (vm, o);
914 vlib_cli_output (vm, "error during replaying API trace");
920 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
922 FILE *f = fopen ((char *) filename, "r");
927 vlib_cli_output (vm, "failed to open %s!\n", filename);
931 buf = vl_msg_read_file (f);
936 vlib_cli_output (vm, "no content in %s!\n", filename);
940 vlib_cli_output (vm, buf);
944 /** api_trace_command_fn - control the binary API trace / replay feature
946 Note: this command MUST be marked thread-safe. Replay with
947 multiple worker threads depends in many cases on worker thread
948 graph replica maintenance. If we (implicitly) assert a worker
949 thread barrier at the debug CLI level, all graph replica changes
950 are deferred until the replay operation completes. If an interface
951 is deleted, the wheels fall off.
954 static clib_error_t *
955 api_trace_command_fn (vlib_main_t * vm,
956 unformat_input_t * input, vlib_cli_command_t * cmd)
958 unformat_input_t _line_input, *line_input = &_line_input;
959 u32 nitems = 256 << 10;
960 api_main_t *am = vlibapi_get_main ();
961 vl_api_trace_which_t which = VL_API_TRACE_RX;
963 u8 *chroot_filename = 0;
965 u32 last = (u32) ~ 0;
969 /* Get a line of input. */
970 if (!unformat_user (input, unformat_line_input, line_input))
973 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
975 if (unformat (line_input, "on") || unformat (line_input, "enable"))
977 if (unformat (line_input, "nitems %d", &nitems))
979 vlib_worker_thread_barrier_sync (vm);
980 vl_msg_api_trace_configure (am, which, nitems);
981 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
982 vlib_worker_thread_barrier_release (vm);
984 else if (unformat (line_input, "off"))
986 vlib_worker_thread_barrier_sync (vm);
987 vl_msg_api_trace_onoff (am, which, 0);
988 vlib_worker_thread_barrier_release (vm);
990 else if (unformat (line_input, "save-json %s", &filename))
992 if (strstr ((char *) filename, "..") ||
993 index ((char *) filename, '/'))
995 vlib_cli_output (vm, "illegal characters in filename '%s'",
1000 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1002 vec_free (filename);
1004 if (file_exists (chroot_filename))
1006 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1010 fp = fopen ((char *) chroot_filename, "w");
1013 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1016 vlib_worker_thread_barrier_sync (vm);
1017 rv = vl_msg_api_trace_save (am, which, fp, 1);
1019 vlib_cli_output (vm, "API Trace data not present\n");
1021 vlib_cli_output (vm, "failed to save api trace\n");
1023 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1024 vlib_worker_thread_barrier_release (vm);
1027 else if (unformat (line_input, "save %s", &filename))
1029 if (strstr ((char *) filename, "..")
1030 || index ((char *) filename, '/'))
1032 vlib_cli_output (vm, "illegal characters in filename '%s'",
1037 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1039 vec_free (filename);
1041 if (file_exists (chroot_filename))
1043 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1047 fp = fopen ((char *) chroot_filename, "w");
1050 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1053 vlib_worker_thread_barrier_sync (vm);
1054 rv = vl_msg_api_trace_save (am, which, fp, 0);
1055 vlib_worker_thread_barrier_release (vm);
1058 vlib_cli_output (vm, "API Trace data not present\n");
1060 vlib_cli_output (vm, "File for writing is closed\n");
1062 vlib_cli_output (vm, "Error while writing header to file\n");
1064 vlib_cli_output (vm, "Error while writing trace to file\n");
1066 vlib_cli_output (vm,
1067 "Error while writing end of buffer trace to file\n");
1069 vlib_cli_output (vm,
1070 "Error while writing start of buffer trace to file\n");
1072 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1074 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1077 else if (unformat (line_input, "tojson %s", &filename))
1079 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1081 else if (unformat (line_input, "dump-file-json %s", &filename))
1083 vl_msg_dump_file_json (vm, filename);
1085 else if (unformat (line_input, "dump-file %s", &filename))
1087 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1089 else if (unformat (line_input, "dump-json"))
1091 vl_msg_api_dump_trace (vm, which, 1);
1093 else if (unformat (line_input, "dump"))
1095 vl_msg_api_dump_trace (vm, which, 0);
1097 else if (unformat (line_input, "replay-json %s", &filename))
1099 vl_msg_replay_json (vm, filename);
1101 else if (unformat (line_input, "replay %s", &filename))
1103 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1105 else if (unformat (line_input, "initializers %s", &filename))
1107 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1109 else if (unformat (line_input, "tx"))
1111 which = VL_API_TRACE_TX;
1113 else if (unformat (line_input, "first %d", &first))
1117 else if (unformat (line_input, "last %d", &last))
1121 else if (unformat (line_input, "status"))
1123 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1126 else if (unformat (line_input, "free"))
1128 vlib_worker_thread_barrier_sync (vm);
1129 vl_msg_api_trace_onoff (am, which, 0);
1130 vl_msg_api_trace_free (am, which);
1131 vlib_worker_thread_barrier_release (vm);
1133 else if (unformat (line_input, "post-mortem-on"))
1134 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1135 else if (unformat (line_input, "post-mortem-off"))
1136 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1138 return clib_error_return (0, "unknown input `%U'",
1139 format_unformat_error, input);
1142 vec_free (filename);
1143 vec_free (chroot_filename);
1144 unformat_free (line_input);
1149 * Display, replay, or save a binary API trace
1153 VLIB_CLI_COMMAND (api_trace_command, static) = {
1154 .path = "api trace",
1155 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1156 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1157 "json|replay <file>|replay-json <file>][nitems <n>]"
1158 "[initializers <file>]",
1159 .function = api_trace_command_fn,
1164 static clib_error_t *
1165 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1167 u32 nitems = 256 << 10;
1168 vl_api_trace_which_t which = VL_API_TRACE_RX;
1169 api_main_t *am = vlibapi_get_main ();
1171 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1173 if (unformat (input, "on") || unformat (input, "enable"))
1175 if (unformat (input, "nitems %d", &nitems))
1177 vl_msg_api_trace_configure (am, which, nitems);
1178 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1179 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1181 else if (unformat (input, "save-api-table %s",
1182 &am->save_msg_table_filename))
1185 return clib_error_return (0, "unknown input `%U'",
1186 format_unformat_error, input);
1192 * This module has three configuration parameters:
1193 * "on" or "enable" - enables binary api tracing
1194 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1195 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1197 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1199 static clib_error_t *
1200 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1202 api_main_t *am = vlibapi_get_main ();
1205 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1207 if (unformat (input, "length %d", &nitems) ||
1208 (unformat (input, "len %d", &nitems)))
1211 am->vlib_input_queue_length = nitems;
1213 clib_warning ("vlib input queue length %d too small, ignored",
1217 return clib_error_return (0, "unknown input `%U'",
1218 format_unformat_error, input);
1223 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1226 extract_name (u8 * s)
1232 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1233 vec_dec_len (rv, 1);
1235 rv[vec_len (rv)] = 0;
1241 extract_crc (u8 * s)
1248 for (i = vec_len (rv) - 1; i >= 0; i--)
1252 vec_delete (rv, i + 1, 0);
1266 } msg_table_unserialize_t;
1269 table_id_cmp (void *a1, void *a2)
1271 msg_table_unserialize_t *n1 = a1;
1272 msg_table_unserialize_t *n2 = a2;
1274 return (n1->msg_index - n2->msg_index);
1278 table_name_and_crc_cmp (void *a1, void *a2)
1280 msg_table_unserialize_t *n1 = a1;
1281 msg_table_unserialize_t *n2 = a2;
1283 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1286 static clib_error_t *
1287 dump_api_table_file_command_fn (vlib_main_t * vm,
1288 unformat_input_t * input,
1289 vlib_cli_command_t * cmd)
1292 api_main_t *am = vlibapi_get_main ();
1293 serialize_main_t _sm, *sm = &_sm;
1294 clib_error_t *error;
1298 int compare_current = 0;
1299 int numeric_sort = 0;
1300 msg_table_unserialize_t *table = 0, *item;
1302 u32 ndifferences = 0;
1304 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1306 if (unformat (input, "file %s", &filename))
1308 else if (unformat (input, "compare-current")
1309 || unformat (input, "compare"))
1310 compare_current = 1;
1311 else if (unformat (input, "numeric"))
1314 return clib_error_return (0, "unknown input `%U'",
1315 format_unformat_error, input);
1318 if (numeric_sort && compare_current)
1319 return clib_error_return
1320 (0, "Comparison and numeric sorting are incompatible");
1323 return clib_error_return (0, "File not specified");
1325 /* Load the serialized message table from the table dump */
1327 error = unserialize_open_clib_file (sm, (char *) filename);
1332 unserialize_integer (sm, &nmsgs, sizeof (u32));
1334 for (i = 0; i < nmsgs; i++)
1336 msg_index = unserialize_likely_small_unsigned_integer (sm);
1337 unserialize_cstring (sm, (char **) &name_and_crc);
1338 vec_add2 (table, item, 1);
1339 item->msg_index = msg_index;
1340 item->name_and_crc = name_and_crc;
1341 item->name = extract_name (name_and_crc);
1342 item->crc = extract_crc (name_and_crc);
1343 item->which = 0; /* file */
1345 unserialize_close (sm);
1347 /* Compare with the current image? */
1348 if (compare_current)
1350 /* Append the current message table */
1351 u8 *tblv = vl_api_serialize_message_table (am, 0);
1353 serialize_open_vector (sm, tblv);
1354 unserialize_integer (sm, &nmsgs, sizeof (u32));
1356 for (i = 0; i < nmsgs; i++)
1358 msg_index = unserialize_likely_small_unsigned_integer (sm);
1359 unserialize_cstring (sm, (char **) &name_and_crc);
1361 vec_add2 (table, item, 1);
1362 item->msg_index = msg_index;
1363 item->name_and_crc = name_and_crc;
1364 item->name = extract_name (name_and_crc);
1365 item->crc = extract_crc (name_and_crc);
1366 item->which = 1; /* current_image */
1371 /* Sort the table. */
1373 vec_sort_with_function (table, table_id_cmp);
1375 vec_sort_with_function (table, table_name_and_crc_cmp);
1377 if (compare_current)
1383 * In this case, the recovered table will have two entries per
1384 * API message. So, if entries i and i+1 match, the message definitions
1385 * are identical. Otherwise, the crc is different, or a message is
1386 * present in only one of the tables.
1388 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1389 vec_validate_init_empty (dashes, 60, '-');
1390 vec_terminate_c_string (dashes);
1391 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1393 for (i = 0; i < vec_len (table);)
1395 /* Last message lonely? */
1396 if (i == vec_len (table) - 1)
1402 /* Identical pair? */
1404 ((char *) table[i].name_and_crc,
1405 (char *) table[i + 1].name_and_crc,
1406 vec_len (table[i].name_and_crc)))
1414 /* Only in one of two tables? */
1415 if (i + 1 == vec_len (table)
1416 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1419 vlib_cli_output (vm, "%-60s | only in %s",
1420 table[i].name, table[i].which ?
1425 /* In both tables, but with different signatures */
1426 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1429 if (ndifferences == 0)
1430 vlib_cli_output (vm, "No api message signature differences found.");
1432 vlib_cli_output (vm, "\nFound %u api message signature differences",
1437 /* Dump the table, sorted as shown above */
1438 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1440 for (i = 0; i < vec_len (table); i++)
1443 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1444 item->msg_index, item->crc);
1448 for (i = 0; i < vec_len (table); i++)
1450 vec_free (table[i].name_and_crc);
1451 vec_free (table[i].name);
1452 vec_free (table[i].crc);
1461 * Displays a serialized API message decode table, sorted by message name
1464 * @cliexstart{show api dump file <filename>}
1465 * Message name MsgID CRC
1466 * accept_session 407 8e2a127e
1467 * accept_session_reply 408 67d8c22a
1468 * add_node_next 549 e4202993
1469 * add_node_next_reply 550 e89d6eed
1475 * Compares a serialized API message decode table with the current image
1478 * @cliexstart{show api dump file <filename> compare}
1479 * ip_add_del_route definition changed
1480 * ip_table_add_del definition changed
1481 * l2_macs_event only in image
1482 * vnet_ip4_fib_counters only in file
1483 * vnet_ip4_nbr_counters only in file
1488 * Display a serialized API message decode table, compare a saved
1489 * decode table with the current image, to establish API differences.
1493 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1495 .path = "show api dump",
1496 .short_help = "show api dump file <filename> [numeric | compare-current]",
1497 .function = dump_api_table_file_command_fn,
1502 * fd.io coding-style-patch-verification: ON
1505 * eval: (c-set-style "gnu")