From dfb3b8771292e4c863ca266856aa2b5eb7cc7518 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Fri, 16 Aug 2019 17:48:44 -0700 Subject: session: add explicit reset api Type: feature This can be used to forcefully close a session. It's only available to builtin applications for now. Transports must support the reset api otherwise normal close is used. Change-Id: I5e6d681cbc4c8045385e293e0e9d86fa2bf45849 Signed-off-by: Florin Coras --- src/vnet/session/session.c | 46 +++++++++++++++++++++++++++++++++++------ src/vnet/session/session.h | 2 ++ src/vnet/session/session_node.c | 6 ++++++ src/vnet/session/transport.c | 9 ++++++++ src/vnet/session/transport.h | 2 ++ src/vnet/tcp/tcp.c | 13 ++++++++++++ 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index a102825c6f5..45292454e57 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -144,7 +144,7 @@ session_add_self_custom_tx_evt (transport_connection_t * tc, u8 has_prio) } static void -session_program_transport_close (session_t * s) +session_program_transport_ctrl_evt (session_t * s, session_evt_type_t evt) { u32 thread_index = vlib_get_thread_index (); session_evt_elt_t *elt; @@ -158,10 +158,10 @@ session_program_transport_close (session_t * s) elt = session_evt_alloc_ctrl (wrk); clib_memset (&elt->evt, 0, sizeof (session_event_t)); elt->evt.session_handle = session_handle (s); - elt->evt.event_type = SESSION_CTRL_EVT_CLOSE; + elt->evt.event_type = evt; } else - session_send_ctrl_evt_to_thread (s, SESSION_CTRL_EVT_CLOSE); + session_send_ctrl_evt_to_thread (s, evt); } session_t * @@ -888,7 +888,7 @@ session_transport_delete_notify (transport_connection_t * tc) s->session_state = SESSION_STATE_CLOSED; session_cleanup_notify (s, SESSION_CLEANUP_TRANSPORT); svm_fifo_dequeue_drop_all (s->tx_fifo); - session_program_transport_close (s); + session_program_transport_ctrl_evt (s, SESSION_CTRL_EVT_CLOSE); break; case SESSION_STATE_TRANSPORT_DELETED: break; @@ -1194,12 +1194,26 @@ session_close (session_t * s) * acknowledge the close */ if (s->session_state == SESSION_STATE_TRANSPORT_CLOSED || s->session_state == SESSION_STATE_TRANSPORT_DELETED) - session_program_transport_close (s); + session_program_transport_ctrl_evt (s, SESSION_CTRL_EVT_CLOSE); return; } s->session_state = SESSION_STATE_CLOSING; - session_program_transport_close (s); + session_program_transport_ctrl_evt (s, SESSION_CTRL_EVT_CLOSE); +} + +/** + * Force a close without waiting for data to be flushed + */ +void +session_reset (session_t * s) +{ + if (s->session_state >= SESSION_STATE_CLOSING) + return; + /* Drop all outstanding tx data */ + svm_fifo_dequeue_drop_all (s->tx_fifo); + s->session_state = SESSION_STATE_CLOSING; + session_program_transport_ctrl_evt (s, SESSION_CTRL_EVT_RESET); } /** @@ -1234,6 +1248,26 @@ session_transport_close (session_t * s) s->thread_index); } +/** + * Force transport close + */ +void +session_transport_reset (session_t * s) +{ + if (s->session_state >= SESSION_STATE_APP_CLOSED) + { + if (s->session_state == SESSION_STATE_TRANSPORT_CLOSED) + s->session_state = SESSION_STATE_CLOSED; + else if (s->session_state >= SESSION_STATE_TRANSPORT_DELETED) + session_free_w_fifos (s); + return; + } + + s->session_state = SESSION_STATE_APP_CLOSED; + transport_reset (session_get_transport_proto (s), s->connection_index, + s->thread_index); +} + /** * Cleanup transport and session state. * diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h index 5af824ade60..de44bed27c9 100644 --- a/src/vnet/session/session.h +++ b/src/vnet/session/session.h @@ -376,7 +376,9 @@ int session_open (u32 app_index, session_endpoint_t * tep, u32 opaque); int session_listen (session_t * s, session_endpoint_cfg_t * sep); int session_stop_listen (session_t * s); void session_close (session_t * s); +void session_reset (session_t * s); void session_transport_close (session_t * s); +void session_transport_reset (session_t * s); void session_transport_cleanup (session_t * s); int session_send_io_evt_to_thread (svm_fifo_t * f, session_evt_type_t evt_type); diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index 5af54a8165a..1d662a20e3c 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -902,6 +902,12 @@ session_event_dispatch (session_worker_t * wrk, vlib_node_runtime_t * node, break; session_transport_close (s); break; + case SESSION_CTRL_EVT_RESET: + s = session_get_from_handle_if_valid (e->session_handle); + if (PREDICT_FALSE (!s)) + break; + session_transport_reset (s); + break; case SESSION_IO_EVT_BUILTIN_RX: s = session_event_get_session (e, thread_index); if (PREDICT_FALSE (!s || s->session_state >= SESSION_STATE_CLOSING)) diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c index 22a356eaae2..aa8deac5400 100644 --- a/src/vnet/session/transport.c +++ b/src/vnet/session/transport.c @@ -324,6 +324,15 @@ transport_close (transport_proto_t tp, u32 conn_index, u8 thread_index) tp_vfts[tp].close (conn_index, thread_index); } +void +transport_reset (transport_proto_t tp, u32 conn_index, u8 thread_index) +{ + if (tp_vfts[tp].reset) + tp_vfts[tp].reset (conn_index, thread_index); + else + tp_vfts[tp].close (conn_index, thread_index); +} + u32 transport_start_listen (transport_proto_t tp, u32 session_index, transport_endpoint_t * tep) diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h index c4f74ebe991..cbe3c36734c 100644 --- a/src/vnet/session/transport.h +++ b/src/vnet/session/transport.h @@ -39,6 +39,7 @@ typedef struct _transport_proto_vft u32 (*stop_listen) (u32 conn_index); int (*connect) (transport_endpoint_cfg_t * rmt); void (*close) (u32 conn_index, u32 thread_index); + void (*reset) (u32 conn_index, u32 thread_index); void (*cleanup) (u32 conn_index, u32 thread_index); clib_error_t *(*enable) (vlib_main_t * vm, u8 is_en); @@ -96,6 +97,7 @@ do { \ int transport_connect (transport_proto_t tp, transport_endpoint_cfg_t * tep); void transport_close (transport_proto_t tp, u32 conn_index, u8 thread_index); +void transport_reset (transport_proto_t tp, u32 conn_index, u8 thread_index); u32 transport_start_listen (transport_proto_t tp, u32 session_index, transport_endpoint_t * tep); u32 transport_stop_listen (transport_proto_t tp, u32 conn_index); diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index 44ee8c8bfcb..f9cb2a28e27 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -477,6 +477,18 @@ tcp_session_cleanup (u32 conn_index, u32 thread_index) tcp_connection_cleanup (tc); } +static void +tcp_session_reset (u32 conn_index, u32 thread_index) +{ + tcp_connection_t *tc; + tc = tcp_connection_get (conn_index, thread_index); + session_transport_closed_notify (&tc->connection); + tcp_send_reset (tc); + tcp_connection_timers_reset (tc); + tcp_connection_set_state (tc, TCP_STATE_CLOSED); + tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, tcp_cfg.cleanup_time); +} + /** * Initialize all connection timers as invalid */ @@ -1258,6 +1270,7 @@ const static transport_proto_vft_t tcp_proto = { .connect = tcp_session_open, .close = tcp_session_close, .cleanup = tcp_session_cleanup, + .reset = tcp_session_reset, .send_mss = tcp_session_send_mss, .send_space = tcp_session_send_space, .update_time = tcp_update_time, -- cgit 1.2.3-korg