X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlibmemory%2Fmemory_client.c;h=c61c3cbdd5130babc38feababdd2fccd7848b88e;hb=920180e5e0722c78c258ff26476fd5efa434032d;hp=234a0a5a330d6319eb1b34b63268dd0eb112a22b;hpb=7cd468a3d7dee7d6c92f69a0bb7061ae208ec727;p=vpp.git diff --git a/src/vlibmemory/memory_client.c b/src/vlibmemory/memory_client.c index 234a0a5a330..c61c3cbdd51 100644 --- a/src/vlibmemory/memory_client.c +++ b/src/vlibmemory/memory_client.c @@ -17,33 +17,16 @@ *------------------------------------------------------------------ */ -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include + +/* A hack. vl_client_get_first_plugin_msg_id depends on it */ +#include #include @@ -61,23 +44,12 @@ #include #undef vl_printfun -typedef struct -{ - u8 rx_thread_jmpbuf_valid; - u8 connected_to_vlib; - jmp_buf rx_thread_jmpbuf; - pthread_t rx_thread_handle; - /* Plugin message base lookup scheme */ - volatile u8 first_msg_id_reply_ready; - u16 first_msg_id_reply; -} memory_client_main_t; - memory_client_main_t memory_client_main; static void * rx_thread_fn (void *arg) { - unix_shared_memory_queue_t *q; + svm_queue_t *q; memory_client_main_t *mm = &memory_client_main; api_main_t *am = &api_main; @@ -87,10 +59,9 @@ rx_thread_fn (void *arg) if (setjmp (mm->rx_thread_jmpbuf) == 0) { mm->rx_thread_jmpbuf_valid = 1; + clib_mem_set_thread_index (); while (1) - { - vl_msg_api_queue_handler (q); - } + vl_msg_api_queue_handler (q); } pthread_exit (0); } @@ -99,31 +70,277 @@ static void vl_api_rx_thread_exit_t_handler (vl_api_rx_thread_exit_t * mp) { memory_client_main_t *mm = &memory_client_main; - vl_msg_api_free (mp); - longjmp (mm->rx_thread_jmpbuf, 1); + if (mm->rx_thread_jmpbuf_valid) + longjmp (mm->rx_thread_jmpbuf, 1); } static void -noop_handler (void *notused) +vl_api_name_and_crc_free (void) { + api_main_t *am = &api_main; + int i; + u8 **keys = 0; + hash_pair_t *hp; + + if (!am->msg_index_by_name_and_crc) + return; + + /* *INDENT-OFF* */ + hash_foreach_pair (hp, am->msg_index_by_name_and_crc, + ({ + vec_add1 (keys, (u8 *) hp->key); + })); + /* *INDENT-ON* */ + for (i = 0; i < vec_len (keys); i++) + vec_free (keys[i]); + vec_free (keys); + hash_free (am->msg_index_by_name_and_crc); } -#define foreach_api_msg \ -_(RX_THREAD_EXIT, rx_thread_exit) +static void +vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp) +{ + serialize_main_t _sm, *sm = &_sm; + api_main_t *am = &api_main; + u8 *tblv; + u32 nmsgs; + int i; + u8 *name_and_crc; + u32 msg_index; + + am->my_client_index = mp->index; + am->my_registration = (vl_api_registration_t *) (uword) mp->handle; -static int -connect_to_vlib_internal (char *svm_name, char *client_name, - int rx_queue_size, int want_pthread) + /* Clean out any previous hash table (unlikely) */ + vl_api_name_and_crc_free (); + + am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword)); + + /* Recreate the vnet-side API message handler table */ + tblv = uword_to_pointer (mp->message_table, u8 *); + unserialize_open_data (sm, tblv, vec_len (tblv)); + unserialize_integer (sm, &nmsgs, sizeof (u32)); + + for (i = 0; i < nmsgs; i++) + { + msg_index = unserialize_likely_small_unsigned_integer (sm); + unserialize_cstring (sm, (char **) &name_and_crc); + hash_set_mem (am->msg_index_by_name_and_crc, name_and_crc, msg_index); + } +} + +static void +noop_handler (void *notused) +{ +} + +void vl_msg_api_send_shmem (svm_queue_t * q, u8 * elem); +int +vl_client_connect (const char *name, int ctx_quota, int input_queue_size) { + svm_region_t *svm; + vl_api_memclnt_create_t *mp; + vl_api_memclnt_create_reply_t *rp; + svm_queue_t *vl_input_queue; + vl_shmem_hdr_t *shmem_hdr; int rv = 0; - memory_client_main_t *mm = &memory_client_main; + void *oldheap; + api_main_t *am = &api_main; - if ((rv = vl_client_api_map (svm_name))) + if (am->my_registration) { - clib_warning ("vl_client_api map rv %d", rv); - return rv; + clib_warning ("client %s already connected...", name); + return -1; + } + + if (am->vlib_rp == 0) + { + clib_warning ("am->vlib_rp NULL"); + return -1; + } + + svm = am->vlib_rp; + shmem_hdr = am->shmem_hdr; + + if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0) + { + clib_warning ("shmem_hdr / input queue NULL"); + return -1; + } + + pthread_mutex_lock (&svm->mutex); + oldheap = svm_push_data_heap (svm); + vl_input_queue = svm_queue_alloc_and_init (input_queue_size, sizeof (uword), + getpid ()); + svm_pop_heap (oldheap); + pthread_mutex_unlock (&svm->mutex); + + am->my_client_index = ~0; + am->my_registration = 0; + am->vl_input_queue = vl_input_queue; + + mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_create_t)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE); + mp->ctx_quota = ctx_quota; + mp->input_queue = (uword) vl_input_queue; + strncpy ((char *) mp->name, name, sizeof (mp->name) - 1); + + vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp); + + while (1) + { + int qstatus; + struct timespec ts, tsrem; + int i; + + /* Wait up to 10 seconds */ + for (i = 0; i < 1000; i++) + { + qstatus = svm_queue_sub (vl_input_queue, (u8 *) & rp, + SVM_Q_NOWAIT, 0); + if (qstatus == 0) + goto read_one_msg; + ts.tv_sec = 0; + ts.tv_nsec = 10000 * 1000; /* 10 ms */ + while (nanosleep (&ts, &tsrem) < 0) + ts = tsrem; + } + /* Timeout... */ + clib_warning ("memclnt_create_reply timeout"); + return -1; + + read_one_msg: + if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_REPLY) + { + clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id)); + continue; + } + rv = clib_net_to_host_u32 (rp->response); + + vl_msg_api_handler ((void *) rp); + break; + } + return (rv); +} + +static void +vl_api_memclnt_delete_reply_t_handler (vl_api_memclnt_delete_reply_t * mp) +{ + void *oldheap; + api_main_t *am = &api_main; + + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + svm_queue_free (am->vl_input_queue); + pthread_mutex_unlock (&am->vlib_rp->mutex); + svm_pop_heap (oldheap); + + am->my_client_index = ~0; + am->my_registration = 0; + am->vl_input_queue = 0; +} + +void +vl_client_send_disconnect (u8 do_cleanup) +{ + vl_api_memclnt_delete_t *mp; + vl_shmem_hdr_t *shmem_hdr; + api_main_t *am = &api_main; + + ASSERT (am->vlib_rp); + shmem_hdr = am->shmem_hdr; + ASSERT (shmem_hdr && shmem_hdr->vl_input_queue); + + mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE); + mp->index = am->my_client_index; + mp->handle = (uword) am->my_registration; + mp->do_cleanup = do_cleanup; + + vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp); +} + +int +vl_client_disconnect (void) +{ + vl_api_memclnt_delete_reply_t *rp; + svm_queue_t *vl_input_queue; + api_main_t *am = &api_main; + time_t begin; + + vl_input_queue = am->vl_input_queue; + vl_client_send_disconnect (0 /* wait for reply */ ); + + /* + * Have to be careful here, in case the client is disconnecting + * because e.g. the vlib process died, or is unresponsive. + */ + begin = time (0); + while (1) + { + time_t now; + + now = time (0); + + if (now >= (begin + 2)) + { + clib_warning ("peer unresponsive, give up"); + am->my_client_index = ~0; + am->my_registration = 0; + am->shmem_hdr = 0; + return -1; + } + if (svm_queue_sub (vl_input_queue, (u8 *) & rp, SVM_Q_NOWAIT, 0) < 0) + continue; + + /* drain the queue */ + if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY) + { + clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id)); + vl_msg_api_handler ((void *) rp); + continue; + } + vl_msg_api_handler ((void *) rp); + break; } + vl_api_name_and_crc_free (); + return 0; +} + +/** + * Stave off the binary API dead client reaper + * Only sent to inactive clients + */ +static void +vl_api_memclnt_keepalive_t_handler (vl_api_memclnt_keepalive_t * mp) +{ + vl_api_memclnt_keepalive_reply_t *rmp; + api_main_t *am; + vl_shmem_hdr_t *shmem_hdr; + + am = &api_main; + shmem_hdr = am->shmem_hdr; + + rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_MEMCLNT_KEEPALIVE_REPLY); + rmp->context = mp->context; + vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & rmp); +} + +#define foreach_api_msg \ +_(RX_THREAD_EXIT, rx_thread_exit) \ +_(MEMCLNT_CREATE_REPLY, memclnt_create_reply) \ +_(MEMCLNT_DELETE_REPLY, memclnt_delete_reply) \ +_(MEMCLNT_KEEPALIVE, memclnt_keepalive) + +void +vl_client_install_client_message_handlers (void) +{ + #define _(N,n) \ vl_msg_api_set_handlers(VL_API_##N, #n, \ vl_api_##n##_t_handler, \ @@ -133,6 +350,47 @@ connect_to_vlib_internal (char *svm_name, char *client_name, sizeof(vl_api_##n##_t), 1); foreach_api_msg; #undef _ +} + +int +vl_client_api_map (const char *region_name) +{ + int rv; + + if ((rv = vl_map_shmem (region_name, 0 /* is_vlib */ )) < 0) + return rv; + + vl_client_install_client_message_handlers (); + return 0; +} + +void +vl_client_api_unmap (void) +{ + vl_unmap_shmem_client (); +} + +u8 +vl_mem_client_is_connected (void) +{ + return (memory_client_main.connected_to_vlib != 0); +} + +static int +connect_to_vlib_internal (const char *svm_name, + const char *client_name, + int rx_queue_size, void *(*thread_fn) (void *), + int do_map) +{ + int rv = 0; + memory_client_main_t *mm = &memory_client_main; + api_main_t *am = &api_main; + + if (do_map && (rv = vl_client_api_map (svm_name))) + { + clib_warning ("vl_client_api map rv %d", rv); + return rv; + } if (vl_client_connect (client_name, 0 /* punt quota */ , rx_queue_size /* input queue */ ) < 0) @@ -143,12 +401,19 @@ connect_to_vlib_internal (char *svm_name, char *client_name, /* Start the rx queue thread */ - if (want_pthread) + if (thread_fn) { rv = pthread_create (&mm->rx_thread_handle, - NULL /*attr */ , rx_thread_fn, 0); + NULL /*attr */ , thread_fn, 0); if (rv) - clib_warning ("pthread_create returned %d", rv); + { + clib_warning ("pthread_create returned %d", rv); + am->rx_thread_handle = 0; + } + else + { + am->rx_thread_handle = mm->rx_thread_handle; + } } mm->connected_to_vlib = 1; @@ -156,23 +421,54 @@ connect_to_vlib_internal (char *svm_name, char *client_name, } int -vl_client_connect_to_vlib (char *svm_name, char *client_name, - int rx_queue_size) +vl_client_connect_to_vlib (const char *svm_name, + const char *client_name, int rx_queue_size) { return connect_to_vlib_internal (svm_name, client_name, rx_queue_size, - 1 /* want pthread */ ); + rx_thread_fn, 1 /* do map */ ); } int -vl_client_connect_to_vlib_no_rx_pthread (char *svm_name, char *client_name, +vl_client_connect_to_vlib_no_rx_pthread (const char *svm_name, + const char *client_name, int rx_queue_size) { return connect_to_vlib_internal (svm_name, client_name, rx_queue_size, - 0 /* want pthread */ ); + 0 /* no rx_thread_fn */ , + 1 /* do map */ ); } -void -vl_client_disconnect_from_vlib (void) +int +vl_client_connect_to_vlib_no_map (const char *svm_name, + const char *client_name, int rx_queue_size) +{ + return connect_to_vlib_internal (svm_name, client_name, rx_queue_size, + rx_thread_fn, 0 /* dont map */ ); +} + +int +vl_client_connect_to_vlib_no_rx_pthread_no_map (const char *svm_name, + const char *client_name, + int rx_queue_size) +{ + return connect_to_vlib_internal (svm_name, client_name, rx_queue_size, + 0 /* want pthread */ , + 0 /* dont map */ ); +} + +int +vl_client_connect_to_vlib_thread_fn (const char *svm_name, + const char *client_name, + int rx_queue_size, + void *(*thread_fn) (void *)) +{ + return connect_to_vlib_internal (svm_name, client_name, rx_queue_size, + thread_fn, 1 /* do map */ ); +} + + +static void +disconnect_from_vlib_internal (u8 do_unmap) { memory_client_main_t *mm = &memory_client_main; api_main_t *am = &api_main; @@ -189,9 +485,22 @@ vl_client_disconnect_from_vlib (void) if (mm->connected_to_vlib) { vl_client_disconnect (); - vl_client_api_unmap (); + if (do_unmap) + vl_client_api_unmap (); } - memset (mm, 0, sizeof (*mm)); + clib_memset (mm, 0, sizeof (*mm)); +} + +void +vl_client_disconnect_from_vlib (void) +{ + disconnect_from_vlib_internal (1); +} + +void +vl_client_disconnect_from_vlib_no_unmap (void) +{ + disconnect_from_vlib_internal (0); } static void vl_api_get_first_msg_id_reply_t_handler @@ -205,7 +514,7 @@ static void vl_api_get_first_msg_id_reply_t_handler } u16 -vl_client_get_first_plugin_msg_id (char *plugin_name) +vl_client_get_first_plugin_msg_id (const char *plugin_name) { vl_api_get_first_msg_id_t *mp; api_main_t *am = &api_main; @@ -218,7 +527,7 @@ vl_client_get_first_plugin_msg_id (char *plugin_name) if (strlen (plugin_name) + 1 > sizeof (mp->name)) return (rv); - memset (&clib_time, 0, sizeof (clib_time)); + clib_memset (&clib_time, 0, sizeof (clib_time)); clib_time_init (&clib_time); /* Push this plugin's first_msg_id_reply handler */ @@ -229,19 +538,44 @@ vl_client_get_first_plugin_msg_id (char *plugin_name) /* Ask the data-plane for the message-ID base of the indicated plugin */ mm->first_msg_id_reply_ready = 0; - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID); - mp->client_index = am->my_client_index; - strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1); + /* Not using shm client */ + if (!am->my_registration) + { + mp = vl_socket_client_msg_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID); + mp->client_index = am->my_client_index; + strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1); + + if (vl_socket_client_write () <= 0) + goto sock_err; + if (vl_socket_client_read (1)) + goto sock_err; + + if (mm->first_msg_id_reply_ready == 1) + { + rv = mm->first_msg_id_reply; + goto result; + } - vl_msg_api_send_shmem (am->shmem_hdr->vl_input_queue, (u8 *) & mp); + sock_err: + /* Restore old handler */ + am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY] = old_handler; - /* Synchronously wait for the answer */ - do + return -1; + } + else { - timeout = clib_time_now (&clib_time) + 1.0; + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID); + mp->client_index = am->my_client_index; + strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1); + + vl_msg_api_send_shmem (am->shmem_hdr->vl_input_queue, (u8 *) & mp); + /* Synchronously wait for the answer */ + timeout = clib_time_now (&clib_time) + 1.0; while (clib_time_now (&clib_time) < timeout) { if (mm->first_msg_id_reply_ready == 1) @@ -255,7 +589,6 @@ vl_client_get_first_plugin_msg_id (char *plugin_name) return rv; } - while (0); result: @@ -268,12 +601,6 @@ result: return rv; } -void -vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n) -{ - clib_warning ("STUB called..."); -} - /* * fd.io coding-style-patch-verification: ON *