日期:2014-05-16 浏览次数:20974 次
这里主要说的是TCP拥塞情况下的状态状态处理
/* Process an event, which can update packets-in-flight not trivially. * Main goal of this function is to calculate new estimate for left_out, * taking into account both packets sitting in receiver's buffer and * packets lost by network. * * Besides that it does CWND reduction, when packet loss is detected * and changes state of machine. * * It does _not_ decide what to send, it is made in function * tcp_xmit_retransmit_queue(). */ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); int is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); // 判断是不是重复的ACK int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && // 判断是不是丢包:若是重复ACK 或者 SACK而且提前确认中没有到的包数量>重拍指标 (tcp_fackets_out(tp) > tp->reordering)); // 后面会单独说说SACK和FACK内容,觉得总是理解不好 int fast_rexmit = 0; if (WARN_ON(!tp->packets_out && tp->sacked_out)) // 如果packet_out为0,那么不可能有sacked_out tp->sacked_out = 0; if (WARN_ON(!tp->sacked_out && tp->fackets_out)) tp->fackets_out = 0; /* Now state machine starts. // 下面开始状态处理 * A. ECE, hence prohibit cwnd undoing, the reduction is required. */ if (flag & FLAG_ECE) // 如果是ECE tp->prior_ssthresh = 0;// 禁止拥塞窗口撤销,并开始减小拥塞窗口 /* B. In all the states check for reneging SACKs. */ if (tcp_check_sack_reneging(sk, flag)) // 检查ACK是不是确认了已经被SACK选择确认的包了 return; /* C. Process data loss notification, provided it is valid. */ if (tcp_is_fack(tp) && (flag & FLAG_DATA_LOST) && // 提前确认、数据丢失 before(tp->snd_una, tp->high_seq) && // 我们需要注意high_seq 可以标志为LOST的段序号的最大值 icsk->icsk_ca_state != TCP_CA_Open && // 状态不是OPEN tp->fackets_out > tp->reordering) { // 同上面说的 tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering); // 发现丢包,需要标志出丢失的包。 (1) 这个函数后面看 NET_INC_STATS_BH(LINUX_MIB_TCPLOSS); } /* D. Check consistency of the current state. */ tcp_verify_left_out(tp); // #define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out) // 检查丢失的包应该比发送出去的包小,即确定确定left_out < packets_out /* E. Check state exit conditions. State can be terminated * when high_seq is ACKed. */ // 下面检测状态退出条件!当high_seq 被确认的时候,这个状态就可以终止了 if (icsk->icsk_ca_state == TCP_CA_Open) { // 如果是open状态 BUG_TRAP(tp->retrans_out == 0); // 重传数量应该=0才是合理的 tp->retrans_stamp = 0; // 将重传发送时间置0 } else if (!before(tp->snd_una, tp->high_seq)) { // 如果high_seq已经被确认 switch (icsk->icsk_ca_state) { // case TCP_CA_Loss: // icsk->icsk_retransmits = 0; // 超时重传次数归零 if (tcp_try_undo_recovery(sk)) // 尝试将前面的拥塞窗口的调整撤销,在这种情况下弄不清楚包的情况(2) return; // 如果使用了SACK,那么不管undo成功与否,都会返回Open态 break; case TCP_CA_CWR: // 发生某些道路拥塞,需要减慢发送速度 /* CWR is to be held something *above* high_seq * is ACKed for CWR bit to reach receiver. */ if (tp->snd_una != tp->high_seq) {