/* Remove acknowledged frames from the retransmission queue. If our packet
* is before the ack sequence we can discard it as it's confirmed to have
* arrived at the other end.
*/
static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
u32 prior_snd_una, int *acked,
struct tcp_sacktag_state *sack,
struct skb_mstamp *now)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct skb_mstamp first_ackt, last_ackt;
struct tcp_sock *tp = tcp_sk(sk);
u32 prior_sacked = tp->sacked_out;
u32 reord = tp->packets_out;
bool fully_acked = true;
long sack_rtt_us = -1L;
long seq_rtt_us = -1L;
long ca_rtt_us = -1L;
struct sk_buff *skb;
u32 pkts_acked = 0;
u32 last_in_flight = 0;
bool rtt_update;
int flag = 0;
first_ackt.v64 = 0;
//tcp_send_head表示下一个将要发送的数据,还没有被发送
while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) {
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
u8 sacked = scb->sacked;
u32 acked_pcount;
tcp_ack_tstamp(sk, skb, prior_snd_una);
/* Determine how many packets and what bytes were acked, tso and else */
//scb->end_seq在UNA之前表示整个skb都被应答了(不管是大包还是小包)
//scb->end_seq在UNA之后表示整个SKB部分数据被应答了,TSO的情况
if (after(scb->end_seq, tp->snd_una)) {
//如果是大包那么tcp_gso_segs肯定不为1
//UNA在skb起始序号之前
//上面两种情况都属于异常情况直接break终止报文处理,也即这种报文下载在处理
if (tcp_skb_pcount(skb) == 1 ||
!after(tp->snd_una, scb->seq))
break;
//大包的时候检查应答了多少个报文
acked_pcount = tcp_tso_acked(sk, skb);
if (!acked_pcount)
break;
//fully_acked表示SKB整包是否被应答
fully_acked = false;
} else {
/* Speedup tcp_unlink_write_queue() and next loop */
//预期SKB
prefetchw(skb->next);
acked_pcount = tcp_skb_pcount(skb);
}
//进入这里表示这个SKB已经被应答了
//当前处理的SKB曾经被重传过
if (unlikely(sacked & TCPCB_RETRANS)) {
//并且是被SACK触发的重传
if (sacked & TCPCB_SACKED_RETRANS)
//当前ACK应答了被SACK触发重传的报文,所以需要更新tp->retrans_out计数器
tp->retrans_out -= acked_pcount;
//应答了重传的报文
flag |= FLAG_RETRANS_DATA_ACKED;
//当前ACK应答了没有被重传过的报文,也没不是被SACK应答,也即是正常ACK顺序应答
} else if (!(sacked & TCPCB_SACKED_ACKED)) {
//处理被正顺序应答的报文需要更新乱序数据包量统计reord和更新last_ackt
last_ackt = skb->skb_mstamp;
WARN_ON_ONCE(last_ackt.v64 == 0);
if (!first_ackt.v64)
first_ackt = last_ackt;
last_in_flight = TCP_SKB_CB(skb)->tx.in_flight;
//数据包被正顺序应答,所以可以减少乱序计数
reord = min(pkts_acked, reord);
if (!after(scb->end_seq, tp->high_seq))
flag |= FLAG_ORIG_SACK_ACKED;
}
//当前处理的报文曾经是被SACK应大过
if (sacked & TCPCB_SACKED_ACKED) {
//sacked_out更新,tp->sacked_out记录当前SACK了多少报文,当前SACK的报文被移除时计数需要更新
tp->sacked_out -= acked_pcount;
} else if (tcp_is_sack(tp)) {
tp->delivered += acked_pcount;
//没有打开TIMSTAMP,此处必然被执行
//如果是sack应答数据不会更新rack.mstamp
if (!tcp_skb_spurious_retrans(tp, skb))
tcp_rack_advance(tp, &skb->skb_mstamp, sacked);
}
//如果当前处理的SKB被判定为丢失,那么在移除之际需要更新tp->lost_out
if (sacked & TCPCB_LOST)
tp->lost_out -= acked_pcount;
//更新packets_out
tp->packets_out -= acked_pcount;
//pkts_acked记录当前ACK应答触发的tcp_clean_rtx_queue函数调用一共处理了多少数据
pkts_acked += acked_pcount;
//通过ACK应答情况计算发送速率
tcp_rate_skb_delivered(sk, skb, sack->rate);
/* Initial outgoing SYN's get put onto the write_queue
* just like anything else we transmit. It is not
* true data, and if we misinform our callers that
* this ACK acks real data, we will erroneously exit
* connection startup slow start one packet too
* quickly. This is severely frowned upon behavior.
*/
//区分是DATA应答还是SYN应答
if (likely(!(scb->tcp_flags & TCPHDR_SYN))) {
flag |= FLAG_DATA_ACKED;
} else {
flag |= FLAG_SYN_ACKED;
tp->retrans_stamp = 0;
}
//描述当前处理的大包是被整包应答还是部分应答
if (!fully_acked)
break;
//将SKB从发送队列中摘除
tcp_unlink_write_queue(skb, sk);
//释放SKB的内存空间
sk_wmem_free_skb(sk, skb);
//下一个将要被重传的报文是当前处理的SKB,那么当前是顺序应答将retransmit_skb_hint置空
//tp->retransmit_skb_hint描述的是下一次重传的其实位置
if (unlikely(skb == tp->retransmit_skb_hint))
tp->retransmit_skb_hint = NULL;
//tp->lost_skb_hint描述的是下一次丢包标记的其实位置
if (unlikely(skb == tp->lost_skb_hint))
tp->lost_skb_hint = NULL;
}
if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una)))
tp->snd_up = tp->snd_una;
if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
flag |= FLAG_SACK_RENEGING;
if (likely(first_ackt.v64) && !(flag & FLAG_RETRANS_DATA_ACKED)) {
seq_rtt_us = skb_mstamp_us_delta(now, &first_ackt);
ca_rtt_us = skb_mstamp_us_delta(now, &last_ackt);
}
if (sack->first_sackt.v64) {
sack_rtt_us = skb_mstamp_us_delta(now, &sack->first_sackt);
ca_rtt_us = skb_mstamp_us_delta(now, &sack->last_sackt);
}
sack->rate->rtt_us = ca_rtt_us; /* RTT of last (S)ACKed packet, or -1 */
rtt_update = tcp_ack_update_rtt(sk, flag, seq_rtt_us, sack_rtt_us,
ca_rtt_us);
if (flag & FLAG_ACKED) {
tcp_rearm_rto(sk);
if (unlikely(icsk->icsk_mtup.probe_size &&
!after(tp->mtu_probe.probe_seq_end, tp->snd_una))) {
tcp_mtup_probe_success(sk);
}
if (tcp_is_reno(tp)) {
tcp_remove_reno_sacks(sk, pkts_acked);
} else {
int delta;
/* Non-retransmitted hole got filled? That's reordering */
if (reord < prior_fackets)
tcp_update_reordering(sk, tp->fackets_out - reord, 0);
delta = tcp_is_fack(tp) ? pkts_acked :
prior_sacked - tp->sacked_out;
tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta);
}
tp->fackets_out -= min(pkts_acked, tp->fackets_out);
} else if (skb && rtt_update && sack_rtt_us >= 0 &&
sack_rtt_us > skb_mstamp_us_delta(now, &skb->skb_mstamp)) {
/* Do not re-arm RTO if the sack RTT is measured from data sent
* after when the head was last (re)transmitted. Otherwise the
* timeout may continue to extend in loss recovery.
*/
tcp_rearm_rto(sk);
}
if (icsk->icsk_ca_ops->pkts_acked) {
struct ack_sample sample = { .pkts_acked = pkts_acked,
.rtt_us = ca_rtt_us,
.in_flight = last_in_flight };
icsk->icsk_ca_ops->pkts_acked(sk, &sample);
}
#if FASTRETRANS_DEBUG > 0
WARN_ON((int)tp->sacked_out < 0);
WARN_ON((int)tp->lost_out < 0);
WARN_ON((int)tp->retrans_out < 0);
if (!tp->packets_out && tcp_is_sack(tp)) {
icsk = inet_csk(sk);
if (tp->lost_out) {
pr_debug("Leak l=%u %d\n",
tp->lost_out, icsk->icsk_ca_state);
tp->lost_out = 0;
}
if (tp->sacked_out) {
pr_debug("Leak s=%u %d\n",
tp->sacked_out, icsk->icsk_ca_state);
tp->sacked_out = 0;
}
if (tp->retrans_out) {
pr_debug("Leak r=%u %d\n",
tp->retrans_out, icsk->icsk_ca_state);
tp->retrans_out = 0;
}
}
#endif
*acked = pkts_acked;
return flag;
}
tcp_clean_rtx_queue函数
最新推荐文章于 2024-05-29 21:21:23 发布