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
64 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
66 .path = "show api histogram",
67 .short_help = "show api histogram",
68 .function = vl_api_show_histogram_command,
72 vl_api_clear_histogram_command (vlib_main_t * vm,
73 unformat_input_t * input,
74 vlib_cli_command_t * cli_cmd)
78 for (i = 0; i < SLEEP_N_BUCKETS; i++)
79 vector_rate_histogram[i] = 0;
84 * Clear the binary api sleep-time histogram
86 VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
88 .path = "clear api histogram",
89 .short_help = "clear api histogram",
90 .function = vl_api_clear_histogram_command,
94 vl_api_client_command (vlib_main_t * vm,
95 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
97 vl_api_registration_t **regpp, *regp;
100 api_main_t *am = vlibapi_get_main ();
101 u32 *confused_indices = 0;
103 if (!pool_elts (am->vl_clients))
105 vlib_cli_output (vm, "Shared memory clients");
106 vlib_cli_output (vm, "%20s %8s %14s %18s %s",
107 "Name", "PID", "Queue Length", "Queue VA", "Health");
109 pool_foreach (regpp, am->vl_clients)
115 if (regp->unanswered_pings > 0)
116 health = "questionable";
120 q = regp->vl_input_queue;
122 vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
123 regp->name, q->consumer_pid, q->cursize,
128 clib_warning ("NULL client registration index %d",
129 regpp - am->vl_clients);
130 vec_add1 (confused_indices, regpp - am->vl_clients);
134 /* This should "never happen," but if it does, fix it... */
135 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
138 for (i = 0; i < vec_len (confused_indices); i++)
140 pool_put_index (am->vl_clients, confused_indices[i]);
143 vec_free (confused_indices);
145 if (am->missing_clients)
146 vlib_cli_output (vm, "%u messages with missing clients",
147 am->missing_clients);
149 vl_sock_api_dump_clients (vm, am);
154 static clib_error_t *
155 vl_api_status_command (vlib_main_t * vm,
156 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
158 api_main_t *am = vlibapi_get_main ();
160 /* check if rx_trace and tx_trace are not null pointers */
161 if (am->rx_trace == 0)
163 vlib_cli_output (vm, "RX Trace disabled\n");
167 if (am->rx_trace->enabled == 0)
168 vlib_cli_output (vm, "RX Trace disabled\n");
170 vlib_cli_output (vm, "RX Trace enabled\n");
173 if (am->tx_trace == 0)
175 vlib_cli_output (vm, "TX Trace disabled\n");
179 if (am->tx_trace->enabled == 0)
180 vlib_cli_output (vm, "TX Trace disabled\n");
182 vlib_cli_output (vm, "TX Trace enabled\n");
188 VLIB_CLI_COMMAND (cli_show_api_command, static) =
191 .short_help = "Show API information",
195 * Display current api client connections
197 VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
199 .path = "show api clients",
200 .short_help = "Client information",
201 .function = vl_api_client_command,
205 * Display the current api message tracing status
207 VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
209 .path = "show api trace-status",
210 .short_help = "Display API trace status",
211 .function = vl_api_status_command,
214 static clib_error_t *
215 vl_api_message_table_command (vlib_main_t * vm,
216 unformat_input_t * input,
217 vlib_cli_command_t * cli_cmd)
219 api_main_t *am = vlibapi_get_main ();
223 if (unformat (input, "verbose"))
228 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
230 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
233 for (i = 1; i < vec_len (am->msg_data); i++)
235 vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
238 vlib_cli_output (vm, "%-4d %s", i,
239 m->name ? m->name : " [no handler]");
243 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
244 m->name ? m->name : " [no handler]", m->bounce,
253 * Display the current api message decode tables
255 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
257 .path = "show api message-table",
258 .short_help = "Message Table",
259 .function = vl_api_message_table_command,
263 range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
265 int len0, len1, clen;
267 len0 = vec_len (a0->name);
268 len1 = vec_len (a1->name);
269 clen = len0 < len1 ? len0 : len1;
270 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
274 format_api_msg_range (u8 * s, va_list * args)
276 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
279 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
281 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
287 static clib_error_t *
288 vl_api_show_plugin_command (vlib_main_t * vm,
289 unformat_input_t * input,
290 vlib_cli_command_t * cli_cmd)
292 api_main_t *am = vlibapi_get_main ();
293 vl_api_msg_range_t *rp = 0;
296 if (vec_len (am->msg_ranges) == 0)
298 vlib_cli_output (vm, "No plugin API message ranges configured...");
302 rp = vec_dup (am->msg_ranges);
304 vec_sort_with_function (rp, range_compare);
306 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
307 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
309 for (i = 0; i < vec_len (rp); i++)
310 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
318 * Display the plugin binary API message range table
320 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
322 .path = "show api plugin",
323 .short_help = "show api plugin",
324 .function = vl_api_show_plugin_command,
336 format_vl_msg_api_trace_status (u8 * s, va_list * args)
338 api_main_t *am = va_arg (*args, api_main_t *);
339 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
345 case VL_API_TRACE_TX:
347 trace_name = "TX trace";
350 case VL_API_TRACE_RX:
352 trace_name = "RX trace";
361 s = format (s, "%s: not yet configured.\n", trace_name);
365 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
366 trace_name, vec_len (tp->traces), tp->nitems,
367 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
372 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
373 u32 first_index, u32 last_index,
374 vl_api_replay_t which)
376 vl_api_trace_file_header_t *hp;
382 api_main_t *am = vlibapi_get_main ();
384 u32 nitems, nitems_msgtbl;
386 fd = open ((char *) filename, O_RDONLY);
390 vlib_cli_output (vm, "Couldn't open %s\n", filename);
394 if (fstat (fd, &statb) < 0)
396 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
401 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
403 vlib_cli_output (vm, "File not plausible: %s\n", filename);
408 file_size = statb.st_size;
409 file_size = (file_size + 4095) & ~(4095);
411 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
413 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
415 vlib_cli_output (vm, "mmap failed: %s\n", filename);
421 clib_mem_unpoison (hp, file_size);
423 nitems = ntohl (hp->nitems);
425 if (last_index == (u32) ~ 0)
427 last_index = nitems - 1;
430 if (first_index >= nitems || last_index >= nitems)
432 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
433 first_index, last_index, nitems - 1);
434 munmap (hp, file_size);
439 "Note: wrapped/incomplete trace, results may vary\n");
441 size_t file_size_left = file_size;
443 #define assert_size(size_left, s) \
446 if ((s) >= size_left) \
448 vlib_cli_output (vm, "corrupted file"); \
449 munmap (hp, file_size); \
450 vec_free (msgid_vec); \
457 assert_size (file_size_left, sizeof (hp[0]));
458 msg = (u8 *) (hp + 1);
460 serialize_main_t _sm, *sm = &_sm;
461 u32 msgtbl_size = ntohl (hp->msgtbl_size);
464 assert_size (file_size_left, msgtbl_size);
466 unserialize_open_data (sm, msg, msgtbl_size);
467 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
469 for (i = 0; i < nitems_msgtbl; i++)
471 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
472 unserialize_cstring (sm, (char **) &name_and_crc);
473 u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
474 ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
475 if (~0 == msg_index2)
476 vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
478 vec_validate (msgid_vec, msg_index);
479 msgid_vec[msg_index] = msg_index2;
484 for (i = 0; i < first_index; i++)
489 assert_size (file_size_left, sizeof (u32));
490 size = clib_host_to_net_u32 (*(u32 *) msg);
493 assert_size (file_size_left, clib_max (size, sizeof (u16)));
494 msg_id = ntohs (*((u16 *) msg));
495 if (msg_id >= vec_len (msgid_vec) ||
496 msgid_vec[msg_id] >= vec_len (am->msg_data))
497 vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
504 am->replay_in_progress = 1;
506 for (; i <= last_index; i++)
508 vl_api_msg_data_t *m;
513 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
515 assert_size (file_size_left, sizeof (u32));
516 size = clib_host_to_net_u32 (*(u32 *) msg);
519 assert_size (file_size_left, clib_max (size, sizeof (u16)));
520 msg_id = ntohs (*((u16 *) msg));
522 if (msg_id >= vec_len (msgid_vec) ||
523 msgid_vec[msg_id] >= vec_len (am->msg_data))
526 vm, "warning: unknown msg id %d for msg number %d, skipping\n",
532 msg_id = msgid_vec[msg_id];
533 m = vl_api_get_msg_data (am, msg_id);
535 /* Copy the buffer (from the read-only mmap'ed file) */
536 vec_validate (tmpbuf, size - 1 + sizeof (uword));
537 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
538 clib_memset (tmpbuf, 0xf, sizeof (uword));
541 * Endian swap if needed. All msg data is supposed to be in
542 * network byte order.
544 if (((which == DUMP || which == DUMP_JSON) &&
545 clib_arch_is_little_endian))
547 if (m && m->endian_handler == 0)
549 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
550 munmap (hp, file_size);
552 am->replay_in_progress = 0;
557 m->endian_handler (tmpbuf + sizeof (uword));
561 /* msg_id always in network byte order */
562 if (clib_arch_is_little_endian)
564 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
571 vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
572 tmpbuf + sizeof (uword));
576 vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
577 tmpbuf + sizeof (uword));
586 vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
587 msg_id, tmpbuf + sizeof (uword));
589 vlib_cli_output (vm, "*/\n");
591 s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
594 for (j = 0; j < m->trace_size; j++)
597 s = format (s, "\n ");
598 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
600 s = format (s, "\n};\n%c", 0);
601 vlib_cli_output (vm, (char *) s);
607 if (m && m->handler && m->replay_allowed)
610 vl_msg_api_barrier_sync ();
611 m->handler (tmpbuf + sizeof (uword));
613 vl_msg_api_barrier_release ();
617 if (m && m->replay_allowed)
618 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
625 vec_set_len (tmpbuf, 0);
629 munmap (hp, file_size);
631 vec_free (msgid_vec);
632 am->replay_in_progress = 0;
636 file_exists (u8 *fname)
639 fp = fopen ((char *) fname, "r");
655 vl_msg_print_trace (u8 *msg, void *ctx)
657 vl_msg_print_args *a = ctx;
658 api_main_t *am = vlibapi_get_main ();
659 u16 msg_id = ntohs (*((u16 *) msg));
660 vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
661 u8 is_json = a->is_json;
666 vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
670 if (clib_arch_is_little_endian && (m->endian_handler != NULL))
672 u32 msg_length = vec_len (msg);
673 vec_validate (tmpbuf, msg_length - 1);
674 clib_memcpy_fast (tmpbuf, msg, msg_length);
677 m->endian_handler (tmpbuf);
680 vlib_cli_output (a->vm, "%U\n",
681 is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
689 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
691 api_main_t *am = vlibapi_get_main ();
696 case VL_API_TRACE_TX:
699 case VL_API_TRACE_RX:
706 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
709 vl_msg_print_args args;
710 clib_memset (&args, 0, sizeof (args));
711 args.is_json = is_json;
713 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
719 vl_msg_read_file (FILE *f)
721 const size_t bufsize = 1024;
722 char *buf[bufsize], *v = 0;
725 while ((n = fread (buf, 1, bufsize, f)))
728 /* most callers expect a NULL-terminated C-string */
736 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
739 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
747 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
751 if (!am->msg_id_by_name)
753 vlib_cli_output (vm, "message id table not yet initialized!\n");
757 p = hash_get_mem (am->msg_id_by_name, name);
765 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
767 api_main_t *am = vlibapi_get_main ();
769 int len = 0, rv = -1;
770 vl_api_msg_data_t *m;
773 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
776 vlib_cli_output (vm, "Missing '_msgname' element!\n");
779 char *name = cJSON_GetStringValue (msg_id_obj);
781 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
784 vlib_cli_output (vm, "Missing '_crc' element!\n");
787 char *crc = cJSON_GetStringValue (crc_obj);
790 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
791 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
792 m = vl_api_get_msg_data (am, msg_id);
793 if (msg_id == (u16) ~0)
795 msg_id = vl_msg_find_id_by_name (vm, am, name);
796 if (msg_id == (u16) ~0)
798 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
806 if (m->replay_allowed)
809 vlib_cli_output (vm, "warning: msg %d has different signature\n");
811 if (!m->fromjson_handler)
813 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
818 msg = (u8 *) m->fromjson_handler (o, &len);
821 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
826 if (clib_arch_is_little_endian)
827 m->endian_handler (msg);
831 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
838 vl_msg_api_barrier_sync ();
841 vl_msg_api_barrier_release ();
853 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
855 api_main_t *am = vlibapi_get_main ();
858 FILE *f = fopen ((char *) filename, "r");
862 vlib_cli_output (vm, "failed to open %s!\n", filename);
866 char *buf = vl_msg_read_file (f);
869 o = cJSON_Parse (buf);
873 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
874 cJSON_GetErrorPtr ());
878 if (cJSON_IsArray (o))
880 am->replay_in_progress = 1;
881 size_t size = cJSON_GetArraySize (o);
882 for (int i = 0; i < size; i++)
884 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
887 am->replay_in_progress = 0;
894 rv = vl_msg_exec_json_command (vm, o);
898 vlib_cli_output (vm, "error during replaying API trace");
904 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
906 FILE *f = fopen ((char *) filename, "r");
911 vlib_cli_output (vm, "failed to open %s!\n", filename);
915 buf = vl_msg_read_file (f);
920 vlib_cli_output (vm, "no content in %s!\n", filename);
924 vlib_cli_output (vm, buf);
928 /** api_trace_command_fn - control the binary API trace / replay feature
930 Note: this command MUST be marked thread-safe. Replay with
931 multiple worker threads depends in many cases on worker thread
932 graph replica maintenance. If we (implicitly) assert a worker
933 thread barrier at the debug CLI level, all graph replica changes
934 are deferred until the replay operation completes. If an interface
935 is deleted, the wheels fall off.
938 static clib_error_t *
939 api_trace_command_fn (vlib_main_t * vm,
940 unformat_input_t * input, vlib_cli_command_t * cmd)
942 unformat_input_t _line_input, *line_input = &_line_input;
943 u32 nitems = 256 << 10;
944 api_main_t *am = vlibapi_get_main ();
945 vl_api_trace_which_t which = VL_API_TRACE_RX;
947 u8 *chroot_filename = 0;
949 u32 last = (u32) ~ 0;
953 /* Get a line of input. */
954 if (!unformat_user (input, unformat_line_input, line_input))
957 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
959 if (unformat (line_input, "on") || unformat (line_input, "enable"))
961 if (unformat (line_input, "nitems %d", &nitems))
963 vlib_worker_thread_barrier_sync (vm);
964 vl_msg_api_trace_configure (am, which, nitems);
965 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
966 vlib_worker_thread_barrier_release (vm);
968 else if (unformat (line_input, "off"))
970 vlib_worker_thread_barrier_sync (vm);
971 vl_msg_api_trace_onoff (am, which, 0);
972 vlib_worker_thread_barrier_release (vm);
974 else if (unformat (line_input, "save-json %s", &filename))
976 if (strstr ((char *) filename, "..") ||
977 index ((char *) filename, '/'))
979 vlib_cli_output (vm, "illegal characters in filename '%s'",
984 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
988 if (file_exists (chroot_filename))
990 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
994 fp = fopen ((char *) chroot_filename, "w");
997 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1000 vlib_worker_thread_barrier_sync (vm);
1001 rv = vl_msg_api_trace_save (am, which, fp, 1);
1003 vlib_cli_output (vm, "API Trace data not present\n");
1005 vlib_cli_output (vm, "failed to save api trace\n");
1007 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1008 vlib_worker_thread_barrier_release (vm);
1011 else if (unformat (line_input, "save %s", &filename))
1013 if (strstr ((char *) filename, "..")
1014 || index ((char *) filename, '/'))
1016 vlib_cli_output (vm, "illegal characters in filename '%s'",
1021 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1023 vec_free (filename);
1025 if (file_exists (chroot_filename))
1027 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1031 fp = fopen ((char *) chroot_filename, "w");
1034 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1037 vlib_worker_thread_barrier_sync (vm);
1038 rv = vl_msg_api_trace_save (am, which, fp, 0);
1039 vlib_worker_thread_barrier_release (vm);
1042 vlib_cli_output (vm, "API Trace data not present\n");
1044 vlib_cli_output (vm, "File for writing is closed\n");
1046 vlib_cli_output (vm, "Error while writing header to file\n");
1048 vlib_cli_output (vm, "Error while writing trace to file\n");
1050 vlib_cli_output (vm,
1051 "Error while writing end of buffer trace to file\n");
1053 vlib_cli_output (vm,
1054 "Error while writing start of buffer trace to file\n");
1056 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1058 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1061 else if (unformat (line_input, "tojson %s", &filename))
1063 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1065 else if (unformat (line_input, "dump-file-json %s", &filename))
1067 vl_msg_dump_file_json (vm, filename);
1069 else if (unformat (line_input, "dump-file %s", &filename))
1071 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1073 else if (unformat (line_input, "dump-json"))
1075 vl_msg_api_dump_trace (vm, which, 1);
1077 else if (unformat (line_input, "dump"))
1079 vl_msg_api_dump_trace (vm, which, 0);
1081 else if (unformat (line_input, "replay-json %s", &filename))
1083 vl_msg_replay_json (vm, filename);
1085 else if (unformat (line_input, "replay %s", &filename))
1087 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1089 else if (unformat (line_input, "initializers %s", &filename))
1091 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1093 else if (unformat (line_input, "tx"))
1095 which = VL_API_TRACE_TX;
1097 else if (unformat (line_input, "first %d", &first))
1101 else if (unformat (line_input, "last %d", &last))
1105 else if (unformat (line_input, "status"))
1107 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1110 else if (unformat (line_input, "free"))
1112 vlib_worker_thread_barrier_sync (vm);
1113 vl_msg_api_trace_onoff (am, which, 0);
1114 vl_msg_api_trace_free (am, which);
1115 vlib_worker_thread_barrier_release (vm);
1117 else if (unformat (line_input, "post-mortem-on"))
1118 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1119 else if (unformat (line_input, "post-mortem-off"))
1120 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1122 return clib_error_return (0, "unknown input `%U'",
1123 format_unformat_error, input);
1126 vec_free (filename);
1127 vec_free (chroot_filename);
1128 unformat_free (line_input);
1133 * Display, replay, or save a binary API trace
1136 VLIB_CLI_COMMAND (api_trace_command, static) = {
1137 .path = "api trace",
1138 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1139 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1140 "json|replay <file>|replay-json <file>][nitems <n>]"
1141 "[initializers <file>]",
1142 .function = api_trace_command_fn,
1146 static clib_error_t *
1147 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1149 u32 nitems = 256 << 10;
1150 vl_api_trace_which_t which = VL_API_TRACE_RX;
1151 api_main_t *am = vlibapi_get_main ();
1153 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1155 if (unformat (input, "on") || unformat (input, "enable"))
1157 if (unformat (input, "nitems %d", &nitems))
1159 vl_msg_api_trace_configure (am, which, nitems);
1160 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1161 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1163 else if (unformat (input, "save-api-table %s",
1164 &am->save_msg_table_filename))
1167 return clib_error_return (0, "unknown input `%U'",
1168 format_unformat_error, input);
1174 * This module has three configuration parameters:
1175 * "on" or "enable" - enables binary api tracing
1176 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1177 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1179 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1181 static clib_error_t *
1182 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1184 api_main_t *am = vlibapi_get_main ();
1187 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1189 if (unformat (input, "length %d", &nitems) ||
1190 (unformat (input, "len %d", &nitems)))
1193 am->vlib_input_queue_length = nitems;
1195 clib_warning ("vlib input queue length %d too small, ignored",
1199 return clib_error_return (0, "unknown input `%U'",
1200 format_unformat_error, input);
1205 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1208 extract_name (u8 * s)
1214 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1215 vec_dec_len (rv, 1);
1217 rv[vec_len (rv)] = 0;
1223 extract_crc (u8 * s)
1230 for (i = vec_len (rv) - 1; i >= 0; i--)
1234 vec_delete (rv, i + 1, 0);
1248 } msg_table_unserialize_t;
1251 table_id_cmp (void *a1, void *a2)
1253 msg_table_unserialize_t *n1 = a1;
1254 msg_table_unserialize_t *n2 = a2;
1256 return (n1->msg_index - n2->msg_index);
1260 table_name_and_crc_cmp (void *a1, void *a2)
1262 msg_table_unserialize_t *n1 = a1;
1263 msg_table_unserialize_t *n2 = a2;
1265 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1268 static clib_error_t *
1269 dump_api_table_file_command_fn (vlib_main_t * vm,
1270 unformat_input_t * input,
1271 vlib_cli_command_t * cmd)
1274 api_main_t *am = vlibapi_get_main ();
1275 serialize_main_t _sm, *sm = &_sm;
1276 clib_error_t *error;
1280 int compare_current = 0;
1281 int numeric_sort = 0;
1282 msg_table_unserialize_t *table = 0, *item;
1284 u32 ndifferences = 0;
1286 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1288 if (unformat (input, "file %s", &filename))
1290 else if (unformat (input, "compare-current")
1291 || unformat (input, "compare"))
1292 compare_current = 1;
1293 else if (unformat (input, "numeric"))
1296 return clib_error_return (0, "unknown input `%U'",
1297 format_unformat_error, input);
1300 if (numeric_sort && compare_current)
1301 return clib_error_return
1302 (0, "Comparison and numeric sorting are incompatible");
1305 return clib_error_return (0, "File not specified");
1307 /* Load the serialized message table from the table dump */
1309 error = unserialize_open_clib_file (sm, (char *) filename);
1314 unserialize_integer (sm, &nmsgs, sizeof (u32));
1316 for (i = 0; i < nmsgs; i++)
1318 msg_index = unserialize_likely_small_unsigned_integer (sm);
1319 unserialize_cstring (sm, (char **) &name_and_crc);
1320 vec_add2 (table, item, 1);
1321 item->msg_index = msg_index;
1322 item->name_and_crc = name_and_crc;
1323 item->name = extract_name (name_and_crc);
1324 item->crc = extract_crc (name_and_crc);
1325 item->which = 0; /* file */
1327 unserialize_close (sm);
1329 /* Compare with the current image? */
1330 if (compare_current)
1332 /* Append the current message table */
1333 u8 *tblv = vl_api_serialize_message_table (am, 0);
1335 serialize_open_vector (sm, tblv);
1336 unserialize_integer (sm, &nmsgs, sizeof (u32));
1338 for (i = 0; i < nmsgs; i++)
1340 msg_index = unserialize_likely_small_unsigned_integer (sm);
1341 unserialize_cstring (sm, (char **) &name_and_crc);
1343 vec_add2 (table, item, 1);
1344 item->msg_index = msg_index;
1345 item->name_and_crc = name_and_crc;
1346 item->name = extract_name (name_and_crc);
1347 item->crc = extract_crc (name_and_crc);
1348 item->which = 1; /* current_image */
1353 /* Sort the table. */
1355 vec_sort_with_function (table, table_id_cmp);
1357 vec_sort_with_function (table, table_name_and_crc_cmp);
1359 if (compare_current)
1365 * In this case, the recovered table will have two entries per
1366 * API message. So, if entries i and i+1 match, the message definitions
1367 * are identical. Otherwise, the crc is different, or a message is
1368 * present in only one of the tables.
1370 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1371 vec_validate_init_empty (dashes, 60, '-');
1372 vec_terminate_c_string (dashes);
1373 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1375 for (i = 0; i < vec_len (table);)
1377 /* Last message lonely? */
1378 if (i == vec_len (table) - 1)
1384 /* Identical pair? */
1386 ((char *) table[i].name_and_crc,
1387 (char *) table[i + 1].name_and_crc,
1388 vec_len (table[i].name_and_crc)))
1396 /* Only in one of two tables? */
1397 if (i + 1 == vec_len (table)
1398 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1401 vlib_cli_output (vm, "%-60s | only in %s",
1402 table[i].name, table[i].which ?
1407 /* In both tables, but with different signatures */
1408 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1411 if (ndifferences == 0)
1412 vlib_cli_output (vm, "No api message signature differences found.");
1414 vlib_cli_output (vm, "\nFound %u api message signature differences",
1419 /* Dump the table, sorted as shown above */
1420 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1422 for (i = 0; i < vec_len (table); i++)
1425 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1426 item->msg_index, item->crc);
1430 for (i = 0; i < vec_len (table); i++)
1432 vec_free (table[i].name_and_crc);
1433 vec_free (table[i].name);
1434 vec_free (table[i].crc);
1443 * Displays a serialized API message decode table, sorted by message name
1446 * @cliexstart{show api dump file <filename>}
1447 * Message name MsgID CRC
1448 * accept_session 407 8e2a127e
1449 * accept_session_reply 408 67d8c22a
1450 * add_node_next 549 e4202993
1451 * add_node_next_reply 550 e89d6eed
1457 * Compares a serialized API message decode table with the current image
1460 * @cliexstart{show api dump file <filename> compare}
1461 * ip_add_del_route definition changed
1462 * ip_table_add_del definition changed
1463 * l2_macs_event only in image
1464 * vnet_ip4_fib_counters only in file
1465 * vnet_ip4_nbr_counters only in file
1470 * Display a serialized API message decode table, compare a saved
1471 * decode table with the current image, to establish API differences.
1474 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1476 .path = "show api dump",
1477 .short_help = "show api dump file <filename> [numeric | compare-current]",
1478 .function = dump_api_table_file_command_fn,
1482 * fd.io coding-style-patch-verification: ON
1485 * eval: (c-set-style "gnu")