TCP BIC 拥塞控制源码分析

    1、对于TCP协议数据传输优化来说最大的难点就在于物理带宽的估计,网络的复杂性决定了拥塞控制算法作用的有限性和Linux内核支持的拥塞控制算法(reno、newreno、hybla、bic、cubic、westwood、vegas、yeah等)的多样性,只有准确的带宽估计才能够充分的利用带宽,所以当前的主要难点是带宽估计。

    2、BIC 主要用来解决高速大延时网络(High-speed networks with large delays)的带宽估计问题。

    3、BIC算法其实是看透了带宽探测、估计的过程,所以其使用了二分查找技术来准确、快速的估计带宽。



BIC二分查找逻辑分析:

    如上图,横轴是last_max_cwnd,意义是上次丢包时预估的带宽值,这个值将对下一轮的带宽估计起着关键影响,纵坐标是snd_cwnd,这幅图描述的是BIC在拥塞避免阶段的snd_cwnd调节。  

    带宽逼近过程(snd_cwnd < last_max_cwnd):     

         1、dist = last_max_cwnd - snd_cwnd:

         2、dist < A,snd_cwnd快逼近带宽值预估值了,snd_cwnd的探测速度要放慢,否则可能会出现丢包。

         3、A < dist < B,那么此时应该将snd_cwnd探测速度调节到适中值。

         4、dist > B,snd_cwnd离last_max_cwnd距离很远,需要加快它的探测速度。

 

    新带宽探测过程(snd_cwnd > last_max_cwnd):

         1、dist = last_max_cwnd - snd_cwnd:

         2、如果 dist < C,那么需要慢速探测;

         3、如果 C < dist < D,那么中速探测;

         4、如果 dist > D,那么应该快速探测。


/* 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	epoch_start;	/* beginning of an epoch */
#define ACK_RATIO_SHIFT	4
	u32	delayed_ack;	/* estimate the ratio of Packets/ACKs << 4 */
};

   u32cnt; /* increase cwnd by 1 after ACKs */

     用来记录进入拥塞避免状态后,需要接收到多少个ACK才能出发snd_cwnd + 1

   u32  last_max_cwnd;/* last maximum snd_cwnd */

      丢包的时候,BIC需要选取一个snd_cwnd值作为二分查找的上限值,如果当前二分查找的带宽值大于上一次丢包记录的last_max_cwnd那么last_max_cwnd更新为当前的snd_cwnd,否则为0.9 * snd_cwnd,关于这个问题其实很好理解,如果当前探测到的带宽值比设定的二分阈值小,那么说明当前带宽比之前预计的带宽要小,所以下次预测带宽值要缩小,缩小为原来的0.9倍。

   u32 loss_cwnd; /* congestion window at last loss */

     用来记录丢包时的拥塞窗口值。

   u32 last_time;/* time when updated last_cwnd */

      用来记录最近一次拥塞避免阶段snd_cwnd调节的timestamp,如果多次进入时间差很小那么只会调节一次,避免频繁的调节。

   u32	epoch_start;	/* beginning of an epoch */

     用来记录计入拥塞避免状态的timestamp,这个变量在BIC拥塞控制算法具体实现中,没有太大意义。

<span style="font-size:14px;">   </span><span style="font-size:18px;">u32	delayed_ack;	/* estimate the ratio of Packets/ACKs << 4 */</span>

   用来记录延时ACK的个数,BIC考虑的延时ACK对带宽估计的影响。

/*
 * 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))
				/ (cwnd - ca->last_max_cwnd);
		else
			/* linear increase */
			ca->cnt = cwnd / max_increment;
	}

	/* if in slow start or link utilization is very low */
	if (ca->loss_cwnd == 0) {
		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;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值