"Name", "PID", "Queue Length", "Queue VA", "Health");
/* *INDENT-OFF* */
- pool_foreach (regpp, am->vl_clients,
- ({
+ pool_foreach (regpp, am->vl_clients)
+ {
regp = *regpp;
if (regp)
regpp - am->vl_clients);
vec_add1 (confused_indices, regpp - am->vl_clients);
}
- }));
+ }
/* *INDENT-ON* */
/* This should "never happen," but if it does, fix it... */
vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
"MP-safe");
- for (i = 1; i < vec_len (am->msg_names); i++)
+ for (i = 1; i < vec_len (am->msg_data); i++)
{
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
if (verbose == 0)
{
vlib_cli_output (vm, "%-4d %s", i,
- am->msg_names[i] ? am->msg_names[i] :
- " [no handler]");
+ m->name ? m->name : " [no handler]");
}
else
{
vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
- am->msg_names[i] ? am->msg_names[i] :
- " [no handler]", am->message_bounce[i],
- am->is_mp_safe[i]);
+ m->name ? m->name : " [no handler]", m->bounce,
+ m->is_mp_safe);
}
}
typedef enum
{
DUMP,
- CUSTOM_DUMP,
+ DUMP_JSON,
REPLAY,
INITIALIZERS,
} vl_api_replay_t;
return s;
}
-void vl_msg_api_custom_dump_configure (api_main_t * am)
- __attribute__ ((weak));
-void
-vl_msg_api_custom_dump_configure (api_main_t * am)
-{
-}
-
static void
vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
u32 first_index, u32 last_index,
{
vl_api_trace_file_header_t *hp;
int i, fd;
+ u16 *msgid_vec = 0;
struct stat statb;
size_t file_size;
u8 *msg;
api_main_t *am = vlibapi_get_main ();
u8 *tmpbuf = 0;
u32 nitems, nitems_msgtbl;
- void **saved_print_handlers = 0;
fd = open ((char *) filename, O_RDONLY);
}
file_size = statb.st_size;
- file_size = (file_size + 4095) & ~(4096);
+ file_size = (file_size + 4095) & ~(4095);
hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
}
close (fd);
+ clib_mem_unpoison (hp, file_size);
+
nitems = ntohl (hp->nitems);
if (last_index == (u32) ~ 0)
vlib_cli_output (vm,
"Note: wrapped/incomplete trace, results may vary\n");
- if (which == CUSTOM_DUMP)
- {
- saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
- vl_msg_api_custom_dump_configure (am);
- }
+ size_t file_size_left = file_size;
+
+#define assert_size(size_left, s) \
+ do \
+ { \
+ if ((s) >= size_left) \
+ { \
+ vlib_cli_output (vm, "corrupted file"); \
+ munmap (hp, file_size); \
+ vec_free (msgid_vec); \
+ return; \
+ } \
+ size_left -= s; \
+ } \
+ while (0);
+
+ assert_size (file_size_left, sizeof (hp[0]));
msg = (u8 *) (hp + 1);
- u16 *msgid_vec = 0;
serialize_main_t _sm, *sm = &_sm;
u32 msgtbl_size = ntohl (hp->msgtbl_size);
u8 *name_and_crc;
+ assert_size (file_size_left, msgtbl_size);
+
unserialize_open_data (sm, msg, msgtbl_size);
unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
{
u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
unserialize_cstring (sm, (char **) &name_and_crc);
- u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
+ u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
+ ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
+ if (~0 == msg_index2)
+ vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
+ msg_index);
vec_validate (msgid_vec, msg_index);
msgid_vec[msg_index] = msg_index2;
}
for (i = 0; i < first_index; i++)
{
- trace_cfg_t *cfgp;
int size;
u16 msg_id;
+ assert_size (file_size_left, sizeof (u32));
size = clib_host_to_net_u32 (*(u32 *) msg);
msg += sizeof (u32);
+ assert_size (file_size_left, clib_max (size, sizeof (u16)));
msg_id = ntohs (*((u16 *) msg));
- if (msg_id < vec_len (msgid_vec))
- msg_id = msgid_vec[msg_id];
- cfgp = am->api_trace_cfg + msg_id;
- if (!cfgp)
- {
- vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
- munmap (hp, file_size);
- return;
- }
+ if (msg_id >= vec_len (msgid_vec) ||
+ msgid_vec[msg_id] >= vec_len (am->msg_data))
+ vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
+ msg_id, i);
+
msg += size;
}
for (; i <= last_index; i++)
{
- trace_cfg_t *cfgp;
+ vl_api_msg_data_t *m;
u16 msg_id;
int size;
if (which == DUMP)
vlib_cli_output (vm, "---------- trace %d -----------\n", i);
+ assert_size (file_size_left, sizeof (u32));
size = clib_host_to_net_u32 (*(u32 *) msg);
msg += sizeof (u32);
+ assert_size (file_size_left, clib_max (size, sizeof (u16)));
msg_id = ntohs (*((u16 *) msg));
- if (msg_id < vec_len (msgid_vec))
- {
- msg_id = msgid_vec[msg_id];
- }
- cfgp = am->api_trace_cfg + msg_id;
- if (!cfgp)
+ if (msg_id >= vec_len (msgid_vec) ||
+ msgid_vec[msg_id] >= vec_len (am->msg_data))
{
- vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
- munmap (hp, file_size);
- vec_free (tmpbuf);
- am->replay_in_progress = 0;
- return;
+ vlib_cli_output (
+ vm, "warning: unknown msg id %d for msg number %d, skipping\n",
+ msg_id, i);
+ msg += size;
+ continue;
}
+ msg_id = msgid_vec[msg_id];
+ m = vl_api_get_msg_data (am, msg_id);
+
/* Copy the buffer (from the read-only mmap'ed file) */
vec_validate (tmpbuf, size - 1 + sizeof (uword));
clib_memcpy (tmpbuf + sizeof (uword), msg, size);
* Endian swap if needed. All msg data is supposed to be in
* network byte order.
*/
- if (((which == DUMP || which == CUSTOM_DUMP)
- && clib_arch_is_little_endian))
+ if (((which == DUMP || which == DUMP_JSON) &&
+ clib_arch_is_little_endian))
{
- void (*endian_fp) (void *);
- if (msg_id >= vec_len (am->msg_endian_handlers)
- || (am->msg_endian_handlers[msg_id] == 0))
+ if (m && m->endian_handler == 0)
{
vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
munmap (hp, file_size);
am->replay_in_progress = 0;
return;
}
- endian_fp = am->msg_endian_handlers[msg_id];
- (*endian_fp) (tmpbuf + sizeof (uword));
+ if (m)
+ {
+ m->endian_handler (tmpbuf + sizeof (uword));
+ }
}
/* msg_id always in network byte order */
switch (which)
{
- case CUSTOM_DUMP:
- case DUMP:
- if (msg_id < vec_len (am->msg_print_handlers) &&
- am->msg_print_handlers[msg_id])
- {
- u8 *(*print_fp) (void *, void *);
+ case DUMP_JSON:
+ vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
+ tmpbuf + sizeof (uword));
+ break;
- print_fp = (void *) am->msg_print_handlers[msg_id];
- (*print_fp) (tmpbuf + sizeof (uword), vm);
- }
- else
- {
- vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
- msg_id);
- break;
- }
+ case DUMP:
+ vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
+ tmpbuf + sizeof (uword));
break;
case INITIALIZERS:
- if (msg_id < vec_len (am->msg_print_handlers) &&
- am->msg_print_handlers[msg_id])
+ if (m)
{
u8 *s;
int j;
- u8 *(*print_fp) (void *, void *);
-
- print_fp = (void *) am->msg_print_handlers[msg_id];
- vlib_cli_output (vm, "/*");
+ vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
+ msg_id, tmpbuf + sizeof (uword));
- (*print_fp) (tmpbuf + sizeof (uword), vm);
vlib_cli_output (vm, "*/\n");
- s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
- am->msg_names[msg_id], i,
- am->api_trace_cfg[msg_id].size);
+ s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
+ m->trace_size);
- for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
+ for (j = 0; j < m->trace_size; j++)
{
if ((j & 7) == 0)
s = format (s, "\n ");
break;
case REPLAY:
- if (msg_id < vec_len (am->msg_print_handlers) &&
- am->msg_print_handlers[msg_id] && cfgp->replay_enable)
+ if (m && m->handler && m->replay_allowed)
{
- void (*handler) (void *, vlib_main_t *);
-
- handler = (void *) am->msg_handlers[msg_id];
-
- if (!am->is_mp_safe[msg_id])
+ if (!m->is_mp_safe)
vl_msg_api_barrier_sync ();
- (*handler) (tmpbuf + sizeof (uword), vm);
- if (!am->is_mp_safe[msg_id])
+ m->handler (tmpbuf + sizeof (uword));
+ if (!m->is_mp_safe)
vl_msg_api_barrier_release ();
}
else
{
- if (cfgp->replay_enable)
+ if (m && m->replay_allowed)
vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
msg_id);
break;
break;
}
- _vec_len (tmpbuf) = 0;
+ vec_set_len (tmpbuf, 0);
msg += size;
}
- if (saved_print_handlers)
+ munmap (hp, file_size);
+ vec_free (tmpbuf);
+ vec_free (msgid_vec);
+ am->replay_in_progress = 0;
+}
+
+static int
+file_exists (u8 *fname)
+{
+ FILE *fp = 0;
+ fp = fopen ((char *) fname, "r");
+ if (fp)
+ {
+ fclose (fp);
+ return 1;
+ }
+ return 0;
+}
+
+typedef struct
+{
+ vlib_main_t *vm;
+ u8 is_json;
+} vl_msg_print_args;
+
+static int
+vl_msg_print_trace (u8 *msg, void *ctx)
+{
+ vl_msg_print_args *a = ctx;
+ api_main_t *am = vlibapi_get_main ();
+ u16 msg_id = ntohs (*((u16 *) msg));
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
+ u8 is_json = a->is_json;
+ u8 *tmpbuf = 0;
+
+ if (!m)
{
- clib_memcpy (am->msg_print_handlers, saved_print_handlers,
- vec_len (am->msg_print_handlers) * sizeof (void *));
- vec_free (saved_print_handlers);
+ vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
+ return 0;
}
- munmap (hp, file_size);
+ if (clib_arch_is_little_endian && (m->endian_handler != NULL))
+ {
+ u32 msg_length = vec_len (msg);
+ vec_validate (tmpbuf, msg_length - 1);
+ clib_memcpy_fast (tmpbuf, msg, msg_length);
+ msg = tmpbuf;
+
+ m->endian_handler (tmpbuf);
+ }
+
+ vlib_cli_output (a->vm, "%U\n",
+ is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
+ am, msg_id, msg);
+
vec_free (tmpbuf);
- am->replay_in_progress = 0;
+ return 0;
+}
+
+static int
+vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
+{
+ api_main_t *am = vlibapi_get_main ();
+ vl_api_trace_t *tp;
+
+ switch (which)
+ {
+ case VL_API_TRACE_TX:
+ tp = am->tx_trace;
+ break;
+ case VL_API_TRACE_RX:
+ tp = am->rx_trace;
+ break;
+ default:
+ return -1;
+ }
+
+ if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
+ return -1;
+
+ vl_msg_print_args args;
+ clib_memset (&args, 0, sizeof (args));
+ args.is_json = is_json;
+ args.vm = vm;
+ vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
+
+ return 0;
+}
+
+static char *
+vl_msg_read_file (FILE *f)
+{
+ const size_t bufsize = 1024;
+ char *buf[bufsize], *v = 0;
+ size_t n;
+
+ while ((n = fread (buf, 1, bufsize, f)))
+ vec_add (v, buf, n);
+
+ /* most callers expect a NULL-terminated C-string */
+ if (v)
+ vec_add1 (v, 0);
+
+ return v;
+}
+
+static u16
+vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
+{
+ uword *p;
+ p = hash_get_mem (am->msg_index_by_name_and_crc, name);
+ if (!p)
+ return (u16) ~0;
+
+ return p[0];
+}
+
+static u16
+vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
+{
+ uword *p;
+
+ if (!am->msg_id_by_name)
+ {
+ vlib_cli_output (vm, "message id table not yet initialized!\n");
+ return (u16) ~0;
+ }
+
+ p = hash_get_mem (am->msg_id_by_name, name);
+ if (!p)
+ return (u16) ~0;
+
+ return p[0];
+}
+
+static int
+vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
+{
+ api_main_t *am = vlibapi_get_main ();
+ u16 msg_id;
+ int len = 0, rv = -1;
+ vl_api_msg_data_t *m;
+ u8 *msg = 0;
+
+ cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
+ if (!msg_id_obj)
+ {
+ vlib_cli_output (vm, "Missing '_msgname' element!\n");
+ return rv;
+ }
+ char *name = cJSON_GetStringValue (msg_id_obj);
+
+ cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
+ if (!crc_obj)
+ {
+ vlib_cli_output (vm, "Missing '_crc' element!\n");
+ return rv;
+ }
+ char *crc = cJSON_GetStringValue (crc_obj);
+ u8 proc_warning = 0;
+
+ u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
+ msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
+ m = vl_api_get_msg_data (am, msg_id);
+ if (msg_id == (u16) ~0)
+ {
+ msg_id = vl_msg_find_id_by_name (vm, am, name);
+ if (msg_id == (u16) ~0)
+ {
+ vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
+ vec_free (name_crc);
+ return rv;
+ }
+ proc_warning = 1;
+ }
+ vec_free (name_crc);
+
+ if (m->replay_allowed)
+ {
+ if (proc_warning)
+ vlib_cli_output (vm, "warning: msg %d has different signature\n");
+
+ if (!m->fromjson_handler)
+ {
+ vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
+ msg_id);
+ return rv;
+ }
+
+ msg = (u8 *) m->fromjson_handler (o, &len);
+ if (!msg)
+ {
+ vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
+ msg_id);
+ return rv;
+ }
+
+ if (clib_arch_is_little_endian)
+ m->endian_handler (msg);
+
+ if (!m->handler)
+ {
+ vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
+ goto end;
+ }
+
+ if (m->handler)
+ {
+ if (!m->is_mp_safe)
+ vl_msg_api_barrier_sync ();
+ m->handler (msg);
+ if (!m->is_mp_safe)
+ vl_msg_api_barrier_release ();
+ }
+ }
+
+ rv = 0;
+end:
+ if (msg)
+ cJSON_free (msg);
+ return rv;
}
+static void
+vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
+{
+ api_main_t *am = vlibapi_get_main ();
+ cJSON *o = 0;
+ int rv = 0;
+ FILE *f = fopen ((char *) filename, "r");
+
+ if (!f)
+ {
+ vlib_cli_output (vm, "failed to open %s!\n", filename);
+ return;
+ }
+
+ char *buf = vl_msg_read_file (f);
+ fclose (f);
+
+ o = cJSON_Parse (buf);
+ vec_free (buf);
+ if (!o)
+ {
+ vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
+ cJSON_GetErrorPtr ());
+ return;
+ }
+
+ if (cJSON_IsArray (o))
+ {
+ am->replay_in_progress = 1;
+ size_t size = cJSON_GetArraySize (o);
+ for (int i = 0; i < size; i++)
+ {
+ rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
+ if (rv < 0)
+ {
+ am->replay_in_progress = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ rv = vl_msg_exec_json_command (vm, o);
+ }
+
+ if (rv < 0)
+ vlib_cli_output (vm, "error during replaying API trace");
+
+ cJSON_Delete (o);
+}
+
+static void
+vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
+{
+ FILE *f = fopen ((char *) filename, "r");
+ char *buf;
+
+ if (!f)
+ {
+ vlib_cli_output (vm, "failed to open %s!\n", filename);
+ return;
+ }
+
+ buf = vl_msg_read_file (f);
+ fclose (f);
+
+ if (!buf)
+ {
+ vlib_cli_output (vm, "no content in %s!\n", filename);
+ return;
+ }
+
+ vlib_cli_output (vm, buf);
+ vec_free (buf);
+}
+
+/** api_trace_command_fn - control the binary API trace / replay feature
+
+ Note: this command MUST be marked thread-safe. Replay with
+ multiple worker threads depends in many cases on worker thread
+ graph replica maintenance. If we (implicitly) assert a worker
+ thread barrier at the debug CLI level, all graph replica changes
+ are deferred until the replay operation completes. If an interface
+ is deleted, the wheels fall off.
+ */
+
static clib_error_t *
api_trace_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
+ unformat_input_t _line_input, *line_input = &_line_input;
u32 nitems = 256 << 10;
api_main_t *am = vlibapi_get_main ();
vl_api_trace_which_t which = VL_API_TRACE_RX;
FILE *fp;
int rv;
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (input, "on") || unformat (input, "enable"))
+ if (unformat (line_input, "on") || unformat (line_input, "enable"))
{
- if (unformat (input, "nitems %d", &nitems))
+ if (unformat (line_input, "nitems %d", &nitems))
;
+ vlib_worker_thread_barrier_sync (vm);
vl_msg_api_trace_configure (am, which, nitems);
vl_msg_api_trace_onoff (am, which, 1 /* on */ );
+ vlib_worker_thread_barrier_release (vm);
}
- else if (unformat (input, "off"))
+ else if (unformat (line_input, "off"))
{
+ vlib_worker_thread_barrier_sync (vm);
vl_msg_api_trace_onoff (am, which, 0);
+ vlib_worker_thread_barrier_release (vm);
+ }
+ else if (unformat (line_input, "save-json %s", &filename))
+ {
+ if (strstr ((char *) filename, "..") ||
+ index ((char *) filename, '/'))
+ {
+ vlib_cli_output (vm, "illegal characters in filename '%s'",
+ filename);
+ goto out;
+ }
+
+ chroot_filename = format (0, "/tmp/%s%c", filename, 0);
+
+ vec_free (filename);
+
+ if (file_exists (chroot_filename))
+ {
+ vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
+ goto out;
+ }
+
+ fp = fopen ((char *) chroot_filename, "w");
+ if (fp == NULL)
+ {
+ vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
+ goto out;
+ }
+ vlib_worker_thread_barrier_sync (vm);
+ rv = vl_msg_api_trace_save (am, which, fp, 1);
+ if (rv == -1)
+ vlib_cli_output (vm, "API Trace data not present\n");
+ else if (rv < 0)
+ vlib_cli_output (vm, "failed to save api trace\n");
+ else
+ vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
+ vlib_worker_thread_barrier_release (vm);
+ fclose (fp);
}
- else if (unformat (input, "save %s", &filename))
+ else if (unformat (line_input, "save %s", &filename))
{
if (strstr ((char *) filename, "..")
|| index ((char *) filename, '/'))
vec_free (filename);
+ if (file_exists (chroot_filename))
+ {
+ vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
+ goto out;
+ }
+
fp = fopen ((char *) chroot_filename, "w");
if (fp == NULL)
{
vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
goto out;
}
- rv = vl_msg_api_trace_save (am, which, fp);
+ vlib_worker_thread_barrier_sync (vm);
+ rv = vl_msg_api_trace_save (am, which, fp, 0);
+ vlib_worker_thread_barrier_release (vm);
fclose (fp);
if (rv == -1)
vlib_cli_output (vm, "API Trace data not present\n");
vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
goto out;
}
- else if (unformat (input, "dump %s", &filename))
+ else if (unformat (line_input, "tojson %s", &filename))
+ {
+ vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
+ }
+ else if (unformat (line_input, "dump-file-json %s", &filename))
+ {
+ vl_msg_dump_file_json (vm, filename);
+ }
+ else if (unformat (line_input, "dump-file %s", &filename))
{
vl_msg_api_process_file (vm, filename, first, last, DUMP);
}
- else if (unformat (input, "custom-dump %s", &filename))
+ else if (unformat (line_input, "dump-json"))
+ {
+ vl_msg_api_dump_trace (vm, which, 1);
+ }
+ else if (unformat (line_input, "dump"))
{
- vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
+ vl_msg_api_dump_trace (vm, which, 0);
}
- else if (unformat (input, "replay %s", &filename))
+ else if (unformat (line_input, "replay-json %s", &filename))
+ {
+ vl_msg_replay_json (vm, filename);
+ }
+ else if (unformat (line_input, "replay %s", &filename))
{
vl_msg_api_process_file (vm, filename, first, last, REPLAY);
}
- else if (unformat (input, "initializers %s", &filename))
+ else if (unformat (line_input, "initializers %s", &filename))
{
vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
}
- else if (unformat (input, "tx"))
+ else if (unformat (line_input, "tx"))
{
which = VL_API_TRACE_TX;
}
- else if (unformat (input, "first %d", &first))
+ else if (unformat (line_input, "first %d", &first))
{
;
}
- else if (unformat (input, "last %d", &last))
+ else if (unformat (line_input, "last %d", &last))
{
;
}
- else if (unformat (input, "status"))
+ else if (unformat (line_input, "status"))
{
vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
am, which);
}
- else if (unformat (input, "free"))
+ else if (unformat (line_input, "free"))
{
+ vlib_worker_thread_barrier_sync (vm);
vl_msg_api_trace_onoff (am, which, 0);
vl_msg_api_trace_free (am, which);
+ vlib_worker_thread_barrier_release (vm);
}
- else if (unformat (input, "post-mortem-on"))
+ else if (unformat (line_input, "post-mortem-on"))
vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
- else if (unformat (input, "post-mortem-off"))
+ else if (unformat (line_input, "post-mortem-off"))
vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
else
return clib_error_return (0, "unknown input `%U'",
out:
vec_free (filename);
vec_free (chroot_filename);
+ unformat_free (line_input);
return 0;
}
?*/
/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (api_trace_command, static) =
-{
+VLIB_CLI_COMMAND (api_trace_command, static) = {
.path = "api trace",
- .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
- "[post-mortem-on][dump|custom-dump|save|replay <file>]",
+ .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
+ "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
+ "json|replay <file>|replay-json <file>][nitems <n>]"
+ "[initializers <file>]",
.function = api_trace_command_fn,
-};
-/* *INDENT-ON* */
-
-static clib_error_t *
-vl_api_trace_command (vlib_main_t * vm,
- unformat_input_t * input, vlib_cli_command_t * cli_cmd)
-{
- u32 nitems = 1024;
- vl_api_trace_which_t which = VL_API_TRACE_RX;
- api_main_t *am = vlibapi_get_main ();
-
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
- goto configure;
- else if (unformat (input, "tx nitems %u", &nitems)
- || unformat (input, "tx"))
- {
- which = VL_API_TRACE_RX;
- goto configure;
- }
- else if (unformat (input, "on rx"))
- {
- vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
- }
- else if (unformat (input, "on tx"))
- {
- vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
- }
- else if (unformat (input, "on"))
- {
- vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
- }
- else if (unformat (input, "off"))
- {
- vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
- vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
- }
- else if (unformat (input, "free"))
- {
- vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
- vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
- vl_msg_api_trace_free (am, VL_API_TRACE_RX);
- vl_msg_api_trace_free (am, VL_API_TRACE_TX);
- }
- else if (unformat (input, "debug on"))
- {
- am->msg_print_flag = 1;
- }
- else if (unformat (input, "debug off"))
- {
- am->msg_print_flag = 0;
- }
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
- }
- return 0;
-
-configure:
- if (vl_msg_api_trace_configure (am, which, nitems))
- {
- vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
- which, nitems);
- }
-
- return 0;
-}
-
-/*?
- * Control the binary API trace mechanism
-?*/
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (trace, static) =
-{
- .path = "set api-trace",
- .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
- .function = vl_api_trace_command,
+ .is_mp_safe = 1,
};
/* *INDENT-ON* */
rv = vec_dup (s);
while (vec_len (rv) && rv[vec_len (rv)] != '_')
- _vec_len (rv)--;
+ vec_dec_len (rv, 1);
rv[vec_len (rv)] = 0;