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 u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
491 ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
492 if (~0 == msg_index2)
493 vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
495 vec_validate (msgid_vec, msg_index);
496 msgid_vec[msg_index] = msg_index2;
501 for (i = 0; i < first_index; i++)
506 assert_size (file_size_left, sizeof (u32));
507 size = clib_host_to_net_u32 (*(u32 *) msg);
510 assert_size (file_size_left, clib_max (size, sizeof (u16)));
511 msg_id = ntohs (*((u16 *) msg));
512 if (msg_id >= vec_len (msgid_vec) ||
513 msgid_vec[msg_id] >= vec_len (am->api_trace_cfg))
514 vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
521 am->replay_in_progress = 1;
523 for (; i <= last_index; i++)
530 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
532 assert_size (file_size_left, sizeof (u32));
533 size = clib_host_to_net_u32 (*(u32 *) msg);
536 assert_size (file_size_left, clib_max (size, sizeof (u16)));
537 msg_id = ntohs (*((u16 *) msg));
539 if (msg_id >= vec_len (msgid_vec) ||
540 msgid_vec[msg_id] >= vec_len (am->api_trace_cfg))
543 vm, "warning: unknown msg id %d for msg number %d, skipping\n",
549 msg_id = msgid_vec[msg_id];
550 cfgp = am->api_trace_cfg + msg_id;
552 /* Copy the buffer (from the read-only mmap'ed file) */
553 vec_validate (tmpbuf, size - 1 + sizeof (uword));
554 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
555 clib_memset (tmpbuf, 0xf, sizeof (uword));
558 * Endian swap if needed. All msg data is supposed to be in
559 * network byte order.
561 if (((which == DUMP || which == DUMP_JSON) &&
562 clib_arch_is_little_endian))
564 void (*endian_fp) (void *);
565 if (msg_id >= vec_len (am->msg_endian_handlers)
566 || (am->msg_endian_handlers[msg_id] == 0))
568 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
569 munmap (hp, file_size);
571 am->replay_in_progress = 0;
574 endian_fp = am->msg_endian_handlers[msg_id];
575 (*endian_fp) (tmpbuf + sizeof (uword));
578 /* msg_id always in network byte order */
579 if (clib_arch_is_little_endian)
581 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
588 if (msg_id < vec_len (am->msg_print_json_handlers) &&
589 am->msg_print_json_handlers[msg_id])
591 u8 *(*print_fp) (void *, void *);
593 print_fp = (void *) am->msg_print_json_handlers[msg_id];
594 (*print_fp) (tmpbuf + sizeof (uword), vm);
598 vlib_cli_output (vm, "Skipping msg id %d: no JSON print fcn\n",
605 if (msg_id < vec_len (am->msg_print_handlers) &&
606 am->msg_print_handlers[msg_id])
608 u8 *(*print_fp) (void *, void *);
610 print_fp = (void *) am->msg_print_handlers[msg_id];
611 (*print_fp) (tmpbuf + sizeof (uword), vm);
615 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
622 if (msg_id < vec_len (am->msg_print_handlers) &&
623 am->msg_print_handlers[msg_id])
627 u8 *(*print_fp) (void *, void *);
629 print_fp = (void *) am->msg_print_handlers[msg_id];
631 vlib_cli_output (vm, "/*");
633 (*print_fp) (tmpbuf + sizeof (uword), vm);
634 vlib_cli_output (vm, "*/\n");
636 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
637 am->msg_names[msg_id], i,
638 am->api_trace_cfg[msg_id].size);
640 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
643 s = format (s, "\n ");
644 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
646 s = format (s, "\n};\n%c", 0);
647 vlib_cli_output (vm, (char *) s);
653 if (msg_id < vec_len (am->msg_print_handlers) &&
654 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
656 void (*handler) (void *, vlib_main_t *);
658 handler = (void *) am->msg_handlers[msg_id];
660 if (!am->is_mp_safe[msg_id])
661 vl_msg_api_barrier_sync ();
662 (*handler) (tmpbuf + sizeof (uword), vm);
663 if (!am->is_mp_safe[msg_id])
664 vl_msg_api_barrier_release ();
668 if (cfgp->replay_enable)
669 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
676 _vec_len (tmpbuf) = 0;
680 munmap (hp, file_size);
682 vec_free (msgid_vec);
683 am->replay_in_progress = 0;
687 file_exists (u8 *fname)
690 fp = fopen ((char *) fname, "r");
706 vl_msg_print_trace (u8 *msg, void *ctx)
708 vl_msg_print_args *a = ctx;
709 api_main_t *am = vlibapi_get_main ();
710 u16 msg_id = ntohs (*((u16 *) msg));
711 void (*print_fp) (void *, void *);
712 void (**handlers) (void *, void *);
713 u8 is_json = a->is_json;
716 if (clib_arch_is_little_endian)
718 u32 msg_length = vec_len (msg);
719 vec_validate (tmpbuf, msg_length - 1);
720 clib_memcpy_fast (tmpbuf, msg, msg_length);
723 void (*endian_fp) (void *);
724 endian_fp = am->msg_endian_handlers[msg_id];
725 (*endian_fp) (tmpbuf);
729 handlers = am->msg_print_json_handlers;
731 handlers = am->msg_print_handlers;
733 if (msg_id < vec_len (handlers) && handlers[msg_id])
735 print_fp = (void *) handlers[msg_id];
736 (*print_fp) (msg, a->vm);
740 vlib_cli_output (a->vm, "Skipping msg id %d: no print fcn\n", msg_id);
748 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
750 api_main_t *am = vlibapi_get_main ();
755 case VL_API_TRACE_TX:
758 case VL_API_TRACE_RX:
765 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
768 vl_msg_print_args args;
769 clib_memset (&args, 0, sizeof (args));
770 args.is_json = is_json;
772 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
778 vl_msg_read_file (FILE *f)
780 const size_t bufsize = 1024;
781 char *buf[bufsize], *v = 0;
784 while ((n = fread (buf, 1, bufsize, f)))
787 /* most callers expect a NULL-terminated C-string */
795 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
798 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
806 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
810 if (!am->msg_id_by_name)
812 vlib_cli_output (vm, "message id table not yet initialized!\n");
816 p = hash_get_mem (am->msg_id_by_name, name);
824 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
826 api_main_t *am = vlibapi_get_main ();
828 void *(*fromjson) (cJSON *, int *);
829 int len = 0, rv = -1;
833 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
836 vlib_cli_output (vm, "Missing '_msgname' element!\n");
839 char *name = cJSON_GetStringValue (msg_id_obj);
841 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
844 vlib_cli_output (vm, "Missing '_crc' element!\n");
847 char *crc = cJSON_GetStringValue (crc_obj);
850 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
851 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
852 if (msg_id == (u16) ~0)
854 msg_id = vl_msg_find_id_by_name (vm, am, name);
855 if (msg_id == (u16) ~0)
857 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
865 cfgp = am->api_trace_cfg + msg_id;
866 if (!am->api_trace_cfg)
868 vlib_cli_output (vm, "msg id %d no trace config\n", msg_id);
872 if (cfgp->replay_enable)
876 vlib_cli_output (vm, "warning: msg %d has different signature\n");
878 fromjson = am->msg_fromjson_handlers[msg_id];
881 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
886 msg = (u8 *) fromjson (o, &len);
889 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
894 if (clib_arch_is_little_endian)
896 void (*endian_fp) (void *);
897 endian_fp = am->msg_endian_handlers[msg_id];
901 void (*handler) (void *, vlib_main_t *);
902 handler = (void *) am->msg_handlers[msg_id];
905 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
909 if (!am->is_mp_safe[msg_id])
910 vl_msg_api_barrier_sync ();
911 (*handler) (msg, vm);
912 if (!am->is_mp_safe[msg_id])
913 vl_msg_api_barrier_release ();
924 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
926 api_main_t *am = vlibapi_get_main ();
929 FILE *f = fopen ((char *) filename, "r");
933 vlib_cli_output (vm, "failed to open %s!\n", filename);
937 char *buf = vl_msg_read_file (f);
940 o = cJSON_Parse (buf);
944 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
945 cJSON_GetErrorPtr ());
949 if (cJSON_IsArray (o))
951 am->replay_in_progress = 1;
952 size_t size = cJSON_GetArraySize (o);
953 for (int i = 0; i < size; i++)
955 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
958 am->replay_in_progress = 0;
965 rv = vl_msg_exec_json_command (vm, o);
969 vlib_cli_output (vm, "error during replaying API trace");
975 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
977 FILE *f = fopen ((char *) filename, "r");
982 vlib_cli_output (vm, "failed to open %s!\n", filename);
986 buf = vl_msg_read_file (f);
991 vlib_cli_output (vm, "no content in %s!\n", filename);
995 vlib_cli_output (vm, buf);
999 /** api_trace_command_fn - control the binary API trace / replay feature
1001 Note: this command MUST be marked thread-safe. Replay with
1002 multiple worker threads depends in many cases on worker thread
1003 graph replica maintenance. If we (implicitly) assert a worker
1004 thread barrier at the debug CLI level, all graph replica changes
1005 are deferred until the replay operation completes. If an interface
1006 is deleted, the wheels fall off.
1009 static clib_error_t *
1010 api_trace_command_fn (vlib_main_t * vm,
1011 unformat_input_t * input, vlib_cli_command_t * cmd)
1013 unformat_input_t _line_input, *line_input = &_line_input;
1014 u32 nitems = 256 << 10;
1015 api_main_t *am = vlibapi_get_main ();
1016 vl_api_trace_which_t which = VL_API_TRACE_RX;
1018 u8 *chroot_filename = 0;
1020 u32 last = (u32) ~ 0;
1024 /* Get a line of input. */
1025 if (!unformat_user (input, unformat_line_input, line_input))
1028 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1030 if (unformat (line_input, "on") || unformat (line_input, "enable"))
1032 if (unformat (line_input, "nitems %d", &nitems))
1034 vlib_worker_thread_barrier_sync (vm);
1035 vl_msg_api_trace_configure (am, which, nitems);
1036 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1037 vlib_worker_thread_barrier_release (vm);
1039 else if (unformat (line_input, "off"))
1041 vlib_worker_thread_barrier_sync (vm);
1042 vl_msg_api_trace_onoff (am, which, 0);
1043 vlib_worker_thread_barrier_release (vm);
1045 else if (unformat (line_input, "save-json %s", &filename))
1047 if (strstr ((char *) filename, "..") ||
1048 index ((char *) filename, '/'))
1050 vlib_cli_output (vm, "illegal characters in filename '%s'",
1055 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1057 vec_free (filename);
1059 if (file_exists (chroot_filename))
1061 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1065 fp = fopen ((char *) chroot_filename, "w");
1068 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1071 vlib_worker_thread_barrier_sync (vm);
1072 rv = vl_msg_api_trace_save (am, which, fp, 1);
1074 vlib_cli_output (vm, "API Trace data not present\n");
1076 vlib_cli_output (vm, "failed to save api trace\n");
1078 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1079 vlib_worker_thread_barrier_release (vm);
1082 else if (unformat (line_input, "save %s", &filename))
1084 if (strstr ((char *) filename, "..")
1085 || index ((char *) filename, '/'))
1087 vlib_cli_output (vm, "illegal characters in filename '%s'",
1092 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1094 vec_free (filename);
1096 if (file_exists (chroot_filename))
1098 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1102 fp = fopen ((char *) chroot_filename, "w");
1105 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1108 vlib_worker_thread_barrier_sync (vm);
1109 rv = vl_msg_api_trace_save (am, which, fp, 0);
1110 vlib_worker_thread_barrier_release (vm);
1113 vlib_cli_output (vm, "API Trace data not present\n");
1115 vlib_cli_output (vm, "File for writing is closed\n");
1117 vlib_cli_output (vm, "Error while writing header to file\n");
1119 vlib_cli_output (vm, "Error while writing trace to file\n");
1121 vlib_cli_output (vm,
1122 "Error while writing end of buffer trace to file\n");
1124 vlib_cli_output (vm,
1125 "Error while writing start of buffer trace to file\n");
1127 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1129 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1132 else if (unformat (line_input, "tojson %s", &filename))
1134 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1136 else if (unformat (line_input, "dump-file-json %s", &filename))
1138 vl_msg_dump_file_json (vm, filename);
1140 else if (unformat (line_input, "dump-file %s", &filename))
1142 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1144 else if (unformat (line_input, "dump-json"))
1146 vl_msg_api_dump_trace (vm, which, 1);
1148 else if (unformat (line_input, "dump"))
1150 vl_msg_api_dump_trace (vm, which, 0);
1152 else if (unformat (line_input, "replay-json %s", &filename))
1154 vl_msg_replay_json (vm, filename);
1156 else if (unformat (line_input, "replay %s", &filename))
1158 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1160 else if (unformat (line_input, "initializers %s", &filename))
1162 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1164 else if (unformat (line_input, "tx"))
1166 which = VL_API_TRACE_TX;
1168 else if (unformat (line_input, "first %d", &first))
1172 else if (unformat (line_input, "last %d", &last))
1176 else if (unformat (line_input, "status"))
1178 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1181 else if (unformat (line_input, "free"))
1183 vlib_worker_thread_barrier_sync (vm);
1184 vl_msg_api_trace_onoff (am, which, 0);
1185 vl_msg_api_trace_free (am, which);
1186 vlib_worker_thread_barrier_release (vm);
1188 else if (unformat (line_input, "post-mortem-on"))
1189 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1190 else if (unformat (line_input, "post-mortem-off"))
1191 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1193 return clib_error_return (0, "unknown input `%U'",
1194 format_unformat_error, input);
1197 vec_free (filename);
1198 vec_free (chroot_filename);
1199 unformat_free (line_input);
1204 * Display, replay, or save a binary API trace
1208 VLIB_CLI_COMMAND (api_trace_command, static) = {
1209 .path = "api trace",
1210 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1211 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1212 "json|replay <file>|replay-json <file>][nitems <n>]"
1213 "[initializers <file>]",
1214 .function = api_trace_command_fn,
1219 static clib_error_t *
1220 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1222 u32 nitems = 256 << 10;
1223 vl_api_trace_which_t which = VL_API_TRACE_RX;
1224 api_main_t *am = vlibapi_get_main ();
1226 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1228 if (unformat (input, "on") || unformat (input, "enable"))
1230 if (unformat (input, "nitems %d", &nitems))
1232 vl_msg_api_trace_configure (am, which, nitems);
1233 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1234 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1236 else if (unformat (input, "save-api-table %s",
1237 &am->save_msg_table_filename))
1240 return clib_error_return (0, "unknown input `%U'",
1241 format_unformat_error, input);
1247 * This module has three configuration parameters:
1248 * "on" or "enable" - enables binary api tracing
1249 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1250 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1252 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1254 static clib_error_t *
1255 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1257 api_main_t *am = vlibapi_get_main ();
1260 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1262 if (unformat (input, "length %d", &nitems) ||
1263 (unformat (input, "len %d", &nitems)))
1266 am->vlib_input_queue_length = nitems;
1268 clib_warning ("vlib input queue length %d too small, ignored",
1272 return clib_error_return (0, "unknown input `%U'",
1273 format_unformat_error, input);
1278 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1281 extract_name (u8 * s)
1287 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1290 rv[vec_len (rv)] = 0;
1296 extract_crc (u8 * s)
1303 for (i = vec_len (rv) - 1; i >= 0; i--)
1307 vec_delete (rv, i + 1, 0);
1321 } msg_table_unserialize_t;
1324 table_id_cmp (void *a1, void *a2)
1326 msg_table_unserialize_t *n1 = a1;
1327 msg_table_unserialize_t *n2 = a2;
1329 return (n1->msg_index - n2->msg_index);
1333 table_name_and_crc_cmp (void *a1, void *a2)
1335 msg_table_unserialize_t *n1 = a1;
1336 msg_table_unserialize_t *n2 = a2;
1338 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1341 static clib_error_t *
1342 dump_api_table_file_command_fn (vlib_main_t * vm,
1343 unformat_input_t * input,
1344 vlib_cli_command_t * cmd)
1347 api_main_t *am = vlibapi_get_main ();
1348 serialize_main_t _sm, *sm = &_sm;
1349 clib_error_t *error;
1353 int compare_current = 0;
1354 int numeric_sort = 0;
1355 msg_table_unserialize_t *table = 0, *item;
1357 u32 ndifferences = 0;
1359 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1361 if (unformat (input, "file %s", &filename))
1363 else if (unformat (input, "compare-current")
1364 || unformat (input, "compare"))
1365 compare_current = 1;
1366 else if (unformat (input, "numeric"))
1369 return clib_error_return (0, "unknown input `%U'",
1370 format_unformat_error, input);
1373 if (numeric_sort && compare_current)
1374 return clib_error_return
1375 (0, "Comparison and numeric sorting are incompatible");
1378 return clib_error_return (0, "File not specified");
1380 /* Load the serialized message table from the table dump */
1382 error = unserialize_open_clib_file (sm, (char *) filename);
1387 unserialize_integer (sm, &nmsgs, sizeof (u32));
1389 for (i = 0; i < nmsgs; i++)
1391 msg_index = unserialize_likely_small_unsigned_integer (sm);
1392 unserialize_cstring (sm, (char **) &name_and_crc);
1393 vec_add2 (table, item, 1);
1394 item->msg_index = msg_index;
1395 item->name_and_crc = name_and_crc;
1396 item->name = extract_name (name_and_crc);
1397 item->crc = extract_crc (name_and_crc);
1398 item->which = 0; /* file */
1400 unserialize_close (sm);
1402 /* Compare with the current image? */
1403 if (compare_current)
1405 /* Append the current message table */
1406 u8 *tblv = vl_api_serialize_message_table (am, 0);
1408 serialize_open_vector (sm, tblv);
1409 unserialize_integer (sm, &nmsgs, sizeof (u32));
1411 for (i = 0; i < nmsgs; i++)
1413 msg_index = unserialize_likely_small_unsigned_integer (sm);
1414 unserialize_cstring (sm, (char **) &name_and_crc);
1416 vec_add2 (table, item, 1);
1417 item->msg_index = msg_index;
1418 item->name_and_crc = name_and_crc;
1419 item->name = extract_name (name_and_crc);
1420 item->crc = extract_crc (name_and_crc);
1421 item->which = 1; /* current_image */
1426 /* Sort the table. */
1428 vec_sort_with_function (table, table_id_cmp);
1430 vec_sort_with_function (table, table_name_and_crc_cmp);
1432 if (compare_current)
1438 * In this case, the recovered table will have two entries per
1439 * API message. So, if entries i and i+1 match, the message definitions
1440 * are identical. Otherwise, the crc is different, or a message is
1441 * present in only one of the tables.
1443 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1444 vec_validate_init_empty (dashes, 60, '-');
1445 vec_terminate_c_string (dashes);
1446 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1448 for (i = 0; i < vec_len (table);)
1450 /* Last message lonely? */
1451 if (i == vec_len (table) - 1)
1457 /* Identical pair? */
1459 ((char *) table[i].name_and_crc,
1460 (char *) table[i + 1].name_and_crc,
1461 vec_len (table[i].name_and_crc)))
1469 /* Only in one of two tables? */
1470 if (i + 1 == vec_len (table)
1471 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1474 vlib_cli_output (vm, "%-60s | only in %s",
1475 table[i].name, table[i].which ?
1480 /* In both tables, but with different signatures */
1481 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1484 if (ndifferences == 0)
1485 vlib_cli_output (vm, "No api message signature differences found.");
1487 vlib_cli_output (vm, "\nFound %u api message signature differences",
1492 /* Dump the table, sorted as shown above */
1493 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1495 for (i = 0; i < vec_len (table); i++)
1498 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1499 item->msg_index, item->crc);
1503 for (i = 0; i < vec_len (table); i++)
1505 vec_free (table[i].name_and_crc);
1506 vec_free (table[i].name);
1507 vec_free (table[i].crc);
1516 * Displays a serialized API message decode table, sorted by message name
1519 * @cliexstart{show api dump file <filename>}
1520 * Message name MsgID CRC
1521 * accept_session 407 8e2a127e
1522 * accept_session_reply 408 67d8c22a
1523 * add_node_next 549 e4202993
1524 * add_node_next_reply 550 e89d6eed
1530 * Compares a serialized API message decode table with the current image
1533 * @cliexstart{show api dump file <filename> compare}
1534 * ip_add_del_route definition changed
1535 * ip_table_add_del definition changed
1536 * l2_macs_event only in image
1537 * vnet_ip4_fib_counters only in file
1538 * vnet_ip4_nbr_counters only in file
1543 * Display a serialized API message decode table, compare a saved
1544 * decode table with the current image, to establish API differences.
1548 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1550 .path = "show api dump",
1551 .short_help = "show api dump file <filename> [numeric | compare-current]",
1552 .function = dump_api_table_file_command_fn,
1557 * fd.io coding-style-patch-verification: ON
1560 * eval: (c-set-style "gnu")