日期:2014-05-16 浏览次数:21193 次
这里主要说的是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) {