3.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <eduma...@google.com>

[ Upstream commit 2ed0edf9090bf4afa2c6fc4f38575a85a80d4b20 ]

commit 17a6e9f1aa9 ("tcp_cubic: fix clock dependency") added an
overflow error in bictcp_update() in following code :

/* change the unit from HZ to bictcp_HZ */
t = ((tcp_time_stamp + msecs_to_jiffies(ca->delay_min>>3) -
      ca->epoch_start) << BICTCP_HZ) / HZ;

Because msecs_to_jiffies() being unsigned long, compiler does
implicit type promotion.

We really want to constrain (tcp_time_stamp - ca->epoch_start)
to a signed 32bit value, or else 't' has unexpected high values.

This bugs triggers an increase of retransmit rates ~24 days after
boot [1], as the high order bit of tcp_time_stamp flips.

[1] for hosts with HZ=1000

Big thanks to Van Jacobson for spotting this problem.

Diagnosed-by: Van Jacobson <v...@google.com>
Signed-off-by: Eric Dumazet <eduma...@google.com>
Cc: Neal Cardwell <ncardw...@google.com>
Cc: Yuchung Cheng <ych...@google.com>
Cc: Stephen Hemminger <step...@networkplumber.org>
Acked-by: Neal Cardwell <ncardw...@google.com>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 net/ipv4/tcp_cubic.c |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -206,8 +206,8 @@ static u32 cubic_root(u64 a)
  */
 static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 {
-       u64 offs;
-       u32 delta, t, bic_target, max_cnt;
+       u32 delta, bic_target, max_cnt;
+       u64 offs, t;
 
        ca->ack_cnt++;  /* count the number of ACKs */
 
@@ -250,9 +250,11 @@ static inline void bictcp_update(struct
         * if the cwnd < 1 million packets !!!
         */
 
+       t = (s32)(tcp_time_stamp - ca->epoch_start);
+       t += msecs_to_jiffies(ca->delay_min >> 3);
        /* change the unit from HZ to bictcp_HZ */
-       t = ((tcp_time_stamp + msecs_to_jiffies(ca->delay_min>>3)
-             - ca->epoch_start) << BICTCP_HZ) / HZ;
+       t <<= BICTCP_HZ;
+       do_div(t, HZ);
 
        if (t < ca->bic_K)              /* t - K */
                offs = ca->bic_K - t;


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to