From 534468e9f768ae7465ef722520dadfd916cdc9fb Mon Sep 17 00:00:00 2001 From: liuyacan Date: Sun, 9 May 2021 03:50:40 +0000 Subject: session: support half-close connection Some app(e.g. Envoy) may call shutdown() instead of close() when draining connection. Type: improvement Signed-off-by: liuyacan Change-Id: I9543b9ca3caa87b10b134fd1fc4019124e41e4d2 --- src/vcl/ldp.c | 2 ++ src/vcl/vcl_locked.c | 18 +++++++++++++++++ src/vcl/vcl_locked.h | 1 + src/vcl/vcl_private.h | 1 + src/vcl/vppcom.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/vcl/vppcom.h | 1 + 6 files changed, 78 insertions(+), 1 deletion(-) (limited to 'src/vcl') diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c index 64a4e7c77db..f27f6ba8e97 100644 --- a/src/vcl/ldp.c +++ b/src/vcl/ldp.c @@ -2219,6 +2219,8 @@ shutdown (int fd, int how) if (flags == SHUT_RDWR) rv = close (fd); + else if (flags == SHUT_WR) + rv = vls_shutdown (vlsh); } else { diff --git a/src/vcl/vcl_locked.c b/src/vcl/vcl_locked.c index 757c0fc45a7..69f492b8694 100644 --- a/src/vcl/vcl_locked.c +++ b/src/vcl/vcl_locked.c @@ -1313,6 +1313,24 @@ vls_close (vls_handle_t vlsh) return rv; } +int +vls_shutdown (vls_handle_t vlsh) +{ + vcl_locked_session_t *vls; + int rv; + + vls_mt_detect (); + if (!(vls = vls_get_w_dlock (vlsh))) + return VPPCOM_EBADFD; + + vls_mt_guard (vls, VLS_MT_OP_SPOOL); + rv = vppcom_session_shutdown (vls_to_sh (vls)); + vls_mt_unguard (); + vls_get_and_unlock (vlsh); + + return rv; +} + vls_handle_t vls_epoll_create (void) { diff --git a/src/vcl/vcl_locked.h b/src/vcl/vcl_locked.h index 11b71eee4af..3adcf62bc77 100644 --- a/src/vcl/vcl_locked.h +++ b/src/vcl/vcl_locked.h @@ -26,6 +26,7 @@ typedef int vls_handle_t; vls_handle_t vls_create (uint8_t proto, uint8_t is_nonblocking); +int vls_shutdown (vls_handle_t vlsh); int vls_close (vls_handle_t vlsh); int vls_bind (vls_handle_t vlsh, vppcom_endpt_t * ep); int vls_listen (vls_handle_t vlsh, int q_len); diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h index 6060ef82357..956f077b880 100644 --- a/src/vcl/vcl_private.h +++ b/src/vcl/vcl_private.h @@ -137,6 +137,7 @@ typedef enum vcl_session_flags_ VCL_SESSION_F_IS_VEP = 1 << 1, VCL_SESSION_F_IS_VEP_SESSION = 1 << 2, VCL_SESSION_F_HAS_RX_EVT = 1 << 3, + VCL_SESSION_F_SHUTDOWN = 1 << 4, } __clib_packed vcl_session_flags_t; typedef struct vcl_session_ diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 96a207b741f..0713a7b2d33 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -259,6 +259,23 @@ vcl_send_session_unlisten (vcl_worker_t * wrk, vcl_session_t * s) app_send_ctrl_evt_to_vpp (mq, app_evt); } +static void +vcl_send_session_shutdown (vcl_worker_t *wrk, vcl_session_t *s) +{ + app_session_evt_t _app_evt, *app_evt = &_app_evt; + session_shutdown_msg_t *mp; + svm_msg_q_t *mq; + + /* Send to thread that owns the session */ + mq = s->vpp_evt_q; + app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_SHUTDOWN); + mp = (session_shutdown_msg_t *) app_evt->evt->data; + memset (mp, 0, sizeof (*mp)); + mp->client_index = wrk->api_client_handle; + mp->handle = s->vpp_handle; + app_send_ctrl_evt_to_vpp (mq, app_evt); +} + static void vcl_send_session_disconnect (vcl_worker_t * wrk, vcl_session_t * s) { @@ -789,6 +806,42 @@ vcl_session_disconnected_handler (vcl_worker_t * wrk, return session; } +int +vppcom_session_shutdown (uint32_t session_handle) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + vcl_session_t *session; + vcl_session_state_t state; + u64 vpp_handle; + + session = vcl_session_get_w_handle (wrk, session_handle); + if (PREDICT_FALSE (!session)) + return VPPCOM_EBADFD; + + 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)); + + if (PREDICT_FALSE (state == VCL_STATE_LISTEN)) + { + VDBG (0, "ERROR: Cannot shutdown a listen socket!"); + return VPPCOM_EBADFD; + } + + if (PREDICT_TRUE (state == VCL_STATE_READY)) + { + VDBG (1, "session %u [0x%llx]: sending shutdown...", + session->session_index, vpp_handle); + + vcl_send_session_shutdown (wrk, session); + session->flags |= VCL_SESSION_F_SHUTDOWN; + } + + return VPPCOM_OK; +} + static int vppcom_session_disconnect (u32 session_handle) { @@ -2101,7 +2154,8 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf, return VPPCOM_EBADFD; } - if (PREDICT_FALSE (!vcl_session_is_open (s))) + if (PREDICT_FALSE (!vcl_session_is_open (s) || + s->flags & VCL_SESSION_F_SHUTDOWN)) { VDBG (1, "session %u [0x%llx]: is not open! state 0x%x (%s)", s->session_index, s->vpp_handle, s->session_state, diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h index ae4888566c7..72e5d46bc8f 100644 --- a/src/vcl/vppcom.h +++ b/src/vcl/vppcom.h @@ -172,6 +172,7 @@ extern int vppcom_app_create (const char *app_name); extern void vppcom_app_destroy (void); extern int vppcom_session_create (uint8_t proto, uint8_t is_nonblocking); +extern int vppcom_session_shutdown (uint32_t session_handle); extern int vppcom_session_close (uint32_t session_handle); extern int vppcom_session_bind (uint32_t session_handle, vppcom_endpt_t * ep); extern int vppcom_session_listen (uint32_t session_handle, uint32_t q_len); -- cgit 1.2.3-korg