nat: ED: global session LRU list
Maintain a global session LRU allowing reuse of expired session instead of relying on a scavenging mechanism to periodically walk sessions. Whenever a new session is being allocated in slow path, also attempt to free an expired session from global LRU list. Type: improvement Signed-off-by: Klement Sekera <ksekera@cisco.com> Change-Id: I9edde9ec138de67c9a4888e915b0490ec16415fa
This commit is contained in:
@ -951,7 +951,6 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
|
||||
u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
|
||||
0, def_slow;
|
||||
u32 tcp_closed_drops = 0;
|
||||
|
||||
def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH :
|
||||
NAT_NEXT_IN2OUT_ED_SLOW_PATH;
|
||||
@ -1065,7 +1064,6 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
else
|
||||
{
|
||||
// session in transitory timeout, drop
|
||||
++tcp_closed_drops;
|
||||
b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED];
|
||||
next0 = NAT_NEXT_DROP;
|
||||
}
|
||||
@ -1078,11 +1076,9 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
(f64) nat44_session_get_timeout (sm, s0);
|
||||
if (now >= sess_timeout_time)
|
||||
{
|
||||
// delete session
|
||||
nat_free_session_data (sm, s0, thread_index, 0);
|
||||
nat44_delete_session (sm, s0, thread_index);
|
||||
|
||||
// session no longer exists, go slow path
|
||||
// session is closed, go slow path
|
||||
next0 = def_slow;
|
||||
goto trace0;
|
||||
}
|
||||
|
@ -593,6 +593,14 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
|
||||
s->per_user_list_head_index,
|
||||
per_user_translation_list_elt - tsm->list_pool);
|
||||
|
||||
dlist_elt_t *global_lru_list_elt;
|
||||
pool_get (tsm->global_lru_pool, global_lru_list_elt);
|
||||
global_lru_list_elt->value = s - tsm->sessions;
|
||||
s->global_lru_index = global_lru_list_elt - tsm->global_lru_pool;
|
||||
clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
|
||||
s->global_lru_index);
|
||||
s->last_lru_update = now;
|
||||
|
||||
s->user_index = u - tsm->users;
|
||||
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
|
||||
pool_elts (tsm->sessions));
|
||||
@ -607,7 +615,7 @@ snat_session_t *
|
||||
nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
|
||||
f64 now)
|
||||
{
|
||||
snat_session_t *s;
|
||||
snat_session_t *s = NULL;
|
||||
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
|
||||
|
||||
dlist_elt_t *oldest_elt;
|
||||
@ -633,6 +641,7 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* first try to reuse an expired session from this ip */
|
||||
oldest_index =
|
||||
clib_dlist_remove_head (tsm->list_pool,
|
||||
u->sessions_per_user_list_head_index);
|
||||
@ -647,13 +656,44 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
|
||||
clib_dlist_addtail (tsm->list_pool,
|
||||
u->sessions_per_user_list_head_index, oldest_index);
|
||||
s = nat44_session_reuse_old (sm, u, s, thread_index, now);
|
||||
s->last_lru_update = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
// alloc new session
|
||||
clib_dlist_addhead (tsm->list_pool,
|
||||
u->sessions_per_user_list_head_index, oldest_index);
|
||||
alloc_new:
|
||||
s = NULL;
|
||||
}
|
||||
|
||||
alloc_new:
|
||||
/* try to free an expired session from global LRU list */
|
||||
if (!s)
|
||||
{
|
||||
oldest_index = clib_dlist_remove_head (tsm->global_lru_pool,
|
||||
tsm->global_lru_head_index);
|
||||
if (~0 != oldest_index)
|
||||
{
|
||||
oldest_elt = pool_elt_at_index (tsm->global_lru_pool, oldest_index);
|
||||
s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
|
||||
|
||||
sess_timeout_time =
|
||||
s->last_heard + (f64) nat44_session_get_timeout (sm, s);
|
||||
if (now >= sess_timeout_time
|
||||
|| (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
|
||||
{
|
||||
nat_free_session_data (sm, s, thread_index, 0);
|
||||
nat44_ed_delete_session (sm, s, thread_index, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_dlist_addhead (tsm->global_lru_pool,
|
||||
tsm->global_lru_head_index, oldest_index);
|
||||
}
|
||||
s = NULL;
|
||||
}
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
s = nat44_session_alloc_new (tsm, u, now);
|
||||
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
|
||||
pool_elts (tsm->sessions));
|
||||
@ -4075,6 +4115,13 @@ snat_config (vlib_main_t * vm, unformat_input_t * input)
|
||||
|
||||
pool_alloc (tsm->sessions, sm->max_translations);
|
||||
pool_alloc (tsm->list_pool, sm->max_translations);
|
||||
pool_alloc (tsm->global_lru_pool, sm->max_translations);
|
||||
|
||||
dlist_elt_t *head;
|
||||
pool_get (tsm->global_lru_pool, head);
|
||||
tsm->global_lru_head_index = head - tsm->global_lru_pool;
|
||||
clib_dlist_init (tsm->global_lru_pool,
|
||||
tsm->global_lru_head_index);
|
||||
|
||||
if (sm->endpoint_dependent)
|
||||
{
|
||||
|
@ -320,6 +320,10 @@ typedef CLIB_PACKED(struct
|
||||
u32 per_user_index;
|
||||
u32 per_user_list_head_index;
|
||||
|
||||
/* index in global LRU list */
|
||||
u32 global_lru_index;
|
||||
f64 last_lru_update;
|
||||
|
||||
/* Last heard timer */
|
||||
f64 last_heard;
|
||||
|
||||
@ -521,6 +525,10 @@ typedef struct
|
||||
/* Pool of doubly-linked list elements */
|
||||
dlist_elt_t *list_pool;
|
||||
|
||||
/* LRU session list - head is stale, tail is fresh */
|
||||
dlist_elt_t *global_lru_pool;
|
||||
u32 global_lru_head_index;
|
||||
|
||||
/* NAT thread index */
|
||||
u32 snat_thread_index;
|
||||
|
||||
|
@ -89,6 +89,14 @@ nat44_session_alloc_new (snat_main_per_thread_data_t * tsm, snat_user_t * u,
|
||||
s->per_user_list_head_index,
|
||||
per_user_translation_list_elt - tsm->list_pool);
|
||||
|
||||
dlist_elt_t *lru_list_elt;
|
||||
pool_get (tsm->global_lru_pool, lru_list_elt);
|
||||
s->global_lru_index = lru_list_elt - tsm->global_lru_pool;
|
||||
clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
|
||||
s->global_lru_index);
|
||||
lru_list_elt->value = s - tsm->sessions;
|
||||
s->last_lru_update = now;
|
||||
|
||||
s->ha_last_refreshed = now;
|
||||
return s;
|
||||
}
|
||||
@ -207,6 +215,8 @@ nat44_user_session_cleanup (snat_user_t * u, u32 thread_index, f64 now)
|
||||
|
||||
clib_dlist_remove (tsm->list_pool, s->per_user_index);
|
||||
pool_put_index (tsm->list_pool, s->per_user_index);
|
||||
clib_dlist_remove (tsm->global_lru_pool, s->global_lru_index);
|
||||
pool_put_index (tsm->global_lru_pool, s->global_lru_index);
|
||||
pool_put (tsm->sessions, s);
|
||||
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
|
||||
pool_elts (tsm->sessions));
|
||||
|
@ -286,8 +286,9 @@ nat44_delete_user_with_no_session (snat_main_t * sm, snat_user_t * u,
|
||||
}
|
||||
|
||||
always_inline void
|
||||
nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
|
||||
u32 thread_index)
|
||||
nat44_delete_session_internal (snat_main_t * sm, snat_session_t * ses,
|
||||
u32 thread_index, int global_lru_delete
|
||||
/* delete from global LRU list */ )
|
||||
{
|
||||
snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
|
||||
thread_index);
|
||||
@ -301,6 +302,11 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
|
||||
|
||||
clib_dlist_remove (tsm->list_pool, ses->per_user_index);
|
||||
pool_put_index (tsm->list_pool, ses->per_user_index);
|
||||
if (global_lru_delete)
|
||||
{
|
||||
clib_dlist_remove (tsm->global_lru_pool, ses->global_lru_index);
|
||||
}
|
||||
pool_put_index (tsm->global_lru_pool, ses->global_lru_index);
|
||||
pool_put (tsm->sessions, ses);
|
||||
vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
|
||||
pool_elts (tsm->sessions));
|
||||
@ -318,6 +324,22 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
|
||||
}
|
||||
}
|
||||
|
||||
always_inline void
|
||||
nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
|
||||
u32 thread_index)
|
||||
{
|
||||
return nat44_delete_session_internal (sm, ses, thread_index, 1);
|
||||
}
|
||||
|
||||
always_inline void
|
||||
nat44_ed_delete_session (snat_main_t * sm, snat_session_t * ses,
|
||||
u32 thread_index, int global_lru_delete
|
||||
/* delete from global LRU list */ )
|
||||
{
|
||||
return nat44_delete_session_internal (sm, ses, thread_index,
|
||||
global_lru_delete);
|
||||
}
|
||||
|
||||
/** \brief Set TCP session state.
|
||||
@return 1 if session was closed, otherwise 0
|
||||
*/
|
||||
@ -430,10 +452,22 @@ always_inline void
|
||||
nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
|
||||
u32 thread_index)
|
||||
{
|
||||
clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
|
||||
s->per_user_index);
|
||||
clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
|
||||
s->per_user_list_head_index, s->per_user_index);
|
||||
/* don't update too often - timeout is in a magnitude of seconds anyway */
|
||||
if (s->last_heard > s->last_lru_update + 1)
|
||||
{
|
||||
clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
|
||||
s->per_user_index);
|
||||
clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
|
||||
s->per_user_list_head_index, s->per_user_index);
|
||||
|
||||
clib_dlist_remove (sm->per_thread_data[thread_index].global_lru_pool,
|
||||
s->global_lru_index);
|
||||
clib_dlist_addtail (sm->per_thread_data[thread_index].global_lru_pool,
|
||||
sm->
|
||||
per_thread_data[thread_index].global_lru_head_index,
|
||||
s->global_lru_index);
|
||||
s->last_lru_update = s->last_heard;
|
||||
}
|
||||
}
|
||||
|
||||
always_inline void
|
||||
|
@ -693,7 +693,6 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
|
||||
u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets =
|
||||
0, fragments = 0;
|
||||
u32 tcp_closed_drops = 0;
|
||||
|
||||
stats_node_index = sm->ed_out2in_node_index;
|
||||
|
||||
@ -789,7 +788,6 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
{
|
||||
// session in transitory timeout, drop
|
||||
b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED];
|
||||
++tcp_closed_drops;
|
||||
next0 = NAT_NEXT_DROP;
|
||||
}
|
||||
goto trace0;
|
||||
@ -801,11 +799,9 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
|
||||
(f64) nat44_session_get_timeout (sm, s0);
|
||||
if (now >= sess_timeout_time)
|
||||
{
|
||||
// delete session
|
||||
// session is closed, go slow path
|
||||
nat_free_session_data (sm, s0, thread_index, 0);
|
||||
nat44_delete_session (sm, s0, thread_index);
|
||||
|
||||
// session no longer exists, go slow path
|
||||
next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
|
||||
goto trace0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user