quagga源码分析--路由信息处理zebra-rib
对于各个协议生成的路由信息的处理属于quagga中非常重要的一个功能,如何在内核进行路由增加,更新,删除是一个复杂的过程。
quagga在thread任务调度中加入了一种工作队列,work_queue,与内核的工作队列类似,是一种相对而言,低优先级的任务,这里的任务看成类似的系统进程。
1、队列初始化:
1 /* initialise zebra rib work queue */ 2 static void 3 rib_queue_init(struct zebra_t *zebra) 4 { 5 assert(zebra); 6 7 if (!(zebra->ribq = work_queue_new(zebra->master, 8 "route_node processing"))) 9 { 10 zlog_err("%s: could not initialise work queue!", __func__); 11 return; 12 } 13 14 /* fill in the work queue spec */ 15 zebra->ribq->spec.workfunc = &meta_queue_process; 16 zebra->ribq->spec.errorfunc = NULL; 17 /* XXX: TODO: These should be runtime configurable via vty */ 18 zebra->ribq->spec.max_retries = 3; 19 zebra->ribq->spec.hold = rib_process_hold_time; 20 21 if (!(zebra->mq = meta_queue_new())) 22 { 23 zlog_err("%s: could not initialise meta queue!", __func__); 24 return; 25 } 26 return; 27 }
第19行,zebra->ribq->spec.hold = rib_process_hold_time; 指定了rib工作队列在thread_fetch的时候会等待10毫秒
1 /* Hold time for RIB process, should be very minimal. 2 * it is useful to able to set it otherwise for testing, hence exported 3 * as global here for test-rig code. 4 */ 5 int rib_process_hold_time = 10;
在添加thread任务的时候进行了时间单位换算:
1 /* Add a background thread, with an optional millisec delay */ 2 struct thread* 3 funcname_thread_add_background(struct thread_master *m, 4 int (*func)(struct thread *), 5 void *arg, long delay, 6 debugargdef) { 7 struct timeval trel; 8 9 assert(m != NULL); 10 11 if (delay) { 12 trel.tv_sec = delay / 1000; 13 trel.tv_usec = 1000 * (delay % 1000); 14 } else { 15 trel.tv_sec = 0; 16 trel.tv_usec = 0; 17 } 18 19 return funcname_thread_add_timer_timeval(m, func, THREAD_BACKGROUND, 20 arg, &trel, debugargpass); 21 }
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)
1 struct rib { 2 struct rib *next; /* Link list. */ 3 struct rib *prev; 4 struct nexthop *nexthop; /* Nexthop structure */ 5 unsigned long refcnt; /* Refrence count. */ 6 time_t uptime; /* Uptime. */ 7 int type; /* Type fo this route. */ 8 vrf_id_t vrf_id; /* VRF identifier. */ 9 int table; /* Which routing table */ 10 u_int32_t metric; /* Metric */ 11 u_int32_t mtu; /* MTU */ 12 u_int32_t nexthop_mtu; 13 u_char distance; /* Distance. */ 14 u_char flags; /* Flags of this route. in lib/zebra.h ZEBRA_FLAG_* */ 15 u_char status; /* RIB internal status */ 16 #define RIB_ENTRY_REMOVED (1 << 0) 17 #define RIB_ENTRY_CHANGED (1 << 1) 18 #define RIB_ENTRY_SELECTED_FIB (1 << 2) 19 u_char nexthop_num; /* Nexthop information. */ 20 u_char nexthop_active_num; 21 u_char nexthop_fib_num; 22 };
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结构保持了路由前缀的长度和值,用来做最长前缀匹配:
1 /* Each routing entry. */ 2 struct route_node { 3 struct prefix p; /* Actual prefix of this radix. */ 4 struct route_table *table; /* Tree link. */ 5 struct route_node *parent; 6 struct route_node *link[2]; 7 unsigned int lock; /* Lock of this radix */ 8 void *info; /* Each node of route. */ 9 void *aggregate; /* Aggregation. */ 10 11 #define l_left link[0] 12 #define l_right link[1] 13 };
呃,说好的mtire树呢? 好吧,我们不太可能把成千上万的路由表项塞给linux内核,够用就行。