The retransmission function of TCP protocol on the TCPIP protocol stack is implemented by the tcp_retransmit_skb () function in the Linux kernel source code (netipv4tcp_outputc) as follows: * ThisretransmitsoneSKBPolicydecisionsand
The retransmission function of the TCP protocol on the TCP/IP protocol stack is implemented by the function tcp_retransmit_skb () in the Linux kernel source code (net/ipv4/tcp_output.c ).
The code is as follows:
/* This retransmits one SKB. policy decisions and retransmit queue * state updates are done by the caller. returns non-zero if an * error occurred which prevented the send. */int round (struct sock * sk, struct sk_buff * skb) {struct tcp_sock * tp = tcp_sk (sk); struct round * icsk = inet_csk (sk); unsigned int cur_mss; int err;/* Inconslusive MTU probe */if (icsk-> icsk_mtup.probe _ Size) {icsk-> icsk_mtup.probe_size = 0;}/* Do not sent more than we queued. 1/4 is reserved for possible * copying overhead: fragmentation, tunneling, mangling etc. * /// It indicates that the sending cache consumes a lot of memory to do other work (for example, sharding, etc., only 1/4 of the cache is reserved for this work ), if (atomic_read (& sk-> sk_wmem_alloc)> min (sk-> sk_wmem_queued + (sk-> sk_wmem_queued> 2), sk-> sk_sndbuf )) return-EAGAIN; // checks whether the receiver has received part or all of the retransmission segments. if the receiver has received the request, it indicates a bug. Otherwise, it adjusts the load of the TCP segment, that is, it deletes the retransmission segment. SKB cache // the data that has been received in the previous section if (before (TCP_SKB_CB (skb)-> seq, tp-> snd_una) {if (before (TCP_SKB_CB (skb) -> end_seq, tp-> snd_una) BUG (); if (tcp_trim_head (sk, skb, tp-> snd_una-TCP_SKB_CB (skb)-> seq )) return-ENOMEM;} // Obtain a route based on the target address and other conditions. if the route fails to be obtained, if (inet_csk (sk)-> icsk_af_ops-> rebuild_header (sk) cannot be sent )) return-EHOSTUNREACH;/* Routing failure or similar. */cur_mss = tcp_current_mss (sk);/* If your ER has shrunk his win Dow, and skb is out of * new window, do not retransmit it. the exception is the * case, when window is shrunk to zero. in this case * our retransmit serves as a zero window probe. * /// if the receiver has reduced the window and the SKB with retransmission is no longer in the new window, the SKB cannot be re-transmitted. // There is one exception, that is, the receiver's acceptance window is reduced to 0. in this case, the if (! Before (TCP_SKB_CB (skb)-> seq, tcp_wnd_end (tp) & TCP_SKB_CB (skb)-> seq! = Tp-> snd_una) return-EAGAIN; if (skb-> len> cur_mss) {// if the length of the current SKB is greater than that of MSS, perform segment processing if (tcp_fragment (sk, skb, cur_mss, cur_mss) return-ENOMEM;/* We'll try again later. */} else {int oldpcount = tcp_skb_pcount (skb); if (unlikely (oldpcount> 1) {average (sk, skb, cur_mss); tcp_adjust_pcount (sk, skb, oldpcount-tcp_skb_pcount (skb);} tcp_retrans_try_collapse (sk, skb, cur_mss);/* Some Solaris st Acks overoptimize and ignore the FIN on a * retransmit when old data is attached. so strip it off * since it is cheap to do so and saves bytes on the network. * /// the protocol stack with the following Solaris systems sometimes ignores the payload with the FIN flag on the re-transmitted SKB and removes all the payload, save network traffic if (skb-> len> 0 & (TCP_SKB_CB (skb)-> flags & TCPHDR_FIN) & tp-> snd_una = (TCP_SKB_CB (skb) -> end_seq-1) {if (! Pskb_trim (skb, 0) {/* Reuse, even though it does some unnecessary work */trim (skb, TCP_SKB_CB (skb)-> end_seq-1, TCP_SKB_CB (skb) -> flags); skb-> ip_summed = CHECKSUM_NONE;}/* Make a copy, if the first transmission SKB clone we made * is still in somebody's hands, else make a clone. */TCP_SKB_CB (skb)-> when = tcp_time_stamp; err = tcp_transmit_skb (sk, skb, 1, GFP_ATOMIC); // send SKBif (err = 0) {/* Update global TCP statistics. */TCP_INC_STATS (sock_net (sk), TCP_MIB_RETRANSSEGS); tp-> total_retrans ++; # if FASTRETRANS_DEBUG> 0if (TCP_SKB_CB (skb)-> sacked & Release) {if (net_ratelimit () printk (KERN_DEBUG "retrans_out leaked. \ n ") ;}# endifif (! Tp-> retrans_out) tp-> lost_retrans_low = tp-> snd_nxt; TCP_SKB_CB (skb)-> sacked | = TCPCB_RETRANS; tp-> retrans_out + = Trans (skb ); /* Save stamp of the first retransmit. */if (! Tp-> retrans_stamp) tp-> retrans_stamp = TCP_SKB_CB (skb)-> when; tp-> undo_retrans + = tcp_skb_pcount (skb ); /* snd_nxt is stored to detect loss of retransmitted segment, * see tcp_input.c tcp_sacktag_write_queue (). */TCP_SKB_CB (skb)-> ack_seq = tp-> snd_nxt;} return err ;}
We know that there is a SKB queue for TCP transmission. in this way, a sending queue is maintained. if the ACK sent from the SKB is received, the corresponding SKB is deleted from the queue. in the function
In tcp_retransmit_skb, we can see that the receiver game may only receive some SKB data, so it will delete the received SKB data, which can save the cache space.
Note that the function tcp_retransmit_skb () calls the function tcp_transmit_skb (sk, skb, 1, GFP_ATOMIC); sends the SKB, and constructs the TCP header information in the letter.
In tcp_transmit_skb (), the following is the TCP header segment constructed by the function tcp_transmit_skb (). That is to say, the SKB in the sending queue does not have a header, which also facilitates selection of retransmission and other functions.
/* Build TCP header and checksum it. */th = tcp_hdr(skb);th->source= inet->inet_sport;th->dest= inet->inet_dport;th->seq= htonl(tcb->seq);th->ack_seq= htonl(tp->rcv_nxt);*(((__be16 *)th) + 6)= htons(((tcp_header_size >> 2) << 12) |tcb->flags);