OSPF SPF计算的避让算法

OSPF在计算SPF时,为了防止震荡以及连续收到LSA时多次计算SPF,某些代码里实现了避让算法。代码如下:

#define OSPF_SPF_INCREMENT_VALUE 2
#define ONE_SEC_MICROSECOND      1000000
void ospf_spf_calculate_timer_add (struct ospf_area *area)
{
    struct ospf_master *om = area->top->om;
    struct ospf *top = area->top;
    timeval now, delta, delay, hold;
    time_tzcurrent (&now, NULL);
    delta = TV_SUB (now, area->tv_spf);
    if ((TV_CMP (delta, area->tv_spf_curr)) < 0) {
        delay = TV_SUB (area->tv_spf_curr, delta);
        /* Change the value of tv_spf_curr to 5 times its value */
        area->tv_spf_curr.tv_sec *= OSPF_SPF_INCREMENT_VALUE;
        area->tv_spf_curr.tv_sec += ((OSPF_SPF_INCREMENT_VALUE *
                                      area->tv_spf_curr.tv_usec) / ONE_SEC_MICROSECOND);
        area->tv_spf_curr.tv_usec = (OSPF_SPF_INCREMENT_VALUE *
                                     area->tv_spf_curr.tv_usec) % ONE_SEC_MICROSECOND;
    }
    else {
        delay.tv_sec = delay.tv_usec = 0;
        hold = area->tv_spf_curr;
        hold.tv_sec *= OSPF_SPF_INCREMENT_VALUE;
        hold.tv_sec += ((OSPF_SPF_INCREMENT_VALUE * hold.tv_usec) / ONE_SEC_MICROSECOND);
        hold.tv_usec = (OSPF_SPF_INCREMENT_VALUE * hold.tv_usec) % ONE_SEC_MICROSECOND;
        if (TV_CMP (top->spf_max_delay, hold) < 0)
            hold = top->spf_max_delay;
        if ((TV_CMP (hold, delta)) < 0) {
            area->tv_spf_curr = top->spf_min_delay;
        }
    }
    /* If delay < start delay , delay for another start_delay period */
    if ((TV_CMP (top->spf_start_delay, delay)) > 0) {
        delay = top->spf_start_delay;
    }
    if ((TV_CMP (top->spf_max_delay, area->tv_spf_curr)) < 0) {
        /* Should not be more than max value */
        area->tv_spf_curr = top->spf_max_delay;
    }
    /* Now schedule SPF timer.  */
    OSPF_TV_TIMER_ON (area->t_spf_calc, ospf_spf_calculate_timer, area, delay);
}

Tv_spf:SPF计算完毕后更新此变量

Tv_spf_cur:SPF本次需要延迟的时间,初始值为spf_min_delay

spf_max_delay:SPF最大延迟时间,设定为50s

spf_min_delay:SPF最小延迟时间,设定为500ms

spf_start_delay:SPF开始的延迟时间,设定为spf_min_delay,即500ms

1) 获取当前的系统时间,并计算当前时间和上一次SPF计算完的差值delta

2) 判断delta和spf_cur的差值,如果delta大于spf_cur,进入到a流程,否则进入到b流程

a) 设置delay时间为0,并计算hold值,hold=2*spf_cur,hold最大不能超过spf_max_delay,同时比较hold和delta,如果hold比delta小(即当前需要spf计算的时间超过了2倍的记录的延迟时间)就把spf_cur重新设置为spf_min_delay【即认为不再震荡,重新恢复spf_cur为初始值】

b) 设置delay时间为spf_cur和delta的差值,即认为还没有到设置的延迟时间,需要继续延迟delay的时间再触发。并且,认为发生了震荡,将spf_cur的时间设置为当前的2倍。

3) 判断spf_start_delay和delay的差值,如果大于零,进入a流程,否则b

a) 设置delay为spf_start_delay,即至少要延迟spf_start_delay的时间。

b) 不做任何设置

4) 判断spf_cur是否超过spf_max_delay,如果超过,进入(a),如果不超过进入(b)

a) Spf_cur = spf_max_delay

b) 不做任何处理

5) 开启定时器,超时时间为delay。

根据以上流程,可以看出,如果不是频繁震荡,那么流程总是1->2(a)->3(a)->4(b)->5。这个时候,SPF计算总是在spf_min_delay时间后触发,即500ms。

如果频繁震荡,那么流程会进入1->2(b)->3(b)->4(b)->5,此时设置的定时器将会是一个spf_cur-delta的差值,并且由于spf_cur会被更新为当前的2倍,这个延迟将会越来越大,直至50s。

如果震荡中恢复到稳态,就进入1->2(a),此时又会把spf_cur更新为最小值。

通过以上分析,可以看出无论是否震荡,系统总是延迟spf_min_delay才进行SPF计算,那么当某次接口down,需要快速收敛时,将会有很大的延迟。因此可以把spf_min_delay设置为更小的值来提高收敛速度。


发布了54 篇原创文章 · 获赞 1 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/xingyeping/article/details/80533526