The previous article analyzed how the receiving end sends ack to the sending end. In summary, it is ack immediately, Ack with latency and ACK. Now let's take a look at how the TCP sending end handles ack, essentially, the so-called TCP connection is the processing of seq and ACK by both parties. For seq, the sender is active, while the receiver is passive, but for ACK, the opposite is true, therefore, we must first design the receiving end to send ACK, and then design how to handle ACK based on the needs of TCP traffic control and congestion control and performance factors, linux has adopted the RFC proposal (it seems that there is no unsupported OS, unless it has its own defined standards ). I have already said before about sending ack. It is much simpler to handle ack. Simply put, the receiving end only sends the seq of the last unconfirmed packet in order as its ack. But how can the sending end handle this ack, although it is simpler than the logic and policy for sending ACK, you must thoroughly understand the Protocol to understand the code:
Static int tcp_ack (struct sock * SK, struct sk_buff * SKB, int flag)
{
...
If (after (ACK, TP-> snd_nxt ))
Goto uninteresting_ack;
If (before (ACK, prior_snd_una ))
Goto old_ack;
If (! (Flag & flag_slowpath) & after (ACK, prior_snd_una) {// non-redundant ACK, normal, not fast retransmission
Tcp_update_wl (TP, ack, ack_seq );
TP-> snd_una = ack;
Tcp_westwood_fast_bw (SK, SKB );
Flag | = flag_win_update;
} Else {
If (ack_seq! = Tcp_skb_cb (SKB)-> end_seq) // indicates that the sequence has ACK
Flag | = flag_data;
Flag | = tcp_ack_update_window (SK, TP, SKB, ack, ack_seq); // flag may set the update bit
If (tcp_skb_cb (SKB)-> sacked) // if it is sack, it indicates that packet loss may occur, and it may be set to the sack bit. Select confirm the packets received by the receiving end, sack is designed to improve performance. In fact, this situation can be ignored during code analysis. Sack is selected only when message loss is confirmed)
Flag | = tcp_sacktag_write_queue (SK, SKB, prior_snd_una );
If (tcp_ecn_rcv_ecn_echo (TP, SKB-> H. Th) // vro notifies you of packet loss and sets it to the upper ECE bit.
Flag | = flag_ece;
...
}
...
Flag | = tcp_clean_rtx_queue (SK, & seq_rtt); // clear all confirmed packets whenever possible. If confirmed packets exist, put them in the acked bit.
...
If (tcp_ack_is_dubious (TP, flag) {// if no acked bit is set, no data bit is set, no update bit is set, or sack or ECE bit exists, it indicates that the message may have been lost. The judgment here is complicated. Note | Operator, as long as the first comparison object returns true, returns, and so on. If the flag has a data or acked bit, we cannot be sure that there will be no packet loss, because Ack is sent by the peer end. There are several possible methods, not only bare ACK, but also ack with the rst, the flag with the acked bit cannot be said to have not lost the packet, because although the ACK confirms some packets, the subsequent packets may be lost, in complex cases, you may also choose to confirm-sack. Therefore, you need to further judge the ECE and sack signs. However, in turn, it can be said that if there is neither data bit nor acked bit, if there is no update bit, it must be re-transmitted.
... // Enter the congestion control and retransmit quickly
Tcp_fastretrans_alert (SK, prior_snd_una, prior_packets, flag );
}
... // Otherwise, the system returns normally.
Return 1;
...
}
The most troublesome one is the sack logic. As mentioned above, sack is an optional mechanism for performance consideration. It can enable the sender to re-transmit only lost packets, instead, you do not need to re-transmit the selected out-of-order validation packets, which are configured using the TCP Header option. Before using the sack mechanism, you must allow the SACK option. When the redundant Ack is sent, it carries some information, including which unordered packets have been safely and correctly received and saved to the receiving end, when sending a re-transmitted packet, you do not have to transmit the confirmed out-of-order packets. For details, refer to the code of tcp_sacktag_write_queue.