X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlibmemory%2Fvlib_api_cli.c;h=5b62e61a235bbccaf67ff95a36748445879033ff;hb=fe45f8f5;hp=4a86b8d76bb298ff4749f77427e6e98c3d0f9b00;hpb=05f7ca110bb67f73af69ded6b915ee70754fbb6f;p=vpp.git diff --git a/src/vlibmemory/vlib_api_cli.c b/src/vlibmemory/vlib_api_cli.c old mode 100755 new mode 100644 index 4a86b8d76bb..5b62e61a235 --- a/src/vlibmemory/vlib_api_cli.c +++ b/src/vlibmemory/vlib_api_cli.c @@ -101,7 +101,7 @@ vl_api_client_command (vlib_main_t * vm, vl_api_registration_t **regpp, *regp; svm_queue_t *q; char *health; - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); u32 *confused_indices = 0; if (!pool_elts (am->vl_clients)) @@ -111,8 +111,8 @@ vl_api_client_command (vlib_main_t * vm, "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) @@ -134,7 +134,7 @@ vl_api_client_command (vlib_main_t * vm, regpp - am->vl_clients); vec_add1 (confused_indices, regpp - am->vl_clients); } - })); + } /* *INDENT-ON* */ /* This should "never happen," but if it does, fix it... */ @@ -161,7 +161,7 @@ static clib_error_t * vl_api_status_command (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cli_cmd) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); /* check if rx_trace and tx_trace are not null pointers */ if (am->rx_trace == 0) @@ -228,7 +228,7 @@ vl_api_message_table_command (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cli_cmd) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); int i; int verbose = 0; @@ -242,20 +242,19 @@ vl_api_message_table_command (vlib_main_t * vm, 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); } } @@ -304,7 +303,7 @@ vl_api_show_plugin_command (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cli_cmd) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); vl_api_msg_range_t *rp = 0; int i; @@ -344,7 +343,7 @@ VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) = typedef enum { DUMP, - CUSTOM_DUMP, + DUMP_JSON, REPLAY, INITIALIZERS, } vl_api_replay_t; @@ -385,13 +384,6 @@ format_vl_msg_api_trace_status (u8 * s, va_list * args) 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, @@ -399,14 +391,13 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, { vl_api_trace_file_header_t *hp; int i, fd; + u16 *msgid_vec = 0; struct stat statb; size_t file_size; u8 *msg; - u8 endian_swap_needed = 0; - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); u8 *tmpbuf = 0; - u32 nitems; - void **saved_print_handlers = 0; + u32 nitems, nitems_msgtbl; fd = open ((char *) filename, O_RDONLY); @@ -431,7 +422,7 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, } 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); @@ -443,14 +434,9 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, } close (fd); - if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN) - || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN)) - endian_swap_needed = 1; + clib_mem_unpoison (hp, file_size); - if (endian_swap_needed) - nitems = ntohl (hp->nitems); - else - nitems = hp->nitems; + nitems = ntohl (hp->nitems); if (last_index == (u32) ~ 0) { @@ -468,36 +454,65 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, vlib_cli_output (vm, "Note: wrapped/incomplete trace, results may vary\n"); - if (which == CUSTOM_DUMP) + 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); + + 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)); + + for (i = 0; i < nitems_msgtbl; i++) { - saved_print_handlers = (void **) vec_dup (am->msg_print_handlers); - vl_msg_api_custom_dump_configure (am); + u16 msg_index = unserialize_likely_small_unsigned_integer (sm); + unserialize_cstring (sm, (char **) &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; } - - msg = (u8 *) (hp + 1); + msg += msgtbl_size; 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); - if (clib_arch_is_little_endian) - msg_id = ntohs (*((u16 *) msg)); - else - msg_id = *((u16 *) msg); + assert_size (file_size_left, clib_max (size, sizeof (u16))); + msg_id = ntohs (*((u16 *) msg)); + 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); - 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; - } msg += size; } @@ -506,48 +521,46 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, for (; i <= last_index; i++) { - trace_cfg_t *cfgp; - u16 *msg_idp; + 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); - if (clib_arch_is_little_endian) - msg_id = ntohs (*((u16 *) msg)); - else - msg_id = *((u16 *) msg); + assert_size (file_size_left, clib_max (size, sizeof (u16))); + msg_id = ntohs (*((u16 *) msg)); - 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); clib_memset (tmpbuf, 0xf, sizeof (uword)); /* - * Endian swap if needed. All msg data is supposed to be - * in network byte order. All msg handlers are supposed to - * know that. The generic message dumpers don't know that. - * One could fix apigen, I suppose. + * Endian swap if needed. All msg data is supposed to be in + * network byte order. */ - if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed) + 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); @@ -555,57 +568,46 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, 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 */ if (clib_arch_is_little_endian) { - msg_idp = (u16 *) (tmpbuf + sizeof (uword)); + u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword)); *msg_idp = msg_id; } 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, "/*%U*/", format_vl_api_msg_text, am, + msg_id, tmpbuf + sizeof (uword)); - vlib_cli_output (vm, "/*"); - - (*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 "); @@ -618,22 +620,17 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, 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; @@ -641,70 +638,421 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, 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) { - clib_memcpy (am->msg_print_handlers, saved_print_handlers, - vec_len (am->msg_print_handlers) * sizeof (void *)); - vec_free (saved_print_handlers); + 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) + { + vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id); + return 0; + } + + if (clib_arch_is_little_endian) + { + 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); - munmap (hp, file_size); 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 = &api_main; + api_main_t *am = vlibapi_get_main (); vl_api_trace_which_t which = VL_API_TRACE_RX; - u8 *filename; + u8 *filename = 0; + u8 *chroot_filename = 0; u32 first = 0; u32 last = (u32) ~ 0; 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 (input, "save %s", &filename)) + 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 (line_input, "save %s", &filename)) { - u8 *chroot_filename; if (strstr ((char *) filename, "..") || index ((char *) filename, '/')) { vlib_cli_output (vm, "illegal characters in filename '%s'", filename); - return 0; + 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); - return 0; + 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"); @@ -724,54 +1072,76 @@ api_trace_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "Unknown error while saving: %d", rv); else vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename); - vec_free (chroot_filename); + goto out; + } + else if (unformat (line_input, "tojson %s", &filename)) + { + vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON); } - else if (unformat (input, "dump %s", &filename)) + 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'", format_unformat_error, input); } +out: + vec_free (filename); + vec_free (chroot_filename); + unformat_free (line_input); return 0; } @@ -780,90 +1150,14 @@ api_trace_command_fn (vlib_main_t * vm, ?*/ /* *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 ][last ][status][free]" - "[post-mortem-on][dump|custom-dump|save|replay ]", + .short_help = "api trace [tx][on|off][first ][last ][status][free]" + "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-" + "json|replay |replay-json ][nitems ]" + "[initializers ]", .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 = &api_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* */ @@ -872,7 +1166,7 @@ api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input) { u32 nitems = 256 << 10; vl_api_trace_which_t which = VL_API_TRACE_RX; - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -905,7 +1199,7 @@ VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace"); static clib_error_t * api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); u32 nitems; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -936,7 +1230,7 @@ extract_name (u8 * s) 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; @@ -995,7 +1289,7 @@ dump_api_table_file_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { u8 *filename = 0; - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); serialize_main_t _sm, *sm = &_sm; clib_error_t *error; u32 nmsgs; @@ -1048,7 +1342,7 @@ dump_api_table_file_command_fn (vlib_main_t * vm, item->crc = extract_crc (name_and_crc); item->which = 0; /* file */ } - serialize_close (sm); + unserialize_close (sm); /* Compare with the current image? */ if (compare_current)