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");
389 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
390 u32 first_index, u32 last_index,
391 vl_api_replay_t which)
393 vl_api_trace_file_header_t *hp;
399 api_main_t *am = vlibapi_get_main ();
401 u32 nitems, nitems_msgtbl;
403 fd = open ((char *) filename, O_RDONLY);
407 vlib_cli_output (vm, "Couldn't open %s\n", filename);
411 if (fstat (fd, &statb) < 0)
413 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
418 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
420 vlib_cli_output (vm, "File not plausible: %s\n", filename);
425 file_size = statb.st_size;
426 file_size = (file_size + 4095) & ~(4095);
428 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
430 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
432 vlib_cli_output (vm, "mmap failed: %s\n", filename);
438 CLIB_MEM_UNPOISON (hp, file_size);
440 nitems = ntohl (hp->nitems);
442 if (last_index == (u32) ~ 0)
444 last_index = nitems - 1;
447 if (first_index >= nitems || last_index >= nitems)
449 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
450 first_index, last_index, nitems - 1);
451 munmap (hp, file_size);
456 "Note: wrapped/incomplete trace, results may vary\n");
458 size_t file_size_left = file_size;
460 #define assert_size(size_left, s) \
463 if ((s) >= size_left) \
465 vlib_cli_output (vm, "corrupted file"); \
466 munmap (hp, file_size); \
467 vec_free (msgid_vec); \
474 assert_size (file_size_left, sizeof (hp[0]));
475 msg = (u8 *) (hp + 1);
477 serialize_main_t _sm, *sm = &_sm;
478 u32 msgtbl_size = ntohl (hp->msgtbl_size);
481 assert_size (file_size_left, msgtbl_size);
483 unserialize_open_data (sm, msg, msgtbl_size);
484 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
486 for (i = 0; i < nitems_msgtbl; i++)
488 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
489 unserialize_cstring (sm, (char **) &name_and_crc);
490 u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
491 vec_validate (msgid_vec, msg_index);
492 msgid_vec[msg_index] = msg_index2;
497 for (i = 0; i < first_index; i++)
503 assert_size (file_size_left, sizeof (u32));
504 size = clib_host_to_net_u32 (*(u32 *) msg);
507 assert_size (file_size_left, size);
508 msg_id = ntohs (*((u16 *) msg));
509 if (msg_id < vec_len (msgid_vec))
510 msg_id = msgid_vec[msg_id];
511 cfgp = am->api_trace_cfg + msg_id;
514 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
515 munmap (hp, file_size);
516 vec_free (msgid_vec);
523 am->replay_in_progress = 1;
525 for (; i <= last_index; i++)
532 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
534 size = clib_host_to_net_u32 (*(u32 *) msg);
537 msg_id = ntohs (*((u16 *) msg));
538 if (msg_id < vec_len (msgid_vec))
540 msg_id = msgid_vec[msg_id];
543 cfgp = am->api_trace_cfg + msg_id;
546 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
547 munmap (hp, file_size);
549 am->replay_in_progress = 0;
553 /* Copy the buffer (from the read-only mmap'ed file) */
554 vec_validate (tmpbuf, size - 1 + sizeof (uword));
555 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
556 clib_memset (tmpbuf, 0xf, sizeof (uword));
559 * Endian swap if needed. All msg data is supposed to be in
560 * network byte order.
562 if (((which == DUMP || which == DUMP_JSON) &&
563 clib_arch_is_little_endian))
565 void (*endian_fp) (void *);
566 if (msg_id >= vec_len (am->msg_endian_handlers)
567 || (am->msg_endian_handlers[msg_id] == 0))
569 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
570 munmap (hp, file_size);
572 am->replay_in_progress = 0;
575 endian_fp = am->msg_endian_handlers[msg_id];
576 (*endian_fp) (tmpbuf + sizeof (uword));
579 /* msg_id always in network byte order */
580 if (clib_arch_is_little_endian)
582 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
589 if (msg_id < vec_len (am->msg_print_json_handlers) &&
590 am->msg_print_json_handlers[msg_id])
592 u8 *(*print_fp) (void *, void *);
594 print_fp = (void *) am->msg_print_json_handlers[msg_id];
595 (*print_fp) (tmpbuf + sizeof (uword), vm);
599 vlib_cli_output (vm, "Skipping msg id %d: no JSON print fcn\n",
606 if (msg_id < vec_len (am->msg_print_handlers) &&
607 am->msg_print_handlers[msg_id])
609 u8 *(*print_fp) (void *, void *);
611 print_fp = (void *) am->msg_print_handlers[msg_id];
612 (*print_fp) (tmpbuf + sizeof (uword), vm);
616 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
623 if (msg_id < vec_len (am->msg_print_handlers) &&
624 am->msg_print_handlers[msg_id])
628 u8 *(*print_fp) (void *, void *);
630 print_fp = (void *) am->msg_print_handlers[msg_id];
632 vlib_cli_output (vm, "/*");
634 (*print_fp) (tmpbuf + sizeof (uword), vm);
635 vlib_cli_output (vm, "*/\n");
637 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
638 am->msg_names[msg_id], i,
639 am->api_trace_cfg[msg_id].size);
641 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
644 s = format (s, "\n ");
645 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
647 s = format (s, "\n};\n%c", 0);
648 vlib_cli_output (vm, (char *) s);
654 if (msg_id < vec_len (am->msg_print_handlers) &&
655 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
657 void (*handler) (void *, vlib_main_t *);
659 handler = (void *) am->msg_handlers[msg_id];
661 if (!am->is_mp_safe[msg_id])
662 vl_msg_api_barrier_sync ();
663 (*handler) (tmpbuf + sizeof (uword), vm);
664 if (!am->is_mp_safe[msg_id])
665 vl_msg_api_barrier_release ();
669 if (cfgp->replay_enable)
670 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
677 _vec_len (tmpbuf) = 0;
681 munmap (hp, file_size);
683 vec_free (msgid_vec);
684 am->replay_in_progress = 0;
688 file_exists (u8 *fname)
691 fp = fopen ((char *) fname, "r");
707 vl_msg_print_trace (u8 *msg, void *ctx)
709 vl_msg_print_args *a = ctx;
710 api_main_t *am = vlibapi_get_main ();
711 u16 msg_id = ntohs (*((u16 *) msg));
712 void (*print_fp) (void *, void *);
713 void (**handlers) (void *, void *);
714 u8 is_json = a->is_json;
717 if (clib_arch_is_little_endian)
719 u32 msg_length = vec_len (msg);
720 vec_validate (tmpbuf, msg_length - 1);
721 clib_memcpy_fast (tmpbuf, msg, msg_length);
724 void (*endian_fp) (void *);
725 endian_fp = am->msg_endian_handlers[msg_id];
726 (*endian_fp) (tmpbuf);
730 handlers = am->msg_print_json_handlers;
732 handlers = am->msg_print_handlers;
734 if (msg_id < vec_len (handlers) && handlers[msg_id])
736 print_fp = (void *) handlers[msg_id];
737 (*print_fp) (msg, a->vm);
741 vlib_cli_output (a->vm, "Skipping msg id %d: no print fcn\n", msg_id);
749 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
751 api_main_t *am = vlibapi_get_main ();
756 case VL_API_TRACE_TX:
759 case VL_API_TRACE_RX:
766 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
769 vl_msg_print_args args;
770 clib_memset (&args, 0, sizeof (args));
771 args.is_json = is_json;
773 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
779 vl_msg_read_file (FILE *f)
781 const size_t bufsize = 1024;
782 char *buf[bufsize], *v = 0;
785 while ((n = fread (buf, 1, bufsize, f)))
792 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
795 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
803 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
807 if (!am->msg_id_by_name)
809 vlib_cli_output (vm, "message id table not yet initialized!\n");
813 p = hash_get_mem (am->msg_id_by_name, name);
821 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
823 api_main_t *am = vlibapi_get_main ();
825 void *(*fromjson) (cJSON *, int *);
826 int len = 0, rv = -1;
830 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
833 vlib_cli_output (vm, "Missing '_msgname' element!\n");
836 char *name = cJSON_GetStringValue (msg_id_obj);
838 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
841 vlib_cli_output (vm, "Missing '_crc' element!\n");
844 char *crc = cJSON_GetStringValue (crc_obj);
847 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
848 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
849 if (msg_id == (u16) ~0)
851 msg_id = vl_msg_find_id_by_name (vm, am, name);
852 if (msg_id == (u16) ~0)
854 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
862 cfgp = am->api_trace_cfg + msg_id;
865 vlib_cli_output (vm, "msg id %d no trace config\n", msg_id);
869 if (cfgp->replay_enable)
873 vlib_cli_output (vm, "warning: msg %d has different signature\n");
875 fromjson = am->msg_fromjson_handlers[msg_id];
878 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
883 msg = (u8 *) fromjson (o, &len);
886 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
891 if (clib_arch_is_little_endian)
893 void (*endian_fp) (void *);
894 endian_fp = am->msg_endian_handlers[msg_id];
898 void (*handler) (void *, vlib_main_t *);
899 handler = (void *) am->msg_handlers[msg_id];
902 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
906 if (!am->is_mp_safe[msg_id])
907 vl_msg_api_barrier_sync ();
908 (*handler) (msg, vm);
909 if (!am->is_mp_safe[msg_id])
910 vl_msg_api_barrier_release ();
921 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
923 api_main_t *am = vlibapi_get_main ();
926 FILE *f = fopen ((char *) filename, "r");
930 vlib_cli_output (vm, "failed to open %s!\n", filename);
934 char *buf = vl_msg_read_file (f);
937 o = cJSON_Parse (buf);
941 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
942 cJSON_GetErrorPtr ());
946 if (cJSON_IsArray (o))
948 am->replay_in_progress = 1;
949 size_t size = cJSON_GetArraySize (o);
950 for (int i = 0; i < size; i++)
952 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
955 am->replay_in_progress = 0;
962 rv = vl_msg_exec_json_command (vm, o);
966 vlib_cli_output (vm, "error during replaying API trace");
972 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
974 FILE *f = fopen ((char *) filename, "r");
979 vlib_cli_output (vm, "failed to open %s!\n", filename);
983 buf = vl_msg_read_file (f);
988 vlib_cli_output (vm, "no content in %s!\n", filename);
992 vlib_cli_output (vm, buf);
996 /** api_trace_command_fn - control the binary API trace / replay feature
998 Note: this command MUST be marked thread-safe. Replay with
999 multiple worker threads depends in many cases on worker thread
1000 graph replica maintenance. If we (implicitly) assert a worker
1001 thread barrier at the debug CLI level, all graph replica changes
1002 are deferred until the replay operation completes. If an interface
1003 is deleted, the wheels fall off.
1006 static clib_error_t *
1007 api_trace_command_fn (vlib_main_t * vm,
1008 unformat_input_t * input, vlib_cli_command_t * cmd)
1010 unformat_input_t _line_input, *line_input = &_line_input;
1011 u32 nitems = 256 << 10;
1012 api_main_t *am = vlibapi_get_main ();
1013 vl_api_trace_which_t which = VL_API_TRACE_RX;
1015 u8 *chroot_filename = 0;
1017 u32 last = (u32) ~ 0;
1021 /* Get a line of input. */
1022 if (!unformat_user (input, unformat_line_input, line_input))
1025 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1027 if (unformat (line_input, "on") || unformat (line_input, "enable"))
1029 if (unformat (line_input, "nitems %d", &nitems))
1031 vlib_worker_thread_barrier_sync (vm);
1032 vl_msg_api_trace_configure (am, which, nitems);
1033 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1034 vlib_worker_thread_barrier_release (vm);
1036 else if (unformat (line_input, "off"))
1038 vlib_worker_thread_barrier_sync (vm);
1039 vl_msg_api_trace_onoff (am, which, 0);
1040 vlib_worker_thread_barrier_release (vm);
1042 else if (unformat (line_input, "save-json %s", &filename))
1044 if (strstr ((char *) filename, "..") ||
1045 index ((char *) filename, '/'))
1047 vlib_cli_output (vm, "illegal characters in filename '%s'",
1052 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1054 vec_free (filename);
1056 if (file_exists (chroot_filename))
1058 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1062 fp = fopen ((char *) chroot_filename, "w");
1065 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1068 vlib_worker_thread_barrier_sync (vm);
1069 rv = vl_msg_api_trace_save (am, which, fp, 1);
1071 vlib_cli_output (vm, "API Trace data not present\n");
1073 vlib_cli_output (vm, "failed to save api trace\n");
1075 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1076 vlib_worker_thread_barrier_release (vm);
1079 else if (unformat (line_input, "save %s", &filename))
1081 if (strstr ((char *) filename, "..")
1082 || index ((char *) filename, '/'))
1084 vlib_cli_output (vm, "illegal characters in filename '%s'",
1089 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1091 vec_free (filename);
1093 if (file_exists (chroot_filename))
1095 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1099 fp = fopen ((char *) chroot_filename, "w");
1102 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1105 vlib_worker_thread_barrier_sync (vm);
1106 rv = vl_msg_api_trace_save (am, which, fp, 0);
1107 vlib_worker_thread_barrier_release (vm);
1110 vlib_cli_output (vm, "API Trace data not present\n");
1112 vlib_cli_output (vm, "File for writing is closed\n");
1114 vlib_cli_output (vm, "Error while writing header to file\n");
1116 vlib_cli_output (vm, "Error while writing trace to file\n");
1118 vlib_cli_output (vm,
1119 "Error while writing end of buffer trace to file\n");
1121 vlib_cli_output (vm,
1122 "Error while writing start of buffer trace to file\n");
1124 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1126 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1129 else if (unformat (line_input, "tojson %s", &filename))
1131 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1133 else if (unformat (line_input, "dump-file-json %s", &filename))
1135 vl_msg_dump_file_json (vm, filename);
1137 else if (unformat (line_input, "dump-file %s", &filename))
1139 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1141 else if (unformat (line_input, "dump-json"))
1143 vl_msg_api_dump_trace (vm, which, 1);
1145 else if (unformat (line_input, "dump"))
1147 vl_msg_api_dump_trace (vm, which, 0);
1149 else if (unformat (line_input, "replay-json %s", &filename))
1151 vl_msg_replay_json (vm, filename);
1153 else if (unformat (line_input, "replay %s", &filename))
1155 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1157 else if (unformat (line_input, "initializers %s", &filename))
1159 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1161 else if (unformat (line_input, "tx"))
1163 which = VL_API_TRACE_TX;
1165 else if (unformat (line_input, "first %d", &first))
1169 else if (unformat (line_input, "last %d", &last))
1173 else if (unformat (line_input, "status"))
1175 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1178 else if (unformat (line_input, "free"))
1180 vlib_worker_thread_barrier_sync (vm);
1181 vl_msg_api_trace_onoff (am, which, 0);
1182 vl_msg_api_trace_free (am, which);
1183 vlib_worker_thread_barrier_release (vm);
1185 else if (unformat (line_input, "post-mortem-on"))
1186 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1187 else if (unformat (line_input, "post-mortem-off"))
1188 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1190 return clib_error_return (0, "unknown input `%U'",
1191 format_unformat_error, input);
1194 vec_free (filename);
1195 vec_free (chroot_filename);
1196 unformat_free (line_input);
1201 * Display, replay, or save a binary API trace
1205 VLIB_CLI_COMMAND (api_trace_command, static) = {
1206 .path = "api trace",
1207 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1208 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1209 "json|replay <file>|replay-json <file>][nitems <n>]"
1210 "[initializers <file>]",
1211 .function = api_trace_command_fn,
1216 static clib_error_t *
1217 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1219 u32 nitems = 256 << 10;
1220 vl_api_trace_which_t which = VL_API_TRACE_RX;
1221 api_main_t *am = vlibapi_get_main ();
1223 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1225 if (unformat (input, "on") || unformat (input, "enable"))
1227 if (unformat (input, "nitems %d", &nitems))
1229 vl_msg_api_trace_configure (am, which, nitems);
1230 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1231 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1233 else if (unformat (input, "save-api-table %s",
1234 &am->save_msg_table_filename))
1237 return clib_error_return (0, "unknown input `%U'",
1238 format_unformat_error, input);
1244 * This module has three configuration parameters:
1245 * "on" or "enable" - enables binary api tracing
1246 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1247 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1249 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1251 static clib_error_t *
1252 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1254 api_main_t *am = vlibapi_get_main ();
1257 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1259 if (unformat (input, "length %d", &nitems) ||
1260 (unformat (input, "len %d", &nitems)))
1263 am->vlib_input_queue_length = nitems;
1265 clib_warning ("vlib input queue length %d too small, ignored",
1269 return clib_error_return (0, "unknown input `%U'",
1270 format_unformat_error, input);
1275 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1278 extract_name (u8 * s)
1284 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1287 rv[vec_len (rv)] = 0;
1293 extract_crc (u8 * s)
1300 for (i = vec_len (rv) - 1; i >= 0; i--)
1304 vec_delete (rv, i + 1, 0);
1318 } msg_table_unserialize_t;
1321 table_id_cmp (void *a1, void *a2)
1323 msg_table_unserialize_t *n1 = a1;
1324 msg_table_unserialize_t *n2 = a2;
1326 return (n1->msg_index - n2->msg_index);
1330 table_name_and_crc_cmp (void *a1, void *a2)
1332 msg_table_unserialize_t *n1 = a1;
1333 msg_table_unserialize_t *n2 = a2;
1335 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1338 static clib_error_t *
1339 dump_api_table_file_command_fn (vlib_main_t * vm,
1340 unformat_input_t * input,
1341 vlib_cli_command_t * cmd)
1344 api_main_t *am = vlibapi_get_main ();
1345 serialize_main_t _sm, *sm = &_sm;
1346 clib_error_t *error;
1350 int compare_current = 0;
1351 int numeric_sort = 0;
1352 msg_table_unserialize_t *table = 0, *item;
1354 u32 ndifferences = 0;
1356 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1358 if (unformat (input, "file %s", &filename))
1360 else if (unformat (input, "compare-current")
1361 || unformat (input, "compare"))
1362 compare_current = 1;
1363 else if (unformat (input, "numeric"))
1366 return clib_error_return (0, "unknown input `%U'",
1367 format_unformat_error, input);
1370 if (numeric_sort && compare_current)
1371 return clib_error_return
1372 (0, "Comparison and numeric sorting are incompatible");
1375 return clib_error_return (0, "File not specified");
1377 /* Load the serialized message table from the table dump */
1379 error = unserialize_open_clib_file (sm, (char *) filename);
1384 unserialize_integer (sm, &nmsgs, sizeof (u32));
1386 for (i = 0; i < nmsgs; i++)
1388 msg_index = unserialize_likely_small_unsigned_integer (sm);
1389 unserialize_cstring (sm, (char **) &name_and_crc);
1390 vec_add2 (table, item, 1);
1391 item->msg_index = msg_index;
1392 item->name_and_crc = name_and_crc;
1393 item->name = extract_name (name_and_crc);
1394 item->crc = extract_crc (name_and_crc);
1395 item->which = 0; /* file */
1397 unserialize_close (sm);
1399 /* Compare with the current image? */
1400 if (compare_current)
1402 /* Append the current message table */
1403 u8 *tblv = vl_api_serialize_message_table (am, 0);
1405 serialize_open_vector (sm, tblv);
1406 unserialize_integer (sm, &nmsgs, sizeof (u32));
1408 for (i = 0; i < nmsgs; i++)
1410 msg_index = unserialize_likely_small_unsigned_integer (sm);
1411 unserialize_cstring (sm, (char **) &name_and_crc);
1413 vec_add2 (table, item, 1);
1414 item->msg_index = msg_index;
1415 item->name_and_crc = name_and_crc;
1416 item->name = extract_name (name_and_crc);
1417 item->crc = extract_crc (name_and_crc);
1418 item->which = 1; /* current_image */
1423 /* Sort the table. */
1425 vec_sort_with_function (table, table_id_cmp);
1427 vec_sort_with_function (table, table_name_and_crc_cmp);
1429 if (compare_current)
1435 * In this case, the recovered table will have two entries per
1436 * API message. So, if entries i and i+1 match, the message definitions
1437 * are identical. Otherwise, the crc is different, or a message is
1438 * present in only one of the tables.
1440 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1441 vec_validate_init_empty (dashes, 60, '-');
1442 vec_terminate_c_string (dashes);
1443 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1445 for (i = 0; i < vec_len (table);)
1447 /* Last message lonely? */
1448 if (i == vec_len (table) - 1)
1454 /* Identical pair? */
1456 ((char *) table[i].name_and_crc,
1457 (char *) table[i + 1].name_and_crc,
1458 vec_len (table[i].name_and_crc)))
1466 /* Only in one of two tables? */
1467 if (i + 1 == vec_len (table)
1468 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1471 vlib_cli_output (vm, "%-60s | only in %s",
1472 table[i].name, table[i].which ?
1477 /* In both tables, but with different signatures */
1478 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1481 if (ndifferences == 0)
1482 vlib_cli_output (vm, "No api message signature differences found.");
1484 vlib_cli_output (vm, "\nFound %u api message signature differences",
1489 /* Dump the table, sorted as shown above */
1490 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1492 for (i = 0; i < vec_len (table); i++)
1495 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1496 item->msg_index, item->crc);
1500 for (i = 0; i < vec_len (table); i++)
1502 vec_free (table[i].name_and_crc);
1503 vec_free (table[i].name);
1504 vec_free (table[i].crc);
1513 * Displays a serialized API message decode table, sorted by message name
1516 * @cliexstart{show api dump file <filename>}
1517 * Message name MsgID CRC
1518 * accept_session 407 8e2a127e
1519 * accept_session_reply 408 67d8c22a
1520 * add_node_next 549 e4202993
1521 * add_node_next_reply 550 e89d6eed
1527 * Compares a serialized API message decode table with the current image
1530 * @cliexstart{show api dump file <filename> compare}
1531 * ip_add_del_route definition changed
1532 * ip_table_add_del definition changed
1533 * l2_macs_event only in image
1534 * vnet_ip4_fib_counters only in file
1535 * vnet_ip4_nbr_counters only in file
1540 * Display a serialized API message decode table, compare a saved
1541 * decode table with the current image, to establish API differences.
1545 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1547 .path = "show api dump",
1548 .short_help = "show api dump file <filename> [numeric | compare-current]",
1549 .function = dump_api_table_file_command_fn,
1554 * fd.io coding-style-patch-verification: ON
1557 * eval: (c-set-style "gnu")