diff options
Diffstat (limited to 'src/vlibmemory/memory_api.c')
-rw-r--r-- | src/vlibmemory/memory_api.c | 304 |
1 files changed, 253 insertions, 51 deletions
diff --git a/src/vlibmemory/memory_api.c b/src/vlibmemory/memory_api.c index 4287bd36e5f..39c6b0fd15b 100644 --- a/src/vlibmemory/memory_api.c +++ b/src/vlibmemory/memory_api.c @@ -28,7 +28,6 @@ #undef vl_typedefs /* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) #define vl_printfun #include <vlibmemory/vl_memory_api_h.h> #undef vl_printfun @@ -38,26 +37,6 @@ #include <vlibmemory/vl_memory_api_h.h> #undef vl_endianfun -static inline void * -vl_api_memclnt_create_t_print (vl_api_memclnt_create_t * a, void *handle) -{ - vl_print (handle, "vl_api_memclnt_create_t:\n"); - vl_print (handle, "name: %s\n", a->name); - vl_print (handle, "input_queue: 0x%wx\n", a->input_queue); - vl_print (handle, "context: %u\n", (unsigned) a->context); - vl_print (handle, "ctx_quota: %ld\n", (long) a->ctx_quota); - return handle; -} - -static inline void * -vl_api_memclnt_delete_t_print (vl_api_memclnt_delete_t * a, void *handle) -{ - vl_print (handle, "vl_api_memclnt_delete_t:\n"); - vl_print (handle, "index: %u\n", (unsigned) a->index); - vl_print (handle, "handle: 0x%wx\n", a->handle); - return handle; -} - volatile int **vl_api_queue_cursizes; static void @@ -212,6 +191,7 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp) regp->name = format (0, "%s", mp->name); vec_add1 (regp->name, 0); + regp->keepalive = true; if (am->serialized_message_table_in_shmem == 0) am->serialized_message_table_in_shmem = @@ -238,6 +218,87 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp) } void +vl_api_memclnt_create_v2_t_handler (vl_api_memclnt_create_v2_t *mp) +{ + vl_api_registration_t **regpp; + vl_api_registration_t *regp; + vl_api_memclnt_create_v2_reply_t *rp; + svm_queue_t *q; + int rv = 0; + void *oldheap; + api_main_t *am = vlibapi_get_main (); + u8 *msg_table; + + /* + * This is tortured. Maintain a vlib-address-space private + * pool of client registrations. We use the shared-memory virtual + * address of client structure as a handle, to allow direct + * manipulation of context quota vbls from the client library. + * + * This scheme causes trouble w/ API message trace replay, since + * some random VA from clib_mem_alloc() certainly won't + * occur in the Linux sim. The (very) few places + * that care need to use the pool index. + * + * Putting the registration object(s) into a pool in shared memory and + * using the pool index as a handle seems like a great idea. + * Unfortunately, each and every reference to that pool would need + * to be protected by a mutex: + * + * Client VLIB + * ------ ---- + * convert pool index to + * pointer. + * <deschedule> + * expand pool + * <deschedule> + * kaboom! + */ + + pool_get (am->vl_clients, regpp); + + oldheap = vl_msg_push_heap (); + *regpp = clib_mem_alloc (sizeof (vl_api_registration_t)); + + regp = *regpp; + clib_memset (regp, 0, sizeof (*regp)); + regp->registration_type = REGISTRATION_TYPE_SHMEM; + regp->vl_api_registration_pool_index = regpp - am->vl_clients; + regp->vlib_rp = am->vlib_rp; + regp->shmem_hdr = am->shmem_hdr; + regp->clib_file_index = am->shmem_hdr->clib_file_index; + + q = regp->vl_input_queue = (svm_queue_t *) (uword) mp->input_queue; + VL_MSG_API_SVM_QUEUE_UNPOISON (q); + + regp->name = format (0, "%s", mp->name); + vec_add1 (regp->name, 0); + regp->keepalive = mp->keepalive; + + if (am->serialized_message_table_in_shmem == 0) + am->serialized_message_table_in_shmem = + vl_api_serialize_message_table (am, 0); + + if (am->vlib_rp != am->vlib_primary_rp) + msg_table = vl_api_serialize_message_table (am, 0); + else + msg_table = am->serialized_message_table_in_shmem; + + vl_msg_pop_heap (oldheap); + + rp = vl_msg_api_alloc (sizeof (*rp)); + rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2_REPLY); + rp->handle = (uword) regp; + rp->index = vl_msg_api_handle_from_index_and_epoch ( + regp->vl_api_registration_pool_index, am->shmem_hdr->application_restarts); + rp->context = mp->context; + rp->response = ntohl (rv); + rp->message_table = pointer_to_uword (msg_table); + + vl_msg_api_send_shmem (q, (u8 *) &rp); +} + +void vl_api_call_reaper_functions (u32 client_index) { clib_error_t *error = 0; @@ -417,11 +478,12 @@ vl_api_memclnt_keepalive_t_handler (vl_api_memclnt_keepalive_t * mp) * don't trace memclnt_keepalive[_reply] msgs */ -#define foreach_vlib_api_msg \ -_(MEMCLNT_CREATE, memclnt_create, 1) \ -_(MEMCLNT_DELETE, memclnt_delete, 1) \ -_(MEMCLNT_KEEPALIVE, memclnt_keepalive, 0) \ -_(MEMCLNT_KEEPALIVE_REPLY, memclnt_keepalive_reply, 0) +#define foreach_vlib_api_msg \ + _ (MEMCLNT_CREATE, memclnt_create, 0) \ + _ (MEMCLNT_CREATE_V2, memclnt_create_v2, 0) \ + _ (MEMCLNT_DELETE, memclnt_delete, 0) \ + _ (MEMCLNT_KEEPALIVE, memclnt_keepalive, 0) \ + _ (MEMCLNT_KEEPALIVE_REPLY, memclnt_keepalive_reply, 0) /* * memory_api_init @@ -441,29 +503,40 @@ vl_mem_api_init (const char *region_name) if ((rv = vl_map_shmem (region_name, 1 /* is_vlib */ )) < 0) return rv; -#define _(N,n,t) do { \ - c->id = VL_API_##N; \ - c->name = #n; \ - c->handler = vl_api_##n##_t_handler; \ - c->cleanup = vl_noop_handler; \ - c->endian = vl_api_##n##_t_endian; \ - c->print = vl_api_##n##_t_print; \ - c->size = sizeof(vl_api_##n##_t); \ - c->traced = t; /* trace, so these msgs print */ \ - c->replay = 0; /* don't replay client create/delete msgs */ \ - c->message_bounce = 0; /* don't bounce this message */ \ - vl_msg_api_config(c);} while (0); +#define _(N, n, t) \ + do \ + { \ + c->id = VL_API_##N; \ + c->name = #n; \ + c->handler = vl_api_##n##_t_handler; \ + c->endian = vl_api_##n##_t_endian; \ + c->format_fn = vl_api_##n##_t_format; \ + c->size = sizeof (vl_api_##n##_t); \ + c->traced = t; /* trace, so these msgs print */ \ + c->replay = 0; /* don't replay client create/delete msgs */ \ + c->message_bounce = 0; /* don't bounce this message */ \ + vl_msg_api_config (c); \ + } \ + while (0); foreach_vlib_api_msg; #undef _ +#define vl_msg_name_crc_list +#include <vlibmemory/memclnt.api.h> +#undef vl_msg_name_crc_list + +#define _(id, n, crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); + foreach_vl_msg_name_crc_memclnt; +#undef _ + /* * special-case freeing of memclnt_delete messages, so we can * simply munmap pairwise / private API segments... */ - am->message_bounce[VL_API_MEMCLNT_DELETE] = 1; - am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE_REPLY] = 1; - am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE] = 1; + am->msg_data[VL_API_MEMCLNT_DELETE].bounce = 1; + vl_api_set_msg_thread_safe (am, VL_API_MEMCLNT_KEEPALIVE_REPLY, 1); + vl_api_set_msg_thread_safe (am, VL_API_MEMCLNT_KEEPALIVE, 1); vlib_set_queue_signal_callback (vm, memclnt_queue_callback); @@ -588,12 +661,12 @@ vl_mem_api_dead_client_scan (api_main_t * am, vl_shmem_hdr_t * shm, f64 now) vec_reset_length (dead_indices); vec_reset_length (confused_indices); - /* *INDENT-OFF* */ pool_foreach (regpp, am->vl_clients) { + if (!(*regpp)->keepalive) + continue; vl_mem_send_client_keepalive_w_reg (am, now, regpp, &dead_indices, - &confused_indices); + &confused_indices); } - /* *INDENT-ON* */ /* This should "never happen," but if it does, fix it... */ if (PREDICT_FALSE (vec_len (confused_indices) > 0)) @@ -686,6 +759,139 @@ vl_mem_api_dead_client_scan (api_main_t * am, vl_shmem_hdr_t * shm, f64 now) } } +void (*vl_mem_api_fuzz_hook) (u16, void *); + +/* This is only to be called from a vlib/vnet app */ +static void +vl_mem_api_handler_with_vm_node (api_main_t *am, svm_region_t *vlib_rp, + void *the_msg, vlib_main_t *vm, + vlib_node_runtime_t *node, u8 is_private) +{ + u16 id = clib_net_to_host_u16 (*((u16 *) the_msg)); + vl_api_msg_data_t *m = vl_api_get_msg_data (am, id); + u8 *(*handler) (void *, void *, void *); + svm_region_t *old_vlib_rp; + void *save_shmem_hdr; + int is_mp_safe = 1; + + if (PREDICT_FALSE (am->elog_trace_api_messages)) + { + ELOG_TYPE_DECLARE (e) = { + .format = "api-msg: %s", + .format_args = "T4", + }; + 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) + { + handler = (void *) m->handler; + + if (PREDICT_FALSE (am->rx_trace && am->rx_trace->enabled)) + vl_msg_api_trace (am, am->rx_trace, the_msg); + + if (PREDICT_FALSE (am->msg_print_flag)) + { + fformat (stdout, "[%d]: %s\n", id, m->name); + fformat (stdout, "%U", format_vl_api_msg_text, am, id, the_msg); + } + is_mp_safe = am->msg_data[id].is_mp_safe; + + if (!is_mp_safe) + { + vl_msg_api_barrier_trace_context (am->msg_data[id].name); + vl_msg_api_barrier_sync (); + } + if (is_private) + { + old_vlib_rp = am->vlib_rp; + save_shmem_hdr = am->shmem_hdr; + am->vlib_rp = vlib_rp; + am->shmem_hdr = (void *) vlib_rp->user_ctx; + } + + if (PREDICT_FALSE (vl_mem_api_fuzz_hook != 0)) + (*vl_mem_api_fuzz_hook) (id, the_msg); + + if (m->is_autoendian) + { + void (*endian_fp) (void *); + endian_fp = am->msg_data[id].endian_handler; + (*endian_fp) (the_msg); + } + if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) + clib_call_callbacks (am->perf_counter_cbs, am, id, 0 /* before */); + + (*handler) (the_msg, vm, node); + + if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) + clib_call_callbacks (am->perf_counter_cbs, am, id, 1 /* after */); + if (is_private) + { + am->vlib_rp = old_vlib_rp; + am->shmem_hdr = save_shmem_hdr; + } + if (!is_mp_safe) + 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 (!m || !m->bounce) + { + if (is_private) + { + old_vlib_rp = am->vlib_rp; + save_shmem_hdr = am->shmem_hdr; + am->vlib_rp = vlib_rp; + am->shmem_hdr = (void *) vlib_rp->user_ctx; + } + vl_msg_api_free (the_msg); + if (is_private) + { + am->vlib_rp = old_vlib_rp; + am->shmem_hdr = save_shmem_hdr; + } + } + + if (PREDICT_FALSE (am->elog_trace_api_messages)) + { + ELOG_TYPE_DECLARE (e) = { .format = "api-msg-done(%s): %s", + .format_args = "t4T4", + .n_enum_strings = 2, + .enum_strings = { + "barrier", + "mp-safe", + } }; + + 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); + else + ed->c = elog_string (am->elog_main, "BOGUS"); + ed->barrier = is_mp_safe; + } +} + static inline int void_mem_api_handle_msg_i (api_main_t * am, svm_region_t * vlib_rp, vlib_main_t * vm, vlib_node_runtime_t * node, @@ -699,7 +905,7 @@ void_mem_api_handle_msg_i (api_main_t * am, svm_region_t * vlib_rp, if (!svm_queue_sub2 (q, (u8 *) & mp)) { VL_MSG_API_UNPOISON ((void *) mp); - vl_msg_api_handler_with_vm_node (am, vlib_rp, (void *) mp, vm, node, + vl_mem_api_handler_with_vm_node (am, vlib_rp, (void *) mp, vm, node, is_private); return 0; } @@ -749,8 +955,8 @@ vl_mem_api_handle_rpc (vlib_main_t * vm, vlib_node_runtime_t * node) for (i = 0; i < vec_len (vm->processing_rpc_requests); i++) { mp = vm->processing_rpc_requests[i]; - vl_msg_api_handler_with_vm_node (am, am->vlib_rp, (void *) mp, vm, - node, 0 /* is_private */ ); + vl_mem_api_handler_with_vm_node (am, am->vlib_rp, (void *) mp, vm, + node, 0 /* is_private */); } vl_msg_api_barrier_release (); } @@ -898,7 +1104,6 @@ vl_api_ring_command (vlib_main_t * vm, vl_api_registration_t *regp = 0; /* For horizontal scaling, add a hash table... */ - /* *INDENT-OFF* */ pool_foreach (regpp, am->vl_clients) { regp = *regpp; @@ -910,7 +1115,6 @@ vl_api_ring_command (vlib_main_t * vm, } vlib_cli_output (vm, "regp %llx not found?", regp); continue; - /* *INDENT-ON* */ found: vlib_cli_output (vm, "%U", format_api_message_rings, am, 0 /* print header */ , 0 /* notused */ ); @@ -924,14 +1128,12 @@ vl_api_ring_command (vlib_main_t * vm, /*? * Display binary api message allocation ring statistics ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (cli_show_api_ring_command, static) = { .path = "show api ring-stats", .short_help = "Message ring statistics", .function = vl_api_ring_command, }; -/* *INDENT-ON* */ clib_error_t * vlibmemory_init (vlib_main_t * vm) |