X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlibapi%2Fapi_shared.c;h=d2f17593284f1079d54cd71e7c01cadcc0e52177;hb=0b7200f7eef8881018c1e6dfb7ef10cf1e221362;hp=0c4952b189c1b339cd238b321a977993835916e2;hpb=392206e55a1cbfb0a2e03ae310a4d3953bf3f194;p=vpp.git diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c index 0c4952b189c..d2f17593284 100644 --- a/src/vlibapi/api_shared.c +++ b/src/vlibapi/api_shared.c @@ -30,20 +30,30 @@ #include #include #include +#include /* *INDENT-OFF* */ -api_main_t api_main = - { - .region_name = "/unset", - .api_uid = -1, - .api_gid = -1, - }; +static api_main_t api_global_main = { + .region_name = "/unset", + .api_uid = -1, + .api_gid = -1, +}; /* *INDENT-ON* */ +/* Please use vlibapi_get_main() to access my_api_main */ +__thread api_main_t *my_api_main = &api_global_main; + +void +vl_msg_api_set_global_main (void *am_arg) +{ + ASSERT (am_arg); + my_api_main = (api_main_t *) am_arg; +} + void vl_msg_api_increment_missing_client_counter (void) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); am->missing_clients++; } @@ -69,13 +79,11 @@ vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg) u8 **old_trace; u8 *msg_copy; u32 length; - trace_cfg_t *cfgp; - u16 msg_id = ntohs (*((u16 *) msg)); + u16 msg_id = clib_net_to_host_u16 (*((u16 *) msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id); msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data)); - cfgp = am->api_trace_cfg + msg_id; - - if (!cfgp || !cfgp->trace_enable) + if (!m || !m->trace_enable) return; msg_copy = 0; @@ -97,14 +105,16 @@ vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg) old_trace = tp->traces + tp->curindex++; if (tp->curindex == tp->nitems) tp->curindex = 0; - vec_free (*old_trace); + /* Reuse the trace record, may save some memory allocator traffic */ + msg_copy = *old_trace; + vec_reset_length (msg_copy); this_trace = old_trace; } length = clib_net_to_host_u32 (header->data_len); vec_validate (msg_copy, length - 1); - clib_memcpy (msg_copy, msg, length); + clib_memcpy_fast (msg_copy, msg, length); *this_trace = msg_copy; } @@ -187,80 +197,130 @@ vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which) return 0; } -int -vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp) +u8 * +vl_api_serialize_message_table (api_main_t * am, u8 * vector) { - vl_api_trace_t *tp; - vl_api_trace_file_header_t fh; - int i; - u8 *msg; + serialize_main_t _sm, *sm = &_sm; + hash_pair_t *hp; + u32 nmsg = hash_elts (am->msg_index_by_name_and_crc); - switch (which) - { - case VL_API_TRACE_TX: - tp = am->tx_trace; - break; + serialize_open_vector (sm, vector); - case VL_API_TRACE_RX: - tp = am->rx_trace; - break; + /* serialize the count */ + serialize_integer (sm, nmsg, sizeof (u32)); - default: - /* duh? */ - return -1; - } + /* *INDENT-OFF* */ + hash_foreach_pair (hp, am->msg_index_by_name_and_crc, + ({ + serialize_likely_small_unsigned_integer (sm, hp->value[0]); + serialize_cstring (sm, (char *) hp->key); + })); + /* *INDENT-ON* */ - /* Configured, data present? */ - if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0) - return -1; + return serialize_close_vector (sm); +} - /* "Dare to be stupid" check */ - if (fp == 0) +static int +vl_msg_api_trace_write_one (api_main_t *am, u8 *msg, FILE *fp) +{ + u8 *tmpmem = 0; + int tlen, slen; + + u32 msg_length = vec_len (msg); + vec_validate (tmpmem, msg_length - 1); + clib_memcpy_fast (tmpmem, msg, msg_length); + u16 id = clib_net_to_host_u16 (*((u16 *) msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, id); + + if (m && m->endian_handler) { - return -2; + m->endian_handler (tmpmem); } - /* Write the file header */ - fh.nitems = vec_len (tp->traces); - fh.endian = tp->endian; - fh.wrapped = tp->wrapped; - - if (fwrite (&fh, sizeof (fh), 1, fp) != 1) + if (m && m->tojson_handler) { - return (-10); + cJSON *o = m->tojson_handler (tmpmem); + char *s = cJSON_Print (o); + slen = strlen (s); + tlen = fwrite (s, 1, slen, fp); + cJSON_free (s); + cJSON_Delete (o); + vec_free (tmpmem); + if (tlen != slen) + { + fformat (stderr, "writing to file error\n"); + return -11; + } } + else + fformat (stderr, " [no registered tojson fn]\n"); + + return 0; +} + +#define vl_msg_fwrite(_s, _f) fwrite (_s, 1, sizeof (_s) - 1, _f) + +typedef struct +{ + FILE *fp; + u32 n_traces; + u32 i; +} vl_msg_write_json_args_t; + +static int +vl_msg_write_json_fn (u8 *msg, void *ctx) +{ + vl_msg_write_json_args_t *arg = ctx; + FILE *fp = arg->fp; + api_main_t *am = vlibapi_get_main (); + int rc = vl_msg_api_trace_write_one (am, msg, fp); + if (rc < 0) + return rc; + + if (arg->i < arg->n_traces - 1) + vl_msg_fwrite (",\n", fp); + arg->i++; + return 0; +} + +static int +vl_msg_api_trace_write_json (api_main_t *am, vl_api_trace_t *tp, FILE *fp) +{ + vl_msg_write_json_args_t args; + clib_memset (&args, 0, sizeof (args)); + args.fp = fp; + args.n_traces = vec_len (tp->traces); + vl_msg_fwrite ("[\n", fp); + + int rv = vl_msg_traverse_trace (tp, vl_msg_write_json_fn, &args); + if (rv < 0) + return rv; + + vl_msg_fwrite ("]", fp); + return 0; +} + +int +vl_msg_traverse_trace (vl_api_trace_t *tp, vl_msg_traverse_trace_fn fn, + void *ctx) +{ + int i; + u8 *msg; + int rv = 0; /* No-wrap case */ if (tp->wrapped == 0) { - /* - * Note: vec_len return 0 when fed a NULL pointer. - * Unfortunately, the static analysis tool doesn't - * figure it out, hence the suppressed warnings. - * What a great use of my time. - */ for (i = 0; i < vec_len (tp->traces); i++) { - u32 msg_length; /*sa_ignore NO_NULL_CHK */ msg = tp->traces[i]; - /* - * This retarded check required to pass - * [sic] SA-checking. - */ if (!msg) continue; - msg_length = clib_host_to_net_u32 (vec_len (msg)); - if (fwrite (&msg_length, 1, sizeof (msg_length), fp) - != sizeof (msg_length)) - { - return (-14); - } - if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg)) - { - return (-11); - } + rv = fn (msg, ctx); + if (rv < 0) + return rv; } } else @@ -268,56 +328,103 @@ vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp) /* Wrap case: write oldest -> end of buffer */ for (i = tp->curindex; i < vec_len (tp->traces); i++) { - u32 msg_length; msg = tp->traces[i]; - /* - * This retarded check required to pass - * [sic] SA-checking - */ if (!msg) continue; - msg_length = clib_host_to_net_u32 (vec_len (msg)); - if (fwrite (&msg_length, 1, sizeof (msg_length), fp) - != sizeof (msg_length)) - { - return (-14); - } - - if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg)) - { - return (-12); - } + rv = fn (msg, ctx); + if (rv < 0) + return rv; } /* write beginning of buffer -> oldest-1 */ for (i = 0; i < tp->curindex; i++) { - u32 msg_length; /*sa_ignore NO_NULL_CHK */ msg = tp->traces[i]; - /* - * This retarded check required to pass - * [sic] SA-checking - */ if (!msg) continue; - msg_length = clib_host_to_net_u32 (vec_len (msg)); - if (fwrite (&msg_length, 1, sizeof (msg_length), fp) - != sizeof (msg_length)) - { - return (-14); - } - - if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg)) - { - return (-13); - } + rv = fn (msg, ctx); + if (rv < 0) + return rv; } } return 0; } +static int +vl_api_msg_write_fn (u8 *msg, void *ctx) +{ + FILE *fp = ctx; + u32 msg_length = clib_host_to_net_u32 (vec_len (msg)); + if (fwrite (&msg_length, 1, sizeof (msg_length), fp) != sizeof (msg_length)) + { + return (-14); + } + if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg)) + { + return (-14); + } + return 0; +} + +int +vl_msg_api_trace_save (api_main_t *am, vl_api_trace_which_t which, FILE *fp, + u8 is_json) +{ + vl_api_trace_t *tp; + vl_api_trace_file_header_t fh; + + switch (which) + { + case VL_API_TRACE_TX: + tp = am->tx_trace; + break; + + case VL_API_TRACE_RX: + tp = am->rx_trace; + break; + + default: + /* duh? */ + return -1; + } + + /* Configured, data present? */ + if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0) + return -1; + + /* "Dare to be stupid" check */ + if (fp == 0) + { + return -2; + } + + if (is_json) + return vl_msg_api_trace_write_json (am, tp, fp); + + /* Write the file header */ + fh.wrapped = tp->wrapped; + fh.nitems = clib_host_to_net_u32 (vec_len (tp->traces)); + + u8 *m = vl_api_serialize_message_table (am, 0); + fh.msgtbl_size = clib_host_to_net_u32 (vec_len (m)); + + if (fwrite (&fh, sizeof (fh), 1, fp) != 1) + { + return (-10); + } + + /* Write the message table */ + if (fwrite (m, vec_len (m), 1, fp) != 1) + { + return (-14); + } + vec_free (m); + + return vl_msg_traverse_trace (tp, vl_api_msg_write_fn, fp); +} + int vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which, u32 nitems) @@ -360,7 +467,7 @@ vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which, vl_msg_api_trace_free (am, which); } - memset (tp, 0, sizeof (*tp)); + clib_memset (tp, 0, sizeof (*tp)); if (clib_arch_is_big_endian) { @@ -390,186 +497,160 @@ vl_msg_api_barrier_release (void) } always_inline void -msg_handler_internal (api_main_t * am, - void *the_msg, int trace_it, int do_it, int free_it) +msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len, + int trace_it, int do_it, int free_it) { - u16 id = ntohs (*((u16 *) the_msg)); - u8 *(*print_fp) (void *, void *); + u16 id = clib_net_to_host_u16 (*((u16 *) the_msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, id); - if (id < vec_len (am->msg_handlers) && am->msg_handlers[id]) + if (PREDICT_FALSE (am->elog_trace_api_messages)) + { + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "api-msg: %s", + .format_args = "T4", + }; + /* *INDENT-ON* */ + struct + { + u32 c; + } *ed; + ed = ELOG_DATA (am->elog_main, e); + if (m && m->name) + ed->c = elog_string (am->elog_main, (char *) m->name); + else + ed->c = elog_string (am->elog_main, "BOGUS"); + } + + if (m && m->handler) { if (trace_it) vl_msg_api_trace (am, am->rx_trace, the_msg); if (am->msg_print_flag) { - fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]); - print_fp = (void *) am->msg_print_handlers[id]; - if (print_fp == 0) - { - fformat (stdout, " [no registered print fn]\n"); - } - else + fformat (stdout, "[%d]: %s\n", id, m->name); + fformat (stdout, "%U", format_vl_api_msg_text, am, id, the_msg); + } + + uword calc_size = 0; + ASSERT (NULL != m->calc_size_func); + if (m->calc_size_func) + { + calc_size = m->calc_size_func (the_msg); + if (calc_size > msg_len) { - (*print_fp) (the_msg, stdout); + clib_warning ( + "Truncated message '%s' (id %u) received, calculated size " + "%lu is bigger than actual size %llu, message dropped.", + m->name, id, calc_size, msg_len); } } + else + { + clib_warning ("Message '%s' (id %u) has NULL calc_size_func, cannot " + "verify message size is correct", + m->name, id); + } - if (do_it) + /* don't process message if it's truncated, otherwise byte swaps + * and stuff could corrupt memory even beyond message if it's malicious + * e.g. VLA length field set to 1M elements, but VLA empty */ + if (do_it && calc_size <= msg_len) { - if (!am->is_mp_safe[id]) + + if (!m->is_mp_safe) { vl_msg_api_barrier_trace_context (am->msg_names[id]); vl_msg_api_barrier_sync (); } - (*am->msg_handlers[id]) (the_msg); - if (!am->is_mp_safe[id]) - vl_msg_api_barrier_release (); - } - } - else - { - clib_warning ("no handler for msg id %d", id); - } - if (free_it) - vl_msg_api_free (the_msg); -} + if (m->is_autoendian) + m->endian_handler (the_msg); -/* set to 1 if you want before/after message handler event logging */ -#define ELOG_API_MESSAGE_HANDLERS 0 + if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) + clib_call_callbacks (am->perf_counter_cbs, am, id, + 0 /* before */ ); -#if ELOG_API_MESSAGE_HANDLERS > 0 -static u32 -elog_id_for_msg_name (vlib_main_t * vm, char *msg_name) -{ - uword *p, r; - static uword *h; - u8 *name_copy; + m->handler (the_msg); - if (!h) - h = hash_create_string (0, sizeof (uword)); - - p = hash_get_mem (h, msg_name); - if (p) - return p[0]; - r = elog_string (&vm->elog_main, "%s", msg_name); - - name_copy = format (0, "%s%c", msg_name, 0); - - hash_set_mem (h, name_copy, r); - - return r; -} -#endif - -/* This is only to be called from a vlib/vnet app */ -void -vl_msg_api_handler_with_vm_node (api_main_t * am, - void *the_msg, vlib_main_t * vm, - vlib_node_runtime_t * node) -{ - u16 id = ntohs (*((u16 *) the_msg)); - u8 *(*handler) (void *, void *, void *); + if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) + clib_call_callbacks (am->perf_counter_cbs, am, id, + 1 /* after */ ); -#if ELOG_API_MESSAGE_HANDLERS > 0 - { - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = - { - .format = "api-msg: %s", - .format_args = "T4", - }; - /* *INDENT-ON* */ - struct - { - u32 c; - } *ed; - ed = ELOG_DATA (&vm->elog_main, e); - if (id < vec_len (am->msg_names)) - ed->c = elog_id_for_msg_name (vm, am->msg_names[id]); - else - ed->c = elog_id_for_msg_name (vm, "BOGUS"); - } -#endif - - if (id < vec_len (am->msg_handlers) && am->msg_handlers[id]) - { - handler = (void *) am->msg_handlers[id]; - - if (am->rx_trace && am->rx_trace->enabled) - vl_msg_api_trace (am, am->rx_trace, the_msg); - - if (!am->is_mp_safe[id]) - { - vl_msg_api_barrier_trace_context (am->msg_names[id]); - vl_msg_api_barrier_sync (); + if (!m->is_mp_safe) + vl_msg_api_barrier_release (); } - (*handler) (the_msg, vm, node); - if (!am->is_mp_safe[id]) - vl_msg_api_barrier_release (); } else { clib_warning ("no handler for msg id %d", id); } - /* - * Special-case, so we can e.g. bounce messages off the vnet - * main thread without copying them... - */ - if (!(am->message_bounce[id])) + if (free_it) vl_msg_api_free (the_msg); -#if ELOG_API_MESSAGE_HANDLERS > 0 - { - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = { - .format = "api-msg-done: %s", - .format_args = "T4", - }; - /* *INDENT-ON* */ - - struct + if (PREDICT_FALSE (am->elog_trace_api_messages)) { - u32 c; - } *ed; - ed = ELOG_DATA (&vm->elog_main, e); - if (id < vec_len (am->msg_names)) - ed->c = elog_id_for_msg_name (vm, am->msg_names[id]); - else - ed->c = elog_id_for_msg_name (vm, "BOGUS"); - } -#endif + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "api-msg-done(%s): %s", + .format_args = "t4T4", + .n_enum_strings = 2, + .enum_strings = + { + "barrier", + "mp-safe", + } + }; + /* *INDENT-ON* */ + + struct + { + u32 barrier; + u32 c; + } *ed; + ed = ELOG_DATA (am->elog_main, e); + if (m && m->name) + { + ed->c = elog_string (am->elog_main, (char *) m->name); + ed->barrier = !m->is_mp_safe; + } + else + { + ed->c = elog_string (am->elog_main, "BOGUS"); + ed->barrier = 0; + } + } } void -vl_msg_api_handler (void *the_msg) +vl_msg_api_handler (void *the_msg, uword msg_len) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); - msg_handler_internal (am, the_msg, - (am->rx_trace - && am->rx_trace->enabled) /* trace_it */ , - 1 /* do_it */ , 1 /* free_it */ ); + msg_handler_internal (am, the_msg, msg_len, + (am->rx_trace && am->rx_trace->enabled) /* trace_it */, + 1 /* do_it */, 1 /* free_it */); } void -vl_msg_api_handler_no_free (void *the_msg) +vl_msg_api_handler_no_free (void *the_msg, uword msg_len) { - api_main_t *am = &api_main; - msg_handler_internal (am, the_msg, - (am->rx_trace - && am->rx_trace->enabled) /* trace_it */ , - 1 /* do_it */ , 0 /* free_it */ ); + api_main_t *am = vlibapi_get_main (); + msg_handler_internal (am, the_msg, msg_len, + (am->rx_trace && am->rx_trace->enabled) /* trace_it */, + 1 /* do_it */, 0 /* free_it */); } void -vl_msg_api_handler_no_trace_no_free (void *the_msg) +vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len) { - api_main_t *am = &api_main; - msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ , - 0 /* free_it */ ); + api_main_t *am = vlibapi_get_main (); + msg_handler_internal (am, the_msg, msg_len, 0 /* trace_it */, 1 /* do_it */, + 0 /* free_it */); } /* @@ -582,29 +663,30 @@ vl_msg_api_handler_no_trace_no_free (void *the_msg) * */ void -vl_msg_api_trace_only (void *the_msg) +vl_msg_api_trace_only (void *the_msg, uword msg_len) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); - msg_handler_internal (am, the_msg, - (am->rx_trace - && am->rx_trace->enabled) /* trace_it */ , - 0 /* do_it */ , 0 /* free_it */ ); + msg_handler_internal (am, the_msg, msg_len, + (am->rx_trace && am->rx_trace->enabled) /* trace_it */, + 0 /* do_it */, 0 /* free_it */); } void vl_msg_api_cleanup_handler (void *the_msg) { - api_main_t *am = &api_main; - u16 id = ntohs (*((u16 *) the_msg)); + api_main_t *am = vlibapi_get_main (); + u16 id = clib_net_to_host_u16 (*((u16 *) the_msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, id); - if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers))) + if (PREDICT_FALSE (!m)) { clib_warning ("_vl_msg_id too large: %d\n", id); return; } - if (am->msg_cleanup_handlers[id]) - (*am->msg_cleanup_handlers[id]) (the_msg); + + if (m->cleanup_handler) + m->cleanup_handler (the_msg); vl_msg_api_free (the_msg); } @@ -615,18 +697,18 @@ vl_msg_api_cleanup_handler (void *the_msg) void vl_msg_api_replay_handler (void *the_msg) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); + u16 id = clib_net_to_host_u16 (*((u16 *) the_msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, id); - u16 id = ntohs (*((u16 *) the_msg)); - - if (PREDICT_FALSE (id >= vec_len (am->msg_handlers))) + if (PREDICT_FALSE (!m)) { clib_warning ("_vl_msg_id too large: %d\n", id); return; } /* do NOT trace the message... */ - if (am->msg_handlers[id]) - (*am->msg_handlers[id]) (the_msg); + if (m->handler) + m->handler (the_msg); /* do NOT free the message buffer... */ } @@ -640,99 +722,116 @@ vl_msg_api_get_msg_length (void *msg_arg) * vl_msg_api_socket_handler */ void -vl_msg_api_socket_handler (void *the_msg) +vl_msg_api_socket_handler (void *the_msg, uword msg_len) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); - msg_handler_internal (am, the_msg, - (am->rx_trace - && am->rx_trace->enabled) /* trace_it */ , - 1 /* do_it */ , 0 /* free_it */ ); + msg_handler_internal (am, the_msg, msg_len, + (am->rx_trace && am->rx_trace->enabled) /* trace_it */, + 1 /* do_it */, 0 /* free_it */); } -#define foreach_msg_api_vector \ -_(msg_names) \ -_(msg_handlers) \ -_(msg_cleanup_handlers) \ -_(msg_endian_handlers) \ -_(msg_print_handlers) \ -_(api_trace_cfg) \ -_(message_bounce) \ -_(is_mp_safe) - void vl_msg_api_config (vl_msg_api_msg_config_t * c) { - api_main_t *am = &api_main; - - ASSERT (c->id > 0); - -#define _(a) vec_validate (am->a, c->id); - foreach_msg_api_vector; -#undef _ - - if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler) - clib_warning - ("BUG: re-registering 'vl_api_%s_t_handler'." - "Handler was %llx, replaced by %llx", - c->name, am->msg_handlers[c->id], c->handler); + api_main_t *am = vlibapi_get_main (); + vl_api_msg_data_t *m; - am->msg_names[c->id] = c->name; - am->msg_handlers[c->id] = c->handler; - am->msg_cleanup_handlers[c->id] = c->cleanup; - am->msg_endian_handlers[c->id] = c->endian; - am->msg_print_handlers[c->id] = c->print; - am->message_bounce[c->id] = c->message_bounce; - am->is_mp_safe[c->id] = c->is_mp_safe; + /* + * This happens during the java core tests if the message + * dictionary is missing newly added xxx_reply_t messages. + * Should never happen, but since I shot myself in the foot once + * this way, I thought I'd make it easy to debug if I ever do + * it again... (;-)... + */ + if (c->id == 0) + { + if (c->name) + clib_warning ("Trying to register %s with a NULL msg id!", c->name); + else + clib_warning ("Trying to register a NULL msg with a NULL msg id!"); + clib_warning ("Did you forget to call setup_message_id_table?"); + return; + } - am->api_trace_cfg[c->id].size = c->size; - am->api_trace_cfg[c->id].trace_enable = c->traced; - am->api_trace_cfg[c->id].replay_enable = c->replay; + vec_validate (am->msg_data, c->id); + m = vl_api_get_msg_data (am, c->id); + + if (m->handler && m->handler != c->handler) + clib_warning ("BUG: re-registering 'vl_api_%s_t_handler'." + "Handler was %llx, replaced by %llx", + c->name, m->handler, c->handler); + + m->name = c->name; + m->handler = c->handler; + m->cleanup_handler = c->cleanup; + m->endian_handler = c->endian; + m->format_fn = c->format_fn; + m->tojson_handler = c->tojson; + m->fromjson_handler = c->fromjson; + m->calc_size_func = c->calc_size; + m->bounce = c->message_bounce; + m->is_mp_safe = c->is_mp_safe; + m->is_autoendian = c->is_autoendian; + + m->trace_size = c->size; + m->trace_enable = c->traced; + m->replay_allowed = c->replay; + + if (!am->msg_id_by_name) + am->msg_id_by_name = hash_create_string (0, sizeof (uword)); + + hash_set_mem (am->msg_id_by_name, c->name, c->id); } -/* - * vl_msg_api_set_handlers - * preserve the old API for a while - */ void -vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup, - void *endian, void *print, int size, int traced) +vl_msg_api_clean_handlers (int msg_id) { vl_msg_api_msg_config_t cfg; vl_msg_api_msg_config_t *c = &cfg; - memset (c, 0, sizeof (*c)); - - c->id = id; - c->name = name; - c->handler = handler; - c->cleanup = cleanup; - c->endian = endian; - c->print = print; - c->traced = traced; - c->replay = 1; - c->message_bounce = 0; - c->is_mp_safe = 0; + clib_memset (c, 0, sizeof (*c)); + + c->id = msg_id; vl_msg_api_config (c); } void vl_msg_api_set_cleanup_handler (int msg_id, void *fp) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id); ASSERT (msg_id > 0); - vec_validate (am->msg_cleanup_handlers, msg_id); - am->msg_cleanup_handlers[msg_id] = fp; + m->cleanup_handler = fp; } void -vl_msg_api_queue_handler (unix_shared_memory_queue_t * q) +vl_msg_api_queue_handler (svm_queue_t * q) { uword msg; - while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0)) - vl_msg_api_handler ((void *) msg); + while (!svm_queue_sub (q, (u8 *) &msg, SVM_Q_WAIT, 0)) + { + VL_MSG_API_UNPOISON ((u8 *) msg); + msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) msg - offsetof (msgbuf_t, data)); + vl_msg_api_handler ((void *) msg, ntohl (msgbuf->data_len)); + } +} + +u32 +vl_msg_api_max_length (void *mp) +{ + msgbuf_t *mb; + u32 data_len = ~0; + + /* Work out the maximum sane message length, and return it */ + if (PREDICT_TRUE (mp != 0)) + { + mb = (msgbuf_t *) (((u8 *) mp) - offsetof (msgbuf_t, data)); + data_len = clib_net_to_host_u32 (mb->data_len); + } + return data_len; } vl_api_trace_t * @@ -749,12 +848,6 @@ vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which) } } -void -vl_noop_handler (void *mp) -{ -} - - static u8 post_mortem_dump_enabled; void @@ -766,7 +859,7 @@ vl_msg_api_post_mortem_dump_enable_disable (int enable) void vl_msg_api_post_mortem_dump (void) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); FILE *fp; char filename[64]; int rv; @@ -785,7 +878,7 @@ vl_msg_api_post_mortem_dump (void) rv = write (2, "\n", 1); return; } - rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp); + rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp, 0); fclose (fp); if (rv < 0) { @@ -798,45 +891,10 @@ vl_msg_api_post_mortem_dump (void) /* Layered message handling support */ -void -vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order) -{ - api_main_t *am = &api_main; - - /* Mild idiot proofing */ - if (msg_id_host_byte_order > 10000) - clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d", - msg_id_host_byte_order, - clib_net_to_host_u16 (msg_id_host_byte_order)); - vec_validate (am->pd_msg_handlers, msg_id_host_byte_order); - am->pd_msg_handlers[msg_id_host_byte_order] = fp; -} - -int -vl_msg_api_pd_handler (void *mp, int rv) -{ - api_main_t *am = &api_main; - int (*fp) (void *, int); - u16 msg_id; - - if (clib_arch_is_little_endian) - msg_id = clib_net_to_host_u16 (*((u16 *) mp)); - else - msg_id = *((u16 *) mp); - - if (msg_id >= vec_len (am->pd_msg_handlers) - || am->pd_msg_handlers[msg_id] == 0) - return rv; - - fp = am->pd_msg_handlers[msg_id]; - rv = (*fp) (mp, rv); - return rv; -} - void vl_msg_api_set_first_available_msg_id (u16 first_avail) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); am->first_available_msg_id = first_avail; } @@ -844,7 +902,7 @@ vl_msg_api_set_first_available_msg_id (u16 first_avail) u16 vl_msg_api_get_msg_ids (const char *name, int n) { - api_main_t *am = &api_main; + api_main_t *am = vlibapi_get_main (); u8 *name_copy; vl_api_msg_range_t *rp; uword *p; @@ -903,6 +961,153 @@ vl_msg_api_add_msg_name_crc (api_main_t * am, const char *string, u32 id) hash_set_mem (am->msg_index_by_name_and_crc, string, id); } +void +vl_msg_api_add_version (api_main_t * am, const char *string, + u32 major, u32 minor, u32 patch) +{ + api_version_t version = {.major = major,.minor = minor,.patch = patch }; + ASSERT (strlen (string) < 64); + strncpy (version.name, string, 64 - 1); + vec_add1 (am->api_version_list, version); +} + +u32 +vl_msg_api_get_msg_index (u8 * name_and_crc) +{ + api_main_t *am = vlibapi_get_main (); + uword *p; + + if (am->msg_index_by_name_and_crc) + { + p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc); + if (p) + return p[0]; + } + return ~0; +} + +void * +vl_msg_push_heap_w_region (svm_region_t * vlib_rp) +{ + pthread_mutex_lock (&vlib_rp->mutex); + return svm_push_data_heap (vlib_rp); +} + +void * +vl_msg_push_heap (void) +{ + api_main_t *am = vlibapi_get_main (); + return vl_msg_push_heap_w_region (am->vlib_rp); +} + +void +vl_msg_pop_heap_w_region (svm_region_t * vlib_rp, void *oldheap) +{ + svm_pop_heap (oldheap); + pthread_mutex_unlock (&vlib_rp->mutex); +} + +void +vl_msg_pop_heap (void *oldheap) +{ + api_main_t *am = vlibapi_get_main (); + vl_msg_pop_heap_w_region (am->vlib_rp, oldheap); +} + +/* Must be nul terminated */ +int +vl_api_c_string_to_api_string (const char *buf, vl_api_string_t * str) +{ + /* copy without nul terminator */ + u32 len = strlen (buf); + if (len > 0) + clib_memcpy_fast (str->buf, buf, len); + str->length = htonl (len); + return len + sizeof (u32); +} + +/* Must NOT be nul terminated */ +int +vl_api_vec_to_api_string (const u8 * vec, vl_api_string_t * str) +{ + u32 len = vec_len (vec); + clib_memcpy (str->buf, vec, len); + str->length = htonl (len); + return len + sizeof (u32); +} + +u32 +vl_api_string_len (vl_api_string_t * astr) +{ + return clib_net_to_host_u32 (astr->length); +} + +u8 * +vl_api_format_string (u8 * s, va_list * args) +{ + vl_api_string_t *a = va_arg (*args, vl_api_string_t *); + vec_add (s, a->buf, clib_net_to_host_u32 (a->length)); + return s; +} + +/* + * Returns a new vector. Remember to free it after use. + * NOT nul terminated. + */ +u8 * +vl_api_from_api_to_new_vec (void *mp, vl_api_string_t * astr) +{ + u8 *v = 0; + + if (vl_msg_api_max_length (mp) < clib_net_to_host_u32 (astr->length)) + return format (0, "Invalid astr->length %u > max (%u)%c", + clib_net_to_host_u32 (astr->length), + vl_msg_api_max_length (mp), 0); + vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length)); + return v; +} + +/* + * Returns a new vector. Remember to free it after use. + * Nul terminated. + */ +char * +vl_api_from_api_to_new_c_string (vl_api_string_t * astr) +{ + char *v = 0; + if (clib_net_to_host_u32 (astr->length) > 0) + { + vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length)); + vec_add1 (v, 0); + } + return v; +} + +void +vl_api_set_elog_main (elog_main_t * m) +{ + api_main_t *am = vlibapi_get_main (); + am->elog_main = m; +} + +int +vl_api_set_elog_trace_api_messages (int enable) +{ + int rv; + api_main_t *am = vlibapi_get_main (); + + rv = am->elog_trace_api_messages; + am->elog_trace_api_messages = enable; + return rv; +} + +int +vl_api_get_elog_trace_api_messages (void) +{ + api_main_t *am = vlibapi_get_main (); + + return am->elog_trace_api_messages; +} /* * fd.io coding-style-patch-verification: ON