quagga源码分析--大内总管zebra
zebra,中文翻译是斑马,于是我打开了宋冬野的《斑马,斑马》作为BGM来完成这个篇章,嘿嘿,小资一把!
zebra姑且戏称它是quagga项目的大内总管。
因为它负责管理其他所有协议进程的路由信息的更新与交互,并负责与内核交换信息,如下的架构:
+----+ +----+ +-----+ +-----+
|bgpd| |ripd| |ospfd| |zebra|
+----+ +----+ +-----+ +-----+
|
+---------------------------|--+
| v |
| UNIX Kernel routing table |
| |
+------------------------------+
好了,简介完了,开始看代码吧:
1、zebra作为其他协议进程的服务端:
/* Make zebra server socket, wiping any existing one (see bug #403). */
void
zebra_zserv_socket_init(char *path) {
#ifdef HAVE_TCP_ZEBRA
zebra_serv();
#else
zebra_serv_un(path ? path : ZEBRA_SERV_PATH);
#endif /* HAVE_TCP_ZEBRA */
}
zebra绑定了(loopback,2600)的地址和端口,并开始监听socket,同时加入到thread事件ZEBRA_SERV当中,来接收客户端发送过来的路由信息:
accept_sock = socket(AF_INET, SOCK_STREAM, ); addr.sin_family = AF_INET; addr.sin_port = htons(ZEBRA_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
addr.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ret = bind(accept_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); ret = listen(accept_sock, ); zebra_event(ZEBRA_SERV, accept_sock, NULL);
2、客户端(比如isis协议):
2.1 创建客户端,并在初始化加入到thread事件调度当中去。
void
isis_zebra_init(struct thread_master *master) {
zclient = zclient_new(master);
zclient_init(zclient, ZEBRA_ROUTE_ISIS); ...... return;
}
void
zclient_init (struct zclient *zclient, int redist_default)
{
int i;
/* Enable zebra client connection by default. */
zclient->enable = ;
/* Set -1 to the default socket value. */
zclient->sock = -;
.....
zclient_event (ZCLIENT_SCHEDULE, zclient);
}
static void
zclient_event(enum event event, struct zclient *zclient) {
switch (event) {
case ZCLIENT_SCHEDULE:
if (!zclient->t_connect) zclient->t_connect =
thread_add_event(zclient->master, zclient_connect, zclient, );
break;
......
}
}
2.2 在zclient_connect里调用zclient_socket完成客户端sock的初始化:
int zclient_socket_connect(struct zclient *zclient) {
#ifdef HAVE_TCP_ZEBRA
zclient->sock = zclient_socket();
#else
zclient->sock = zclient_socket_un(zclient_serv_path_get());
#endif
return zclient->sock;
}
static int
zclient_socket(void) {
int sock;
int ret;
struct sockaddr_in serv; /* We should think about IPv6 connection. */
sock = socket(AF_INET, SOCK_STREAM, );
if (sock < ) return -; /* Make server socket. */
memset(&serv, , sizeof(struct sockaddr_in));
serv.sin_family = AF_INET;
serv.sin_port = htons(ZEBRA_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
serv.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
serv.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Connect to zebra. */
ret = connect(sock, (struct sockaddr *)&serv, sizeof(serv));
if (ret < ) {
close(sock);
return -;
}
return sock;
}
嗯,服务端和客户端就这样完成了tcp通信连接,其他的客户端(如bgpd,ospfd等等)都是调用zclient_socket完成连接,代码复用了哦!
3、下面来看看作为大内总管,zebra如何处理日常事务:
首先是在thread的调度中,增加了read事件(可以看到整个系统,都是由thread模块在在暗中维持的运转)
thread_add_read(zebrad.master, zebra_client_read, client, sock);
/* Handler of zebra service request. */
static int
zebra_client_read(struct thread *thread) {
......
command = stream_getw(client->ibuf); ..... switch (command) {
..... case ZEBRA_IPV4_ROUTE_ADD:
zread_ipv4_add(client, length, vrf_id);
break;
case ZEBRA_IPV4_ROUTE_DELETE:
zread_ipv4_delete(client, length, vrf_id);
break;
......
default:
zlog_info("Zebra received unknown command %d", command);
break;
} ...... zebra_event(ZEBRA_READ, sock, client);
return ;
}
如上述代码,从消息内容中读取到对应事件号,比如ZEBRA_IPV4_ROUTE_ADD,ZEBRA_IPV4_ROUTE_DELETE,即是增加ipv4路由和删除ipv4路由。
4、再来看看大内总管(zebra)如何与皇上(内核)交互的:
在main里对这个过程做了初始化,函数是rib_init。
/* Routing information base initialize. */
void
rib_init(void)
{
rib_queue_init(&zebrad);
} /* fill in the work queue spec */
zebra->ribq->spec.workfunc = &meta_queue_process;
上面代码创建一个工作队列,作为thread调度模块的一个低等级的后台调度(THREAD_BACKGROUND)执行的任务。在meta_queue_process函数里处理各个子队列:
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
* is pointed to the meta queue structure.
*/
static wq_item_status
meta_queue_process(struct work_queue *dummy, void *data)
{
struct meta_queue *mq = data;
unsigned i; for (i = ; i < MQ_SIZE; i++) if (process_subq(mq->subq[i], i))
{
mq->size--;
break;
}
return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
}
process_subq函数里调用rib_process函数,即开始了对路由信息的处理,整个内核的路由的新旧比较与更新:
int
kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
{
int route = ; if (zserv_privs.change(ZPRIVS_RAISE))
zlog (NULL, LOG_ERR, "Can't raise privileges"); if (old)
route |= kernel_rtm (RTM_DELETE, p, old); if (new)
route |= kernel_rtm (RTM_ADD, p, new); if (zserv_privs.change(ZPRIVS_LOWER))
zlog (NULL, LOG_ERR, "Can't lower privileges"); return route;
}
可以看到,最后使用netlink通信来更新内核的路由信息。
quagga源码分析--大内总管zebra的更多相关文章
- quagga源码分析--路由信息处理zebra-rib
对于各个协议生成的路由信息的处理属于quagga中非常重要的一个功能,如何在内核进行路由增加,更新,删除是一个复杂的过程. quagga在thread任务调度中加入了一种工作队列,work_queue ...
- quagga源码分析--内核通信netlink
Linux操作系统中当CPU处于内核状态时,可以分为有用户上下文的状态和执行硬件.软件中断两种.其中当处于有用户上下文时,由于内核态和用户态的内 存映射机制不同,不可直接将本地变量传给用户态的内存区: ...
- quagga源码分析--通用库command
quagga作为一个路由器软件,自然要提供人机接口. quagga提供snmp管理接口,而且,自然就会有对应的命令行管理格式,当然一般路由软件不会提供界面形式的,也许有webui,然而quagga并没 ...
- quagga源码分析--通用库thread
quagga是开源路由器软件,提供的用户界面与思科,华为的路由器的人机接口几乎一致,非常有学习价值,尤其是开源的协议代码,简直亮瞎了我的小眼睛. quagga的介绍,我就不赘述了,有兴趣的可以找度娘或 ...
- quagga源码学习--BGP协议的初始化
quagga支持BGP-4,BGP-4+协议,支持多协议(mpls,isis,ospf等等)以及单播,组播路由的导入和分发. 具体的协议,这里就不附录了,网络上有很多资料,或者RFC. 协议源码的学习 ...
- 插件开发之360 DroidPlugin源码分析(五)Service预注册占坑
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52264977 在了解系统的activity,service,broa ...
- 【精】EOS智能合约:system系统合约源码分析
系统合约在链启动阶段就会被部署,是因为系统合约赋予了EOS链资源.命名拍卖.基础数据准备.生产者信息.投票等能力.本篇文章将会从源码角度详细研究system合约. 关键字:EOS,eosio.syst ...
- Netty源码分析第3章(客户端接入流程)---->第2节: 处理接入事件之handle的创建
Netty源码分析第三章: 客户端接入流程 第二节: 处理接入事件之handle的创建 上一小节我们剖析完成了与channel绑定的ChannelConfig初始化相关的流程, 这一小节继续剖析客户端 ...
- 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 百篇博客分析OpenHarmony源码 | v16.02
百篇博客系列篇.本篇为: v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪 ...
随机推荐
- Oracle中注意用户的访问权限
新增表.序列.存储过程等,要注意用户(例如System)的权限.如果在增删改查过程中出现数据库读写权限的报错,则在建表(或者序列.存储过程等)时,在脚本前面加 GRANT CREATE TABLE T ...
- Moon.Orm 5.0 (MQL版)
Moon.Orm 5.0 (MQL版) 实战实例Moon.Orm 5.0 革命性的设计 打造最便捷的异步分页技术(提供下载) 摘要: 一.建一个项目(以WebForm为例)配置文件配置(注意您自己的路 ...
- Cygwin 是一个用于 Windows 的类 UNIX shell 环境
cygwin的安装使用 Cygwin 是一个用于 Windows 的类 UNIX shell 环境. 它由两个组件组成:一个 UNIX API 库,它模拟 UNIX 操作系统提供的许多特性:以及 ...
- Javascript多线程引擎(五)
Javascript多线程引擎(五)之异常处理 C语言没有提供一个像Java一样的异常处理机制, 这就带来了一个问题, 对于一个子函数中发生异常后, 需要在父函数调用子函数的位置进行Check, 如果 ...
- 松瀚SN8P2711 2722 ADC初始化程序及应用--汇编源码
/* 松瀚 SN8P2711 2722 ADC初始化程序 及应用实例 */ INIT_ADC: MOV A, #0XB2 // 启动ADC电路 使能AIN通道 B0MOV ADM, A MOV A,# ...
- Js模块模式
模块模式 索引 引子 什么是模块模式 命名空间模式 声明依赖 私有和特权成员 即时函数 揭示模块模式 结语 引子 这篇算是对第9篇中内容的发散和补充,当时我只是把模块模式中的一些内容简单的归为函数篇中 ...
- 推荐系列:最小与最大[DP+余式定理]
最小与最大 [问题描述] 做过了乘积最大这道题,相信这道题也难不倒你. 已知一个数串,可以在适当的位置加入乘号(设加了k个,当然也可不加,即分成k+1个部分),设这k+1个部分的乘积(如果k=0,则乘 ...
- 用py2exe打包pyqt4出现的问题(转)
使用pyqt完成窗体界面很方便,但是打包成exe之后会有问题,在网上找到解决办法如下: Another Solution to the same problem: from distutils.cor ...
- 迟到的 WPF 学习 —— 布局
布局是 WPF 很重头的一部分内容,这一部分梳理和记录关于布局章节的知识点. 1. WPF 使用一种基于流(Flow-based)的概念来处理布局逻辑,将传统的基于"坐标"的思想尽 ...
- 5个Unix命令
5个Unix命令 原文: http://spin.atomicobject.com/2013/09/09/5-unix-commands/ 希望早几年知道的5个Unix命令 使用*nix系统已经有一段 ...