tcp_bic.c 9.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * Binary Increase Congestion control for TCP
 *
 * This is from the implementation of BICTCP in
 * Lison-Xu, Kahaled Harfoush, and Injong Rhee.
 *  "Binary Increase Congestion Control for Fast, Long Distance
 *  Networks" in InfoComm 2004
 * Available from:
 *  http://www.csc.ncsu.edu/faculty/rhee/export/bitcp.pdf
 *
 * Unless BIC is enabled and congestion window is large
 * this behaves the same as the original Reno.
 */

#include <linux/config.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <net/tcp.h>


#define BICTCP_BETA_SCALE    1024	/* Scale factor beta calculation
					 * max_cwnd = snd_cwnd * beta
					 */
#define BICTCP_B		4	 /*
					  * In binary search,
					  * go to point (max+min)/N
					  */

static int fast_convergence = 1;
30
static int max_increment = 16;
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
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 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(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");


/* BIC TCP Parameters */
struct bictcp {
	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	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 */
#define ACK_RATIO_SHIFT	4
	u32	delayed_ack;	/* estimate the ratio of Packets/ACKs << 4 */
};

static inline void bictcp_reset(struct bictcp *ca)
{
	ca->cnt = 0;
	ca->last_max_cwnd = 0;
	ca->loss_cwnd = 0;
	ca->last_cwnd = 0;
	ca->last_time = 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;
}

89
static void bictcp_init(struct sock *sk)
90
{
91
	bictcp_reset(inet_csk_ca(sk));
92
	if (initial_ssthresh)
93
		tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
}

/*
 * Compute congestion window to use.
 */
static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
{
	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;

	if (ca->epoch_start == 0) /* record the beginning of an epoch */
		ca->epoch_start = tcp_time_stamp;

	/* start off normal */
	if (cwnd <= low_window) {
		ca->cnt = cwnd;
		return;
	}

	/* binary increase */
	if (cwnd < ca->last_max_cwnd) {
		__u32 	dist = (ca->last_max_cwnd - cwnd)
			/ BICTCP_B;

		if (dist > max_increment)
			/* linear increase */
			ca->cnt = cwnd / max_increment;
		else if (dist <= 1U)
			/* binary search increase */
			ca->cnt = (cwnd * smooth_part) / BICTCP_B;
		else
			/* binary search increase */
			ca->cnt = cwnd / dist;
	} else {
		/* slow start AMD linear increase */
		if (cwnd < ca->last_max_cwnd + BICTCP_B)
			/* slow start */
			ca->cnt = (cwnd * smooth_part) / BICTCP_B;
		else if (cwnd < ca->last_max_cwnd + max_increment*(BICTCP_B-1))
			/* slow start */
			ca->cnt = (cwnd * (BICTCP_B-1))
139
				/ (cwnd - ca->last_max_cwnd);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
		else
			/* linear increase */
			ca->cnt = cwnd / max_increment;
	}

	/* if in slow start or link utilization is very low */
	if ( ca->loss_cwnd == 0 ||
	     (cwnd > ca->loss_cwnd && ca->low_utilization)) {
		if (ca->cnt > 20) /* increase cwnd 5% per RTT */
			ca->cnt = 20;
	}

	ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack;
	if (ca->cnt == 0)			/* cannot be zero */
		ca->cnt = 1;
}


/* Detect low utilization in congestion avoidance */
159
static inline void bictcp_low_utilization(struct sock *sk, int flag)
160
{
161 162
	const struct tcp_sock *tp = tcp_sk(sk);
	struct bictcp *ca = inet_csk_ca(sk);
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	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;

}

212
static void bictcp_cong_avoid(struct sock *sk, u32 ack,
213 214
			      u32 seq_rtt, u32 in_flight, int data_acked)
{
215 216
	struct tcp_sock *tp = tcp_sk(sk);
	struct bictcp *ca = inet_csk_ca(sk);
217

218
	bictcp_low_utilization(sk, data_acked);
219

220
	if (!tcp_is_cwnd_limited(sk, in_flight))
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
		return;

	if (tp->snd_cwnd <= tp->snd_ssthresh) {
		/* In "safe" area, increase. */
		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
			tp->snd_cwnd++;
	} else {
		bictcp_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++;
	}

}

/*
 *	behave like Reno until low_window is reached,
 *	then increase congestion window slowly
 */
247
static u32 bictcp_recalc_ssthresh(struct sock *sk)
248
{
249 250
	const struct tcp_sock *tp = tcp_sk(sk);
	struct bictcp *ca = inet_csk_ca(sk);
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274

	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 * (BICTCP_BETA_SCALE + beta))
			/ (2 * BICTCP_BETA_SCALE);
	else
		ca->last_max_cwnd = tp->snd_cwnd;

	ca->loss_cwnd = tp->snd_cwnd;


	if (tp->snd_cwnd <= low_window)
		return max(tp->snd_cwnd >> 1U, 2U);
	else
		return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U);
}

275
static u32 bictcp_undo_cwnd(struct sock *sk)
276
{
277 278
	const struct tcp_sock *tp = tcp_sk(sk);
	const struct bictcp *ca = inet_csk_ca(sk);
279 280 281
	return max(tp->snd_cwnd, ca->last_max_cwnd);
}

282
static u32 bictcp_min_cwnd(struct sock *sk)
283
{
284
	const struct tcp_sock *tp = tcp_sk(sk);
285 286 287
	return tp->snd_ssthresh;
}

288
static void bictcp_state(struct sock *sk, u8 new_state)
289 290
{
	if (new_state == TCP_CA_Loss)
291
		bictcp_reset(inet_csk_ca(sk));
292 293 294 295 296
}

/* Track delayed acknowledgement ratio using sliding window
 * ratio = (15*ratio + sample) / 16
 */
297
static void bictcp_acked(struct sock *sk, u32 cnt)
298
{
299 300 301 302
	const struct inet_connection_sock *icsk = inet_csk(sk);

	if (cnt > 0 && 	icsk->icsk_ca_state == TCP_CA_Open) {
		struct bictcp *ca = inet_csk_ca(sk);
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
		cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
		ca->delayed_ack += cnt;
	}
}


static struct tcp_congestion_ops bictcp = {
	.init		= bictcp_init,
	.ssthresh	= bictcp_recalc_ssthresh,
	.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		= "bic",
};

static int __init bictcp_register(void)
{
323
	BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE);
324 325 326 327 328 329 330 331 332 333 334 335 336 337
	return tcp_register_congestion_control(&bictcp);
}

static void __exit bictcp_unregister(void)
{
	tcp_unregister_congestion_control(&bictcp);
}

module_init(bictcp_register);
module_exit(bictcp_unregister);

MODULE_AUTHOR("Stephen Hemminger");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("BIC TCP");