session: postpone ct cleanups

Add infra to postpone cleanups while tx events are not delivered.

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I7611ac2442116f71a229569a7e274eb58eb84546
This commit is contained in:
Florin Coras
2021-11-09 08:38:24 -08:00
committed by Florin Coras
parent a360e6fc11
commit 440c7b5570

View File

@@ -41,9 +41,16 @@ typedef struct ct_segments_
ct_segment_t *segments;
} ct_segments_ctx_t;
typedef struct ct_cleanup_req_
{
u32 ct_index;
} ct_cleanup_req_t;
typedef struct ct_main_
{
ct_connection_t **connections; /**< Per-worker connection pools */
ct_cleanup_req_t **pending_cleanups;
u8 *heave_cleanups;
u32 n_workers; /**< Number of vpp workers */
u32 n_sessions; /**< Cumulative sessions counter */
u32 *ho_reusable; /**< Vector of reusable ho indices */
@@ -863,11 +870,103 @@ global_scope:
return SESSION_E_LOCAL_CONNECT;
}
static void
ct_session_postponed_cleanup (ct_connection_t *ct)
{
app_worker_t *app_wrk;
session_t *s;
s = session_get (ct->c_s_index, ct->c_thread_index);
app_wrk = app_worker_get_if_valid (s->app_wrk_index);
if (ct->flags & CT_CONN_F_CLIENT)
{
if (app_wrk)
app_worker_cleanup_notify (app_wrk, s, SESSION_CLEANUP_TRANSPORT);
/* Normal free for client session as the fifos are allocated through
* the connects segment manager in a segment that's not shared with
* the server */
session_free_w_fifos (s);
ct_session_dealloc_fifos (ct, ct->client_rx_fifo, ct->client_tx_fifo);
}
else
{
/* Manual session and fifo segment cleanup to avoid implicit
* segment manager cleanups and notifications */
app_wrk = app_worker_get_if_valid (s->app_wrk_index);
if (app_wrk)
{
app_worker_cleanup_notify (app_wrk, s, SESSION_CLEANUP_TRANSPORT);
app_worker_cleanup_notify (app_wrk, s, SESSION_CLEANUP_SESSION);
}
ct_session_dealloc_fifos (ct, s->rx_fifo, s->tx_fifo);
session_free (s);
}
ct_connection_free (ct);
}
static void
ct_handle_cleanups (void *args)
{
uword thread_index = pointer_to_uword (args);
const u32 max_cleanups = 100;
ct_main_t *cm = &ct_main;
ct_cleanup_req_t *req;
ct_connection_t *ct;
u32 n_to_handle = 0;
session_t *s;
cm->heave_cleanups[thread_index] = 0;
n_to_handle = clib_fifo_elts (cm->pending_cleanups[thread_index]);
n_to_handle = clib_min (n_to_handle, max_cleanups);
while (n_to_handle)
{
clib_fifo_sub2 (cm->pending_cleanups[thread_index], req);
ct = ct_connection_get (req->ct_index, thread_index);
s = session_get (ct->c_s_index, ct->c_thread_index);
if (!svm_fifo_has_event (s->tx_fifo))
ct_session_postponed_cleanup (ct);
else
clib_fifo_add1 (cm->pending_cleanups[thread_index], *req);
n_to_handle -= 1;
}
if (clib_fifo_elts (cm->pending_cleanups[thread_index]))
{
cm->heave_cleanups[thread_index] = 1;
session_send_rpc_evt_to_thread_force (
thread_index, ct_handle_cleanups,
uword_to_pointer (thread_index, void *));
}
}
static void
ct_program_cleanup (ct_connection_t *ct)
{
ct_main_t *cm = &ct_main;
ct_cleanup_req_t *req;
uword thread_index;
thread_index = ct->c_thread_index;
clib_fifo_add2 (cm->pending_cleanups[thread_index], req);
req->ct_index = ct->c_c_index;
if (cm->heave_cleanups[thread_index])
return;
cm->heave_cleanups[thread_index] = 1;
session_send_rpc_evt_to_thread_force (
thread_index, ct_handle_cleanups, uword_to_pointer (thread_index, void *));
}
static void
ct_session_close (u32 ct_index, u32 thread_index)
{
ct_connection_t *ct, *peer_ct;
app_worker_t *app_wrk;
session_t *s;
ct = ct_connection_get (ct_index, thread_index);
@@ -884,30 +983,16 @@ ct_session_close (u32 ct_index, u32 thread_index)
else if (peer_ct->c_s_index != ~0)
session_transport_closing_notify (&peer_ct->connection);
else
{
/* should not happen */
clib_warning ("ct peer without session");
ct_connection_free (peer_ct);
}
if (ct->flags & CT_CONN_F_CLIENT)
{
/* Normal free for client session as the fifos are allocated through
* the connects segment manager in a segment that's not shared with
* the server */
session_free_w_fifos (s);
ct_session_dealloc_fifos (ct, ct->client_rx_fifo, ct->client_tx_fifo);
}
else
{
/* Manual session and fifo segment cleanup to avoid implicit
* segment manager cleanups and notifications */
app_wrk = app_worker_get_if_valid (s->app_wrk_index);
if (app_wrk)
app_worker_cleanup_notify (app_wrk, s, SESSION_CLEANUP_SESSION);
ct_session_dealloc_fifos (ct, s->rx_fifo, s->tx_fifo);
session_free (s);
}
ct_connection_free (ct);
/* Do not send closed notify to make sure pending tx events are
* still delivered and program cleanup */
ct_program_cleanup (ct);
}
static transport_connection_t *
@@ -1046,6 +1131,8 @@ ct_enable_disable (vlib_main_t * vm, u8 is_en)
cm->n_workers = vlib_num_workers ();
vec_validate (cm->connections, cm->n_workers);
vec_validate (cm->pending_cleanups, cm->n_workers);
vec_validate (cm->heave_cleanups, cm->n_workers);
clib_spinlock_init (&cm->ho_reuseable_lock);
clib_rwlock_init (&cm->app_segs_lock);
return 0;