From 47c40e2d944c9a29677d0542103207ba8372b66a Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Mon, 26 Nov 2018 17:01:36 -0800 Subject: vcl: basic support for apps that fork - intercept fork and register a new worker with vpp - share sessions between parent and forked child - keep binary api state per worker Change-Id: Ib177517d661724fa042bd2d98d18e777056352a2 Signed-off-by: Florin Coras --- src/vcl/ldp.c | 6 +- src/vcl/vcl_bapi.c | 46 ++++---- src/vcl/vcl_cfg.c | 1 - src/vcl/vcl_debug.h | 11 +- src/vcl/vcl_private.c | 164 +++++++++++++++++++++++--- src/vcl/vcl_private.h | 38 ++++-- src/vcl/vppcom.c | 255 ++++++++++++++++++++++------------------- src/vcl/vppcom.h | 1 + src/vnet/session/application.c | 2 +- src/vppinfra/pool.h | 2 +- 10 files changed, 358 insertions(+), 168 deletions(-) diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c index 5c70643ed24..915d1caa40c 100644 --- a/src/vcl/ldp.c +++ b/src/vcl/ldp.c @@ -346,7 +346,7 @@ ldp_init (void) int close (int fd) { - int rv; + int rv, refcnt; const char *func_str; u32 sid = ldp_sid_from_fd (fd); @@ -388,13 +388,15 @@ close (int fd) LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x)", getpid (), fd, fd, func_str, sid, sid); + refcnt = vppcom_session_attr (sid, VPPCOM_ATTR_GET_REFCNT, 0, 0); rv = vppcom_session_close (sid); if (rv != VPPCOM_OK) { errno = -rv; rv = -1; } - ldp_fd_free_w_sid (sid); + if (refcnt == 1) + ldp_fd_free_w_sid (sid); } else { diff --git a/src/vcl/vcl_bapi.c b/src/vcl/vcl_bapi.c index cc494ed3b6d..93ba0ab6c4d 100644 --- a/src/vcl/vcl_bapi.c +++ b/src/vcl/vcl_bapi.c @@ -354,20 +354,22 @@ vppcom_api_hookup (void) void vppcom_send_session_enable_disable (u8 is_enable) { + vcl_worker_t *wrk = vcl_worker_get_current (); vl_api_session_enable_disable_t *bmp; bmp = vl_msg_api_alloc (sizeof (*bmp)); memset (bmp, 0, sizeof (*bmp)); bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE); - bmp->client_index = vcm->my_client_index; + bmp->client_index = wrk->my_client_index; bmp->context = htonl (0xfeedface); bmp->is_enable = is_enable; - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp); } void vppcom_app_send_attach (void) { + vcl_worker_t *wrk = vcl_worker_get_current (); vl_api_application_attach_t *bmp; u8 nsid_len = vec_len (vcm->cfg.namespace_id); u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp || @@ -377,7 +379,7 @@ vppcom_app_send_attach (void) memset (bmp, 0, sizeof (*bmp)); bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH); - bmp->client_index = vcm->my_client_index; + bmp->client_index = wrk->my_client_index; bmp->context = htonl (0xfeedface); bmp->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT | @@ -402,20 +404,21 @@ vppcom_app_send_attach (void) clib_memcpy_fast (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len); bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret; } - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp); } void vppcom_app_send_detach (void) { + vcl_worker_t *wrk = vcl_worker_get_current (); vl_api_application_detach_t *bmp; bmp = vl_msg_api_alloc (sizeof (*bmp)); memset (bmp, 0, sizeof (*bmp)); bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH); - bmp->client_index = vcm->my_client_index; + bmp->client_index = wrk->my_client_index; bmp->context = htonl (0xfeedface); - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp); } void @@ -429,14 +432,14 @@ vcl_send_app_worker_add_del (u8 is_add) memset (mp, 0, sizeof (*mp)); mp->_vl_msg_id = ntohs (VL_API_APP_WORKER_ADD_DEL); - mp->client_index = vcm->my_client_index; + mp->client_index = wrk->my_client_index; mp->app_index = clib_host_to_net_u32 (vcm->app_index); mp->context = wrk_index; mp->is_add = is_add; if (!is_add) mp->wrk_index = clib_host_to_net_u32 (wrk_index); - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & mp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & mp); } void @@ -448,7 +451,7 @@ vppcom_send_connect_sock (vcl_session_t * session) cmp = vl_msg_api_alloc (sizeof (*cmp)); memset (cmp, 0, sizeof (*cmp)); cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK); - cmp->client_index = vcm->my_client_index; + cmp->client_index = wrk->my_client_index; cmp->context = session->session_index; cmp->wrk_index = wrk->vpp_wrk_index; cmp->is_ip4 = session->transport.is_ip4; @@ -456,20 +459,21 @@ vppcom_send_connect_sock (vcl_session_t * session) cmp->port = session->transport.rmt_port; cmp->proto = session->session_type; clib_memcpy_fast (cmp->options, session->options, sizeof (cmp->options)); - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & cmp); } void vppcom_send_disconnect_session (u64 vpp_handle) { + vcl_worker_t *wrk = vcl_worker_get_current (); vl_api_disconnect_session_t *dmp; dmp = vl_msg_api_alloc (sizeof (*dmp)); memset (dmp, 0, sizeof (*dmp)); dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION); - dmp->client_index = vcm->my_client_index; + dmp->client_index = wrk->my_client_index; dmp->handle = vpp_handle; - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & dmp); } /* VPP combines bind and listen as one operation. VCL manages the separation @@ -486,7 +490,7 @@ vppcom_send_bind_sock (vcl_session_t * session) memset (bmp, 0, sizeof (*bmp)); bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK); - bmp->client_index = vcm->my_client_index; + bmp->client_index = wrk->my_client_index; bmp->context = session->session_index; bmp->wrk_index = wrk->vpp_wrk_index; bmp->is_ip4 = session->transport.is_ip4; @@ -494,7 +498,7 @@ vppcom_send_bind_sock (vcl_session_t * session) bmp->port = session->transport.lcl_port; bmp->proto = session->session_type; clib_memcpy_fast (bmp->options, session->options, sizeof (bmp->options)); - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & bmp); } void @@ -507,15 +511,16 @@ vppcom_send_unbind_sock (u64 vpp_handle) memset (ump, 0, sizeof (*ump)); ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK); - ump->client_index = vcm->my_client_index; + ump->client_index = wrk->my_client_index; ump->wrk_index = wrk->vpp_wrk_index; ump->handle = vpp_handle; - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & ump); } void vppcom_send_accept_session_reply (u64 handle, u32 context, int retval) { + vcl_worker_t *wrk = vcl_worker_get_current (); vl_api_accept_session_reply_t *rmp; rmp = vl_msg_api_alloc (sizeof (*rmp)); @@ -524,7 +529,7 @@ vppcom_send_accept_session_reply (u64 handle, u32 context, int retval) rmp->retval = htonl (retval); rmp->context = context; rmp->handle = handle; - vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp); + vl_msg_api_send_shmem (wrk->vl_input_queue, (u8 *) & rmp); } u32 @@ -549,6 +554,7 @@ vppcom_init_error_string_table (void) int vppcom_connect_to_vpp (char *app_name) { + vcl_worker_t *wrk = vcl_worker_get_current (); api_main_t *am = &api_main; vppcom_cfg_t *vcl_cfg = &vcm->cfg; @@ -584,9 +590,9 @@ vppcom_connect_to_vpp (char *app_name) } - vcm->vl_input_queue = am->shmem_hdr->vl_input_queue; - vcm->my_client_index = (u32) am->my_client_index; - vcm->app_state = STATE_APP_CONN_VPP; + wrk->vl_input_queue = am->shmem_hdr->vl_input_queue; + wrk->my_client_index = (u32) am->my_client_index; + wrk->wrk_state = STATE_APP_CONN_VPP; VDBG (0, "app (%s) is connected to VPP!", app_name); vcl_evt (VCL_EVT_INIT, vcm); diff --git a/src/vcl/vcl_cfg.c b/src/vcl/vcl_cfg.c index 402bb91315f..8baae82942d 100644 --- a/src/vcl/vcl_cfg.c +++ b/src/vcl/vcl_cfg.c @@ -23,7 +23,6 @@ static vppcom_main_t _vppcom_main = { .debug = VPPCOM_DEBUG_INIT, .is_init = 0, .app_index = ~0, - .my_client_index = ~0 }; vppcom_main_t *vcm = &_vppcom_main; diff --git a/src/vcl/vcl_debug.h b/src/vcl/vcl_debug.h index 48ff21af1de..191d4004eba 100644 --- a/src/vcl/vcl_debug.h +++ b/src/vcl/vcl_debug.h @@ -23,15 +23,18 @@ #define VDBG(_lvl, _fmt, _args...) \ if (VCL_DBG_ON && vcm->debug > _lvl) \ - clib_warning ("vcl<%d:%d>: " _fmt, vcm->current_pid, \ + clib_warning ("vcl<%d:%d>: " _fmt, \ + vcm->workers[__vcl_worker_index].current_pid, \ __vcl_worker_index, ##_args) #define VWRN(_fmt, _args...) \ -clib_warning ("vcl<%d:%d>: " _fmt, vcm->current_pid, \ - __vcl_worker_index, ##_args) + clib_warning ("vcl<%d:%d>: " _fmt, \ + vcm->workers[__vcl_worker_index].current_pid, \ + __vcl_worker_index, ##_args) #define VERR(_fmt, _args...) \ - clib_warning ("vcl<%d:%d>: ERROR " _fmt, vcm->current_pid, \ + clib_warning ("vcl<%d:%d>: ERROR " _fmt, \ + vcm->workers[__vcl_worker_index].current_pid, \ __vcl_worker_index, ##_args) #define foreach_vcl_dbg_evt \ diff --git a/src/vcl/vcl_private.c b/src/vcl/vcl_private.c index d159a49a89c..86dccfe1cc9 100644 --- a/src/vcl/vcl_private.c +++ b/src/vcl/vcl_private.c @@ -220,12 +220,12 @@ vcl_worker_free (vcl_worker_t * wrk) pool_put (vcm->workers, wrk); } -static void -vcl_worker_cleanup (void *arg) +void +vcl_worker_cleanup (void) { vcl_worker_t *wrk = vcl_worker_get_current (); - VDBG (0, "cleaning up worker %u", wrk->wrk_index); + clib_spinlock_lock (&vcm->workers_lock); vcl_send_app_worker_add_del (0 /* is_add */ ); close (wrk->mqs_epfd); hash_free (wrk->session_index_by_vpp_handles); @@ -235,6 +235,14 @@ vcl_worker_cleanup (void *arg) vec_free (wrk->mq_msg_vector); vcl_set_worker_index (~0); vcl_worker_free (wrk); + clib_spinlock_unlock (&vcm->workers_lock); + VDBG (0, "cleaned up worker %u", wrk->wrk_index); +} + +static void +vcl_worker_cleanup_cb (void *arg) +{ + vcl_worker_cleanup (); } vcl_worker_t * @@ -255,6 +263,8 @@ vcl_worker_alloc_and_init () clib_spinlock_lock (&vcm->workers_lock); wrk = vcl_worker_alloc (); vcl_set_worker_index (wrk->wrk_index); + wrk->thread_id = pthread_self (); + wrk->current_pid = getpid (); wrk->mqs_epfd = -1; if (vcm->cfg.use_mq_eventfd) @@ -263,7 +273,7 @@ vcl_worker_alloc_and_init () if (wrk->mqs_epfd < 0) { clib_unix_warning ("epoll_create() returned"); - return 0; + goto done; } } @@ -276,32 +286,160 @@ vcl_worker_alloc_and_init () vec_reset_length (wrk->mq_msg_vector); vec_validate (wrk->unhandled_evts_vector, 128); vec_reset_length (wrk->unhandled_evts_vector); + clib_spinlock_unlock (&vcm->workers_lock); - if (wrk->wrk_index == 0) - { - clib_spinlock_unlock (&vcm->workers_lock); - return wrk; - } +done: + return wrk; +} + +int +vcl_worker_register_with_vpp (void) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + + clib_spinlock_lock (&vcm->workers_lock); vcm->app_state = STATE_APP_ADDING_WORKER; vcl_send_app_worker_add_del (1 /* is_add */ ); if (vcl_wait_for_app_state_change (STATE_APP_READY)) { clib_warning ("failed to add worker to vpp"); - return 0; + return -1; } - if (pthread_key_create (&vcl_worker_stop_key, vcl_worker_cleanup)) + if (pthread_key_create (&vcl_worker_stop_key, vcl_worker_cleanup_cb)) clib_warning ("failed to add pthread cleanup function"); if (pthread_setspecific (vcl_worker_stop_key, &wrk->thread_id)) clib_warning ("failed to setup key value"); - wrk->thread_id = pthread_self (); clib_spinlock_unlock (&vcm->workers_lock); VDBG (0, "added worker %u", wrk->wrk_index); + return 0; +} - return wrk; +int +vcl_worker_set_bapi (void) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + int i; + + /* Find the first worker with the same pid */ + for (i = 0; i < vec_len (vcm->workers); i++) + { + if (i == wrk->wrk_index) + continue; + if (vcm->workers[i].current_pid == wrk->current_pid) + { + wrk->vl_input_queue = vcm->workers[i].vl_input_queue; + wrk->my_client_index = vcm->workers[i].my_client_index; + return 0; + } + } + return -1; +} + +vcl_shared_session_t * +vcl_shared_session_alloc (void) +{ + vcl_shared_session_t *ss; + pool_get (vcm->shared_sessions, ss); + memset (ss, 0, sizeof (*ss)); + ss->ss_index = ss - vcm->shared_sessions; + return ss; +} + +vcl_shared_session_t * +vcl_shared_session_get (u32 ss_index) +{ + if (pool_is_free_index (vcm->shared_sessions, ss_index)) + return 0; + return pool_elt_at_index (vcm->shared_sessions, ss_index); +} + +void +vcl_shared_session_free (vcl_shared_session_t * ss) +{ + pool_put (vcm->shared_sessions, ss); +} + +void +vcl_worker_share_session (vcl_worker_t * parent, vcl_worker_t * wrk, + vcl_session_t * new_s) +{ + vcl_shared_session_t *ss; + vcl_session_t *s; + + s = vcl_session_get (parent, new_s->session_index); + if (s->shared_index == ~0) + { + ss = vcl_shared_session_alloc (); + vec_add1 (ss->workers, parent->wrk_index); + s->shared_index = ss->ss_index; + } + else + { + ss = vcl_shared_session_get (s->shared_index); + } + new_s->shared_index = ss->ss_index; + vec_add1 (ss->workers, wrk->wrk_index); +} + +int +vcl_worker_unshare_session (vcl_worker_t * wrk, vcl_session_t * s) +{ + vcl_shared_session_t *ss; + int i; + + ss = vcl_shared_session_get (s->shared_index); + for (i = 0; i < vec_len (ss->workers); i++) + { + if (ss->workers[i] == wrk->wrk_index) + { + vec_del1 (ss->workers, i); + break; + } + } + + if (vec_len (ss->workers) == 0) + { + vcl_shared_session_free (ss); + return 1; + } + + return 0; +} + +void +vcl_worker_share_sessions (u32 parent_wrk_index) +{ + vcl_worker_t *parent_wrk, *wrk; + vcl_session_t *new_s; + + parent_wrk = vcl_worker_get (parent_wrk_index); + if (!parent_wrk->sessions) + return; + + wrk = vcl_worker_get_current (); + wrk->sessions = pool_dup (parent_wrk->sessions); + wrk->session_index_by_vpp_handles = + hash_dup (parent_wrk->session_index_by_vpp_handles); + + /* *INDENT-OFF* */ + pool_foreach (new_s, wrk->sessions, ({ + vcl_worker_share_session (parent_wrk, wrk, new_s); + })); + /* *INDENT-ON* */ +} + +int +vcl_session_get_refcnt (vcl_session_t * s) +{ + vcl_shared_session_t *ss; + ss = vcl_shared_session_get (s->shared_index); + if (ss) + return vec_len (ss->workers); + return 0; } /* diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h index 0204bd5493e..0420322d3f4 100644 --- a/src/vcl/vcl_private.h +++ b/src/vcl/vcl_private.h @@ -136,6 +136,12 @@ do { \ #define VCL_SESS_ATTR_TEST(ATTR, VAL) \ ((ATTR) & (1 << (VAL)) ? 1 : 0) +typedef struct vcl_shared_session_ +{ + u32 ss_index; + u32 *workers; +} vcl_shared_session_t; + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -161,6 +167,7 @@ typedef struct svm_msg_q_t *our_evt_q; u64 options[16]; vcl_session_msg_t *accept_evts_fifo; + u32 shared_index; #if VCL_ELOG elog_track_t elog_track; #endif @@ -225,6 +232,15 @@ typedef struct vcl_worker_ /** Worker index in vpp*/ u32 vpp_wrk_index; + /** API client handle */ + u32 my_client_index; + + /** State of the connection, shared between msg RX thread and main thread */ + volatile app_state_t wrk_state; + + /** VPP binary api input queue */ + svm_queue_t *vl_input_queue; + /** Message queues epoll fd. Initialized only if using mqs with eventfds */ int mqs_epfd; @@ -268,6 +284,9 @@ typedef struct vcl_worker_ /** Used also as a thread stop key buffer */ pthread_t thread_id; + + /** Current pid, may be different from main_pid if forked child */ + pid_t current_pid; } vcl_worker_t; typedef struct vppcom_main_t_ @@ -279,18 +298,9 @@ typedef struct vppcom_main_t_ /** Main process pid */ pid_t main_pid; - /** Current pid, may be different from main_pid if forked child */ - pid_t current_pid; - /** App's index in vpp. It's used by vpp to identify the app */ u32 app_index; - /** API client handle */ - u32 my_client_index; - - /** VPP binary api input queue */ - svm_queue_t *vl_input_queue; - /** State of the connection, shared between msg RX thread and main thread */ volatile app_state_t app_state; @@ -302,12 +312,15 @@ typedef struct vppcom_main_t_ /** Flag indicating that a new segment is being mounted */ volatile u32 mounting_segment; + volatile u32 forking; + /** Workers */ vcl_worker_t *workers; /** Lock to protect worker registrations */ clib_spinlock_t workers_lock; + vcl_shared_session_t *shared_sessions; #ifdef VCL_ELOG /* VPP Event-logger */ elog_main_t elog_main; @@ -330,6 +343,7 @@ vcl_session_alloc (vcl_worker_t * wrk) pool_get (wrk->sessions, s); memset (s, 0, sizeof (*s)); s->session_index = s - wrk->sessions; + s->shared_index = ~0; return s; } @@ -481,6 +495,12 @@ int vcl_mq_epoll_add_evfd (vcl_worker_t * wrk, svm_msg_q_t * mq); int vcl_mq_epoll_del_evfd (vcl_worker_t * wrk, u32 mqc_index); vcl_worker_t *vcl_worker_alloc_and_init (void); +void vcl_worker_cleanup (void); +int vcl_worker_register_with_vpp (void); +int vcl_worker_set_bapi (void); +void vcl_worker_share_sessions (u32 parent_wrk_index); +int vcl_worker_unshare_session (vcl_worker_t * wrk, vcl_session_t * s); +int vcl_session_get_refcnt (vcl_session_t * s); static inline vcl_worker_t * vcl_worker_get (u32 wrk_index) diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 589d57c3872..195e6cbc602 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -423,7 +423,7 @@ vcl_session_reset_handler (vcl_worker_t * wrk, session->session_state = STATE_CLOSE_ON_EMPTY; VDBG (0, "reset handle 0x%llx, sid %u ", reset_msg->handle, sid); vcl_send_session_reset_reply (vcl_session_vpp_evt_q (wrk, session), - vcm->my_client_index, reset_msg->handle, 0); + wrk->my_client_index, reset_msg->handle, 0); return sid; } @@ -673,7 +673,7 @@ vppcom_session_disconnect (u32 session_handle) if (state & STATE_CLOSE_ON_EMPTY) { vpp_evt_q = vcl_session_vpp_evt_q (wrk, session); - vcl_send_session_disconnected_reply (vpp_evt_q, vcm->my_client_index, + vcl_send_session_disconnected_reply (vpp_evt_q, wrk->my_client_index, vpp_handle, 0); VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending disconnect " "REPLY...", getpid (), vpp_handle, session_handle); @@ -691,12 +691,14 @@ vppcom_session_disconnect (u32 session_handle) static void vcl_cleanup_bapi (void) { + socket_client_main_t *scm = &socket_client_main; api_main_t *am = &api_main; am->my_client_index = ~0; am->my_registration = 0; am->vl_input_queue = 0; am->msg_index_by_name_and_crc = 0; + scm->socket_fd = 0; vl_client_api_unmap (); } @@ -705,14 +707,22 @@ void vcl_app_fork_child_handler (void) { u8 *child_name; - int rv; - - vcm->current_pid = getpid (); - vcl_set_worker_index (0); + int rv, parent_wrk; VDBG (0, "initializing forked child"); - child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0); + /* + * Allocate worker + */ + parent_wrk = vcl_get_worker_index (); + vcl_set_worker_index (~0); + if (!vcl_worker_alloc_and_init ()) + VERR ("couldn't allocate new worker"); + + /* + * Attach to binary api + */ + child_name = format (0, "%v-child-%u%c", vcm->app_name, getpid (), 0); vcl_cleanup_bapi (); vppcom_api_hookup (); vcm->app_state = STATE_APP_START; @@ -724,14 +734,23 @@ vcl_app_fork_child_handler (void) return; } - vcm->app_state = STATE_APP_ADDING_WORKER; - vcl_send_app_worker_add_del (1 /* is_add */ ); - if (vcl_wait_for_app_state_change (STATE_APP_READY)) - { - VERR ("failed to add worker to vpp"); - return; - } + /* + * Register worker with vpp and share sessions + */ + vcl_worker_register_with_vpp (); + vcl_worker_share_sessions (parent_wrk); + VDBG (0, "forked child main worker initialized"); + vcm->forking = 0; +} + +void +vcl_app_fork_parent_handler (void) +{ + vcm->forking = 1; + + while (vcm->forking) + ; } /* @@ -743,55 +762,58 @@ vppcom_app_create (char *app_name) vppcom_cfg_t *vcl_cfg = &vcm->cfg; int rv; - if (!vcm->is_init) + if (vcm->is_init) { - vcm->is_init = 1; - vppcom_cfg (&vcm->cfg); - vcl_cfg = &vcm->cfg; - - vcm->main_cpu = pthread_self (); - vcm->main_pid = vcm->current_pid = getpid (); - vcm->app_name = format (0, "%s", app_name); - vppcom_init_error_string_table (); - svm_fifo_segment_main_init (vcl_cfg->segment_baseva, - 20 /* timeout in secs */ ); - pool_init_fixed (vcm->workers, vcl_cfg->max_workers); - clib_spinlock_init (&vcm->workers_lock); - vcl_worker_alloc_and_init (); - pthread_atfork (NULL, NULL, vcl_app_fork_child_handler); + clib_warning ("already initialized"); + return -1; } - if (vcm->my_client_index == ~0) - { - /* API hookup and connect to VPP */ - vppcom_api_hookup (); - vcl_elog_init (vcm); - vcm->app_state = STATE_APP_START; - rv = vppcom_connect_to_vpp (app_name); - if (rv) - { - VERR ("couldn't connect to VPP!"); - return rv; - } - VDBG (0, "sending session enable"); - rv = vppcom_app_session_enable (); - if (rv) - { - VERR ("vppcom_app_session_enable() failed!"); - return rv; - } + vcm->is_init = 1; + vppcom_cfg (&vcm->cfg); + vcl_cfg = &vcm->cfg; - VDBG (0, "sending app attach"); - rv = vppcom_app_attach (); - if (rv) - { - VERR ("vppcom_app_attach() failed!"); - return rv; - } + vcm->main_cpu = pthread_self (); + vcm->main_pid = getpid (); + vcm->app_name = format (0, "%s", app_name); + vppcom_init_error_string_table (); + svm_fifo_segment_main_init (vcl_cfg->segment_baseva, + 20 /* timeout in secs */ ); + pool_alloc (vcm->workers, vcl_cfg->max_workers); + clib_spinlock_init (&vcm->workers_lock); + pthread_atfork (NULL, vcl_app_fork_parent_handler, + vcl_app_fork_child_handler); - VDBG (0, "app_name '%s', my_client_index %d (0x%x)", - app_name, vcm->my_client_index, vcm->my_client_index); + /* Allocate default worker */ + vcl_worker_alloc_and_init (); + + /* API hookup and connect to VPP */ + vppcom_api_hookup (); + vcl_elog_init (vcm); + vcm->app_state = STATE_APP_START; + rv = vppcom_connect_to_vpp (app_name); + if (rv) + { + VERR ("couldn't connect to VPP!"); + return rv; } + VDBG (0, "sending session enable"); + rv = vppcom_app_session_enable (); + if (rv) + { + VERR ("vppcom_app_session_enable() failed!"); + return rv; + } + + VDBG (0, "sending app attach"); + rv = vppcom_app_attach (); + if (rv) + { + VERR ("vppcom_app_attach() failed!"); + return rv; + } + + VDBG (0, "app_name '%s', my_client_index %d (0x%x)", app_name, + vcm->workers[0].my_client_index, vcm->workers[0].my_client_index); return VPPCOM_OK; } @@ -802,27 +824,27 @@ vppcom_app_destroy (void) int rv; f64 orig_app_timeout; - if (vcm->my_client_index == ~0) - return; - - VDBG (0, "detaching from VPP, my_client_index %d (0x%x)", - vcm->my_client_index, vcm->my_client_index); vcl_evt (VCL_EVT_DETACH, vcm); - vppcom_app_send_detach (); - orig_app_timeout = vcm->cfg.app_timeout; - vcm->cfg.app_timeout = 2.0; - rv = vcl_wait_for_app_state_change (STATE_APP_ENABLED); - vcm->cfg.app_timeout = orig_app_timeout; - if (PREDICT_FALSE (rv)) - VDBG (0, "application detach timed out! returning %d (%s)", - rv, vppcom_retval_str (rv)); + if (vec_len (vcm->workers) == 1) + { + vppcom_app_send_detach (); + orig_app_timeout = vcm->cfg.app_timeout; + vcm->cfg.app_timeout = 2.0; + rv = vcl_wait_for_app_state_change (STATE_APP_ENABLED); + vcm->cfg.app_timeout = orig_app_timeout; + if (PREDICT_FALSE (rv)) + VDBG (0, "application detach timed out! returning %d (%s)", rv, + vppcom_retval_str (rv)); + } + else + { + vcl_worker_cleanup (); + } vcl_elog_stop (vcm); vl_client_disconnect_from_vlib (); vec_free (vcm->app_name); - vcm->my_client_index = ~0; - vcm->app_state = STATE_APP_START; } int @@ -853,8 +875,8 @@ int vppcom_session_close (uint32_t session_handle) { vcl_worker_t *wrk = vcl_worker_get_current (); + u8 is_vep, do_disconnect = 1; vcl_session_t *session = 0; - u8 is_vep, is_vep_session; session_state_t state; u32 next_sh, vep_sh; int rv = VPPCOM_OK; @@ -864,24 +886,17 @@ vppcom_session_close (uint32_t session_handle) if (!session) return VPPCOM_EBADFD; + if (session->shared_index != ~0) + do_disconnect = vcl_worker_unshare_session (wrk, session); + is_vep = session->is_vep; - is_vep_session = session->is_vep_session; next_sh = session->vep.next_sh; vep_sh = session->vep.vep_sh; state = session->session_state; vpp_handle = session->vpp_handle; - if (VPPCOM_DEBUG > 0) - { - if (is_vep) - clib_warning ("VCL<%d>: vep_idx %u / sid %u: " - "closing epoll session...", - getpid (), session_handle, session_handle); - else - clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %d: " - "closing session...", - getpid (), vpp_handle, session_handle); - } + VDBG (0, "Closing session handle %u vpp handle %u", session_handle, + vpp_handle); if (is_vep) { @@ -889,34 +904,34 @@ vppcom_session_close (uint32_t session_handle) { rv = vppcom_epoll_ctl (session_handle, EPOLL_CTL_DEL, next_sh, 0); if (PREDICT_FALSE (rv < 0)) - VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL " - "vep_idx %u failed! rv %d (%s)", - getpid (), vpp_handle, next_sh, vep_sh, - rv, vppcom_retval_str (rv)); + VDBG (0, "vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL vep_idx %u" + " failed! rv %d (%s)", vpp_handle, next_sh, vep_sh, rv, + vppcom_retval_str (rv)); next_sh = session->vep.next_sh; } } else { - if (is_vep_session) + if (session->is_vep_session) { rv = vppcom_epoll_ctl (vep_sh, EPOLL_CTL_DEL, session_handle, 0); if (rv < 0) - VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL " - "vep_idx %u failed! rv %d (%s)", - getpid (), vpp_handle, session_handle, - vep_sh, rv, vppcom_retval_str (rv)); + VDBG (0, "vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL vep_idx %u " + "failed! rv %d (%s)", vpp_handle, session_handle, vep_sh, + rv, vppcom_retval_str (rv)); } + if (!do_disconnect) + goto cleanup; + if (state & STATE_LISTEN) { rv = vppcom_session_unbind (session_handle); if (PREDICT_FALSE (rv < 0)) - VDBG (0, "VCL<%d>: vpp handle 0x%llx, sid %u: listener unbind " - "failed! rv %d (%s)", - getpid (), vpp_handle, session_handle, - rv, vppcom_retval_str (rv)); + VDBG (0, "vpp handle 0x%llx, sid %u: listener unbind failed! " + "rv %d (%s)", vpp_handle, session_handle, rv, + vppcom_retval_str (rv)); } else if (state & STATE_OPEN) { @@ -929,6 +944,8 @@ vppcom_session_close (uint32_t session_handle) } } +cleanup: + if (vcl_session_is_ct (session)) { vcl_cut_through_registration_t *ctr; @@ -952,15 +969,8 @@ vppcom_session_close (uint32_t session_handle) } vcl_session_free (wrk, session); - if (VPPCOM_DEBUG > 0) - { - if (is_vep) - clib_warning ("VCL<%d>: vep_idx %u / sid %u: epoll session removed.", - getpid (), session_handle, session_handle); - else - clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session removed.", - getpid (), vpp_handle, session_handle); - } + VDBG (0, "session handle %u vpp handle %u removed", session_handle, + vpp_handle); vcl_evt (VCL_EVT_CLOSE, session, rv); @@ -1986,9 +1996,9 @@ vppcom_select (unsigned long n_bits, unsigned long *read_map, clib_bitmap_foreach (sid, wrk->wr_bitmap, ({ if (!(session = vcl_session_get (wrk, sid))) { - VDBG (0, "VCL<%d>: session %d specified in write_map is closed.", - getpid (), sid); - return VPPCOM_EBADFD; + if (except_map && sid < minbits) + clib_bitmap_set_no_check (except_map, sid, 1); + continue; } rv = svm_fifo_is_full (session->tx_fifo); @@ -2006,9 +2016,9 @@ check_rd: clib_bitmap_foreach (sid, wrk->rd_bitmap, ({ if (!(session = vcl_session_get (wrk, sid))) { - VDBG (0, "VCL<%d>: session %d specified in write_map is closed.", - getpid (), sid); - return VPPCOM_EBADFD; + if (except_map && sid < minbits) + clib_bitmap_set_no_check (except_map, sid, 1); + continue; } rv = vppcom_session_read_ready (session); @@ -3150,6 +3160,10 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, rv = VPPCOM_EINVAL; break; + case VPPCOM_ATTR_GET_REFCNT: + rv = vcl_session_get_refcnt (session); + break; + default: rv = VPPCOM_EINVAL; break; @@ -3355,15 +3369,22 @@ vppcom_session_index (uint32_t session_handle) int vppcom_session_handle (uint32_t session_index) { - return vcl_get_worker_index () << 24 | session_index; + return (vcl_get_worker_index () << 24) | session_index; } int vppcom_worker_register (void) { - if (vcl_worker_alloc_and_init ()) - return VPPCOM_OK; - return VPPCOM_EEXIST; + if (!vcl_worker_alloc_and_init ()) + return VPPCOM_EEXIST; + + if (vcl_worker_set_bapi ()) + return VPPCOM_EEXIST; + + if (vcl_worker_register_with_vpp ()) + return VPPCOM_EEXIST; + + return VPPCOM_OK; } int diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h index 0c0b7ce45fd..30ab7c4a56a 100644 --- a/src/vcl/vppcom.h +++ b/src/vcl/vppcom.h @@ -137,6 +137,7 @@ typedef enum VPPCOM_ATTR_SET_TCP_KEEPINTVL, VPPCOM_ATTR_GET_TCP_USER_MSS, VPPCOM_ATTR_SET_TCP_USER_MSS, + VPPCOM_ATTR_GET_REFCNT, } vppcom_attr_op_t; typedef struct _vcl_poll diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 9b77af90577..380c960bdaf 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -2379,7 +2379,7 @@ show_app_command_fn (vlib_main_t * vm, unformat_input_t * input, if (app_index != ~0) { - app = application_get (app_index); + app = application_get_if_valid (app_index); if (!app) return clib_error_return (0, "No app with index %u", app_index); diff --git a/src/vppinfra/pool.h b/src/vppinfra/pool.h index 47bae07add0..10262e90ec7 100644 --- a/src/vppinfra/pool.h +++ b/src/vppinfra/pool.h @@ -373,7 +373,7 @@ do { \ * @param P pool to copy * @return copy of pool */ -#define pool_dup(P) pool_dup_aligned(P, 0) +#define pool_dup(P) pool_dup_aligned(P,0) /** Low-level free pool operator (do not call directly). */ always_inline void * -- cgit 1.2.3-korg