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)))
788 /* most callers expect a NULL-terminated C-string */
796 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
799 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
807 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
811 if (!am->msg_id_by_name)
813 vlib_cli_output (vm, "message id table not yet initialized!\n");
817 p = hash_get_mem (am->msg_id_by_name, name);
825 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
827 api_main_t *am = vlibapi_get_main ();
829 void *(*fromjson) (cJSON *, int *);
830 int len = 0, rv = -1;
834 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
837 vlib_cli_output (vm, "Missing '_msgname' element!\n");
840 char *name = cJSON_GetStringValue (msg_id_obj);
842 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
845 vlib_cli_output (vm, "Missing '_crc' element!\n");
848 char *crc = cJSON_GetStringValue (crc_obj);
851 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
852 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
853 if (msg_id == (u16) ~0)
855 msg_id = vl_msg_find_id_by_name (vm, am, name);
856 if (msg_id == (u16) ~0)
858 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
866 cfgp = am->api_trace_cfg + msg_id;
867 if (!am->api_trace_cfg)
869 vlib_cli_output (vm, "msg id %d no trace config\n", msg_id);
873 if (cfgp->replay_enable)
877 vlib_cli_output (vm, "warning: msg %d has different signature\n");
879 fromjson = am->msg_fromjson_handlers[msg_id];
882 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
887 msg = (u8 *) fromjson (o, &len);
890 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
895 if (clib_arch_is_little_endian)
897 void (*endian_fp) (void *);
898 endian_fp = am->msg_endian_handlers[msg_id];
902 void (*handler) (void *, vlib_main_t *);
903 handler = (void *) am->msg_handlers[msg_id];
906 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
910 if (!am->is_mp_safe[msg_id])
911 vl_msg_api_barrier_sync ();
912 (*handler) (msg, vm);
913 if (!am->is_mp_safe[msg_id])
914 vl_msg_api_barrier_release ();
925 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
927 api_main_t *am = vlibapi_get_main ();
930 FILE *f = fopen ((char *) filename, "r");
934 vlib_cli_output (vm, "failed to open %s!\n", filename);
938 char *buf = vl_msg_read_file (f);
941 o = cJSON_Parse (buf);
945 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
946 cJSON_GetErrorPtr ());
950 if (cJSON_IsArray (o))
952 am->replay_in_progress = 1;
953 size_t size = cJSON_GetArraySize (o);
954 for (int i = 0; i < size; i++)
956 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
959 am->replay_in_progress = 0;
966 rv = vl_msg_exec_json_command (vm, o);
970 vlib_cli_output (vm, "error during replaying API trace");
976 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
978 FILE *f = fopen ((char *) filename, "r");
983 vlib_cli_output (vm, "failed to open %s!\n", filename);
987 buf = vl_msg_read_file (f);
992 vlib_cli_output (vm, "no content in %s!\n", filename);
996 vlib_cli_output (vm, buf);
1000 /** api_trace_command_fn - control the binary API trace / replay feature
1002 Note: this command MUST be marked thread-safe. Replay with
1003 multiple worker threads depends in many cases on worker thread
1004 graph replica maintenance. If we (implicitly) assert a worker
1005 thread barrier at the debug CLI level, all graph replica changes
1006 are deferred until the replay operation completes. If an interface
1007 is deleted, the wheels fall off.
1010 static clib_error_t *
1011 api_trace_command_fn (vlib_main_t * vm,
1012 unformat_input_t * input, vlib_cli_command_t * cmd)
1014 unformat_input_t _line_input, *line_input = &_line_input;
1015 u32 nitems = 256 << 10;
1016 api_main_t *am = vlibapi_get_main ();
1017 vl_api_trace_which_t which = VL_API_TRACE_RX;
1019 u8 *chroot_filename = 0;
1021 u32 last = (u32) ~ 0;
1025 /* Get a line of input. */
1026 if (!unformat_user (input, unformat_line_input, line_input))
1029 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1031 if (unformat (line_input, "on") || unformat (line_input, "enable"))
1033 if (unformat (line_input, "nitems %d", &nitems))
1035 vlib_worker_thread_barrier_sync (vm);
1036 vl_msg_api_trace_configure (am, which, nitems);
1037 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1038 vlib_worker_thread_barrier_release (vm);
1040 else if (unformat (line_input, "off"))
1042 vlib_worker_thread_barrier_sync (vm);
1043 vl_msg_api_trace_onoff (am, which, 0);
1044 vlib_worker_thread_barrier_release (vm);
1046 else if (unformat (line_input, "save-json %s", &filename))
1048 if (strstr ((char *) filename, "..") ||
1049 index ((char *) filename, '/'))
1051 vlib_cli_output (vm, "illegal characters in filename '%s'",
1056 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1058 vec_free (filename);
1060 if (file_exists (chroot_filename))
1062 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1066 fp = fopen ((char *) chroot_filename, "w");
1069 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1072 vlib_worker_thread_barrier_sync (vm);
1073 rv = vl_msg_api_trace_save (am, which, fp, 1);
1075 vlib_cli_output (vm, "API Trace data not present\n");
1077 vlib_cli_output (vm, "failed to save api trace\n");
1079 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1080 vlib_worker_thread_barrier_release (vm);
1083 else if (unformat (line_input, "save %s", &filename))
1085 if (strstr ((char *) filename, "..")
1086 || index ((char *) filename, '/'))
1088 vlib_cli_output (vm, "illegal characters in filename '%s'",
1093 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1095 vec_free (filename);
1097 if (file_exists (chroot_filename))
1099 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1103 fp = fopen ((char *) chroot_filename, "w");
1106 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1109 vlib_worker_thread_barrier_sync (vm);
1110 rv = vl_msg_api_trace_save (am, which, fp, 0);
1111 vlib_worker_thread_barrier_release (vm);
1114 vlib_cli_output (vm, "API Trace data not present\n");
1116 vlib_cli_output (vm, "File for writing is closed\n");
1118 vlib_cli_output (vm, "Error while writing header to file\n");
1120 vlib_cli_output (vm, "Error while writing trace to file\n");
1122 vlib_cli_output (vm,
1123 "Error while writing end of buffer trace to file\n");
1125 vlib_cli_output (vm,
1126 "Error while writing start of buffer trace to file\n");
1128 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1130 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1133 else if (unformat (line_input, "tojson %s", &filename))
1135 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1137 else if (unformat (line_input, "dump-file-json %s", &filename))
1139 vl_msg_dump_file_json (vm, filename);
1141 else if (unformat (line_input, "dump-file %s", &filename))
1143 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1145 else if (unformat (line_input, "dump-json"))
1147 vl_msg_api_dump_trace (vm, which, 1);
1149 else if (unformat (line_input, "dump"))
1151 vl_msg_api_dump_trace (vm, which, 0);
1153 else if (unformat (line_input, "replay-json %s", &filename))
1155 vl_msg_replay_json (vm, filename);
1157 else if (unformat (line_input, "replay %s", &filename))
1159 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1161 else if (unformat (line_input, "initializers %s", &filename))
1163 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1165 else if (unformat (line_input, "tx"))
1167 which = VL_API_TRACE_TX;
1169 else if (unformat (line_input, "first %d", &first))
1173 else if (unformat (line_input, "last %d", &last))
1177 else if (unformat (line_input, "status"))
1179 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1182 else if (unformat (line_input, "free"))
1184 vlib_worker_thread_barrier_sync (vm);
1185 vl_msg_api_trace_onoff (am, which, 0);
1186 vl_msg_api_trace_free (am, which);
1187 vlib_worker_thread_barrier_release (vm);
1189 else if (unformat (line_input, "post-mortem-on"))
1190 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1191 else if (unformat (line_input, "post-mortem-off"))
1192 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1194 return clib_error_return (0, "unknown input `%U'",
1195 format_unformat_error, input);
1198 vec_free (filename);
1199 vec_free (chroot_filename);
1200 unformat_free (line_input);
1205 * Display, replay, or save a binary API trace
1209 VLIB_CLI_COMMAND (api_trace_command, static) = {
1210 .path = "api trace",
1211 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1212 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1213 "json|replay <file>|replay-json <file>][nitems <n>]"
1214 "[initializers <file>]",
1215 .function = api_trace_command_fn,
1220 static clib_error_t *
1221 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1223 u32 nitems = 256 << 10;
1224 vl_api_trace_which_t which = VL_API_TRACE_RX;
1225 api_main_t *am = vlibapi_get_main ();
1227 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1229 if (unformat (input, "on") || unformat (input, "enable"))
1231 if (unformat (input, "nitems %d", &nitems))
1233 vl_msg_api_trace_configure (am, which, nitems);
1234 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1235 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1237 else if (unformat (input, "save-api-table %s",
1238 &am->save_msg_table_filename))
1241 return clib_error_return (0, "unknown input `%U'",
1242 format_unformat_error, input);
1248 * This module has three configuration parameters:
1249 * "on" or "enable" - enables binary api tracing
1250 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1251 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1253 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1255 static clib_error_t *
1256 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1258 api_main_t *am = vlibapi_get_main ();
1261 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1263 if (unformat (input, "length %d", &nitems) ||
1264 (unformat (input, "len %d", &nitems)))
1267 am->vlib_input_queue_length = nitems;
1269 clib_warning ("vlib input queue length %d too small, ignored",
1273 return clib_error_return (0, "unknown input `%U'",
1274 format_unformat_error, input);
1279 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1282 extract_name (u8 * s)
1288 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1291 rv[vec_len (rv)] = 0;
1297 extract_crc (u8 * s)
1304 for (i = vec_len (rv) - 1; i >= 0; i--)
1308 vec_delete (rv, i + 1, 0);
1322 } msg_table_unserialize_t;
1325 table_id_cmp (void *a1, void *a2)
1327 msg_table_unserialize_t *n1 = a1;
1328 msg_table_unserialize_t *n2 = a2;
1330 return (n1->msg_index - n2->msg_index);
1334 table_name_and_crc_cmp (void *a1, void *a2)
1336 msg_table_unserialize_t *n1 = a1;
1337 msg_table_unserialize_t *n2 = a2;
1339 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1342 static clib_error_t *
1343 dump_api_table_file_command_fn (vlib_main_t * vm,
1344 unformat_input_t * input,
1345 vlib_cli_command_t * cmd)
1348 api_main_t *am = vlibapi_get_main ();
1349 serialize_main_t _sm, *sm = &_sm;
1350 clib_error_t *error;
1354 int compare_current = 0;
1355 int numeric_sort = 0;
1356 msg_table_unserialize_t *table = 0, *item;
1358 u32 ndifferences = 0;
1360 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1362 if (unformat (input, "file %s", &filename))
1364 else if (unformat (input, "compare-current")
1365 || unformat (input, "compare"))
1366 compare_current = 1;
1367 else if (unformat (input, "numeric"))
1370 return clib_error_return (0, "unknown input `%U'",
1371 format_unformat_error, input);
1374 if (numeric_sort && compare_current)
1375 return clib_error_return
1376 (0, "Comparison and numeric sorting are incompatible");
1379 return clib_error_return (0, "File not specified");
1381 /* Load the serialized message table from the table dump */
1383 error = unserialize_open_clib_file (sm, (char *) filename);
1388 unserialize_integer (sm, &nmsgs, sizeof (u32));
1390 for (i = 0; i < nmsgs; i++)
1392 msg_index = unserialize_likely_small_unsigned_integer (sm);
1393 unserialize_cstring (sm, (char **) &name_and_crc);
1394 vec_add2 (table, item, 1);
1395 item->msg_index = msg_index;
1396 item->name_and_crc = name_and_crc;
1397 item->name = extract_name (name_and_crc);
1398 item->crc = extract_crc (name_and_crc);
1399 item->which = 0; /* file */
1401 unserialize_close (sm);
1403 /* Compare with the current image? */
1404 if (compare_current)
1406 /* Append the current message table */
1407 u8 *tblv = vl_api_serialize_message_table (am, 0);
1409 serialize_open_vector (sm, tblv);
1410 unserialize_integer (sm, &nmsgs, sizeof (u32));
1412 for (i = 0; i < nmsgs; i++)
1414 msg_index = unserialize_likely_small_unsigned_integer (sm);
1415 unserialize_cstring (sm, (char **) &name_and_crc);
1417 vec_add2 (table, item, 1);
1418 item->msg_index = msg_index;
1419 item->name_and_crc = name_and_crc;
1420 item->name = extract_name (name_and_crc);
1421 item->crc = extract_crc (name_and_crc);
1422 item->which = 1; /* current_image */
1427 /* Sort the table. */
1429 vec_sort_with_function (table, table_id_cmp);
1431 vec_sort_with_function (table, table_name_and_crc_cmp);
1433 if (compare_current)
1439 * In this case, the recovered table will have two entries per
1440 * API message. So, if entries i and i+1 match, the message definitions
1441 * are identical. Otherwise, the crc is different, or a message is
1442 * present in only one of the tables.
1444 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1445 vec_validate_init_empty (dashes, 60, '-');
1446 vec_terminate_c_string (dashes);
1447 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1449 for (i = 0; i < vec_len (table);)
1451 /* Last message lonely? */
1452 if (i == vec_len (table) - 1)
1458 /* Identical pair? */
1460 ((char *) table[i].name_and_crc,
1461 (char *) table[i + 1].name_and_crc,
1462 vec_len (table[i].name_and_crc)))
1470 /* Only in one of two tables? */
1471 if (i + 1 == vec_len (table)
1472 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1475 vlib_cli_output (vm, "%-60s | only in %s",
1476 table[i].name, table[i].which ?
1481 /* In both tables, but with different signatures */
1482 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1485 if (ndifferences == 0)
1486 vlib_cli_output (vm, "No api message signature differences found.");
1488 vlib_cli_output (vm, "\nFound %u api message signature differences",
1493 /* Dump the table, sorted as shown above */
1494 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1496 for (i = 0; i < vec_len (table); i++)
1499 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1500 item->msg_index, item->crc);
1504 for (i = 0; i < vec_len (table); i++)
1506 vec_free (table[i].name_and_crc);
1507 vec_free (table[i].name);
1508 vec_free (table[i].crc);
1517 * Displays a serialized API message decode table, sorted by message name
1520 * @cliexstart{show api dump file <filename>}
1521 * Message name MsgID CRC
1522 * accept_session 407 8e2a127e
1523 * accept_session_reply 408 67d8c22a
1524 * add_node_next 549 e4202993
1525 * add_node_next_reply 550 e89d6eed
1531 * Compares a serialized API message decode table with the current image
1534 * @cliexstart{show api dump file <filename> compare}
1535 * ip_add_del_route definition changed
1536 * ip_table_add_del definition changed
1537 * l2_macs_event only in image
1538 * vnet_ip4_fib_counters only in file
1539 * vnet_ip4_nbr_counters only in file
1544 * Display a serialized API message decode table, compare a saved
1545 * decode table with the current image, to establish API differences.
1549 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1551 .path = "show api dump",
1552 .short_help = "show api dump file <filename> [numeric | compare-current]",
1553 .function = dump_api_table_file_command_fn,
1558 * fd.io coding-style-patch-verification: ON
1561 * eval: (c-set-style "gnu")