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



原文地址:https://www.cnblogs.com/aiwz/p/6333353.html