FRR BGP协议分析12 -- ZEBRA路由的处理1

当前面初始化完成的时候,zebra客户端线程(zebra_apic)静静等待客户端的消息,zebra dplane也急不可待了。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第1张图片

本次我们以BGP 为例,当BGP 根据自己的规则优选路由后,就会发给zebra,在函数bgp_process_main_one里面,把路由发布出去后,就会执行fib update动作,调用bgp_zebra_announce函数发布路由到zebra里面。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第2张图片

他们之间通过struct zapi_route 消息通信

FRR BGP协议分析12 -- ZEBRA路由的处理1_第3张图片

首先填充消息内容,最后调用zclient_route_send 发送到zebra进程处理。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第4张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第5张图片

按照前面初始化阶段的分析,我们知道zebra为BGP创建的zebra_apic线程会被唤醒,执行fd可读的事件回调函数zserv_read。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第6张图片

本次我们先借助zserv_read来看下sock读取字节流的报文的处理方法,然后在继续讨论路由的处理。

  • 先读取头部

FRR BGP协议分析12 -- ZEBRA路由的处理1_第7张图片

  • 解析头部,获取头部后面的数据区长度

  • 在根据头部里面的数据区长度,获取数据

FRR BGP协议分析12 -- ZEBRA路由的处理1_第8张图片

获取完所有的消息后,又把消息添加事件到zebra主线程继续处理?为啥这么处理了?zebra_apic线程就只读取下消息,然后所有的消息给主线程处理?减少锁?

FRR BGP协议分析12 -- ZEBRA路由的处理1_第9张图片

我们先看看zserv_process_messages函数的注释,然后继续跟踪消息的处理:

FRR BGP协议分析12 -- ZEBRA路由的处理1_第10张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第11张图片

先从client的ibuf里面出队报文,然后缓存起来,然后遍历缓存,每个消息调用zserv_handle_commands来实现函数调转,路由添加的cmd是ZEBRA_ROUTE_ADD,对应执行函数是zread_route_add,此函数继续解析处理路由消息。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第12张图片

  • 使用zapi_route_decode解析路由消息的msg,获取前缀、nexthop等各种信息,还原struct zapi_route消息

FRR BGP协议分析12 -- ZEBRA路由的处理1_第13张图片

  • 生成一个新的route entry然后填充里面的各种信息,这里我们先认识下zebra里面最重要的路由的节点的数据结构

FRR BGP协议分析12 -- ZEBRA路由的处理1_第14张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第15张图片

然后处理nexthop的信息,遍历所有的nexthop生成struct nexthop数据结构,我们在来认识下这个重要的数据结构

FRR BGP协议分析12 -- ZEBRA路由的处理1_第16张图片

生成nexthop信息,并加入route entry的nexthop链表里面,后续用于负载均衡

FRR BGP协议分析12 -- ZEBRA路由的处理1_第17张图片

如果消息里面有mpls label的信息,也需要添加到nexthop里面

FRR BGP协议分析12 -- ZEBRA路由的处理1_第18张图片

Route entry填充好后,继续调用rib_add_multipath处理路由信息添加,让我们继续走下去细看。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第19张图片

rib_add_multipath 又引入了两个新的数据结构struct route_table和struct route_node,我们来看下:

FRR BGP协议分析12 -- ZEBRA路由的处理1_第20张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第21张图片

结合前面给出的nexthop,整个路由表项的处理就是由route_table\route_node\route_entry 组织而成的,route_table包含了一个二叉树结构来保存所有的路由前缀和下一跳路由表项,prefix结构保持了路由前缀的长度和值,用来做最长前缀匹配,那,说好的mtire树呢? 好吧,我们不太可能把成千上万的路由表项塞给linux内核,够用就行。

整体的数据结构关系如下图所示:

FRR BGP协议分析12 -- ZEBRA路由的处理1_第22张图片

rib_add_multipath 先查找本次的路由表的route_table,然后在table中根据前缀查找是否有相同的route_node表项,其中srcdest_rnode_get查找如果没有node,则会生成一个新的route_node,然后加入route_table的二叉树中,然后调用rib_addnode,添加route_entry表项。

FRR BGP协议分析12 -- ZEBRA路由的处理1_第23张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第24张图片

rib_addnode 直接调用rib_link 继续处理,首先会在route_node的info字段生成一个rib_dest_t的结构体,上面的图也已经画了出来,同时会把route_node里面的route_entry使用链表连接起来,表示同一个前缀的不同路由。

然后会判断是否有重分发的配置,如果bgp的路由重分发到ospf等,本次不分析,如果没有重分发,那么直接调用rib_queue_add入zebrad.mq work queue处理,当work queue调度处理的时候,会调回调函数meta_queue_process继续处理

FRR BGP协议分析12 -- ZEBRA路由的处理1_第25张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第26张图片

FRR BGP协议分析12 -- ZEBRA路由的处理1_第27张图片

 

你可能感兴趣的:(FRR)