2 *------------------------------------------------------------------
3 * Copyright (c) 2018 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
20 #include <sys/types.h>
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
27 vl_api_show_histogram_command (vlib_main_t * vm,
28 unformat_input_t * input,
29 vlib_cli_command_t * cli_cmd)
34 for (i = 0; i < SLEEP_N_BUCKETS; i++)
36 total_counts += vector_rate_histogram[i];
39 if (total_counts == 0)
41 vlib_cli_output (vm, "No control-plane activity.");
48 percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
49 / (f64) total_counts; \
51 vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
52 vector_rate_histogram[SLEEP_##n##_US], \
55 foreach_histogram_bucket;
62 * Display the binary api sleep-time histogram
65 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
67 .path = "show api histogram",
68 .short_help = "show api histogram",
69 .function = vl_api_show_histogram_command,
74 vl_api_clear_histogram_command (vlib_main_t * vm,
75 unformat_input_t * input,
76 vlib_cli_command_t * cli_cmd)
80 for (i = 0; i < SLEEP_N_BUCKETS; i++)
81 vector_rate_histogram[i] = 0;
86 * Clear the binary api sleep-time histogram
89 VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
91 .path = "clear api histogram",
92 .short_help = "clear api histogram",
93 .function = vl_api_clear_histogram_command,
98 vl_api_client_command (vlib_main_t * vm,
99 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
101 vl_api_registration_t **regpp, *regp;
104 api_main_t *am = vlibapi_get_main ();
105 u32 *confused_indices = 0;
107 if (!pool_elts (am->vl_clients))
109 vlib_cli_output (vm, "Shared memory clients");
110 vlib_cli_output (vm, "%20s %8s %14s %18s %s",
111 "Name", "PID", "Queue Length", "Queue VA", "Health");
114 pool_foreach (regpp, am->vl_clients)
120 if (regp->unanswered_pings > 0)
121 health = "questionable";
125 q = regp->vl_input_queue;
127 vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
128 regp->name, q->consumer_pid, q->cursize,
133 clib_warning ("NULL client registration index %d",
134 regpp - am->vl_clients);
135 vec_add1 (confused_indices, regpp - am->vl_clients);
140 /* This should "never happen," but if it does, fix it... */
141 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
144 for (i = 0; i < vec_len (confused_indices); i++)
146 pool_put_index (am->vl_clients, confused_indices[i]);
149 vec_free (confused_indices);
151 if (am->missing_clients)
152 vlib_cli_output (vm, "%u messages with missing clients",
153 am->missing_clients);
155 vl_sock_api_dump_clients (vm, am);
160 static clib_error_t *
161 vl_api_status_command (vlib_main_t * vm,
162 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
164 api_main_t *am = vlibapi_get_main ();
166 /* check if rx_trace and tx_trace are not null pointers */
167 if (am->rx_trace == 0)
169 vlib_cli_output (vm, "RX Trace disabled\n");
173 if (am->rx_trace->enabled == 0)
174 vlib_cli_output (vm, "RX Trace disabled\n");
176 vlib_cli_output (vm, "RX Trace enabled\n");
179 if (am->tx_trace == 0)
181 vlib_cli_output (vm, "TX Trace disabled\n");
185 if (am->tx_trace->enabled == 0)
186 vlib_cli_output (vm, "TX Trace disabled\n");
188 vlib_cli_output (vm, "TX Trace enabled\n");
195 VLIB_CLI_COMMAND (cli_show_api_command, static) =
198 .short_help = "Show API information",
203 * Display current api client connections
206 VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
208 .path = "show api clients",
209 .short_help = "Client information",
210 .function = vl_api_client_command,
215 * Display the current api message tracing status
218 VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
220 .path = "show api trace-status",
221 .short_help = "Display API trace status",
222 .function = vl_api_status_command,
226 static clib_error_t *
227 vl_api_message_table_command (vlib_main_t * vm,
228 unformat_input_t * input,
229 vlib_cli_command_t * cli_cmd)
231 api_main_t *am = vlibapi_get_main ();
235 if (unformat (input, "verbose"))
240 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
242 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
245 for (i = 1; i < vec_len (am->msg_data); i++)
247 vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
250 vlib_cli_output (vm, "%-4d %s", i,
251 m->name ? m->name : " [no handler]");
255 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
256 m->name ? m->name : " [no handler]", m->bounce,
265 * Display the current api message decode tables
268 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
270 .path = "show api message-table",
271 .short_help = "Message Table",
272 .function = vl_api_message_table_command,
277 range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
279 int len0, len1, clen;
281 len0 = vec_len (a0->name);
282 len1 = vec_len (a1->name);
283 clen = len0 < len1 ? len0 : len1;
284 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
288 format_api_msg_range (u8 * s, va_list * args)
290 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
293 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
295 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
301 static clib_error_t *
302 vl_api_show_plugin_command (vlib_main_t * vm,
303 unformat_input_t * input,
304 vlib_cli_command_t * cli_cmd)
306 api_main_t *am = vlibapi_get_main ();
307 vl_api_msg_range_t *rp = 0;
310 if (vec_len (am->msg_ranges) == 0)
312 vlib_cli_output (vm, "No plugin API message ranges configured...");
316 rp = vec_dup (am->msg_ranges);
318 vec_sort_with_function (rp, range_compare);
320 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
321 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
323 for (i = 0; i < vec_len (rp); i++)
324 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
332 * Display the plugin binary API message range table
335 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
337 .path = "show api plugin",
338 .short_help = "show api plugin",
339 .function = vl_api_show_plugin_command,
352 format_vl_msg_api_trace_status (u8 * s, va_list * args)
354 api_main_t *am = va_arg (*args, api_main_t *);
355 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
361 case VL_API_TRACE_TX:
363 trace_name = "TX trace";
366 case VL_API_TRACE_RX:
368 trace_name = "RX trace";
377 s = format (s, "%s: not yet configured.\n", trace_name);
381 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
382 trace_name, vec_len (tp->traces), tp->nitems,
383 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
388 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
389 u32 first_index, u32 last_index,
390 vl_api_replay_t which)
392 vl_api_trace_file_header_t *hp;
398 api_main_t *am = vlibapi_get_main ();
400 u32 nitems, nitems_msgtbl;
402 fd = open ((char *) filename, O_RDONLY);
406 vlib_cli_output (vm, "Couldn't open %s\n", filename);
410 if (fstat (fd, &statb) < 0)
412 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
417 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
419 vlib_cli_output (vm, "File not plausible: %s\n", filename);
424 file_size = statb.st_size;
425 file_size = (file_size + 4095) & ~(4095);
427 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
429 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
431 vlib_cli_output (vm, "mmap failed: %s\n", filename);
437 clib_mem_unpoison (hp, file_size);
439 nitems = ntohl (hp->nitems);
441 if (last_index == (u32) ~ 0)
443 last_index = nitems - 1;
446 if (first_index >= nitems || last_index >= nitems)
448 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
449 first_index, last_index, nitems - 1);
450 munmap (hp, file_size);
455 "Note: wrapped/incomplete trace, results may vary\n");
457 size_t file_size_left = file_size;
459 #define assert_size(size_left, s) \
462 if ((s) >= size_left) \
464 vlib_cli_output (vm, "corrupted file"); \
465 munmap (hp, file_size); \
466 vec_free (msgid_vec); \
473 assert_size (file_size_left, sizeof (hp[0]));
474 msg = (u8 *) (hp + 1);
476 serialize_main_t _sm, *sm = &_sm;
477 u32 msgtbl_size = ntohl (hp->msgtbl_size);
480 assert_size (file_size_left, msgtbl_size);
482 unserialize_open_data (sm, msg, msgtbl_size);
483 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
485 for (i = 0; i < nitems_msgtbl; i++)
487 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
488 unserialize_cstring (sm, (char **) &name_and_crc);
489 u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
490 ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
491 if (~0 == msg_index2)
492 vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
494 vec_validate (msgid_vec, msg_index);
495 msgid_vec[msg_index] = msg_index2;
500 for (i = 0; i < first_index; i++)
505 assert_size (file_size_left, sizeof (u32));
506 size = clib_host_to_net_u32 (*(u32 *) msg);
509 assert_size (file_size_left, clib_max (size, sizeof (u16)));
510 msg_id = ntohs (*((u16 *) msg));
511 if (msg_id >= vec_len (msgid_vec) ||
512 msgid_vec[msg_id] >= vec_len (am->msg_data))
513 vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
520 am->replay_in_progress = 1;
522 for (; i <= last_index; i++)
524 vl_api_msg_data_t *m;
529 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
531 assert_size (file_size_left, sizeof (u32));
532 size = clib_host_to_net_u32 (*(u32 *) msg);
535 assert_size (file_size_left, clib_max (size, sizeof (u16)));
536 msg_id = ntohs (*((u16 *) msg));
538 if (msg_id >= vec_len (msgid_vec) ||
539 msgid_vec[msg_id] >= vec_len (am->msg_data))
542 vm, "warning: unknown msg id %d for msg number %d, skipping\n",
548 msg_id = msgid_vec[msg_id];
549 m = vl_api_get_msg_data (am, msg_id);
551 /* Copy the buffer (from the read-only mmap'ed file) */
552 vec_validate (tmpbuf, size - 1 + sizeof (uword));
553 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
554 clib_memset (tmpbuf, 0xf, sizeof (uword));
557 * Endian swap if needed. All msg data is supposed to be in
558 * network byte order.
560 if (((which == DUMP || which == DUMP_JSON) &&
561 clib_arch_is_little_endian))
563 if (m && m->endian_handler == 0)
565 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
566 munmap (hp, file_size);
568 am->replay_in_progress = 0;
573 m->endian_handler (tmpbuf + sizeof (uword));
577 /* msg_id always in network byte order */
578 if (clib_arch_is_little_endian)
580 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
587 if (m && m->print_json_handler)
589 m->print_json_handler (tmpbuf + sizeof (uword), vm);
593 vlib_cli_output (vm, "Skipping msg id %d: no JSON print fcn\n",
600 if (m && m->print_handler)
602 m->print_handler (tmpbuf + sizeof (uword), vm);
606 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
613 if (m && m->print_handler)
618 vlib_cli_output (vm, "/*");
620 m->print_handler (tmpbuf + sizeof (uword), vm);
621 vlib_cli_output (vm, "*/\n");
623 s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
626 for (j = 0; j < m->trace_size; j++)
629 s = format (s, "\n ");
630 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
632 s = format (s, "\n};\n%c", 0);
633 vlib_cli_output (vm, (char *) s);
639 if (m && m->print_handler && m->replay_allowed)
642 vl_msg_api_barrier_sync ();
643 m->handler (tmpbuf + sizeof (uword));
645 vl_msg_api_barrier_release ();
649 if (m->replay_allowed)
650 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
657 vec_set_len (tmpbuf, 0);
661 munmap (hp, file_size);
663 vec_free (msgid_vec);
664 am->replay_in_progress = 0;
668 file_exists (u8 *fname)
671 fp = fopen ((char *) fname, "r");
687 vl_msg_print_trace (u8 *msg, void *ctx)
689 vl_msg_print_args *a = ctx;
690 api_main_t *am = vlibapi_get_main ();
691 u16 msg_id = ntohs (*((u16 *) msg));
692 vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
693 void (*handler) (void *, void *) = 0;
694 u8 is_json = a->is_json;
699 vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
703 if (clib_arch_is_little_endian)
705 u32 msg_length = vec_len (msg);
706 vec_validate (tmpbuf, msg_length - 1);
707 clib_memcpy_fast (tmpbuf, msg, msg_length);
710 m->endian_handler (tmpbuf);
713 handler = is_json ? m->print_json_handler : m->print_handler;
716 handler (msg, a->vm);
718 vlib_cli_output (a->vm, "Skipping msg id %d: no print fcn\n", msg_id);
725 vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
727 api_main_t *am = vlibapi_get_main ();
732 case VL_API_TRACE_TX:
735 case VL_API_TRACE_RX:
742 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
745 vl_msg_print_args args;
746 clib_memset (&args, 0, sizeof (args));
747 args.is_json = is_json;
749 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
755 vl_msg_read_file (FILE *f)
757 const size_t bufsize = 1024;
758 char *buf[bufsize], *v = 0;
761 while ((n = fread (buf, 1, bufsize, f)))
764 /* most callers expect a NULL-terminated C-string */
772 vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
775 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
783 vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
787 if (!am->msg_id_by_name)
789 vlib_cli_output (vm, "message id table not yet initialized!\n");
793 p = hash_get_mem (am->msg_id_by_name, name);
801 vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
803 api_main_t *am = vlibapi_get_main ();
805 int len = 0, rv = -1;
806 vl_api_msg_data_t *m;
809 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
812 vlib_cli_output (vm, "Missing '_msgname' element!\n");
815 char *name = cJSON_GetStringValue (msg_id_obj);
817 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
820 vlib_cli_output (vm, "Missing '_crc' element!\n");
823 char *crc = cJSON_GetStringValue (crc_obj);
826 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
827 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
828 m = vl_api_get_msg_data (am, msg_id);
829 if (msg_id == (u16) ~0)
831 msg_id = vl_msg_find_id_by_name (vm, am, name);
832 if (msg_id == (u16) ~0)
834 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
842 if (m->replay_allowed)
845 vlib_cli_output (vm, "warning: msg %d has different signature\n");
847 if (!m->fromjson_handler)
849 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
854 msg = (u8 *) m->fromjson_handler (o, &len);
857 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
862 if (clib_arch_is_little_endian)
863 m->endian_handler (msg);
867 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
872 vl_msg_api_barrier_sync ();
875 vl_msg_api_barrier_release ();
886 vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
888 api_main_t *am = vlibapi_get_main ();
891 FILE *f = fopen ((char *) filename, "r");
895 vlib_cli_output (vm, "failed to open %s!\n", filename);
899 char *buf = vl_msg_read_file (f);
902 o = cJSON_Parse (buf);
906 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
907 cJSON_GetErrorPtr ());
911 if (cJSON_IsArray (o))
913 am->replay_in_progress = 1;
914 size_t size = cJSON_GetArraySize (o);
915 for (int i = 0; i < size; i++)
917 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
920 am->replay_in_progress = 0;
927 rv = vl_msg_exec_json_command (vm, o);
931 vlib_cli_output (vm, "error during replaying API trace");
937 vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
939 FILE *f = fopen ((char *) filename, "r");
944 vlib_cli_output (vm, "failed to open %s!\n", filename);
948 buf = vl_msg_read_file (f);
953 vlib_cli_output (vm, "no content in %s!\n", filename);
957 vlib_cli_output (vm, buf);
961 /** api_trace_command_fn - control the binary API trace / replay feature
963 Note: this command MUST be marked thread-safe. Replay with
964 multiple worker threads depends in many cases on worker thread
965 graph replica maintenance. If we (implicitly) assert a worker
966 thread barrier at the debug CLI level, all graph replica changes
967 are deferred until the replay operation completes. If an interface
968 is deleted, the wheels fall off.
971 static clib_error_t *
972 api_trace_command_fn (vlib_main_t * vm,
973 unformat_input_t * input, vlib_cli_command_t * cmd)
975 unformat_input_t _line_input, *line_input = &_line_input;
976 u32 nitems = 256 << 10;
977 api_main_t *am = vlibapi_get_main ();
978 vl_api_trace_which_t which = VL_API_TRACE_RX;
980 u8 *chroot_filename = 0;
982 u32 last = (u32) ~ 0;
986 /* Get a line of input. */
987 if (!unformat_user (input, unformat_line_input, line_input))
990 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
992 if (unformat (line_input, "on") || unformat (line_input, "enable"))
994 if (unformat (line_input, "nitems %d", &nitems))
996 vlib_worker_thread_barrier_sync (vm);
997 vl_msg_api_trace_configure (am, which, nitems);
998 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
999 vlib_worker_thread_barrier_release (vm);
1001 else if (unformat (line_input, "off"))
1003 vlib_worker_thread_barrier_sync (vm);
1004 vl_msg_api_trace_onoff (am, which, 0);
1005 vlib_worker_thread_barrier_release (vm);
1007 else if (unformat (line_input, "save-json %s", &filename))
1009 if (strstr ((char *) filename, "..") ||
1010 index ((char *) filename, '/'))
1012 vlib_cli_output (vm, "illegal characters in filename '%s'",
1017 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1019 vec_free (filename);
1021 if (file_exists (chroot_filename))
1023 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1027 fp = fopen ((char *) chroot_filename, "w");
1030 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1033 vlib_worker_thread_barrier_sync (vm);
1034 rv = vl_msg_api_trace_save (am, which, fp, 1);
1036 vlib_cli_output (vm, "API Trace data not present\n");
1038 vlib_cli_output (vm, "failed to save api trace\n");
1040 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1041 vlib_worker_thread_barrier_release (vm);
1044 else if (unformat (line_input, "save %s", &filename))
1046 if (strstr ((char *) filename, "..")
1047 || index ((char *) filename, '/'))
1049 vlib_cli_output (vm, "illegal characters in filename '%s'",
1054 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1056 vec_free (filename);
1058 if (file_exists (chroot_filename))
1060 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1064 fp = fopen ((char *) chroot_filename, "w");
1067 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1070 vlib_worker_thread_barrier_sync (vm);
1071 rv = vl_msg_api_trace_save (am, which, fp, 0);
1072 vlib_worker_thread_barrier_release (vm);
1075 vlib_cli_output (vm, "API Trace data not present\n");
1077 vlib_cli_output (vm, "File for writing is closed\n");
1079 vlib_cli_output (vm, "Error while writing header to file\n");
1081 vlib_cli_output (vm, "Error while writing trace to file\n");
1083 vlib_cli_output (vm,
1084 "Error while writing end of buffer trace to file\n");
1086 vlib_cli_output (vm,
1087 "Error while writing start of buffer trace to file\n");
1089 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1091 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1094 else if (unformat (line_input, "tojson %s", &filename))
1096 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1098 else if (unformat (line_input, "dump-file-json %s", &filename))
1100 vl_msg_dump_file_json (vm, filename);
1102 else if (unformat (line_input, "dump-file %s", &filename))
1104 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1106 else if (unformat (line_input, "dump-json"))
1108 vl_msg_api_dump_trace (vm, which, 1);
1110 else if (unformat (line_input, "dump"))
1112 vl_msg_api_dump_trace (vm, which, 0);
1114 else if (unformat (line_input, "replay-json %s", &filename))
1116 vl_msg_replay_json (vm, filename);
1118 else if (unformat (line_input, "replay %s", &filename))
1120 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1122 else if (unformat (line_input, "initializers %s", &filename))
1124 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1126 else if (unformat (line_input, "tx"))
1128 which = VL_API_TRACE_TX;
1130 else if (unformat (line_input, "first %d", &first))
1134 else if (unformat (line_input, "last %d", &last))
1138 else if (unformat (line_input, "status"))
1140 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1143 else if (unformat (line_input, "free"))
1145 vlib_worker_thread_barrier_sync (vm);
1146 vl_msg_api_trace_onoff (am, which, 0);
1147 vl_msg_api_trace_free (am, which);
1148 vlib_worker_thread_barrier_release (vm);
1150 else if (unformat (line_input, "post-mortem-on"))
1151 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1152 else if (unformat (line_input, "post-mortem-off"))
1153 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1155 return clib_error_return (0, "unknown input `%U'",
1156 format_unformat_error, input);
1159 vec_free (filename);
1160 vec_free (chroot_filename);
1161 unformat_free (line_input);
1166 * Display, replay, or save a binary API trace
1170 VLIB_CLI_COMMAND (api_trace_command, static) = {
1171 .path = "api trace",
1172 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1173 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1174 "json|replay <file>|replay-json <file>][nitems <n>]"
1175 "[initializers <file>]",
1176 .function = api_trace_command_fn,
1181 static clib_error_t *
1182 api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1184 u32 nitems = 256 << 10;
1185 vl_api_trace_which_t which = VL_API_TRACE_RX;
1186 api_main_t *am = vlibapi_get_main ();
1188 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1190 if (unformat (input, "on") || unformat (input, "enable"))
1192 if (unformat (input, "nitems %d", &nitems))
1194 vl_msg_api_trace_configure (am, which, nitems);
1195 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1196 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1198 else if (unformat (input, "save-api-table %s",
1199 &am->save_msg_table_filename))
1202 return clib_error_return (0, "unknown input `%U'",
1203 format_unformat_error, input);
1209 * This module has three configuration parameters:
1210 * "on" or "enable" - enables binary api tracing
1211 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1212 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1214 VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1216 static clib_error_t *
1217 api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1219 api_main_t *am = vlibapi_get_main ();
1222 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1224 if (unformat (input, "length %d", &nitems) ||
1225 (unformat (input, "len %d", &nitems)))
1228 am->vlib_input_queue_length = nitems;
1230 clib_warning ("vlib input queue length %d too small, ignored",
1234 return clib_error_return (0, "unknown input `%U'",
1235 format_unformat_error, input);
1240 VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1243 extract_name (u8 * s)
1249 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1250 vec_dec_len (rv, 1);
1252 rv[vec_len (rv)] = 0;
1258 extract_crc (u8 * s)
1265 for (i = vec_len (rv) - 1; i >= 0; i--)
1269 vec_delete (rv, i + 1, 0);
1283 } msg_table_unserialize_t;
1286 table_id_cmp (void *a1, void *a2)
1288 msg_table_unserialize_t *n1 = a1;
1289 msg_table_unserialize_t *n2 = a2;
1291 return (n1->msg_index - n2->msg_index);
1295 table_name_and_crc_cmp (void *a1, void *a2)
1297 msg_table_unserialize_t *n1 = a1;
1298 msg_table_unserialize_t *n2 = a2;
1300 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1303 static clib_error_t *
1304 dump_api_table_file_command_fn (vlib_main_t * vm,
1305 unformat_input_t * input,
1306 vlib_cli_command_t * cmd)
1309 api_main_t *am = vlibapi_get_main ();
1310 serialize_main_t _sm, *sm = &_sm;
1311 clib_error_t *error;
1315 int compare_current = 0;
1316 int numeric_sort = 0;
1317 msg_table_unserialize_t *table = 0, *item;
1319 u32 ndifferences = 0;
1321 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1323 if (unformat (input, "file %s", &filename))
1325 else if (unformat (input, "compare-current")
1326 || unformat (input, "compare"))
1327 compare_current = 1;
1328 else if (unformat (input, "numeric"))
1331 return clib_error_return (0, "unknown input `%U'",
1332 format_unformat_error, input);
1335 if (numeric_sort && compare_current)
1336 return clib_error_return
1337 (0, "Comparison and numeric sorting are incompatible");
1340 return clib_error_return (0, "File not specified");
1342 /* Load the serialized message table from the table dump */
1344 error = unserialize_open_clib_file (sm, (char *) filename);
1349 unserialize_integer (sm, &nmsgs, sizeof (u32));
1351 for (i = 0; i < nmsgs; i++)
1353 msg_index = unserialize_likely_small_unsigned_integer (sm);
1354 unserialize_cstring (sm, (char **) &name_and_crc);
1355 vec_add2 (table, item, 1);
1356 item->msg_index = msg_index;
1357 item->name_and_crc = name_and_crc;
1358 item->name = extract_name (name_and_crc);
1359 item->crc = extract_crc (name_and_crc);
1360 item->which = 0; /* file */
1362 unserialize_close (sm);
1364 /* Compare with the current image? */
1365 if (compare_current)
1367 /* Append the current message table */
1368 u8 *tblv = vl_api_serialize_message_table (am, 0);
1370 serialize_open_vector (sm, tblv);
1371 unserialize_integer (sm, &nmsgs, sizeof (u32));
1373 for (i = 0; i < nmsgs; i++)
1375 msg_index = unserialize_likely_small_unsigned_integer (sm);
1376 unserialize_cstring (sm, (char **) &name_and_crc);
1378 vec_add2 (table, item, 1);
1379 item->msg_index = msg_index;
1380 item->name_and_crc = name_and_crc;
1381 item->name = extract_name (name_and_crc);
1382 item->crc = extract_crc (name_and_crc);
1383 item->which = 1; /* current_image */
1388 /* Sort the table. */
1390 vec_sort_with_function (table, table_id_cmp);
1392 vec_sort_with_function (table, table_name_and_crc_cmp);
1394 if (compare_current)
1400 * In this case, the recovered table will have two entries per
1401 * API message. So, if entries i and i+1 match, the message definitions
1402 * are identical. Otherwise, the crc is different, or a message is
1403 * present in only one of the tables.
1405 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1406 vec_validate_init_empty (dashes, 60, '-');
1407 vec_terminate_c_string (dashes);
1408 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1410 for (i = 0; i < vec_len (table);)
1412 /* Last message lonely? */
1413 if (i == vec_len (table) - 1)
1419 /* Identical pair? */
1421 ((char *) table[i].name_and_crc,
1422 (char *) table[i + 1].name_and_crc,
1423 vec_len (table[i].name_and_crc)))
1431 /* Only in one of two tables? */
1432 if (i + 1 == vec_len (table)
1433 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1436 vlib_cli_output (vm, "%-60s | only in %s",
1437 table[i].name, table[i].which ?
1442 /* In both tables, but with different signatures */
1443 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1446 if (ndifferences == 0)
1447 vlib_cli_output (vm, "No api message signature differences found.");
1449 vlib_cli_output (vm, "\nFound %u api message signature differences",
1454 /* Dump the table, sorted as shown above */
1455 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1457 for (i = 0; i < vec_len (table); i++)
1460 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1461 item->msg_index, item->crc);
1465 for (i = 0; i < vec_len (table); i++)
1467 vec_free (table[i].name_and_crc);
1468 vec_free (table[i].name);
1469 vec_free (table[i].crc);
1478 * Displays a serialized API message decode table, sorted by message name
1481 * @cliexstart{show api dump file <filename>}
1482 * Message name MsgID CRC
1483 * accept_session 407 8e2a127e
1484 * accept_session_reply 408 67d8c22a
1485 * add_node_next 549 e4202993
1486 * add_node_next_reply 550 e89d6eed
1492 * Compares a serialized API message decode table with the current image
1495 * @cliexstart{show api dump file <filename> compare}
1496 * ip_add_del_route definition changed
1497 * ip_table_add_del definition changed
1498 * l2_macs_event only in image
1499 * vnet_ip4_fib_counters only in file
1500 * vnet_ip4_nbr_counters only in file
1505 * Display a serialized API message decode table, compare a saved
1506 * decode table with the current image, to establish API differences.
1510 VLIB_CLI_COMMAND (dump_api_table_file, static) =
1512 .path = "show api dump",
1513 .short_help = "show api dump file <filename> [numeric | compare-current]",
1514 .function = dump_api_table_file_command_fn,
1519 * fd.io coding-style-patch-verification: ON
1522 * eval: (c-set-style "gnu")