tcp ack 处理注释分析

return 0;
}


/* This routine deals with incoming acks, but not outgoing ones. */
static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
{
struct inet_connection_sock *icsk = inet_csk(sk);  // 获得连接sock
struct tcp_sock *tp = tcp_sk(sk); // 获得tcp_sock   
u32 prior_snd_una = tp->snd_una;  /* 此ACK之前的snd_una */  
u32 ack_seq = TCP_SKB_CB(skb)->seq;  /* 此ACK的开始序号 */  
u32 ack = TCP_SKB_CB(skb)->ack_seq;  /* 此ACK的确认序号 */
bool is_dupack = false;
u32 prior_in_flight;
u32 prior_fackets;
int prior_packets;
int prior_sacked = tp->sacked_out;
int pkts_acked = 0;
int newly_acked_sacked = 0;
int frto_cwnd = 0;


/* If the ack is older than previous acks
* then we can probably ignore it. */
 // 如果确认序号比我还下一个准备发送的序号还要大,即确认了我们尚未发送的数据,那么显然不合理
if (before(ack, prior_snd_una))
goto old_ack;  // 老的ACK

/* If the ack includes data we haven't sent yet, discard
* this segment (RFC793 Section 3.9). */
// 如果ack 包的序号比下次准备发送的数据的序号还要大就是无效的ACK 包
if (after(ack, tp->snd_nxt))
goto invalid_ack;  //无效的ack

// 如果ack 包序号比上次确认的ACK 序号还大, 说明ack 属于确认更新窗口, 有效ACK
if (after(ack, prior_snd_una))
flag |= FLAG_SND_UNA_ADVANCED; // 有效那么设置标识FLAG_SND_UNA_ADVANCED

if (sysctl_tcp_abc) { 
// 是否设置了tcp_abc,若有,  则我们不需要对每个ack确认都要拥塞避免,所以我们需要计算已经ack(确认)的字节数。   
if (icsk->icsk_ca_state < TCP_CA_CWR)
tp->bytes_acked += ack - prior_snd_una;  // 已经(确定)ack的字节数增大了( ack - prior_snd_una )大小
else if (icsk->icsk_ca_state == TCP_CA_Loss)
/* we assume just one segment left network */
tp->bytes_acked += min(ack - prior_snd_una,
  tp->mss_cache);
}

prior_fackets = tp->fackets_out;  // 得到fack的数据包的字节数
prior_in_flight = tcp_packets_in_flight(tp);  // 计算还在传输的数据段的字节数,下面会说手这个函数!( 1 )




/*处理路径只要有调用tcp_ack 函数决定,  上面函数知识更新窗口,或者带有数据及更新窗口*/
/*flag 不为等于FLAG_SLOWPATH , 就进行快处理路径, 只处理窗口更新ACK 包*/
if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
/* Window is constant, pure forward advance.
* No more checks are required.
* Note, we use the fact that SND.UNA>=SND.WL2.
*/
// 需要更新sock中的snd_wl1字段:tp->snd_wl1 = ack_seq;( 记录造成发送窗口更新的第一个数据 )
tcp_update_wl(tp, ack_seq);

// snd_una更新为已经确认的序列号!下一次期待从这里开始的确认!!!  
tp->snd_una = ack; 
// 窗口更新标识
flag |= FLAG_WIN_UPDATE;

// 重要函数!!!进入拥塞操作!这个函数最后看,这里处理的是“正常的ACK”事件(999999)
tcp_ca_event(sk, CA_EVENT_FAST_ACK);


NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPACKS);
} else {
/*ACK 中包含数据,flag 至上FLAG_DATA*/
if (ack_seq != TCP_SKB_CB(skb)->end_seq)
flag |= FLAG_DATA;
else
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPUREACKS);


/*ACK 是否能更新windows 窗口FLAG_WIN_UPDATE*/
flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);


/* ACK SACK 处理 , 如果出现SACK 就会出现问题, 如有数据丢失等.....*/
if (TCP_SKB_CB(skb)->sacked)
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
/*ACK ecn 处理, 对方拥塞控制报告,通过ecn*/
if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
flag |= FLAG_ECE;


tcp_ca_event(sk, CA_EVENT_SLOW_ACK);
}


/* We passed data and got it acked, remove any soft error
* log. Something worked...
*/
sk->sk_err_soft = 0;
icsk->icsk_probes_out = 0;
tp->rcv_tstamp = tcp_time_stamp;
/*获得发出去没有收到确认的包数量*/
prior_packets = tp->packets_out; 
if (!prior_packets) // 如果为0,则可能是0窗口探测包 
goto no_queue;




/* See if we can take anything off of the retransmit queue. */
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);


pkts_acked = prior_packets - tp->packets_out;
newly_acked_sacked = (prior_packets - prior_sacked) -
    (tp->packets_out - tp->sacked_out);


/*如果sock 已经进入快速重传处理*/
if (tp->frto_counter)
frto_cwnd = tcp_process_frto(sk, flag);
/* Guarantee sacktag reordering detection against wrap-arounds */
if (before(tp->frto_highmark, tp->snd_una))
tp->frto_highmark = 0;


// 可疑的ACK
/*1: 如果flag 不是FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED 就是可疑ack*/
/*2: 如果flag 是FLAG_CA_ALERT  就是可疑ack*/
/*3: 如果sock 状态不是TCP_CA_Open, 当作可疑ACK 处理*/
if (tcp_ack_is_dubious(sk, flag)) {
/* Advance CWND, if state allows this. */
/*可疑的ACK 下判断是否存在增长CWND 处理*/
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd && tcp_may_raise_cwnd(sk, flag))
/*拥塞算法处理窗口变化*/
tcp_cong_avoid(sk, ack, prior_in_flight);
//
/*判断是否重复的ack 到来??, 如果不是FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED, 以及没有更新*/
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
     is_dupack, flag);
} else {
/*如果flag  确认新的数据FLAG_DATA_ACKED 以及没有发生快速重传 */
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
/*拥塞算法处理窗口变化*/
tcp_cong_avoid(sk, ack, prior_in_flight);
}


if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
dst_confirm(sk->sk_dst_cache);


return 1;


no_queue:
/* If data was DSACKed, see if we can undo a cwnd reduction. */
if (flag & FLAG_DSACKING_ACK)
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
     is_dupack, flag);
/* If this ack opens up a zero window, clear backoff.  It was
* being used to time the probes, and is probably far higher than
* it needs to be for normal retransmission.
*/
// 这里判断发送缓冲区是否为空,如果不为空,则进入判断需要重启keepalive定时器还是关闭定时器
if (tcp_send_head(sk))
tcp_ack_probe(sk);
return 1;


invalid_ack:
SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
return -1;


old_ack:
/* If data was SACKed, tag it and see if we should send more data.
* If data was DSACKed, see if we can undo a cwnd reduction.
*/
if (TCP_SKB_CB(skb)->sacked) {
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
newly_acked_sacked = tp->sacked_out - prior_sacked;
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
     is_dupack, flag);
}


SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
return 0;

}

Kernel version 2.6.32

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值