VPP TCP定时器
對于多線程VPP,為主線程和worker線程分別分配timer_wheel,處理函數為tcp_expired_timers_dispatch。
static clib_error_t * tcp_main_enable (vlib_main_t * vm) {vlib_thread_main_t *vtm = vlib_get_thread_main ();num_threads = 1 /* main thread */ + vtm->n_threads;vec_validate (tm->wrk_ctx, num_threads - 1);n_workers = num_threads == 1 ? 1 : vtm->n_threads;for (thread = 0; thread < num_threads; thread++){ wrk = &tm->wrk_ctx[thread];tcp_timer_initialize_wheel (&wrk->timer_wheel,tcp_expired_timers_dispatch,vlib_time_now (vm));}超時處理函數中,首先根據線程號獲得對應的tcp_worker_ctx_t上下文結構,并且獲取當前待處理的定時器數量。
static void tcp_expired_timers_dispatch (u32 * expired_timers) {u32 thread_index = vlib_get_thread_index (), n_left, max_per_loop;u32 connection_index, timer_id, n_expired, max_loops;tcp_worker_ctx_t *wrk;tcp_connection_t *tc;int i;wrk = tcp_get_worker (thread_index);n_expired = vec_len (expired_timers);tcp_worker_stats_inc (wrk, timer_expirations, n_expired);n_left = clib_fifo_elts (wrk->pending_timers);遍歷超時的定時器,參數expired_timers的每個元素,最高的4位保存了定時器的ID,后28位保存了TCP連接的索引值。如果定時器ID為重傳的SYN報文定時器,由函數tcp_half_open_connection_get獲取TCP連接結構(實際上是根據連接索引,在線程號為0的TCP worker結構中獲取TCP連接);否則,由函數tcp_connection_get根據當前的線程號和連接索引獲取TCP連接結構。
此處將TCP連接的定時器處理句柄設置為無效,設置掛起定時器ID。
/** Invalidate all timer handles before dispatching. This avoids dangling* index references to timer wheel pool entries that have been freed.*/for (i = 0; i < n_expired; i++){connection_index = expired_timers[i] & 0x0FFFFFFF;timer_id = expired_timers[i] >> 28;if (timer_id != TCP_TIMER_RETRANSMIT_SYN)tc = tcp_connection_get (connection_index, thread_index);elsetc = tcp_half_open_connection_get (connection_index);TCP_EVT (TCP_EVT_TIMER_POP, connection_index, timer_id);tc->timers[timer_id] = TCP_TIMER_HANDLE_INVALID;tc->pending_timers |= (1 << timer_id);}將到期的定時器添加到worker結構中的掛起定時器。之后,計算每次循環最多處理的定時器數量。首先確定最大的循環次數max_loops,即最大時長0.5 * TCP_TIMER_TICK,乘以每一秒的循環數量,即最大的循環次數。其次,所有待處理的定時器(n_left+n_expired)除以max_loops即為每次循環的最大數量。最后,最大值不能大于每次最多可處理的最大向量長度VLIB_FRAME_SIZE(256),
clib_fifo_add (wrk->pending_timers, expired_timers, n_expired);max_loops =clib_max ((u32) 0.5 * TCP_TIMER_TICK * wrk->vm->loops_per_second, 1);max_per_loop = clib_max ((n_left + n_expired) / max_loops, 10);max_per_loop = clib_min (max_per_loop, VLIB_FRAME_SIZE);wrk->max_timers_per_loop = clib_max (n_left ? wrk->max_timers_per_loop : 0,max_per_loop);if (thread_index == 0)session_queue_run_on_main_thread (wrk->vm);掛起定時器處理函數tcp_dispatch_pending_timers如下,如果TCP線程結構中沒有掛起的定時器,結束處理。
static void tcp_dispatch_pending_timers (tcp_worker_ctx_t * wrk) {u32 n_timers, connection_index, timer_id, thread_index, timer_handle;tcp_connection_t *tc;int i;if (!(n_timers = clib_fifo_elts (wrk->pending_timers)))return;每次遍歷處理的定時器數量不能超過以上計算得到到max_timers_per_loop的值,如果掛起定時器已經被重置,即TCP連接的pending_timers已經不再置位,不進行處理。
thread_index = wrk->vm->thread_index;for (i = 0; i < clib_min (n_timers, wrk->max_timers_per_loop); i++){clib_fifo_sub1 (wrk->pending_timers, timer_handle);connection_index = timer_handle & 0x0FFFFFFF;timer_id = timer_handle >> 28;if (PREDICT_TRUE (timer_id != TCP_TIMER_RETRANSMIT_SYN))tc = tcp_connection_get (connection_index, thread_index);elsetc = tcp_half_open_connection_get (connection_index);if (PREDICT_FALSE (!tc))continue;/* Skip if the timer is not pending. Probably it was reset while* waiting for dispatch */if (PREDICT_FALSE (!(tc->pending_timers & (1 << timer_id))))continue;tc->pending_timers &= ~(1 << timer_id);/* Skip timer if it was rearmed while pending dispatch */if (PREDICT_FALSE (tc->timers[timer_id] != TCP_TIMER_HANDLE_INVALID))continue;否則,調用定時器ID注冊的超時處理函數,處理超時的TCP連接。
(*timer_expiration_handlers[timer_id]) (tc);}if (thread_index == 0 && clib_fifo_elts (wrk->pending_timers))session_queue_run_on_main_thread (wrk->vm); }TCP連接定義了如下的四種定時器。
#define foreach_tcp_timer \_(RETRANSMIT, "RETRANSMIT") \_(PERSIST, "PERSIST") \_(WAITCLOSE, "WAIT CLOSE") \_(RETRANSMIT_SYN, "RETRANSMIT SYN") \typedef enum _tcp_timers { #define _(sym, str) TCP_TIMER_##sym,foreach_tcp_timer #undef _TCP_N_TIMERS } __clib_packed tcp_timers_e;以上四種定時器對應如下四個超時處理函數。
static timer_expiration_handler *timer_expiration_handlers[TCP_N_TIMERS] = {tcp_timer_retransmit_handler,tcp_timer_persist_handler,tcp_timer_waitclose_handler,tcp_timer_retransmit_syn_handler, };總結
以上是生活随笔為你收集整理的VPP TCP定时器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机中丢失xvidcore.dll,出
- 下一篇: 10种自动音乐播放器代码