zebra,中文翻译是斑马,于是我打开了宋冬野的《斑马,斑马》作为BGM来完成这个篇章,嘿嘿,小资一把!

zebra姑且戏称它是quagga项目的大内总管。

因为它负责管理其他所有协议进程的路由信息的更新与交互,并负责与内核交换信息,如下的架构:

  1. +----+ +----+ +-----+ +-----+
  2. |bgpd| |ripd| |ospfd| |zebra|
  3. +----+ +----+ +-----+ +-----+
  4. |
  5. +---------------------------|--+
  6. | v |
  7. | UNIX Kernel routing table |
  8. | |
  9. +------------------------------+

好了,简介完了,开始看代码吧:

1、zebra作为其他协议进程的服务端:

  1. /* Make zebra server socket, wiping any existing one (see bug #403). */
  2. void
  3. zebra_zserv_socket_init(char *path) {
  4. #ifdef HAVE_TCP_ZEBRA
  5. zebra_serv();
  6. #else
  7. zebra_serv_un(path ? path : ZEBRA_SERV_PATH);
  8. #endif /* HAVE_TCP_ZEBRA */
  9. }

zebra绑定了(loopback,2600)的地址和端口,并开始监听socket,同时加入到thread事件ZEBRA_SERV当中,来接收客户端发送过来的路由信息:

  1. accept_sock = socket(AF_INET, SOCK_STREAM, );
  2.  
  3. addr.sin_family = AF_INET;
  4.  
  5. addr.sin_port = htons(ZEBRA_PORT);
  6. #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  7. addr.sin_len = sizeof(struct sockaddr_in);
  8. #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  9. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  10.  
  11. ret = bind(accept_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
  12.  
  13. ret = listen(accept_sock, );
  14.  
  15. zebra_event(ZEBRA_SERV, accept_sock, NULL);

2、客户端(比如isis协议):

2.1 创建客户端,并在初始化加入到thread事件调度当中去。

  1. void
  2. isis_zebra_init(struct thread_master *master) {
  3. zclient = zclient_new(master);
  4. zclient_init(zclient, ZEBRA_ROUTE_ISIS);
  5.  
  6. ......
  7.  
  8. return;
  9. }
  1. void
  2. zclient_init (struct zclient *zclient, int redist_default)
  3. {
  4. int i;
  5. /* Enable zebra client connection by default. */
  6. zclient->enable = ;
  7. /* Set -1 to the default socket value. */
  8. zclient->sock = -;
  9. .....
  10. zclient_event (ZCLIENT_SCHEDULE, zclient);
  11. }  
  1. static void
  2. zclient_event(enum event event, struct zclient *zclient) {
  3. switch (event) {
  4. case ZCLIENT_SCHEDULE:
  5. if (!zclient->t_connect) zclient->t_connect =
  6. thread_add_event(zclient->master, zclient_connect, zclient, );
  7. break;
  8. ......
  9. }
  10. }

2.2 在zclient_connect里调用zclient_socket完成客户端sock的初始化:

  1. int zclient_socket_connect(struct zclient *zclient) {
  2. #ifdef HAVE_TCP_ZEBRA
  3. zclient->sock = zclient_socket();
  4. #else
  5. zclient->sock = zclient_socket_un(zclient_serv_path_get());
  6. #endif
  7. return zclient->sock;
  8. }
  1. static int
  2. zclient_socket(void) {
  3. int sock;
  4. int ret;
  5. struct sockaddr_in serv;
  6.  
  7. /* We should think about IPv6 connection. */
  8. sock = socket(AF_INET, SOCK_STREAM, );
  9. if (sock < ) return -;
  10.  
  11. /* Make server socket. */
  12. memset(&serv, , sizeof(struct sockaddr_in));
  13. serv.sin_family = AF_INET;
  14. serv.sin_port = htons(ZEBRA_PORT);
  15. #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  16. serv.sin_len = sizeof(struct sockaddr_in);
  17. #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  18. serv.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  19.  
  20. /* Connect to zebra. */
  21. ret = connect(sock, (struct sockaddr *)&serv, sizeof(serv));
  22. if (ret < ) {
  23. close(sock);
  24. return -;
  25. }
  26. return sock;
  27. }

嗯,服务端和客户端就这样完成了tcp通信连接,其他的客户端(如bgpd,ospfd等等)都是调用zclient_socket完成连接,代码复用了哦!

3、下面来看看作为大内总管,zebra如何处理日常事务:

首先是在thread的调度中,增加了read事件(可以看到整个系统,都是由thread模块在在暗中维持的运转)

  1. thread_add_read(zebrad.master, zebra_client_read, client, sock);
  1. /* Handler of zebra service request. */
  2. static int
  3. zebra_client_read(struct thread *thread) {
  4. ......
  5. command = stream_getw(client->ibuf);
  6.  
  7. .....
  8.  
  9. switch (command) {
  10. .....
  11.  
  12. case ZEBRA_IPV4_ROUTE_ADD:
  13. zread_ipv4_add(client, length, vrf_id);
  14. break;
  15. case ZEBRA_IPV4_ROUTE_DELETE:
  16. zread_ipv4_delete(client, length, vrf_id);
  17. break;
  18. ......
  19. default:
  20. zlog_info("Zebra received unknown command %d", command);
  21. break;
  22. }
  23.  
  24. ......
  25.  
  26. zebra_event(ZEBRA_READ, sock, client);
  27. return ;
  28. }

如上述代码,从消息内容中读取到对应事件号,比如ZEBRA_IPV4_ROUTE_ADD,ZEBRA_IPV4_ROUTE_DELETE,即是增加ipv4路由和删除ipv4路由。

4、再来看看大内总管(zebra)如何与皇上(内核)交互的:

在main里对这个过程做了初始化,函数是rib_init。

  1. /* Routing information base initialize. */
  2. void
  3. rib_init(void)
  4. {
  5. rib_queue_init(&zebrad);
  6. }
  7.  
  8. /* fill in the work queue spec */
  9. zebra->ribq->spec.workfunc = &meta_queue_process;

上面代码创建一个工作队列,作为thread调度模块的一个低等级的后台调度(THREAD_BACKGROUND)执行的任务。在meta_queue_process函数里处理各个子队列:

  1. /* Dispatch the meta queue by picking, processing and unlocking the next RN from
  2. * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
  3. * is pointed to the meta queue structure.
  4. */
  5. static wq_item_status
  6. meta_queue_process(struct work_queue *dummy, void *data)
  7. {
  8. struct meta_queue *mq = data;
  9. unsigned i;
  10.  
  11. for (i = ; i < MQ_SIZE; i++) if (process_subq(mq->subq[i], i))
  12. {
  13. mq->size--;
  14. break;
  15. }
  16. return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
  17. }

process_subq函数里调用rib_process函数,即开始了对路由信息的处理,整个内核的路由的新旧比较与更新:

  1. int
  2. kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
  3. {
  4. int route = ;
  5.  
  6. if (zserv_privs.change(ZPRIVS_RAISE))
  7. zlog (NULL, LOG_ERR, "Can't raise privileges");
  8.  
  9. if (old)
  10. route |= kernel_rtm (RTM_DELETE, p, old);
  11.  
  12. if (new)
  13. route |= kernel_rtm (RTM_ADD, p, new);
  14.  
  15. if (zserv_privs.change(ZPRIVS_LOWER))
  16. zlog (NULL, LOG_ERR, "Can't lower privileges");
  17.  
  18. return route;
  19. }

可以看到,最后使用netlink通信来更新内核的路由信息。

quagga源码分析--大内总管zebra的更多相关文章

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

    对于各个协议生成的路由信息的处理属于quagga中非常重要的一个功能,如何在内核进行路由增加,更新,删除是一个复杂的过程. quagga在thread任务调度中加入了一种工作队列,work_queue ...

  2. quagga源码分析--内核通信netlink

    Linux操作系统中当CPU处于内核状态时,可以分为有用户上下文的状态和执行硬件.软件中断两种.其中当处于有用户上下文时,由于内核态和用户态的内 存映射机制不同,不可直接将本地变量传给用户态的内存区: ...

  3. quagga源码分析--通用库command

    quagga作为一个路由器软件,自然要提供人机接口. quagga提供snmp管理接口,而且,自然就会有对应的命令行管理格式,当然一般路由软件不会提供界面形式的,也许有webui,然而quagga并没 ...

  4. quagga源码分析--通用库thread

    quagga是开源路由器软件,提供的用户界面与思科,华为的路由器的人机接口几乎一致,非常有学习价值,尤其是开源的协议代码,简直亮瞎了我的小眼睛. quagga的介绍,我就不赘述了,有兴趣的可以找度娘或 ...

  5. quagga源码学习--BGP协议的初始化

    quagga支持BGP-4,BGP-4+协议,支持多协议(mpls,isis,ospf等等)以及单播,组播路由的导入和分发. 具体的协议,这里就不附录了,网络上有很多资料,或者RFC. 协议源码的学习 ...

  6. 插件开发之360 DroidPlugin源码分析(五)Service预注册占坑

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52264977 在了解系统的activity,service,broa ...

  7. 【精】EOS智能合约:system系统合约源码分析

    系统合约在链启动阶段就会被部署,是因为系统合约赋予了EOS链资源.命名拍卖.基础数据准备.生产者信息.投票等能力.本篇文章将会从源码角度详细研究system合约. 关键字:EOS,eosio.syst ...

  8. Netty源码分析第3章(客户端接入流程)---->第2节: 处理接入事件之handle的创建

    Netty源码分析第三章: 客户端接入流程 第二节: 处理接入事件之handle的创建 上一小节我们剖析完成了与channel绑定的ChannelConfig初始化相关的流程, 这一小节继续剖析客户端 ...

  9. 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 百篇博客分析OpenHarmony源码 | v16.02

    百篇博客系列篇.本篇为: v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪 ...

随机推荐

  1. VS2015安装

    VS2015安装 Secondary Installer Setup Failed求解决方案 看到微软最近的一系列变化,着实让我等兴奋不已.VS2015下载地址就不说了.先来记录一下微软的几个变化吧. ...

  2. How do I create an IIS application and application pool using InnoSetup script

    Create an IIS application. Create a new IIS application pool and set it's .NET version to 4. Set the ...

  3. 通过如何通过js实现复制粘贴功能

    在ie中window.clipboardData(剪切板对象)是可以被获取,所以利用这个方法我们可以实现在IE当中复制粘贴的功能,demo如下! <html> <head> & ...

  4. touch命令功能

    touch命令功能   touch fileA,如果fileA存在,使用touch命令可更改这个文件或目录的日期时间,包括存取时间和更改时间:如果fileA不存在,touch命令会在当前目录下新建一个 ...

  5. iOS基础 - 触摸事件&手势识别

    ================================================================== 一.触摸事件&手势识别 1> 4个触摸事件,针对视图 ...

  6. 创建FTP的Site并用C#进行文件的上传下载

    创建FTP的Site并用C#进行文件的上传下载 文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服 ...

  7. 闲话Android 之 屏幕大小、pixel、分辨率、dpi、dip

    之前都是在自研的产品上做开发,而且我们的屏幕是1dip=1px的,所以在写App布局的时候,随便写单位,也没觉得什么不妥.可是近期我把以前的App里面的一些自定义控件在emulator上跑的时候,才发 ...

  8. -协同IResult

    Caliburn.Micro学习笔记(五)----协同IResult   今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows cust ...

  9. tortoiseSVN 设置ignore

      *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo *.rej *~ #*# .#* .*.swp .DS_Store *.dll ...

  10. Bootstrap3.0学习第六轮(表单)

    Bootstrap3.0学习第六轮(表单) 前言 阅读之前您也可以到Bootstrap3.0入门学习系列导航中进行查看http://www.cnblogs.com/aehyok/p/3404867.h ...