日期:2014-05-16 浏览次数:20929 次
当知道需要重传数据结的时候执行这个函数:
对于函数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