日期:2014-05-16 浏览次数:21085 次
当知道需要重传数据结的时候执行这个函数:
对于函数tcp_xmit_retransmit_queue:需要重传哪些包呢到底?
首先是lost、标记的包;
然后还需要处理:之前发送过的但是尚未收到确认的包(向前重传),或者新数据,在这两者之间有一个选择
/* This gets called after a retransmit timeout, and the initially
* retransmitted data is acknowledged. It tries to continue
* resending the rest of the retransmit queue, until either
* we've sent it all or the congestion window limit is reached.
* If doing SACK, the first ACK which comes back for a timeout
* based retransmit packet might feed us FACK information again.
* If so, we use it to avoid unnecessarily retransmissions.
*/
void tcp_xmit_retransmit_queue(struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int packet_cnt;
if (tp->retransmit_skb_hint) { // 如果有重传信息
skb = tp->retransmit_skb_hint;
packet_cnt = tp->retransmit_cnt_hint; // 保存cnt值
} else {
skb = tcp_write_queue_head(sk); // 发送队列
packet_cnt = 0;
}
// 第一步,如果有丢失的包,那么需要重传
/* First pass: retransmit lost packets. */
if (tp->lost_out) { // lost_out > 0
tcp_for_write_queue_from(skb, sk) { // 遍历
__u8 sacked = TCP_SKB_CB(skb)->sacked; // 获得sacked标识
if (skb == tcp_send_head(sk))
break;
/* we could do better than to assign each time */
tp->retransmit_skb_hint = skb; // 更新两个值
tp->retransmit_cnt_hint = packet_cnt;
/* Assume this retransmit will generate
* only one packet for congestion window
* calculation purposes. This works because
* tcp_retransmit_skb() will chop up the
* packet to be MSS sized and all the
* packet counting works out.
*/
if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) // 如果传输中的报文数量 > 窗口数量,那么没有必要再发送数据
return;
if (sacked & TCPCB_LOST) { // 如果是LOST标识
if (!(sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS))) { // 如果丢失了 && 没有被选择确认或者重传
if (tcp_retransmit_skb(sk, skb)) { // 重传该数据函数!!!最后再看(1)
tp->retransmit_skb_hint = NULL; // 重传之后重置这个值
return; // 返回
}
if (icsk->icsk_ca_state != TCP_CA_Loss)
NET_INC_STATS_BH(LINUX_MIB_TCPFASTRETRANS);
else
NET_INC_STATS_BH(LINUX_MIB_TCPSLOWSTARTRETRANS);
if (skb == tcp_write_queue_head(sk)) // 如果是第一个重传数据,那么重置重传计数器!!!
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
inet_csk(sk)->icsk_rto,
TCP_RTO_MAX);
}
packet_cnt += tcp_skb_pcount(skb); // 重传数量
if (packet_cnt >= tp->lost_out) // 大于lost的数量,那么break;下面就不是lo