节点类型作用:
VLIB_NODE_TYPE_INTERNAL
内部节点,最典型的节点接收缓冲向量,执行操作。vpp大部分节点是这个角色,主要对数据流做内部处理,比如ip4-input-no-checksum/ip4-icmp-input等内部功能节点
VLIB_NODE_TYPE_INPUT
输入节点,通常是设备输入节点。从零开始创建框架并分派到内部节点(internal), 比如dpdk-input/af-packet-input节点,
input节点收包模式分为轮询和中断两种模式vlib_node_state_t.
VLIB_NODE_TYPE_PRE_INPUT
目前只有一个epoll node,对socket相关逻辑提供服务,主要使用在控制业务上。
VLIB_NODE_TYPE_PROCESS
该类型的node可以被挂起也可以被恢复,有独立的分配在heap上的运行栈。类似与在一个线程中实现了多任务的调度机制,主要用来修改vpp node内部参数。
线程节点,和线程一样,可以可以暂停、等待事件、恢复,不同于pthread_thread,他是基于setjump/longjump实现的弦程.
等待一个事件:always_inline f64 vlib_process_wait_for_event_or_clock (vlib_main_t * vm, f64 dt)
发送一个事件: always_inline void vlib_process_signal_event (vlib_main_t * vm, uword node_index, uword type_opaque, uword data)
数据流节点中流程:
- 输入节点轮询(或中断驱动)接口的接收队列,获取批量报文。
- 接着把这些报文按照下个节点功能组成一个矢量(vector)或者一帧(frame)。
- 比如:输入节点收集所有IPv4的报文并把它们传递给ip4-input节点;
- 输入节点收集所有IPv6的报文并把它们传递给ip6-input节点。
- 当ip6-input节点被调度时,它取出这一帧报文,利用双循环(dual-loop) 或四循环(quad-loop)以及预取报文到CPU缓存技术处理报文,以达到最优性能。这能够通过减少缓存未命中数来有效利用CPU缓存。当ip6-input节点处理完当前帧的所有报文后,把报文传递到后续不同的节点。比如:如果某报文校验失败,就被传送到error-drop节点;正常报文被传送到ip6-lookup节点。
- 一帧报文依次通过不同的图形节点,直到它们被interface-output节点发送出去。
VPP图形节点的处理逻辑
第一步:
第二步:
第三步:
第四步:
按照网络功能一次处理一帧报文优势:
- 从软件工程的角度看,每一个图形节点是独立和自治的。
- 从性能的角度看,主要的好处是可以优化CPU指令缓存(i-cache)的使用。当前帧的第一个报文加载当前节点的指令到指令缓存,当前帧的后续报文就可以“免费”使用指令缓存。这里,VPP充分利用了CPU的超标量结构,使报文内存加载和报文处理交织进行,达到更有效地利用CPU处理流水线。
- VPP也充分利用了CPU的预测执行功能来达到更好的性能。从预测重用报文间的转发对象(比如邻接表和路由查找表),以及预先加载报文内容到CPU的本地数据缓存(d-cache)供下一次循环使用,这些有效使用计算硬件的技术,使得VPP可以利用更细粒度的并行性
VLIB_INIT_FUNCTION宏定义分析
举个例子:
VLIB_INIT_FUNCTION (dpdk_init);
VLIB_INIT_FUNCTION 宏定义展开如下所示,主要由VLIB_DECLARE_INIT_FUNCTION宏定义完成注册动作:
1 #ifndef CLIB_MARCH_VARIANT 2 #define VLIB_DECLARE_INIT_FUNCTION(x, tag)