diff -urNp linux-2.6.13-org/include/linux/tcp.h linux-2.6.13/include/linux/tcp.h --- linux-2.6.13-org/include/linux/tcp.h 2005-08-28 18:41:01.000000000 -0500 +++ linux-2.6.13/include/linux/tcp.h 2006-10-25 22:53:58.000000000 -0500 @@ -397,8 +413,8 @@ struct tcp_sock { /* Pluggable TCP congestion control hook */ struct tcp_congestion_ops *ca_ops; - u32 ca_priv[16]; -#define TCP_CA_PRIV_SIZE (16*sizeof(u32)) + u32 ca_priv[18]; +#define TCP_CA_PRIV_SIZE (18*sizeof(u32)) }; static inline struct tcp_sock *tcp_sk(const struct sock *sk) diff -urNp linux-2.6.13-org/net/ipv4/Kconfig linux-2.6.13/net/ipv4/Kconfig --- linux-2.6.13-org/net/ipv4/Kconfig 2005-08-28 18:41:01.000000000 -0500 +++ linux-2.6.13/net/ipv4/Kconfig 2006-10-25 22:53:18.000000000 -0500 @@ -457,6 +457,21 @@ config TCP_CONG_BIC increase provides TCP friendliness. See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ +config TCP_CONG_CUBIC + tristate "CUBIC (BIC 2.0)" + default m + ---help--- + Although BIC achieves pretty good scalability, fairness, and + stability during the current high speed environments, the BIC's + growth function can still be too aggressive for TCP, especially + under short RTT or low speed networks. Furthermore, the several + different phases of window control adds a lot of complexity in + analyzing the protocol. CUBIC uses a new window growth function + while retaining most of strengths of BIC (especially, its stability + and scalability), simplifies the window control and enhances its + TCP friendliness. + See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ + config TCP_CONG_WESTWOOD tristate "TCP Westwood+" default m diff -urNp linux-2.6.13-org/net/ipv4/Makefile linux-2.6.13/net/ipv4/Makefile --- linux-2.6.13-org/net/ipv4/Makefile 2005-08-28 18:41:01.000000000 -0500 +++ linux-2.6.13/net/ipv4/Makefile 2006-10-25 22:53:18.000000000 -0500 @@ -32,6 +32,7 @@ obj-$(CONFIG_IP_VS) += ipvs/ obj-$(CONFIG_IP_TCPDIAG) += tcp_diag.o obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o +obj-$(CONFIG_TCP_CONG_CUBIC) += tcp_cubic.o obj-$(CONFIG_TCP_CONG_WESTWOOD) += tcp_westwood.o obj-$(CONFIG_TCP_CONG_HSTCP) += tcp_highspeed.o obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybla.o diff -urNp linux-2.6.13-org/net/ipv4/tcp_cubic.c linux-2.6.13/net/ipv4/tcp_cubic.c --- linux-2.6.13-org/net/ipv4/tcp_cubic.c 1969-12-31 18:00:00.000000000 -0600 +++ linux-2.6.13/net/ipv4/tcp_cubic.c 2006-10-25 22:53:18.000000000 -0500 @@ -0,0 +1,487 @@ +/* + * Binary Increase Congestion control for TCP v2.0 + * + * This is from the implementation of CUBIC TCP in + * Injong Rhee, Lisong Xu. + * "CUBIC: A New TCP-Friendly High-Speed TCP Variant + * in PFLDnet 2005 + * Available from: + * http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf + * + * Unless CUBIC is enabled and congestion window is large + * this behaves the same as the original Reno. + */ + +#include +#include +#include +#include + + +#define CUBICTCP_BETA_SCALE 1024 /* Scale factor beta calculation + * max_cwnd = snd_cwnd * beta + */ +#define CUBICTCP_B 4 /* + * In binary search, + * go to point (max+min)/N + */ +#define cubictcp_HZ (10) /* CUBIC HZ 2^10 = 1024 */ + +static int fast_convergence = 1; +static int max_increment = 16; +static int low_window = 14; +static int beta = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */ +static int low_utilization_threshold = 153; +static int low_utilization_period = 2; +static int initial_ssthresh = 100; +static int cubic_scale = 41; +static int tcp_friendliness = 1; +static int smooth_part = 20; + +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(low_window, int, 0644); +MODULE_PARM_DESC(low_window, "lower bound on congestion window (for TCP friendliness)"); +module_param(beta, int, 0644); +MODULE_PARM_DESC(beta, "beta for multiplicative increase"); +module_param(low_utilization_threshold, int, 0644); +MODULE_PARM_DESC(low_utilization_threshold, "percent (scaled by 1024) for low utilization mode"); +module_param(low_utilization_period, int, 0644); +MODULE_PARM_DESC(low_utilization_period, "if average delay exceeds then goto to low utilization mode (seconds)"); +module_param(initial_ssthresh, int, 0644); +MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); +module_param(cubic_scale, int, 0644); +MODULE_PARM_DESC(cubic_scale, "scale (scaled by 1024) value for cubic function (cubic_scale/1024)"); +module_param(tcp_friendliness, int, 0644); +MODULE_PARM_DESC(tcp_friendliness, "tun on/off tcp friendliness"); +module_param(smooth_part, int, 0644); +MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax"); + + +/* CUBIC TCP Parameters */ +struct cubictcp { + u32 cnt; /* increase cwnd by 1 after ACKs */ + u32 last_max_cwnd; /* last maximum snd_cwnd */ + u32 loss_cwnd; /* congestion window at last loss */ + u32 last_cwnd; /* the last snd_cwnd */ + u32 last_time; /* time when updated last_cwnd */ + u32 cubic_origin_point; /* origin point of cubic function */ + u32 cubic_K; /* time to origin point from the beginning of the current epoch */ + u32 delay_min; /* min delay */ + u32 delay_max; /* max delay */ + u32 last_delay; + u8 low_utilization; /* 0: high; 1: low */ + u32 low_utilization_start; /* starting time of low utilization detection*/ + u32 epoch_start; /* beginning of an epoch */ + u32 tcp_8times_scale; /* used to estimate tcp's increment per rtt */ + u32 ack_cnt; /* number of acks */ + u32 tcp_cwnd; /* estimated tcp cwnd */ +#define ACK_RATIO_SHIFT 4 + u32 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */ +}; + +static inline void cubictcp_reset(struct cubictcp *ca) +{ + ca->cnt = 0; + ca->last_max_cwnd = 0; + ca->loss_cwnd = 0; + ca->last_cwnd = 0; + ca->last_time = 0; + ca->cubic_origin_point = 0; + ca->cubic_K = 0; + ca->delay_min = 0; + ca->delay_max = 0; + ca->last_delay = 0; + ca->low_utilization = 0; + ca->low_utilization_start = 0; + ca->epoch_start = 0; + ca->delayed_ack = 2 << ACK_RATIO_SHIFT; + ca->ack_cnt = 0; + ca->tcp_cwnd = 0; + ca->tcp_8times_scale = 8*(CUBICTCP_BETA_SCALE+beta)/3/(CUBICTCP_BETA_SCALE-beta); +} + +static void cubictcp_init(struct tcp_sock *tp) +{ + cubictcp_reset(tcp_ca(tp)); + if (initial_ssthresh) + tp->snd_ssthresh = initial_ssthresh; +} + +/* 65536 times the cubic root of 0, 1, 2, 3, 4, 5, 6, 7*/ +static u64 cubictcp_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) +{ + u64 y, app, target, start, end, mid, start_diff, end_diff; + + if (x == 0) + return 0; + + target = x; + + /*first estimate lower and upper bound*/ + y = 1; + while (x >= 8){ + x = (x >> 3); + y = (y << 1); + } + start = (y*cubictcp_table[x])>>16; + if (x==7) + end = (y<<1); + else + end = (y*cubictcp_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; + } + + /*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; + + if (start_diff < end_diff) + return (u32)start; + else + return (u32)end; +} + +static u32 cubictcp_K(u32 dist, u32 srtt) +{ + 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 cubictcp_HZ=2^10, not HZ + + c = cubic_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*cubictcp_HZ */ + d32 = (1 << (10+2*cubictcp_HZ)) / cubic_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 oveflow + 3) so find a "count" between cubictcp_hz-3 and cubictcp_hz + "count" may be less than bictcp_HZ, + then d64 becomes 0. that is OK + */ + d32 = srtt; + count = 0; + while (((d32 & 0x80000000)==0) && (count < cubictcp_HZ)){ + d32 = d32 << 1; + count++; + } + d32 = d32 / HZ; + + /* (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*cubictcp_HZ) */ + d64 = (d64 * dist * d32) >> (count+3-cubictcp_HZ); + + /* cubic root */ + d64 = cubic_root(d64); + + result = (u32)d64; + return result; +} +/* + * Compute congestion window to use. + */ +static inline void cubictcp_update(struct cubictcp *ca, u32 cwnd) +{ + u64 d64; + u32 d32, t, srtt, cubic_target, cubic_increment, min_cnt, max_cnt; + + ca->ack_cnt++; /* count the number of ACKs */ + + if (ca->last_cwnd == cwnd && + (s32)(tcp_time_stamp - ca->last_time) <= HZ / 32) + return; + + 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->tcp_cwnd = cwnd; /* syn with cubic */ + + if (ca->last_max_cwnd <= cwnd) { + ca->cubic_K = 0; + ca->cubic_origin_point = cwnd; + } else { + ca->cubic_K = cubictcp_K(ca->last_max_cwnd-cwnd, srtt); + ca->cubic_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) + and without the support of division of 64bit numbers (so all divisions are done by using d32) + also NOTE the unit of thos veriables + time = (t - K) / 2^cubictcp_HZ + c = cubic_scale >> 10 + rtt = (srtt >> 3) / HZ + !!! The following code does not have overflow problems, if the cwnd < 1 millon packets !!! + */ + + /* change the unit from HZ to cubictcp_HZ */ + t = ((tcp_time_stamp+(ca->delay_min>>3)-ca->epoch_start) << cubictcp_HZ) / HZ; + + if (t < ca->cubic_K) /* t - K */ + d32 = ca->cubic_K - t ; + else + d32 = t - ca->cubic_K ; + d64 = (u64)d32; + d32 = (cubic_scale << 3) * HZ / srtt; /* 1024*c/rtt */ + d64 = (d32 * d64 * d64 * d64) >> (10+3*cubictcp_HZ); /* c/rtt * (t-K)^3 */ + d32 = (u32)d64; + if (t < ca->cubic_K) /* below origin*/ + cubic_target = ca->cubic_origin_point - d32; + else /* above origin*/ + cubic_target = ca->cubic_origin_point + d32; + + /* cubic function - calc cubictcp_cnt*/ + if (cubic_target > cwnd) { + cubic_increment = cubic_target - cwnd; + ca->cnt = cwnd / cubic_increment; + } else { + ca->cnt = 100*cwnd; /* very small increment*/ + } + + /* max increment =Smax * rtt / 0.1 */ + min_cnt = (cwnd*HZ*8)/(10*max_increment*ca->delay_min); /* regular Smax */ + if (ca->cnt < min_cnt) + ca->cnt = min_cnt; + + /* slow start and low utilization */ + if (ca->loss_cwnd == 0) /* could be aggressive in slow start */ + ca->cnt = 50; + + /* TCP Friendly */ + if (tcp_friendliness) { + d32 = (cwnd*ca->tcp_8times_scale) >> 3; + while (ca->ack_cnt > d32) { /* update tcp cwnd */ + ca->ack_cnt -= d32; + ca->tcp_cwnd++; + } + if (ca->tcp_cwnd > cwnd){ /* if cubic is slower than tcp */ + d32 = ca->tcp_cwnd - cwnd; + max_cnt = cwnd / d32; + if (ca->cnt > max_cnt) + ca->cnt = max_cnt; + } + } + + ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack; /*for linux delayed-ack*/ + if (ca->cnt == 0) /* cannot be zero */ + ca->cnt = 1; +} + + +/* Detect low utilization in congestion avoidance */ +static inline void cubictcp_low_utilization(struct tcp_sock *tp, int flag) +{ + struct cubictcp *ca = tcp_ca(tp); + u32 dist, delay; + + /* No time stamp */ + if (!(tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) || + /* Discard delay samples right after fast recovery */ + tcp_time_stamp < ca->epoch_start + HZ || + /* this delay samples may not be accurate */ + flag == 0) { + ca->last_delay = 0; + goto notlow; + } + + delay = ca->last_delay<<3; /* use the same scale as tp->srtt*/ + ca->last_delay = tcp_time_stamp - tp->rx_opt.rcv_tsecr; + if (delay == 0) /* no previous delay sample */ + goto notlow; + + /* first time call or link delay decreases */ + if (ca->delay_min == 0 || ca->delay_min > delay) { + ca->delay_min = ca->delay_max = delay; + goto notlow; + } + + if (ca->delay_max < delay) + ca->delay_max = delay; + + /* utilization is low, if avg delay < dist*threshold + for checking_period time */ + dist = ca->delay_max - ca->delay_min; + if (dist <= ca->delay_min>>6 || + tp->srtt - ca->delay_min >= (dist*low_utilization_threshold)>>10) + goto notlow; + + if (ca->low_utilization_start == 0) { + ca->low_utilization = 0; + ca->low_utilization_start = tcp_time_stamp; + } else if ((s32)(tcp_time_stamp - ca->low_utilization_start) + > low_utilization_period*HZ) { + ca->low_utilization = 1; + } + + return; + + notlow: + ca->low_utilization = 0; + ca->low_utilization_start = 0; + +} + +static void cubictcp_cong_avoid(struct tcp_sock *tp, u32 ack, + u32 seq_rtt, u32 in_flight, int data_acked) +{ + struct cubictcp *ca = tcp_ca(tp); + + cubictcp_low_utilization(tp, data_acked); + + if (in_flight < tp->snd_cwnd) + return; + + if (tp->snd_cwnd <= tp->snd_ssthresh) { + /* In "safe" area, increase. */ + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + } else { + cubictcp_update(ca, tp->snd_cwnd); + + /* In dangerous area, increase slowly. + * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd + */ + if (tp->snd_cwnd_cnt >= ca->cnt) { + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + tp->snd_cwnd_cnt = 0; + } else + tp->snd_cwnd_cnt++; + } + +} + +static u32 cubictcp_recalc_ssthresh(struct tcp_sock *tp) +{ + struct cubictcp *ca = tcp_ca(tp); + + ca->epoch_start = 0; /* end of epoch */ + + /* in case of wrong delay_max*/ + if (ca->delay_min > 0 && ca->delay_max > ca->delay_min) + ca->delay_max = ca->delay_min + + ((ca->delay_max - ca->delay_min)* 90) / 100; + + /* Wmax and fast convergence */ + if (tp->snd_cwnd < ca->last_max_cwnd && fast_convergence) + ca->last_max_cwnd = (tp->snd_cwnd * (CUBICTCP_BETA_SCALE + beta)) + / (2 * CUBICTCP_BETA_SCALE); + else + ca->last_max_cwnd = tp->snd_cwnd; + + ca->loss_cwnd = tp->snd_cwnd; + + return max((tp->snd_cwnd * beta) / CUBICTCP_BETA_SCALE, 2U); +} + +static u32 cubictcp_undo_cwnd(struct tcp_sock *tp) +{ + struct cubictcp *ca = tcp_ca(tp); + + return max(tp->snd_cwnd, ca->last_max_cwnd); +} + +static u32 cubictcp_min_cwnd(struct tcp_sock *tp) +{ + return tp->snd_ssthresh; +} + +static void cubictcp_state(struct tcp_sock *tp, u8 new_state) +{ + if (new_state == TCP_CA_Loss) + cubictcp_reset(tcp_ca(tp)); +} + +/* Track delayed acknowledgement ratio using sliding window + * ratio = (15*ratio + sample) / 16 + */ +static void cubictcp_acked(struct tcp_sock *tp, u32 cnt) +{ + if (cnt > 0 && tp->ca_state == TCP_CA_Open) { + struct cubictcp *ca = tcp_ca(tp); + cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; + ca->delayed_ack += cnt; + } +} + + +static struct tcp_congestion_ops cubictcp = { + .init = cubictcp_init, + .ssthresh = cubictcp_recalc_ssthresh, + .cong_avoid = cubictcp_cong_avoid, + .set_state = cubictcp_state, + .undo_cwnd = cubictcp_undo_cwnd, + .min_cwnd = cubictcp_min_cwnd, + .pkts_acked = cubictcp_acked, + .owner = THIS_MODULE, + .name = "cubic", +}; + +static int __init cubictcp_register(void) +{ + BUG_ON(sizeof(struct cubictcp) > TCP_CA_PRIV_SIZE); + return tcp_register_congestion_control(&cubictcp); +} + +static void __exit cubictcp_unregister(void) +{ + tcp_unregister_congestion_control(&cubictcp); +} + +module_init(cubictcp_register); +module_exit(cubictcp_unregister); + +MODULE_AUTHOR("Sangtae Ha"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("CUBIC TCP");