概述
在FIN_WAIT_2收到对端发来的FIN,并回复ACK之后,会进入TIME_WAIT状态,此时添加定时器,定时器超时会将tw控制块从ehash和bhash中删除,并且释放tw控制块;
启动定时器
TIME_WAIT定时器主要通过inet_twsk_schedule函数进行启动;
tcp_rcv_state_process函数中,在FIN_WAIT_2状态下,收到对端发来的FIN,并且向对端回复了ACK之后,会调用tcp_time_wait函数进入真正的TIME_WAIT状态,此时会创建TIME_WAIT控制块,创建之后调用inet_twsk_schedule启动定时器;
调用关系如下:
1 /** 2 * tcp_rcv_state_process 3 * |-->tcp_time_wait 4 * |-->inet_twsk_alloc 5 * | |-->setup_pinned_timer(&tw->tw_timer, tw_timer_handler,(unsigned long)tw); 6 * |-->__inet_twsk_schedule(tw, timeo, false); 7 * |-->mod_timer(&tw->tw_timer, jiffies + timeo); 8 */
定时器回调函数
定时器超时会进入到tw_timer_handler处理函数,该函数在统计信息之后,调用inet_twsk_kill;
1 static void tw_timer_handler(unsigned long data) 2 { 3 struct inet_timewait_sock *tw = (struct inet_timewait_sock *)data; 4 5 if (tw->tw_kill) 6 __NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITKILLED); 7 else 8 __NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITED); 9 inet_twsk_kill(tw); 10 }
inet_twsk_kill从ehash和bhash中把tw控制块删除,并且释放之;
1 static void inet_twsk_kill(struct inet_timewait_sock *tw) 2 { 3 struct inet_hashinfo *hashinfo = tw->tw_dr->hashinfo; 4 spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); 5 struct inet_bind_hashbucket *bhead; 6 7 spin_lock(lock); 8 sk_nulls_del_node_init_rcu((struct sock *)tw); 9 spin_unlock(lock); 10 11 /* Disassociate with bind bucket. */ 12 bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, 13 hashinfo->bhash_size)]; 14 15 spin_lock(&bhead->lock); 16 inet_twsk_bind_unhash(tw, hashinfo); 17 spin_unlock(&bhead->lock); 18 19 atomic_dec(&tw->tw_dr->tw_count); 20 inet_twsk_put(tw); 21 }