quagga源码分析--路由信息处理zebra-rib

时间:2021-09-07 01:23:26

对于各个协议生成的路由信息的处理属于quagga中非常重要的一个功能,如何在内核进行路由增加,更新,删除是一个复杂的过程。

quagga在thread任务调度中加入了一种工作队列,work_queue,与内核的工作队列类似,是一种相对而言,低优先级的任务,这里的任务看成类似的系统进程。

1、队列初始化:

 /* initialise zebra rib work queue */
static void
rib_queue_init(struct zebra_t *zebra)
{
assert(zebra); if (!(zebra->ribq = work_queue_new(zebra->master,
"route_node processing")))
{
zlog_err("%s: could not initialise work queue!", __func__);
return;
} /* fill in the work queue spec */
zebra->ribq->spec.workfunc = &meta_queue_process;
zebra->ribq->spec.errorfunc = NULL;
/* XXX: TODO: These should be runtime configurable via vty */
zebra->ribq->spec.max_retries = ;
zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new()))
{
zlog_err("%s: could not initialise meta queue!", __func__);
return;
}
return;
}

第19行,zebra->ribq->spec.hold = rib_process_hold_time; 指定了rib工作队列在thread_fetch的时候会等待10毫秒

 /* Hold time for RIB process, should be very minimal.
* it is useful to able to set it otherwise for testing, hence exported
* as global here for test-rig code.
*/
int rib_process_hold_time = ;

在添加thread任务的时候进行了时间单位换算:

 /* Add a background thread, with an optional millisec delay */
struct thread*
funcname_thread_add_background(struct thread_master *m,
int (*func)(struct thread *),
void *arg, long delay,
debugargdef) {
struct timeval trel; assert(m != NULL); if (delay) {
trel.tv_sec = delay / ;
trel.tv_usec = * (delay % );
} else {
trel.tv_sec = ;
trel.tv_usec = ;
} return funcname_thread_add_timer_timeval(m, func, THREAD_BACKGROUND,
arg, &trel, debugargpass);
}

OK,meta_queue_process,就指定了工作队列在调度执行的处理函数,由此guagga就会一直同步更新路由了。

2、每个子网的下一跳路由表项的描述:

quagga使用了双向链表来管理表项,定义了路由表现的详细信息,但比如 status 这个字段是用来在更新路由时来做比较的关键字段。如下宏定义了3种状态:

#define RIB_ENTRY_REMOVED    (1 << 0)
#define RIB_ENTRY_CHANGED    (1 << 1)
#define RIB_ENTRY_SELECTED_FIB    (1 << 2)

 struct rib {
struct rib *next; /* Link list. */
struct rib *prev;
struct nexthop *nexthop; /* Nexthop structure */
unsigned long refcnt; /* Refrence count. */
time_t uptime; /* Uptime. */
int type; /* Type fo this route. */
vrf_id_t vrf_id; /* VRF identifier. */
int table; /* Which routing table */
u_int32_t metric; /* Metric */
u_int32_t mtu; /* MTU */
u_int32_t nexthop_mtu;
u_char distance; /* Distance. */
u_char flags; /* Flags of this route. in lib/zebra.h ZEBRA_FLAG_* */
u_char status; /* RIB internal status */
#define RIB_ENTRY_REMOVED (1 << 0)
#define RIB_ENTRY_CHANGED (1 << 1)
#define RIB_ENTRY_SELECTED_FIB (1 << 2)
u_char nexthop_num; /* Nexthop information. */
u_char nexthop_active_num;
u_char nexthop_fib_num;
};

3、整个路由表的描述:

/* Routing table top structure. */
struct route_table {
struct route_node *top;
/*
* Delegate that performs certain functions for this table.
*/
route_table_delegate_t *delegate;
unsigned long count;
void *info; /* User data. */
};

route_table包含了一个二叉树结构来保存所有的路由前缀和下一跳路由表项,prefix结构保持了路由前缀的长度和值,用来做最长前缀匹配:

 /* Each routing entry. */
struct route_node {
struct prefix p; /* Actual prefix of this radix. */
struct route_table *table; /* Tree link. */
struct route_node *parent;
struct route_node *link[];
unsigned int lock; /* Lock of this radix */
void *info; /* Each node of route. */
void *aggregate; /* Aggregation. */ #define l_left link[0]
#define l_right link[1]
};

呃,说好的mtire树呢? 好吧,我们不太可能把成千上万的路由表项塞给linux内核,够用就行。