• Marcelo Leitner's avatar
    tcp: zero retrans_stamp if all retrans were acked · 1f37bf87
    Marcelo Leitner authored
    Ueki Kohei reported that when we are using NewReno with connections that
    have a very low traffic, we may timeout the connection too early if a
    second loss occurs after the first one was successfully acked but no
    data was transfered later. Below is his description of it:
    
    When SACK is disabled, and a socket suffers multiple separate TCP
    retransmissions, that socket's ETIMEDOUT value is calculated from the
    time of the *first* retransmission instead of the *latest*
    retransmission.
    
    This happens because the tcp_sock's retrans_stamp is set once then never
    cleared.
    
    Take the following connection:
    
                          Linux                    remote-machine
                            |                           |
             send#1---->(*1)|--------> data#1 --------->|
                      |     |                           |
                     RTO    :                           :
                      |     |                           |
                     ---(*2)|----> data#1(retrans) ---->|
                      | (*3)|<---------- ACK <----------|
                      |     |                           |
                      |     :                           :
                      |     :                           :
                      |     :                           :
                    16 minutes (or more)                :
                      |     :                           :
                      |     :                           :
                      |     :                           :
                      |     |                           |
             send#2---->(*4)|--------> data#2 --------->|
                      |     |                           |
                     RTO    :                           :
                      |     |                           |
                     ---(*5)|----> data#2(retrans) ---->|
                      |     |                           |
                      |     |                           |
                    RTO*2   :                           :
                      |     |                           |
                      |     |                           |
          ETIMEDOUT<----(*6)|                           |
    
    (*1) One data packet sent.
    (*2) Because no ACK packet is received, the packet is retransmitted.
    (*3) The ACK packet is received. The transmitted packet is acknowledged.
    
    At this point the first "retransmission event" has passed and been
    recovered from. Any future retransmission is a completely new "event".
    
    (*4) After 16 minutes (to correspond with retries2=15), a new data
    packet is sent. Note: No data is transmitted between (*3) and (*4).
    
    The socket's timeout SHOULD be calculated from this point in time, but
    instead it's calculated from the prior "event" 16 minutes ago.
    
    (*5) Because no ACK packet is received, the packet is retransmitted.
    (*6) At the time of the 2nd retransmission, the socket returns
    ETIMEDOUT.
    
    Therefore, now we clear retrans_stamp as soon as all data during the
    loss window is fully acked.
    
    Reported-by: Ueki Kohei
    Cc: Neal Cardwell <ncardwell@google.com>
    Cc: Yuchung Cheng <ycheng@google.com>
    Signed-off-by: default avatarMarcelo Ricardo Leitner <mleitner@redhat.com>
    Acked-by: default avatarNeal Cardwell <ncardwell@google.com>
    Tested-by: default avatarNeal Cardwell <ncardwell@google.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    1f37bf87
tcp_input.c 171 KB