aboutsummaryrefslogtreecommitdiff
path: root/net/dccp/ccids/lib/tfrc_equation.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ccids/lib/tfrc_equation.c')
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c96
1 files changed, 51 insertions, 45 deletions
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index ddac2c511e2..88ef98285be 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -1,6 +1,4 @@
/*
- * net/dccp/ccids/lib/tfrc_equation.c
- *
* Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
* Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz>
* Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
@@ -13,7 +11,6 @@
*/
#include <linux/module.h>
-#include <asm/div64.h>
#include "../../dccp.h"
#include "tfrc.h"
@@ -27,7 +24,7 @@
The following two-column lookup table implements a part of the TCP throughput
equation from [RFC 3448, sec. 3.1]:
- s
+ s
X_calc = --------------------------------------------------------------
R * sqrt(2*b*p/3) + (3 * t_RTO * sqrt(3*b*p/8) * (p + 32*p^3))
@@ -36,7 +33,7 @@
s is the packet size in bytes
R is the round trip time in seconds
p is the loss event rate, between 0 and 1.0, of the number of loss
- events as a fraction of the number of packets transmitted
+ events as a fraction of the number of packets transmitted
t_RTO is the TCP retransmission timeout value in seconds
b is the number of packets acknowledged by a single TCP ACK
@@ -48,9 +45,9 @@
which we can break down into:
- s
+ s
X_calc = ---------
- R * f(p)
+ R * f(p)
where f(p) is given for 0 < p <= 1 by:
@@ -63,7 +60,7 @@
* the return result f(p)
The lookup table therefore actually tabulates the following function g(q):
- g(q) = 1000000 * f(q/1000000)
+ g(q) = 1000000 * f(q/1000000)
Hence, when p <= 1, q must be less than or equal to 1000000. To achieve finer
granularity for the practically more relevant case of small values of p (up to
@@ -80,10 +77,10 @@
}
With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1,
- lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%)
- lookup[M][0] = g(1000000) = 1000000 * f(100%)
- lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%)
- lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%)
+ lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%)
+ lookup[M][0] = g(1000000) = 1000000 * f(100%)
+ lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%)
+ lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%)
In summary, the two columns represent f(p) for the following ranges:
* The first column is for 0.002 <= p <= 1.0
@@ -611,20 +608,17 @@ static inline u32 tfrc_binsearch(u32 fval, u8 small)
/**
* tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448
+ * @s: packet size in bytes
+ * @R: RTT scaled by 1000000 (i.e., microseconds)
+ * @p: loss ratio estimate scaled by 1000000
*
- * @s: packet size in bytes
- * @R: RTT scaled by 1000000 (i.e., microseconds)
- * @p: loss ratio estimate scaled by 1000000
- * Returns X_calc in bytes per second (not scaled).
- *
- * Note: DO NOT alter this code unless you run test cases against it,
- * as the code has been optimized to stop underflow/overflow.
+ * Returns X_calc in bytes per second (not scaled).
*/
u32 tfrc_calc_x(u16 s, u32 R, u32 p)
{
- int index;
+ u16 index;
u32 f;
- u64 tmp1, tmp2;
+ u64 result;
/* check against invalid parameters and divide-by-zero */
BUG_ON(p > 1000000); /* p must not exceed 100% */
@@ -632,41 +626,41 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
if (R == 0) { /* possible divide by zero */
DCCP_CRIT("WARNING: RTT is 0, returning maximum X_calc.");
return ~0U;
- }
+ }
- if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */
+ if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */
if (p < TFRC_SMALLEST_P) { /* 0.0000 < p < 0.0001 */
DCCP_WARN("Value of p (%d) below resolution. "
"Substituting %d\n", p, TFRC_SMALLEST_P);
index = 0;
- } else /* 0.0001 <= p <= 0.05 */
+ } else /* 0.0001 <= p <= 0.05 */
index = p/TFRC_SMALLEST_P - 1;
- f = tfrc_calc_x_lookup[index][1];
+ f = tfrc_calc_x_lookup[index][1];
- } else { /* 0.05 < p <= 1.00 */
+ } else { /* 0.05 < p <= 1.00 */
index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1;
f = tfrc_calc_x_lookup[index][0];
}
- /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
- * and R are both scaled by 1000000, we need to multiply by 1000000^2.
- * ==> DO NOT alter this unless you test against overflow on 32 bit */
- tmp1 = ((u64)s * 100000000);
- tmp2 = ((u64)R * (u64)f);
- do_div(tmp2, 10000);
- do_div(tmp1, tmp2);
-
- return (u32)tmp1;
+ /*
+ * Compute X = s/(R*f(p)) in bytes per second.
+ * Since f(p) and R are both scaled by 1000000, we need to multiply by
+ * 1000000^2. To avoid overflow, the result is computed in two stages.
+ * This works under almost all reasonable operational conditions, for a
+ * wide range of parameters. Yet, should some strange combination of
+ * parameters result in overflow, the use of scaled_div32 will catch
+ * this and return UINT_MAX - which is a logically adequate consequence.
+ */
+ result = scaled_div(s, R);
+ return scaled_div32(result, f);
}
-EXPORT_SYMBOL_GPL(tfrc_calc_x);
-
-/*
+/**
* tfrc_calc_x_reverse_lookup - try to find p given f(p)
- *
* @fvalue: function value to match, scaled by 1000000
+ *
* Returns closest match for p, also scaled by 1000000
*/
u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
@@ -678,22 +672,34 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
/* Error cases. */
if (fvalue < tfrc_calc_x_lookup[0][1]) {
- DCCP_WARN("fvalue %d smaller than resolution\n", fvalue);
- return tfrc_calc_x_lookup[0][1];
+ DCCP_WARN("fvalue %u smaller than resolution\n", fvalue);
+ return TFRC_SMALLEST_P;
}
if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) {
- DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue);
+ DCCP_WARN("fvalue %u exceeds bounds!\n", fvalue);
return 1000000;
}
if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) {
index = tfrc_binsearch(fvalue, 1);
return (index + 1) * TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE;
- }
-
+ }
+
/* else ... it must be in the coarse-grained column */
index = tfrc_binsearch(fvalue, 0);
return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE;
}
-EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup);
+/**
+ * tfrc_invert_loss_event_rate - Compute p so that 10^6 corresponds to 100%
+ * When @loss_event_rate is large, there is a chance that p is truncated to 0.
+ * To avoid re-entering slow-start in that case, we set p = TFRC_SMALLEST_P > 0.
+ */
+u32 tfrc_invert_loss_event_rate(u32 loss_event_rate)
+{
+ if (loss_event_rate == UINT_MAX) /* see RFC 4342, 8.5 */
+ return 0;
+ if (unlikely(loss_event_rate == 0)) /* map 1/0 into 100% */
+ return 1000000;
+ return max_t(u32, scaled_div(1, loss_event_rate), TFRC_SMALLEST_P);
+}