TCP拥塞控制算法 — CUBIC的补丁(一)
cubic从2.6.37到3.0之间有7个patch,从3.0到3.8(当前最新版本)中无patch。
描述
以下是提交者Stephen Hemminger对这个patch的描述:
fix comparison of jiffies
Jiffies wraps around therefore the correct way to compare is to use cast to signed value.
Note: cubic is not using full jiffies value on 64 bit arch because using full unsigned long
makes struct bictcp grow too large for the available ca_priv area.
Includes correction from Sangtae Ha to improve ack train detection.
代码
--- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -342,9 +342,11 @@ static void hystart_update(struct sock *sk, u32 delay) u32 curr_jiffies = jiffies; /* first detection parameter - ack-train detection */ - if (curr_jiffies - ca->last_jiffies <= msecs_to_jiffies(2)) { + if ((s32)(curr_jiffies - ca->last_jiffies) <= + msecs_to_jiffies(2)) { ca->last_jiffies = curr_jiffies; - if (curr_jiffies - ca->round_start >= ca->delay_min>>4) + if ((s32) (curr_jiffies - ca->round_start) > + ca->delay_min >> 4) ca->found |= HYSTART_ACK_TRAIN; }
分析
@arch/x86/include/asm/posix_types_64.h: typedef long __kernel_time_t; typedef long __kernel_suseconds_t; @include/linux/time.h: struct timeval { __kernel_time_t tv_sec; /* seconds */ __kernel_suseconds_t tv_usec; /* microseconds */ } @include/linux/raid/pq.h: typedef uint32_t u32; #define jiffies raid6_jiffies() #undef HZ #define HZ 1000 static inline uint32_t raid6_jiffies(void) { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec/1000; }
我们可以看到jiffies为u32类型,单位为毫秒。这样一来jiffies在49.7天后就会溢出。
当jiffies达到最大值后,它的值就会回绕到0。
u32 a;
u32 b;
(a - b)为u32的,如果a < b,但是这时的结果为正数,则不能正确表示a和b的大小关系。
所以需要把结果转化为有符号的,即(s32)(a - b)。
评价
我们知道从道理上讲curr_jiffies应该总大于last_jiffies和round_start的,因为后两个是过去的时间。
这个patch并不能保证这一点,所以当curr_jiffies回绕时,还是会出现错误判断!
因为这个时候 (curr_jiffies - ca->round_start )总是小于0的。
当然,回绕发生的概率低(49.7天一次),被这个函数遇到的概率更低,并且除了ack train方法外还有
delay increase来检查退出点,所以影响微乎其微。
其实要更彻底解决这个问题,只需要把ca->round_start和ca->last_jiffies换为u64类型,再使用64位
jiffies即可。这样在任何人的有生之年都别指望看到jiffies溢出了。提交者没有这样做的原因是这会使
bictcp结构的大小超出icsk_ca_priv所指向空间的大小,而其实增大icsk_ca_priv所指向空间大小是很
方便的。
Author
zhangskd @ csdn blog