X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvppcom.c;h=0e81749224e915e4659c1dedc6cf32c3e2c1083f;hb=8ccc6b350;hp=b74570d10da669efef4c837e1762eca6057bba65;hpb=87f7600dd67debf68d1236395cefdc5d6e7484fb;p=vpp.git diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index b74570d10da..0e81749224e 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -37,131 +37,7 @@ vcl_mq_dequeue_batch (vcl_worker_t * wrk, svm_msg_q_t * mq, u32 n_max_msg) return n_msgs; } -const char * -vppcom_session_state_str (vcl_session_state_t state) -{ - char *st; - - switch (state) - { - case VCL_STATE_CLOSED: - st = "STATE_CLOSED"; - break; - case VCL_STATE_LISTEN: - st = "STATE_LISTEN"; - break; - case VCL_STATE_READY: - st = "STATE_READY"; - break; - case VCL_STATE_VPP_CLOSING: - st = "STATE_VPP_CLOSING"; - break; - case VCL_STATE_DISCONNECT: - st = "STATE_DISCONNECT"; - break; - case VCL_STATE_DETACHED: - st = "STATE_DETACHED"; - break; - case VCL_STATE_UPDATED: - st = "STATE_UPDATED"; - break; - case VCL_STATE_LISTEN_NO_MQ: - st = "STATE_LISTEN_NO_MQ"; - break; - default: - st = "UNKNOWN_STATE"; - break; - } - - return st; -} - -u8 * -format_ip4_address (u8 * s, va_list * args) -{ - u8 *a = va_arg (*args, u8 *); - return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); -} - -u8 * -format_ip6_address (u8 * s, va_list * args) -{ - ip6_address_t *a = va_arg (*args, ip6_address_t *); - u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; - - i_max_n_zero = ARRAY_LEN (a->as_u16); - max_n_zeros = 0; - i_first_zero = i_max_n_zero; - n_zeros = 0; - for (i = 0; i < ARRAY_LEN (a->as_u16); i++) - { - u32 is_zero = a->as_u16[i] == 0; - if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) - { - i_first_zero = i; - n_zeros = 0; - } - n_zeros += is_zero; - if ((!is_zero && n_zeros > max_n_zeros) - || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) - { - i_max_n_zero = i_first_zero; - max_n_zeros = n_zeros; - i_first_zero = ARRAY_LEN (a->as_u16); - n_zeros = 0; - } - } - - last_double_colon = 0; - for (i = 0; i < ARRAY_LEN (a->as_u16); i++) - { - if (i == i_max_n_zero && max_n_zeros > 1) - { - s = format (s, "::"); - i += max_n_zeros - 1; - last_double_colon = 1; - } - else - { - s = format (s, "%s%x", - (last_double_colon || i == 0) ? "" : ":", - clib_net_to_host_u16 (a->as_u16[i])); - last_double_colon = 0; - } - } - - return s; -} - -/* Format an IP46 address. */ -u8 * -format_ip46_address (u8 * s, va_list * args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - ip46_type_t type = va_arg (*args, ip46_type_t); - int is_ip4 = 1; - switch (type) - { - case IP46_TYPE_ANY: - is_ip4 = ip46_address_is_ip4 (ip46); - break; - case IP46_TYPE_IP4: - is_ip4 = 1; - break; - case IP46_TYPE_IP6: - is_ip4 = 0; - break; - } - - return is_ip4 ? - format (s, "%U", format_ip4_address, &ip46->ip4) : - format (s, "%U", format_ip6_address, &ip46->ip6); -} - -/* - * VPPCOM Utility Functions - */ static void vcl_msg_add_ext_config (vcl_session_t *s, uword *offset) @@ -219,6 +95,7 @@ vcl_send_session_connect (vcl_worker_t * wrk, vcl_session_t * s) memset (mp, 0, sizeof (*mp)); mp->client_index = wrk->api_client_handle; mp->context = s->session_index; + mp->dscp = s->dscp; mp->wrk_index = wrk->vpp_wrk_index; mp->is_ip4 = s->transport.is_ip4; mp->parent_handle = s->parent_handle; @@ -455,11 +332,12 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp, goto error; } - if (vcl_segment_attach_session (mp->segment_handle, mp->server_rx_fifo, - mp->server_tx_fifo, - mp->vpp_event_queue_address, 0, session)) + if (vcl_segment_attach_session ( + mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo, + mp->vpp_event_queue_address, mp->mq_index, 0, session)) { - VDBG (0, "failed to attach fifos for %u", session->session_index); + VDBG (0, "session %u [0x%llx]: failed to attach fifos", + session->session_index, mp->handle); goto error; } @@ -478,11 +356,6 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp, session->listener_index = listen_session->session_index; listen_session->n_accepted_sessions++; - VDBG (1, "session %u [0x%llx]: client accept request from %s address %U" - " port %d queue %p!", session->session_index, mp->handle, - mp->rmt.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &mp->rmt.ip, - mp->rmt.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, - clib_net_to_host_u16 (mp->rmt.port), session->vpp_evt_q); vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index); vcl_send_session_accepted_reply (session->vpp_evt_q, mp->context, @@ -508,29 +381,46 @@ vcl_session_connected_handler (vcl_worker_t * wrk, session_index = mp->context; session = vcl_session_get (wrk, session_index); - if (!session) + if (PREDICT_FALSE (!session)) { - VDBG (0, "ERROR: vpp handle 0x%llx has no session index (%u)!", - mp->handle, session_index); + VERR ("vpp handle 0x%llx has no session index (%u)!", mp->handle, + session_index); + /* Should not happen but if it does, force vpp session cleanup */ + vcl_session_t tmp_session = { + .vpp_handle = mp->handle, + .vpp_evt_q = 0, + }; + vcl_segment_attach_session ( + mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo, + mp->vpp_event_queue_address, mp->mq_index, 0, session); + if (tmp_session.vpp_evt_q) + vcl_send_session_disconnect (wrk, &tmp_session); return VCL_INVALID_SESSION_INDEX; } + if (mp->retval) { - VDBG (0, "ERROR: session index %u: connect failed! %U", - session_index, format_session_error, mp->retval); + VDBG (0, "session %u: connect failed! %U", session_index, + format_session_error, mp->retval); session->session_state = VCL_STATE_DETACHED; - session->vpp_handle = mp->handle; + session->vpp_handle = VCL_INVALID_SESSION_HANDLE; return session_index; } session->vpp_handle = mp->handle; - if (vcl_segment_attach_session (mp->segment_handle, mp->server_rx_fifo, - mp->server_tx_fifo, - mp->vpp_event_queue_address, 0, session)) + /* Add to lookup table. Even if something fails, session cannot be + * cleaned up prior to notifying vpp and going through the cleanup + * "procedure" see @ref vcl_session_cleanup_handler */ + vcl_session_table_add_vpp_handle (wrk, mp->handle, session_index); + + if (vcl_segment_attach_session ( + mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo, + mp->vpp_event_queue_address, mp->mq_index, 0, session)) { - VDBG (0, "failed to attach fifos for %u", session->session_index); - session->session_state = VCL_STATE_DETACHED; + VDBG (0, "session %u [0x%llx]: failed to attach fifos", + session->session_index, session->vpp_handle); + session->session_state = VCL_STATE_UPDATED; vcl_send_session_disconnect (wrk, session); return session_index; } @@ -538,10 +428,12 @@ vcl_session_connected_handler (vcl_worker_t * wrk, if (mp->ct_rx_fifo) { if (vcl_segment_attach_session (mp->ct_segment_handle, mp->ct_rx_fifo, - mp->ct_tx_fifo, (uword) ~0, 1, session)) + mp->ct_tx_fifo, (uword) ~0, ~0, 1, + session)) { - VDBG (0, "failed to attach ct fifos for %u", session->session_index); - session->session_state = VCL_STATE_DETACHED; + VDBG (0, "session %u [0x%llx]: failed to attach ct fifos", + session->session_index, session->vpp_handle); + session->session_state = VCL_STATE_UPDATED; vcl_send_session_disconnect (wrk, session); return session_index; } @@ -559,12 +451,14 @@ vcl_session_connected_handler (vcl_worker_t * wrk, else session->session_state = VCL_STATE_READY; - /* Add it to lookup table */ - vcl_session_table_add_vpp_handle (wrk, mp->handle, session_index); - - VDBG (1, "session %u [0x%llx] connected! rx_fifo %p, refcnt %d, tx_fifo %p," - " refcnt %d", session_index, mp->handle, session->rx_fifo, - session->rx_fifo->refcnt, session->tx_fifo, session->tx_fifo->refcnt); + VDBG (0, "session %u [0x%llx] connected local: %U:%u remote %U:%u", + session->session_index, session->vpp_handle, vcl_format_ip46_address, + &session->transport.lcl_ip, + session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, + clib_net_to_host_u16 (session->transport.lcl_port), + vcl_format_ip46_address, &session->transport.rmt_ip, + session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, + clib_net_to_host_u16 (session->transport.rmt_port)); return session_index; } @@ -614,7 +508,7 @@ vcl_session_reset_handler (vcl_worker_t * wrk, if (session->session_state != VCL_STATE_CLOSED) session->session_state = VCL_STATE_DISCONNECT; - VDBG (0, "reset session %u [0x%llx]", sid, reset_msg->handle); + VDBG (0, "session %u [0x%llx]: reset", sid, reset_msg->handle); return sid; } @@ -637,8 +531,8 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp) } else { - VDBG (0, "ERROR: session %u [0x%llx]: Invalid session index!", - sid, mp->handle); + VDBG (0, "session %u [0x%llx]: Invalid session index!", sid, + mp->handle); return VCL_INVALID_SESSION_INDEX; } } @@ -654,9 +548,11 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp) if (vcl_session_is_cl (session)) { if (vcl_segment_attach_session (mp->segment_handle, mp->rx_fifo, - mp->tx_fifo, mp->vpp_evt_q, 0, session)) + mp->tx_fifo, mp->vpp_evt_q, mp->mq_index, + 0, session)) { - VDBG (0, "failed to attach fifos for %u", session->session_index); + VDBG (0, "session %u [0x%llx]: failed to attach fifos", + session->session_index, session->vpp_handle); session->session_state = VCL_STATE_DETACHED; return VCL_INVALID_SESSION_INDEX; } @@ -782,7 +678,7 @@ vcl_session_disconnected_handler (vcl_worker_t * wrk, session = vcl_session_get_w_vpp_handle (wrk, msg->handle); if (!session) { - VDBG (0, "request to disconnect unknown handle 0x%llx", msg->handle); + VWRN ("request to disconnect unknown handle 0x%llx", msg->handle); return 0; } @@ -822,7 +718,7 @@ vppcom_session_shutdown (uint32_t session_handle, int how) state = session->session_state; VDBG (1, "session %u [0x%llx] state 0x%x (%s)", session->session_index, - vpp_handle, state, vppcom_session_state_str (state)); + vpp_handle, state, vcl_session_state_str (state)); if (PREDICT_FALSE (state == VCL_STATE_LISTEN)) { @@ -864,8 +760,8 @@ vppcom_session_disconnect (u32 session_handle) vpp_handle = session->vpp_handle; state = session->session_state; - VDBG (1, "session %u [0x%llx] state 0x%x (%s)", session->session_index, - vpp_handle, state, vppcom_session_state_str (state)); + VDBG (1, "session %u [0x%llx]: disconnecting state (%s)", + session->session_index, vpp_handle, vcl_session_state_str (state)); if (PREDICT_FALSE (state == VCL_STATE_LISTEN)) { @@ -886,7 +782,7 @@ vppcom_session_disconnect (u32 session_handle) if (PREDICT_FALSE (!session->vpp_evt_q)) return VPPCOM_OK; - VDBG (1, "session %u [0x%llx]: sending disconnect...", + VDBG (1, "session %u [0x%llx]: sending disconnect", session->session_index, vpp_handle); vcl_send_session_disconnect (wrk, session); } @@ -910,7 +806,7 @@ vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data) session = vcl_session_get_w_vpp_handle (wrk, msg->handle); if (!session) { - VDBG (0, "disconnect confirmed for unknown handle 0x%llx", msg->handle); + VWRN ("disconnect confirmed for unknown handle 0x%llx", msg->handle); return; } @@ -941,15 +837,28 @@ vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data) return; } + /* VPP will reuse the handle so clean it up now */ vcl_session_table_del_vpp_handle (wrk, msg->handle); - /* Should not happen. App did not close the connection so don't free it. */ + + /* App did not close the connection yet so don't free it. */ if (session->session_state != VCL_STATE_CLOSED) { - VDBG (0, "app did not close session %d", session->session_index); + VDBG (0, "session %u: app did not close", session->session_index); session->session_state = VCL_STATE_DETACHED; session->vpp_handle = VCL_INVALID_SESSION_HANDLE; return; } + + /* Session probably tracked with epoll, disconnect not yet handled and + * 1) both transport and session cleanup completed 2) app closed. Wait + * until message is drained to free the session. + * See @ref vcl_handle_mq_event */ + if (session->flags & VCL_SESSION_F_PENDING_DISCONNECT) + { + session->flags |= VCL_SESSION_F_PENDING_FREE; + return; + } + vcl_session_free (wrk, session); } @@ -984,7 +893,7 @@ vcl_session_worker_update_reply_handler (vcl_worker_t * wrk, void *data) if (s->rx_fifo) { if (vcl_segment_attach_session (msg->segment_handle, msg->rx_fifo, - msg->tx_fifo, (uword) ~0, 0, s)) + msg->tx_fifo, (uword) ~0, ~0, 0, s)) { VDBG (0, "failed to attach fifos for %u", s->session_index); return; @@ -1122,9 +1031,16 @@ vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e) disconnected_msg = (session_disconnected_msg_t *) e->data; if (!(s = vcl_session_get_w_vpp_handle (wrk, disconnected_msg->handle))) break; + if (s->session_state == VCL_STATE_CLOSED) + break; if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK)) { - vec_add1 (wrk->unhandled_evts_vector, *e); + s->session_state = VCL_STATE_VPP_CLOSING; + s->flags |= VCL_SESSION_F_PENDING_DISCONNECT; + vec_add2 (wrk->unhandled_evts_vector, ecpy, 1); + *ecpy = *e; + ecpy->postponed = 1; + ecpy->session_index = s->session_index; break; } if (!(s = vcl_session_disconnected_handler (wrk, disconnected_msg))) @@ -1136,9 +1052,16 @@ vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e) reset_msg = (session_reset_msg_t *) e->data; if (!(s = vcl_session_get_w_vpp_handle (wrk, reset_msg->handle))) break; + if (s->session_state == VCL_STATE_CLOSED) + break; if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK)) { - vec_add1 (wrk->unhandled_evts_vector, *e); + s->flags |= VCL_SESSION_F_PENDING_DISCONNECT; + s->session_state = VCL_STATE_DISCONNECT; + vec_add2 (wrk->unhandled_evts_vector, ecpy, 1); + *ecpy = *e; + ecpy->postponed = 1; + ecpy->session_index = s->session_index; break; } vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data); @@ -1215,7 +1138,7 @@ vppcom_wait_for_session_state_change (u32 session_index, while (clib_time_now (&wrk->clib_time) < timeout); VDBG (0, "timeout waiting for state 0x%x (%s)", state, - vppcom_session_state_str (state)); + vcl_session_state_str (state)); vcl_evt (VCL_EVT_SESSION_TIMEOUT, session, session_state); return VPPCOM_ETIMEDOUT; @@ -1333,6 +1256,33 @@ vcl_api_attach (void) return vcl_bapi_attach (); } +static void +vcl_api_retry_attach (vcl_worker_t *wrk) +{ + vcl_session_t *s; + + if (vcl_api_attach ()) + return; + + /* Treat listeners as configuration that needs to be re-added to vpp */ + pool_foreach (s, wrk->sessions) + { + if (s->flags & VCL_SESSION_F_IS_VEP) + continue; + if (s->session_state == VCL_STATE_LISTEN_NO_MQ) + vppcom_session_listen (vcl_session_handle (s), 10); + else + VDBG (0, "internal error: unexpected state %d", s->session_state); + } +} + +static void +vcl_api_handle_disconnect (vcl_worker_t *wrk) +{ + wrk->api_client_handle = ~0; + vcl_worker_detach_sessions (wrk); +} + static void vcl_api_detach (vcl_worker_t * wrk) { @@ -1366,8 +1316,8 @@ vppcom_app_create (const char *app_name) vcm->main_cpu = pthread_self (); vcm->main_pid = getpid (); vcm->app_name = format (0, "%s", app_name); - fifo_segment_main_init (&vcm->segment_main, vcl_cfg->segment_baseva, - 20 /* timeout in secs */ ); + fifo_segment_main_init (&vcm->segment_main, (uword) ~0, + 20 /* timeout in secs */); pool_alloc (vcm->workers, vcl_cfg->max_workers); clib_spinlock_init (&vcm->workers_lock); clib_rwlock_init (&vcm->segment_table_lock); @@ -1446,15 +1396,50 @@ vppcom_session_create (u8 proto, u8 is_nonblocking) } static void -vcl_epoll_wait_clean_lt (vcl_worker_t *wrk, u32 sid) +vcl_epoll_lt_add (vcl_worker_t *wrk, vcl_session_t *s) { - int i; + vcl_session_t *cur, *prev; + + if (wrk->ep_lt_current == VCL_INVALID_SESSION_INDEX) + { + wrk->ep_lt_current = s->session_index; + s->vep.lt_next = s->session_index; + s->vep.lt_prev = s->session_index; + return; + } + + cur = vcl_session_get (wrk, wrk->ep_lt_current); + prev = vcl_session_get (wrk, cur->vep.lt_prev); + + prev->vep.lt_next = s->session_index; + s->vep.lt_prev = prev->session_index; + + s->vep.lt_next = cur->session_index; + cur->vep.lt_prev = s->session_index; +} + +static void +vcl_epoll_lt_del (vcl_worker_t *wrk, vcl_session_t *s) +{ + vcl_session_t *prev, *next; - for (i = vec_len (wrk->ep_level_evts) - 1; i >= 0; i--) + if (s->vep.lt_next == s->session_index) { - if (wrk->ep_level_evts[i] == sid) - vec_del1 (wrk->ep_level_evts, i); + wrk->ep_lt_current = VCL_INVALID_SESSION_INDEX; + s->vep.lt_next = VCL_INVALID_SESSION_INDEX; + return; } + + prev = vcl_session_get (wrk, s->vep.lt_prev); + next = vcl_session_get (wrk, s->vep.lt_next); + + prev->vep.lt_next = next->session_index; + next->vep.lt_prev = prev->session_index; + + if (s->session_index == wrk->ep_lt_current) + wrk->ep_lt_current = s->vep.lt_next; + + s->vep.lt_next = VCL_INVALID_SESSION_INDEX; } int @@ -1487,8 +1472,6 @@ vcl_session_cleanup (vcl_worker_t * wrk, vcl_session_t * s, VDBG (0, "session %u [0x%llx]: EPOLL_CTL_DEL vep_idx %u " "failed! rv %d (%s)", s->session_index, s->vpp_handle, s->vep.vep_sh, rv, vppcom_retval_str (rv)); - if (PREDICT_FALSE (vec_len (wrk->ep_level_evts))) - vcl_epoll_wait_clean_lt (wrk, s->session_index); } if (!do_disconnect) @@ -1522,9 +1505,14 @@ vcl_session_cleanup (vcl_worker_t * wrk, vcl_session_t * s, } else if (s->session_state == VCL_STATE_DETACHED) { - /* Should not happen. VPP cleaned up before app confirmed close */ VDBG (0, "vpp freed session %d before close", s->session_index); - goto free_session; + + if (!(s->flags & VCL_SESSION_F_PENDING_DISCONNECT)) + goto free_session; + + /* Disconnect/reset messages pending but vpp transport and session + * cleanups already done. Free only after messages drained. */ + s->flags |= VCL_SESSION_F_PENDING_FREE; } s->session_state = VCL_STATE_CLOSED; @@ -1583,10 +1571,12 @@ vppcom_session_bind (uint32_t session_handle, vppcom_endpt_t * ep) sizeof (ip6_address_t)); session->transport.lcl_port = ep->port; - VDBG (0, "session %u handle %u: binding to local %s address %U port %u, " - "proto %s", session->session_index, session_handle, - session->transport.is_ip4 ? "IPv4" : "IPv6", - format_ip46_address, &session->transport.lcl_ip, + VDBG (0, + "session %u handle %u: binding to local %s address %U port %u, " + "proto %s", + session->session_index, session_handle, + session->transport.is_ip4 ? "IPv4" : "IPv6", vcl_format_ip46_address, + &session->transport.lcl_ip, session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (session->transport.lcl_port), vppcom_proto_str (session->session_type)); @@ -1610,9 +1600,6 @@ vppcom_session_listen (uint32_t listen_sh, uint32_t q_len) if (!listen_session || (listen_session->flags & VCL_SESSION_F_IS_VEP)) return VPPCOM_EBADFD; - if (q_len == 0 || q_len == ~0) - q_len = vcm->cfg.listen_queue_size; - listen_vpp_handle = listen_session->vpp_handle; if (listen_session->session_state == VCL_STATE_LISTEN) { @@ -1656,9 +1643,11 @@ validate_args_session_accept_ (vcl_worker_t * wrk, vcl_session_t * ls) if ((ls->session_state != VCL_STATE_LISTEN) && (!vcl_session_is_connectable_listener (wrk, ls))) { - VDBG (0, "ERROR: session [0x%llx]: not in listen state! state 0x%x" - " (%s)", ls->vpp_handle, ls->session_state, - vppcom_session_state_str (ls->session_state)); + VDBG (0, + "ERROR: session [0x%llx]: not in listen state! state 0x%x" + " (%s)", + ls->vpp_handle, ls->session_state, + vcl_session_state_str (ls->session_state)); return VPPCOM_EBADFD; } return VPPCOM_OK; @@ -1770,13 +1759,15 @@ handle: sizeof (ip6_address_t)); } - VDBG (0, "listener %u [0x%llx] accepted %u [0x%llx] peer: %U:%u " - "local: %U:%u", listen_session_handle, listen_session->vpp_handle, + VDBG (0, + "listener %u [0x%llx] accepted %u [0x%llx] peer: %U:%u " + "local: %U:%u", + listen_session_handle, listen_session->vpp_handle, client_session_index, client_session->vpp_handle, - format_ip46_address, &client_session->transport.rmt_ip, + vcl_format_ip46_address, &client_session->transport.rmt_ip, client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (client_session->transport.rmt_port), - format_ip46_address, &client_session->transport.lcl_ip, + vcl_format_ip46_address, &client_session->transport.lcl_ip, client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (client_session->transport.lcl_port)); vcl_evt (VCL_EVT_ACCEPT, client_session, listen_session, @@ -1810,22 +1801,21 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) if (PREDICT_FALSE (session->flags & VCL_SESSION_F_IS_VEP)) { - VDBG (0, "ERROR: cannot connect epoll session %u!", - session->session_index); + VWRN ("cannot connect epoll session %u!", session->session_index); return VPPCOM_EBADFD; } if (PREDICT_FALSE (vcl_session_is_ready (session))) { - VDBG (0, "session handle %u [0x%llx]: session already " - "connected to %s %U port %d proto %s, state 0x%x (%s)", - session_handle, session->vpp_handle, - session->transport.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, - &session->transport.rmt_ip, session->transport.is_ip4 ? - IP46_TYPE_IP4 : IP46_TYPE_IP6, + VDBG (0, + "session %u [0x%llx]: already connected to %U:%d proto %s," + " state (%s)", + session->session_index, session->vpp_handle, + vcl_format_ip46_address, &session->transport.rmt_ip, + session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (session->transport.rmt_port), - vppcom_proto_str (session->session_type), session->session_state, - vppcom_session_state_str (session->session_state)); + vppcom_proto_str (session->session_type), + vcl_session_state_str (session->session_state)); return VPPCOM_OK; } @@ -1844,13 +1834,10 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) session->parent_handle = VCL_INVALID_SESSION_HANDLE; session->flags |= VCL_SESSION_F_CONNECTED; - VDBG (0, "session handle %u (%s): connecting to peer %s %U " - "port %d proto %s", session_handle, - vppcom_session_state_str (session->session_state), - session->transport.is_ip4 ? "IPv4" : "IPv6", - format_ip46_address, - &session->transport.rmt_ip, session->transport.is_ip4 ? - IP46_TYPE_IP4 : IP46_TYPE_IP6, + VDBG (0, "session %u: connecting to peer %U:%d proto %s", + session->session_index, vcl_format_ip46_address, + &session->transport.rmt_ip, + session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (session->transport.rmt_port), vppcom_proto_str (session->session_type)); @@ -1905,12 +1892,13 @@ vppcom_session_stream_connect (uint32_t session_handle, if (PREDICT_FALSE (vcl_session_is_ready (session))) { - VDBG (0, "session handle %u [0x%llx]: session already " + VDBG (0, + "session handle %u [0x%llx]: session already " "connected to session %u [0x%llx] proto %s, state 0x%x (%s)", - session_handle, session->vpp_handle, - parent_session_handle, parent_session->vpp_handle, + session_handle, session->vpp_handle, parent_session_handle, + parent_session->vpp_handle, vppcom_proto_str (session->session_type), session->session_state, - vppcom_session_state_str (session->session_state)); + vcl_session_state_str (session->session_state)); return VPPCOM_OK; } @@ -1955,7 +1943,7 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n, u8 is_ct; if (PREDICT_FALSE (!buf)) - return VPPCOM_EINVAL; + return VPPCOM_EFAULT; s = vcl_session_get_w_handle (wrk, session_handle); if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP))) @@ -1965,7 +1953,7 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n, { VDBG (0, "session %u[0x%llx] is not open! state 0x%x (%s)", s->session_index, s->vpp_handle, s->session_state, - vppcom_session_state_str (s->session_state)); + vcl_session_state_str (s->session_state)); return vcl_session_closed_error (s); } @@ -2123,7 +2111,7 @@ vppcom_session_read_segments (uint32_t session_handle, } n_read = svm_fifo_segments (rx_fifo, s->rx_bytes_pending, - (svm_fifo_seg_t *) ds, n_segments, max_bytes); + (svm_fifo_seg_t *) ds, &n_segments, max_bytes); if (n_read < 0) return VPPCOM_EAGAIN; @@ -2161,7 +2149,7 @@ vppcom_session_free_segments (uint32_t session_handle, uint32_t n_bytes) is_ct = vcl_session_is_ct (s); svm_fifo_dequeue_drop (is_ct ? s->ct_rx_fifo : s->rx_fifo, n_bytes); - ASSERT (s->rx_bytes_pending < n_bytes); + ASSERT (s->rx_bytes_pending >= n_bytes); s->rx_bytes_pending -= n_bytes; } @@ -2203,7 +2191,7 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf, { VDBG (1, "session %u [0x%llx]: is not open! state 0x%x (%s)", s->session_index, s->vpp_handle, s->session_state, - vppcom_session_state_str (s->session_state)); + vcl_session_state_str (s->session_state)); return vcl_session_closed_error (s);; } @@ -2211,7 +2199,7 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf, { VDBG (1, "session %u [0x%llx]: is shutdown! state 0x%x (%s)", s->session_index, s->vpp_handle, s->session_state, - vppcom_session_state_str (s->session_state)); + vcl_session_state_str (s->session_state)); return VPPCOM_EPIPE; } @@ -2507,11 +2495,23 @@ vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits, int n_mq_evts, i; u64 buf; + if (PREDICT_FALSE (wrk->api_client_handle == ~0)) + { + vcl_api_retry_attach (wrk); + return 0; + } + vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns)); n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events, vec_len (wrk->mq_events), time_to_wait); for (i = 0; i < n_mq_evts; i++) { + if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0)) + { + vcl_api_handle_disconnect (wrk); + continue; + } + mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32); n_read = read (mqc->mq_fd, &buf, sizeof (buf)); vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map, @@ -2785,6 +2785,7 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle, s->vep.prev_sh = vep_handle; s->vep.vep_sh = vep_handle; s->vep.et_mask = VEP_DEFAULT_ET_MASK; + s->vep.lt_next = VCL_INVALID_SESSION_INDEX; s->vep.ev = *event; s->flags &= ~VCL_SESSION_F_IS_VEP; s->flags |= VCL_SESSION_F_IS_VEP_SESSION; @@ -2927,10 +2928,14 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle, next_session->vep.prev_sh = s->vep.prev_sh; } + if (s->vep.lt_next != VCL_INVALID_SESSION_INDEX) + vcl_epoll_lt_del (wrk, s); + memset (&s->vep, 0, sizeof (s->vep)); s->vep.next_sh = ~0; s->vep.prev_sh = ~0; s->vep.vep_sh = ~0; + s->vep.lt_next = VCL_INVALID_SESSION_INDEX; s->flags &= ~VCL_SESSION_F_IS_VEP_SESSION; if (vcl_session_is_open (s)) @@ -2976,24 +2981,25 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, break; vcl_fifo_rx_evt_valid_or_break (s); session_events = s->vep.ev.events; - if (!(EPOLLIN & s->vep.ev.events) - || (s->flags & VCL_SESSION_F_HAS_RX_EVT)) + if (!(EPOLLIN & s->vep.ev.events) || + (s->flags & VCL_SESSION_F_HAS_RX_EVT) || + (s->vep.lt_next != VCL_INVALID_SESSION_INDEX)) break; add_event = 1; - events[*num_ev].events |= EPOLLIN; + events[*num_ev].events = EPOLLIN; session_evt_data = s->vep.ev.data.u64; s->flags |= VCL_SESSION_F_HAS_RX_EVT; break; case SESSION_IO_EVT_TX: sid = e->session_index; s = vcl_session_get (wrk, sid); - if (vcl_session_is_closed (s)) + if (!s || !vcl_session_is_open (s)) break; session_events = s->vep.ev.events; if (!(EPOLLOUT & session_events)) break; add_event = 1; - events[*num_ev].events |= EPOLLOUT; + events[*num_ev].events = EPOLLOUT; session_evt_data = s->vep.ev.data.u64; svm_fifo_reset_has_deq_ntf (vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo); @@ -3007,10 +3013,11 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, break; session_events = s->vep.ev.events; sid = s->session_index; - if (!(EPOLLIN & session_events)) + if (!(EPOLLIN & session_events) || + (s->vep.lt_next != VCL_INVALID_SESSION_INDEX)) break; add_event = 1; - events[*num_ev].events |= EPOLLIN; + events[*num_ev].events = EPOLLIN; session_evt_data = s->vep.ev.data.u64; break; case SESSION_CTRL_EVT_CONNECTED: @@ -3029,7 +3036,7 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, if (!(EPOLLOUT & session_events)) break; add_event = 1; - events[*num_ev].events |= EPOLLOUT; + events[*num_ev].events = EPOLLOUT; session_evt_data = s->vep.ev.data.u64; if (s->session_state == VCL_STATE_DETACHED) events[*num_ev].events |= EPOLLHUP; @@ -3043,28 +3050,58 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, else { s = vcl_session_get (wrk, e->session_index); + s->flags &= ~VCL_SESSION_F_PENDING_DISCONNECT; } if (vcl_session_is_closed (s) || !(s->flags & VCL_SESSION_F_IS_VEP_SESSION)) - break; + { + if (s && (s->flags & VCL_SESSION_F_PENDING_FREE)) + vcl_session_free (wrk, s); + break; + } sid = s->session_index; session_events = s->vep.ev.events; add_event = 1; - events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP; + if (EPOLLRDHUP & session_events) + { + /* If app can distinguish between RDHUP and HUP, + * we make finer control */ + events[*num_ev].events = EPOLLRDHUP; + if (s->flags & VCL_SESSION_F_WR_SHUTDOWN) + { + events[*num_ev].events |= EPOLLHUP; + } + } + else + { + events[*num_ev].events = EPOLLHUP; + } session_evt_data = s->vep.ev.data.u64; + break; case SESSION_CTRL_EVT_RESET: if (!e->postponed) - sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data); + { + sid = + vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data); + s = vcl_session_get (wrk, sid); + } else - sid = e->session_index; - s = vcl_session_get (wrk, sid); + { + sid = e->session_index; + s = vcl_session_get (wrk, sid); + s->flags &= ~VCL_SESSION_F_PENDING_DISCONNECT; + } if (vcl_session_is_closed (s) || !(s->flags & VCL_SESSION_F_IS_VEP_SESSION)) - break; + { + if (s && (s->flags & VCL_SESSION_F_PENDING_FREE)) + vcl_session_free (wrk, s); + break; + } session_events = s->vep.ev.events; add_event = 1; - events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP; + events[*num_ev].events = EPOLLHUP | EPOLLRDHUP; session_evt_data = s->vep.ev.data.u64; break; case SESSION_CTRL_EVT_UNLISTEN_REPLY: @@ -3104,9 +3141,11 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, s = vcl_session_get (wrk, sid); s->vep.ev.events = 0; } - if (!(EPOLLET & session_events)) + else if (!(EPOLLET & session_events)) { - vec_add1 (wrk->ep_level_evts, sid); + s = vcl_session_get (wrk, sid); + if (s->vep.lt_next == VCL_INVALID_SESSION_INDEX) + vcl_epoll_lt_add (wrk, s); } *num_ev += 1; } @@ -3189,6 +3228,12 @@ vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events, double end = -1; u64 buf; + if (PREDICT_FALSE (wrk->api_client_handle == ~0)) + { + vcl_api_retry_attach (wrk); + return n_evts; + } + vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns)); if (!n_evts) { @@ -3208,6 +3253,13 @@ vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events, for (i = 0; i < n_mq_evts; i++) { + if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0)) + { + /* api socket was closed */ + vcl_api_handle_disconnect (wrk); + continue; + } + mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32); n_read = read (mqc->mq_fd, &buf, sizeof (buf)); vcl_epoll_wait_handle_mq (wrk, mqc->mq, events, maxevents, 0, @@ -3222,46 +3274,41 @@ vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events, return 0; } -static void -vcl_epoll_swap_lt_lists (vcl_worker_t *wrk) -{ - u32 *le; - - le = wrk->ep_level_evts; - wrk->ep_level_evts = wrk->ep_level_evts_fl; - wrk->ep_level_evts_fl = le; -} - static void vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events, int maxevents, u32 *n_evts) { - u32 *sid, add_event = 0, *le = wrk->ep_level_evts_fl; + u32 add_event = 0, next; vcl_session_t *s; u64 evt_data; + int rv; + ASSERT (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX); if (*n_evts >= maxevents) - { - vec_add (wrk->ep_level_evts, le, vec_len (le)); - vec_reset_length (wrk->ep_level_evts_fl); - return; - } + return; - vec_foreach (sid, le) + next = wrk->ep_lt_current; + do { - s = vcl_session_get (wrk, sid[0]); - if (!s) - continue; - if ((s->vep.ev.events & EPOLLIN) && vcl_session_read_ready (s)) + s = vcl_session_get (wrk, next); + next = s->vep.lt_next; + + if ((s->vep.ev.events & EPOLLIN) && (rv = vcl_session_read_ready (s))) + { + add_event = 1; + events[*n_evts].events |= rv > 0 ? EPOLLIN : EPOLLHUP | EPOLLRDHUP; + evt_data = s->vep.ev.data.u64; + } + if ((s->vep.ev.events & EPOLLOUT) && (rv = vcl_session_write_ready (s))) { add_event = 1; - events[*n_evts].events |= EPOLLIN; + events[*n_evts].events |= rv > 0 ? EPOLLOUT : EPOLLHUP | EPOLLRDHUP; evt_data = s->vep.ev.data.u64; } - if ((s->vep.ev.events & EPOLLOUT) && vcl_session_write_ready (s)) + if (!add_event && s->session_state > VCL_STATE_READY) { add_event = 1; - events[*n_evts].events |= EPOLLOUT; + events[*n_evts].events |= EPOLLHUP | EPOLLRDHUP; evt_data = s->vep.ev.data.u64; } if (add_event) @@ -3269,17 +3316,22 @@ vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events, events[*n_evts].data.u64 = evt_data; *n_evts += 1; add_event = 0; - vec_add1 (wrk->ep_level_evts, sid[0]); + if (EPOLLONESHOT & s->vep.ev.events) + s->vep.ev.events = 0; if (*n_evts == maxevents) { - u32 pos = (sid - le) + 1; - vec_add (wrk->ep_level_evts, &le[pos], vec_len (le) - pos); + wrk->ep_lt_current = next; break; } } + else + { + vcl_epoll_lt_del (wrk, s); + if (wrk->ep_lt_current == VCL_INVALID_SESSION_INDEX) + break; + } } - - vec_reset_length (wrk->ep_level_evts_fl); + while (next != wrk->ep_lt_current); } int @@ -3288,7 +3340,7 @@ vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events, { vcl_worker_t *wrk = vcl_worker_get_current (); vcl_session_t *vep_session; - u32 n_evts = 0, do_lt = 0; + u32 n_evts = 0; int i; if (PREDICT_FALSE (maxevents <= 0)) @@ -3307,8 +3359,6 @@ vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events, return VPPCOM_EINVAL; } - memset (events, 0, sizeof (*events) * maxevents); - if (vec_len (wrk->unhandled_evts_vector)) { for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++) @@ -3323,15 +3373,14 @@ vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events, } vec_reset_length (wrk->unhandled_evts_vector); } + + if (PREDICT_FALSE (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX)) + vcl_epoll_wait_handle_lt (wrk, events, maxevents, &n_evts); + /* Request to only drain unhandled */ if ((int) wait_for_time == -2) return n_evts; - if (PREDICT_FALSE (vec_len (wrk->ep_level_evts))) - { - vcl_epoll_swap_lt_lists (wrk); - do_lt = 1; - } if (vcm->cfg.use_mq_eventfd) n_evts = vppcom_epoll_wait_eventfd (wrk, events, maxevents, n_evts, @@ -3340,9 +3389,6 @@ vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events, n_evts = vppcom_epoll_wait_condvar (wrk, events, maxevents, n_evts, wait_for_time); - if (PREDICT_FALSE (do_lt)) - vcl_epoll_wait_handle_lt (wrk, events, maxevents, &n_evts); - return n_evts; } @@ -3420,9 +3466,11 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6, sizeof (ip6_address_t)); *buflen = sizeof (*ep); - VDBG (1, "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, " - "addr = %U, port %u", session_handle, ep->is_ip4, - format_ip46_address, &session->transport.rmt_ip, + VDBG (1, + "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, " + "addr = %U, port %u", + session_handle, ep->is_ip4, vcl_format_ip46_address, + &session->transport.rmt_ip, ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (ep->port)); } @@ -3443,8 +3491,10 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip6, sizeof (ip6_address_t)); *buflen = sizeof (*ep); - VDBG (1, "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U" - " port %d", session_handle, ep->is_ip4, format_ip46_address, + VDBG (1, + "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U" + " port %d", + session_handle, ep->is_ip4, vcl_format_ip46_address, &session->transport.lcl_ip, ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (ep->port)); @@ -3461,8 +3511,10 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, session->transport.lcl_port = ep->port; vcl_ip_copy_from_ep (&session->transport.lcl_ip, ep); *buflen = sizeof (*ep); - VDBG (1, "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U" - " port %d", session_handle, ep->is_ip4, format_ip46_address, + VDBG (1, + "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U" + " port %d", + session_handle, ep->is_ip4, vcl_format_ip46_address, &session->transport.lcl_ip, ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (ep->port)); @@ -3549,6 +3601,18 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, rv = VPPCOM_EINVAL; break; + case VPPCOM_ATTR_SET_DSCP: + if (buffer && buflen && (*buflen >= sizeof (u8))) + { + session->dscp = *(u8 *) buffer; + + VDBG (2, "VPPCOM_ATTR_SET_DSCP: %u (0x%x), buflen %d,", + *(u8 *) buffer, *(u8 *) buffer, *buflen); + } + else + rv = VPPCOM_EINVAL; + break; + case VPPCOM_ATTR_SET_TX_FIFO_LEN: if (buffer && buflen && (*buflen == sizeof (u32))) { @@ -4025,6 +4089,10 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer, if (!vcl_session_is_cl (s)) return VPPCOM_EINVAL; + s->transport.is_ip4 = ep->is_ip4; + s->transport.rmt_port = ep->port; + vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep); + /* Session not connected/bound in vpp. Create it by 'connecting' it */ if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED)) { @@ -4040,10 +4108,6 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer, return rv; s = vcl_session_get (wrk, session_index); } - - s->transport.is_ip4 = ep->is_ip4; - s->transport.rmt_port = ep->port; - vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep); } if (flags) @@ -4353,22 +4417,18 @@ int vppcom_add_cert_key_pair (vppcom_cert_key_pair_t *ckpair) { if (vcm->cfg.vpp_app_socket_api) - { - clib_warning ("not supported"); - return VPPCOM_EINVAL; - } - return vcl_bapi_add_cert_key_pair (ckpair); + return vcl_sapi_add_cert_key_pair (ckpair); + else + return vcl_bapi_add_cert_key_pair (ckpair); } int vppcom_del_cert_key_pair (uint32_t ckpair_index) { if (vcm->cfg.vpp_app_socket_api) - { - clib_warning ("not supported"); - return VPPCOM_EINVAL; - } - return vcl_bapi_del_cert_key_pair (ckpair_index); + return vcl_sapi_del_cert_key_pair (ckpair_index); + else + return vcl_bapi_del_cert_key_pair (ckpair_index); } /*