zebra 线程流具体分析
原文 :http://blog.csdn.net/xuyanbo2008/article/details/7439751
1 zebra线程机制概述
zebra源码中有关线程管理的各个函数放置于zebra-0.95a\lib文件夹的thread.h和thread.c两个文件中。
2 线程管理源码分析
2.1 重要结构体介绍
2.1.1 thread
unsigned char type; /* thread类型,共有六种 */
struct thread *next; /* 指向下一thread的指针,双向链表 */
struct thread *prev; /*指向前一thread的指针*/
struct thread_master *master; /* 指向该thread所属thread_master结构体的指针 */
int (*func) (struct thread *); /* event类型thread的函数指针 */
void *arg; /* event类型thread的参数 */
int val; /* event类型thread的第二个参数*/
int fd; /* read/write类型thread相应的文件描述符 */
struct timeval sands; /* 该thread的剩余时间,timeval类型,此结构体定义在time.h中,有两个元素,秒和微秒 */
RUSAGE_T ru; /* 详细用法信息,RUSAGE这个宏在该thread有用法描述时定义为rusage类型,描述其详细进程资源信息,没有用法描述时定义为timeval类型 */
2.1.2 thread_list
一个thread_list结构体描述一个thread双向链表,也即一个进程队列。
struct thread *head;/* 该线程队列头指针 */
struct thread *tail; /* 该线程队列尾指针 */
2.1.3 thread_master
1.1 相关函数简介
1.1.1 thread_master_create ()
为创建一个新的thread_master结构体动态开辟一块内存空间。
1.1.2 thread_list_add ()
1.1.3 thread_list_add_before ()
在函数参数point所指向的thread前面插入一个新的thread。
1.1.4 thread_list_delete ()
1.1.5 thread_add_unuse ()
向指定thead_master中的unused链表尾部插入新thread。
1.1.6 thread_list_free ()
从内存中释放掉指定thread_master中的指定thread链表所占空间。
1.1.7 thread_master_free ()
1.1.8 thread_trim_head ()
若指定thread链表中非空,删除该链表头指针所指thread,并将其返回,即从线程队列中取出一个线程。
1.1.9 thread_empty ()
1.1.10 thread_timer_remain_second ()
1.1.11 thread_get ()
1.1.12 thread_add_read ()
根据所给参数在指定thread_master中添加并初始化一个read类型的thread并返回之。
1.1.13 thread_add_write ()
根据所给参数在指定thread_master中添加并初始化一个write类型的thread并返回之。
1.1.14 thread_add_timer ()
1.1.15 thread_add_event ()
根据所给参数在指定thread_master中添加并初始化一个event类型的thread并返回之。
1.1.16 thread_cancel ()
删除指定thread,删除后将其类型置为THREAD_UNUSED,并将其插入到该thread_master的unuse链表中。
1.1.17 thread_cancel_event ()
将指定thread_master的event链表中与参数中arg相匹配的thread删除。
1.1.18 thread_timer_wait ()
找出指定thread_master的timer链表中最小的剩余时间并将其返回。
1.1.19 thread_run ()
将指定thread的值赋给thread类型的fetch,然后将其类型置为THREAD_UNUSED,并将其插入unuse链表,返回fetch。
1.1.20 thread_process_fd ()
将指定thread链表中的元素取出插入到该thread_master的ready链表中,返回该链表中插入元素的个数。
1.1.21 thread_fetch ()
1.1.22 thread_consumed_time ()
1.1.23 thread_call ()
执行该thread中的功能函数,如果该thread持续时间超过CPU规定的独占时间,发出警告。
1.1.24 thread_execute ()
一个新的thread可以通过如下三种方式被创建,主要是看你需要创建的thread的类型:
1, thread_add_read:添加一个thread到read queue,该thread负责通过socket接受和读取从client端来的数据。
2, thread_add_write:添加一个thread到write queue,该thread负责通过socket向client端填充和写数据。
4, thread_add_event:添加一个event thread到event queue。
1, 创建thread。首先在unuse queue查找,如果有unuse thread,就使用它,否则重新分配空间。
2,如果event queue为空时,bgp daemon 通过select函数监控读、写、异常三个描述符集。一旦有某个描述符准备就绪,则将该描述符所对应的thread加入ready queue.
而对于timer queue中的thread,只有当select函数超时后才会进入ready queue.
zebrad启动后会,在read queue中会出现两个thread,一个是等待来自local client端bgpd的连接,另一个是等待来自vty client端的连接。
zebra_client_create (client_sock);创建一个新的zebra client
zebra_event (ZEBRA_SERV, accept_sock, NULL);继续监听server socket
vty_accept,加入read queue。作为vty server监听internet的vty socket.。
根据vty_sock和ip地址信息su,创建一个新的vty。
vty_event (VTY_READ, vty_sock, vty);
根据new client vty的vty_sock创建新的VTY_READ thread,加入read queue,该thread的处理函数为vty_read。
sockunion_bind(accept_sock, &su, port, NULL);
close (accept_sock); /* Avoid sd leak. */
/* Listen socket under queue 3. */
ret = listen (accept_sock, 3);
将accept_sock套接口设置成被动监听状态,用于接受连接,只能在服务器端使用。
zlog (NULL, LOG_WARNING, "can't listen socket");
close (accept_sock); /* Avoid sd leak. */
vty_event(VTY_SERV, accept_sock, NULL);
/* Bind socket to specified address. */
int sockunion_bind (int sock, union sockunion *su, unsigned short port,
if (su->sa.sa_family == AF_INET)
size = sizeof (struct sockaddr_in);
su->sin.sin_port = htons (port);
su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
服务器一般将sin_addr.s_addr 字段设置为INADDR_ANY表示套接字应接收任何一个主机网络接口上的连接请求。
客户端将sin_addr.s_addr字段设置为服务器主机的IP地址。
else if (su->sa.sa_family == AF_INET6)
size = sizeof (struct sockaddr_in6);
su->sin6.sin6_port = htons (port);
#if defined(LINUX_IPV6) || defined(NRL)
bzero (&su->sin6.sin6_addr, sizeof (struct in6_addr));
su->sin6.sin6_addr = in6addr_any;
ret = bind (sock, (struct sockaddr *)su, size);
zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno));
/* struct thread_master *master; */
static void vty_event (enum event event, int sock, struct vty *vty)
struct thread *vty_serv_thread;
vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
vty->t_read = thread_add_read (master, vty_read, vty, sock);
thread_cancel (vty->t_timeout);
thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
vty->t_write = thread_add_write (master, vty_flush, vty, sock);
thread_cancel (vty->t_timeout);
thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
/* Make bgpd's server socket. */
void bgp_serv_sock_family (unsigned short port, int family)
bzero (&su, sizeof (union sockunion));
bgp_sock = sockunion_stream_socket (&su); 产生一个BGP socket
ret = sockunion_bind (bgp_sock, &su, port, NULL);
zlog (NULL, LOG_INFO, "Can't listen bgp server socket : %s",
thread_add_read (master, bgp_accept, NULL, bgp_sock); 添加一个thread 到readlist中。
VTY server和BGP server 在使用accept操作的方法如下:
他们均是通过创建一个THREAD_READ 类型的thread,加到Master的readlist的队列后面,thread 的处理函数会执行accept操作。
vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
thread_add_read (master, bgp_accept, NULL, bgp_sock);
bgp和zebra是通过zebra message进行通信,格式如下:
报文头3字节 (前两字节length,后1字节为command type)
#define ZEBRA_INTERFACE_DELETE 2
#define ZEBRA_INTERFACE_ADDRESS_ADD 3
#define ZEBRA_INTERFACE_ADDRESS_DELETE 4
#define ZEBRA_INTERFACE_DOWN 6
#define ZEBRA_IPV4_ROUTE_ADD 7
#define ZEBRA_IPV4_ROUTE_DELETE 8
#define ZEBRA_IPV6_ROUTE_ADD 9
#define ZEBRA_IPV6_ROUTE_DELETE 10
#define ZEBRA_REDISTRIBUTE_ADD 11
#define ZEBRA_REDISTRIBUTE_DELETE 12
#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13
#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15
#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16
bgp端接受到message后,会执行相应的bgp action:
int (*interface_add) (int, struct zclient *, zebra_size_t); ZEBRA_INTERFACE_ADD
int (*interface_delete) (int, struct zclient *, zebra_size_t); ZEBRA_INTERFACE_DELETE
int (*interface_up) (int, struct zclient *, zebra_size_t); ZEBRA_INTERFACE_UP
int (*interface_down) (int, struct zclient *, zebra_size_t); ZEBRA_INTERFACE_DOWN
int (*interface_address_add) (int, struct zclient *, zebra_size_t); ZEBRA_INTERFACE_ADDRESS_ADD
int (*ipv4_route_add) (int, struct zclient *, zebra_size_t); ZEBRA_IPV4_ROUTE_ADD
int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t); ZEBRA_IPV4_ROUTE_DELETE
int (*ipv6_route_add) (int, struct zclient *, zebra_size_t); ZEBRA_IPV6_ROUTE_ADD
int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t); ZEBRA_IPV6_ROUTE_DELETE
zebra 端接受到message后,会执行相应的zebra action:
zebra action func message type
void zread_interface_add (struct zserv *client, u_short length) ZEBRA_INTERFACE_ADD
void zread_interface_delete (struct zserv *client, u_short length) ZEBRA_INTERFACE_DELETE
void zread_ipv4_add (struct zserv *client, u_short length) ZEBRA_IPV4_ROUTE_ADD
void zread_ipv4_delete (struct zserv *client, u_short length) ZEBRA_IPV4_ROUTE_DELETE
void zread_ipv6_add (struct zserv *client, u_short length) ZEBRA_IPV6_ROUTE_ADD
void zread_ipv6_delete (struct zserv *client, u_short length) ZEBRA_IPV6_ROUTE_DELETE
void zebra_redistribute_add (int command, struct zserv *client, int length) ZEBRA_REDISTRIBUTE_ADD
voidzebra_redistribute_default_add (int command,
struct zserv *client, int length) ZEBRA_REDISTRIBUTE_DEFAULT_ADD
void zebra_redistribute_default_delete (int command,
struct zserv *client, int length) ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
void zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) ZEBRA_IPV4_NEXTHOP_LOOKUP
void zread_ipv6_nexthop_lookup (struct zserv *client, u_short length) ZEBRA_IPV6_NEXTHOP_LOOKUP
bgp action:将local_client_socket中数据,写入bgp数据库。
zebra action:将zebra数据库中的信息写入local_server_subsocket,让local client端进行读取。
int bgp_accept (struct thread *thread)
accept_sock = THREAD_FD (thread);
printf("->bgp_accept [%d]\n",accept_sock);
thread_add_read (master, bgp_accept, NULL, accept_sock);
/* Accept client connection. */
bgp_sock = sockunion_accept (accept_sock, &su);
zlog_err ("[Error] BGP socket accept failed (%s)", strerror (errno));
printf("[Error] BGP socket accept failed (%s)", strerror (errno));
if (BGP_DEBUG (events, EVENTS))
zlog_info ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
printf("[Event] BGP connection from host %s", inet_sutop (&su, buf));
peer1 = peer_lookup_by_su (&su);
if (! peer1 || peer1->status == Idle)
if (BGP_DEBUG (events, EVENTS))
zlog_info ("[Event] BGP connection IP address %s is not configured",
zlog_info ("[Event] BGP connection IP address %s is Idle state",
/* Make dummy peer until read Open packet. */
if (BGP_DEBUG (events, EVENTS))
zlog_info ("[Event] Make dummy peer structure until read Open packet");
printf("[Event] Make dummy peer structure until read Open packet\n");
SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
/* Make peer's address string. */
sockunion2str (&su, buf, SU_ADDRSTRLEN);
BGP_EVENT_ADD (peer, TCP_connection_open); 创建一个event thread执行bgp_event函数
int bgp_event (struct thread *thread)
peer = THREAD_ARG (thread); // get peer
event = THREAD_VAL (thread); // get FSM event eg.TCP_connection_open
next = FSM [peer->status -1][event - 1].next_state; next为下一个状态
plog_info (peer->log, "%s [FSM] %s (%s->%s)", peer->host,
LOOKUP (bgp_status_msg, peer->status),
LOOKUP (bgp_status_msg, next));
printf("%s [FSM] %s (%s->%s)", peer->host,
LOOKUP (bgp_status_msg, peer->status),
LOOKUP (bgp_status_msg, next));
ret = (*(FSM [peer->status - 1][event - 1].func))(peer); 执行本状态处理函数
/* When function do not want proceed next job return -1. */
if (next != peer->status) 判断状态是否需要转变
zebra 线程流具体分析相关推荐
- Mocha NTA基于单采集器实现的多种流协议分析
业内主流的Flow协议技术 网络业界基于流(Flow)的分析技术主要有NetFlow.sFlow.cFlow和NetStreem四种.NetFlow是Cisco公司的独有技术,它既是一 ...
- JAVA线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...
- H264码流打包分析(精华)
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit" ...
- java 线程池原理分析
一.为什么使用线程池 1.降低资源消耗,减少线程创建和销毁次数,每个工作线程可以重复利用,执行多个任务 2.可根据系统承受能力,调整工作线程的数目,防止消耗过多的内存 二.java 线程池使用 Exe ...
- 聊聊并发(三)——JAVA线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...
- JAVA线程池的分析和使用--笔记
1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...
- C++11中线程所有权转移分析
移动特性说明 C++标准库中有很多资源占有(resource-owning)类型,比如std::ifstream,std::unique_ptr还有std::thread都是可移动,但不可拷贝. 移动 ...
- H264码流打包分析
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit" ...
- StreamDM:基于Spark Streaming、支持在线学习的流式分析算法引擎
StreamDM:基于Spark Streaming.支持在线学习的流式分析算法引擎 streamDM:Data Mining for Spark Streaming,华为诺亚方舟实验室开源了业界第一 ...
最新文章
- CV之OpenCV:OpenCV库涉及概念、常见函数、常用案例、HALCON软件简介之详细攻略
- ArcSDE服务入门
- 2.Prometheus 监控技术与实践 --- Prometheus基本概念及部署
- BMC远程管理服务器
- 龙骨(Dragonbones)在Unity中换装的实现
- 如何“杀”趋势杀毒网络版
- Window平台Git-Bash的主题配置
- DVWA靶机-反射性XSS漏洞(Reflected)
- Gartner:首席信息官能从IT支出中得到哪些收获?
- 【人体骨骼点】数据集
- 北师大c语言2019在线作业,2019最新C语言考试题库及答案
- Spring boot 配置健康检查
- 二进制空间权重矩阵_空间权重矩阵(SWM)
- 迷你打印机或中小型打印机设置纸张大小,与不规格纸张修改
- 职场英语--邮件自动回复模板
- STM32 USART TX
- 人工智能从入门到精通系列教学视频免费送。。。
- Python_文件操作_深入
- 案例分享 | 汽车连接器焊锡质量检测
- Fiddler 4抓取http请求并修改请求进行调试
热门文章
- android开发获取手机屏幕分辨率
- 关于移动硬盘在WIN10无法打开解决方案
- js添加多marker 高德地图_【高德地图API】从零开始学高德JS API(三)覆盖物——标注|折线|多边形|信息窗口|聚合marker|麻点图|图片覆盖物...
- 盘点2021年流行报表开发工具【测评】
- 嵌入式数据库开发编程(一)——概述
- 多目标跟踪方法 A Baseline for 3D Multi-Object Tracking
- 从调整RSRQ测量参数提升4G驻留比
- 移动通信网络规划:覆盖场景划分
- 《PyInstaller打包实战指南》第二节 PyInstaller的两种打包模式
- 【论文代码复现2】Clustered sampling based on sample size