* this behaves the same as the original Reno.
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <net/tcp.h>
-
+#include <asm/div64.h>
#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
* max_cwnd = snd_cwnd * beta
static int bic_scale = 41;
static int tcp_friendliness = 1;
+static u32 cube_rtt_scale;
+static u32 beta_scale;
+static u64 cube_factor;
+
+/* Note parameters that are used for precomputing scale factors are read-only */
module_param(fast_convergence, int, 0644);
MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence");
module_param(max_increment, int, 0644);
MODULE_PARM_DESC(max_increment, "Limit on increment allowed during binary search");
-module_param(beta, int, 0644);
+module_param(beta, int, 0444);
MODULE_PARM_DESC(beta, "beta for multiplicative increase");
module_param(initial_ssthresh, int, 0644);
MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
-module_param(bic_scale, int, 0644);
+module_param(bic_scale, int, 0444);
MODULE_PARM_DESC(bic_scale, "scale (scaled by 1024) value for bic function (bic_scale/1024)");
module_param(tcp_friendliness, int, 0644);
MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness");
+#include <asm/div64.h>
/* BIC TCP Parameters */
struct bictcp {
tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
}
-/* 65536 times the cubic root */
-static const u64 cubic_table[8]
- = {0, 65536, 82570, 94519, 104030, 112063, 119087, 125367};
-
-/*
- * calculate the cubic root of x
- * the basic idea is that x can be expressed as i*8^j
- * so cubic_root(x) = cubic_root(i)*2^j
- * in the following code, x is i, and y is 2^j
- * because of integer calculation, there are errors in calculation
- * so finally use binary search to find out the exact solution
- */
-static u32 cubic_root(u64 x)
+/* 64bit divisor, dividend and result. dynamic precision */
+static inline u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
{
- u64 y, app, target, start, end, mid, start_diff, end_diff;
-
- if (x == 0)
- return 0;
+ u_int32_t d = divisor;
- target = x;
+ if (divisor > 0xffffffffULL) {
+ unsigned int shift = fls(divisor >> 32);
- /* first estimate lower and upper bound */
- y = 1;
- while (x >= 8){
- x = (x >> 3);
- y = (y << 1);
- }
- start = (y*cubic_table[x])>>16;
- if (x==7)
- end = (y<<1);
- else
- end = (y*cubic_table[x+1]+65535)>>16;
-
- /* binary search for more accurate one */
- while (start < end-1) {
- mid = (start+end) >> 1;
- app = mid*mid*mid;
- if (app < target)
- start = mid;
- else if (app > target)
- end = mid;
- else
- return mid;
- }
+ d = divisor >> shift;
+ dividend >>= shift;
+ }
- /* find the most accurate one from start and end */
- app = start*start*start;
- if (app < target)
- start_diff = target - app;
- else
- start_diff = app - target;
- app = end*end*end;
- if (app < target)
- end_diff = target - app;
- else
- end_diff = app - target;
+ /* avoid 64 bit division if possible */
+ if (dividend >> 32)
+ do_div(dividend, d);
+ else
+ dividend = (uint32_t) dividend / d;
- if (start_diff < end_diff)
- return (u32)start;
- else
- return (u32)end;
+ return dividend;
}
-static inline u32 bictcp_K(u32 dist, u32 srtt)
+/*
+ * calculate the cubic root of x using Newton-Raphson
+ */
+static u32 cubic_root(u64 a)
{
- u64 d64;
- u32 d32;
- u32 count;
- u32 result;
-
- /* calculate the "K" for (wmax-cwnd) = c/rtt * K^3
- so K = cubic_root( (wmax-cwnd)*rtt/c )
- the unit of K is bictcp_HZ=2^10, not HZ
-
- c = bic_scale >> 10
- rtt = (tp->srtt >> 3 ) / HZ
-
- the following code has been designed and tested for
- cwnd < 1 million packets
- RTT < 100 seconds
- HZ < 1,000,00 (corresponding to 10 nano-second)
-
- */
-
- /* 1/c * 2^2*bictcp_HZ */
- d32 = (1 << (10+2*BICTCP_HZ)) / bic_scale;
- d64 = (__u64)d32;
-
- /* srtt * 2^count / HZ
- 1) to get a better accuracy of the following d32,
- the larger the "count", the better the accuracy
- 2) and avoid overflow of the following d64
- the larger the "count", the high possibility of overflow
- 3) so find a "count" between bictcp_hz-3 and bictcp_hz
- "count" may be less than bictcp_HZ,
- then d64 becomes 0. that is OK
- */
- d32 = srtt;
- count = 0;
- while (((d32 & 0x80000000)==0) && (count < BICTCP_HZ)){
- d32 = d32 << 1;
- count++;
- }
- d32 = d32 / HZ;
-
- /* (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*bictcp_HZ) */
- d64 = (d64 * dist * d32) >> (count+3-BICTCP_HZ);
-
- /* cubic root */
- d64 = cubic_root(d64);
-
- result = (u32)d64;
- return result;
+ u32 x, x1;
+
+ /* Initial estimate is based on:
+ * cbrt(x) = exp(log(x) / 3)
+ */
+ x = 1u << (fls64(a)/3);
+
+ /*
+ * Iteration based on:
+ * 2
+ * x = ( 2 * x + a / x ) / 3
+ * k+1 k k
+ */
+ do {
+ x1 = x;
+ x = (2 * x + (uint32_t) div64_64(a, x*x)) / 3;
+ } while (abs(x1 - x) > 1);
+
+ return x;
}
/*
*/
static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
{
- u64 d64;
- u32 d32, t, srtt, bic_target, min_cnt, max_cnt;
+ u64 offs;
+ u32 delta, t, bic_target, min_cnt, max_cnt;
ca->ack_cnt++; /* count the number of ACKs */
ca->last_cwnd = cwnd;
ca->last_time = tcp_time_stamp;
- srtt = (HZ << 3)/10; /* use real time-based growth function */
-
if (ca->epoch_start == 0) {
ca->epoch_start = tcp_time_stamp; /* record the beginning of an epoch */
ca->ack_cnt = 1; /* start counting */
ca->bic_K = 0;
ca->bic_origin_point = cwnd;
} else {
- ca->bic_K = bictcp_K(ca->last_max_cwnd-cwnd, srtt);
+ /* Compute new K based on
+ * (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*bictcp_HZ)
+ */
+ ca->bic_K = cubic_root(cube_factor
+ * (ca->last_max_cwnd - cwnd));
ca->bic_origin_point = ca->last_max_cwnd;
}
}
/* cubic function - calc*/
/* calculate c * time^3 / rtt,
* while considering overflow in calculation of time^3
- * (so time^3 is done by using d64)
+ * (so time^3 is done by using 64 bit)
* and without the support of division of 64bit numbers
- * (so all divisions are done by using d32)
+ * (so all divisions are done by using 32 bit)
* also NOTE the unit of those veriables
* time = (t - K) / 2^bictcp_HZ
* c = bic_scale >> 10
<< BICTCP_HZ) / HZ;
if (t < ca->bic_K) /* t - K */
- d32 = ca->bic_K - t;
+ offs = ca->bic_K - t;
else
- d32 = t - ca->bic_K;
+ offs = t - ca->bic_K;
- d64 = (u64)d32;
- d32 = (bic_scale << 3) * HZ / srtt; /* 1024*c/rtt */
- d64 = (d32 * d64 * d64 * d64) >> (10+3*BICTCP_HZ); /* c/rtt * (t-K)^3 */
- d32 = (u32)d64;
+ /* c/rtt * (t-K)^3 */
+ delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ);
if (t < ca->bic_K) /* below origin*/
- bic_target = ca->bic_origin_point - d32;
+ bic_target = ca->bic_origin_point - delta;
else /* above origin*/
- bic_target = ca->bic_origin_point + d32;
+ bic_target = ca->bic_origin_point + delta;
/* cubic function - calc bictcp_cnt*/
if (bic_target > cwnd) {
/* TCP Friendly */
if (tcp_friendliness) {
- u32 scale = 8*(BICTCP_BETA_SCALE+beta)/3/(BICTCP_BETA_SCALE-beta);
- d32 = (cwnd * scale) >> 3;
- while (ca->ack_cnt > d32) { /* update tcp cwnd */
- ca->ack_cnt -= d32;
+ u32 scale = beta_scale;
+ delta = (cwnd * scale) >> 3;
+ while (ca->ack_cnt > delta) { /* update tcp cwnd */
+ ca->ack_cnt -= delta;
ca->tcp_cwnd++;
}
if (ca->tcp_cwnd > cwnd){ /* if bic is slower than tcp */
- d32 = ca->tcp_cwnd - cwnd;
- max_cnt = cwnd / d32;
+ delta = ca->tcp_cwnd - cwnd;
+ max_cnt = cwnd / delta;
if (ca->cnt > max_cnt)
ca->cnt = max_cnt;
}
return max(tcp_sk(sk)->snd_cwnd, ca->last_max_cwnd);
}
-static u32 bictcp_min_cwnd(struct sock *sk)
-{
- return tcp_sk(sk)->snd_ssthresh;
-}
-
static void bictcp_state(struct sock *sk, u8 new_state)
{
if (new_state == TCP_CA_Loss)
.cong_avoid = bictcp_cong_avoid,
.set_state = bictcp_state,
.undo_cwnd = bictcp_undo_cwnd,
- .min_cwnd = bictcp_min_cwnd,
.pkts_acked = bictcp_acked,
.owner = THIS_MODULE,
.name = "cubic",
static int __init cubictcp_register(void)
{
BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
+
+ /* Precompute a bunch of the scaling factors that are used per-packet
+ * based on SRTT of 100ms
+ */
+
+ beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta);
+
+ cube_rtt_scale = (bic_scale << 3) / 10; /* 1024*c/rtt */
+
+ /* calculate the "K" for (wmax-cwnd) = c/rtt * K^3
+ * so K = cubic_root( (wmax-cwnd)*rtt/c )
+ * the unit of K is bictcp_HZ=2^10, not HZ
+ *
+ * c = bic_scale >> 10
+ * rtt = 100ms
+ *
+ * the following code has been designed and tested for
+ * cwnd < 1 million packets
+ * RTT < 100 seconds
+ * HZ < 1,000,00 (corresponding to 10 nano-second)
+ */
+
+ /* 1/c * 2^2*bictcp_HZ * srtt */
+ cube_factor = 1ull << (10+3*BICTCP_HZ); /* 2^40 */
+
+ /* divide by bic_scale and by constant Srtt (100ms) */
+ do_div(cube_factor, bic_scale * 10);
+
return tcp_register_congestion_control(&cubictcp);
}