2.1. 与结点相关的结构体
2.1.1. 全局结构体
vlib_main_t:每个线程一份,记录着线程使用到的全局数据信息.
比如:
/* Node graph main structure. */
vlib_node_main_t node_main;
/* Command line interface. */
vlib_cli_main_t cli_main;
/* Packet trace buffer. */
vlib_trace_main_t trace_main;
......
2.1.2. Node相关结构体
vlib_node_t:结点的主结构,包括结点的处理功能函数,名称,结点类型等,主要保存一些相对静态信息
vlib_node_main_t:Node graph相关的全局信息,nodes数组、vlib_next_frame_t、vlib_pending_frame_t等数据
vlib_node_registration_t:注册node结点时使用,保存结点业务逻辑的函数地址,结点类型,结点状态,结点名称等
vlib_node_runtime_t:实际在调度node过程中使用的结构,主要记录在处理过程中的信息变动
vlib_frame_t:每个node都有一个对应的vlib_frame_t,用来保存供node使用的数据集合(标量、矢量)
vlib_next_frame_t:主要是node内部逻辑使用,用于定位该node的下一结点所对应的frame地址
vlib_pending_frame_t:当一个node处理完数据包,则填充该待处理帧管理表数据结,调度框架便能在下一次调度时找到需要接收该数据包的下一个node
2.2. vlib_node_type_t
VLIB_NODE_TYPE_INTERNAL
/* An internal node on the call graph (could be output).
Internal nodes (including output nodes) move data from node to node (or out of the graph for output nodes). */
VLIB_NODE_TYPE_INPUT
/* Nodes which input data into the processing graph.
Input nodes are called for each iteration of main loop. */
VLIB_NODE![1](https://yqfile.alicdn.com/de8130d739704d7c949da6337f99d6d070e55b4f.png)
_TYPE_PRE_INPUT
/* Nodes to be called before all input nodes.
Used, for example, to clean out driver TX rings before processing input. */
VLIB_NODE_TYPE_PROCESS
/* "Process" nodes which can be suspended and later resumed.
A lightweight cooperative multi-tasking thread model. Context switching costs a setjmp/longjump pair. */
2.2.1. VLIB_NODE_TYPE_INPUT结点
以dpdk-input结点为例:
2.2.1.1. dpdk burst收包
DPDK收到的数据包保存在rte_mbuf中,通过rx_vectors按queue_id进行索引。
dpdk_rx_burst将返回收到的包个数n_buffers。
2.2.1.2. 得到to_next指针
to_next指针指向下一结点frame的起始vector地址,用于存放数据包的索引值。
该宏主要调用以下两个函数:
nf = vlib_node_runtime_get_next_frame(vm, node, next_index);
f = vlib_get_frame(vm, nf->frame_index);
首先,在vlib_node_runtime_t node中的next_frames数组中根据next_index找到下一结点相关的vlib_next_frame_t信息。
找到vlib_next_frame_t后,便可从其中保存的frame_index域找到下一结点对应的vlib_frame_t _f结构体。
并通过计算:
u32 _n = _f->n_vectors;
(to_next) = vlib_frame_vector_args(_f) + _n * sizeof ((to_next)[0]);
返回未使用的vector的起始地址
2.2.1.3. 从DPDK rte_mbuf到vlib_buffer_t
为了方便管理,VPP自定义了vlib_buffer_t类型的缓冲区,其与rte_mbuf的关系如下:#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
vlib_buffer_t存放在rte_mbuf的headroom中,通过此方法将DPDK与VPP的内存管理机制管理起来
- 从xd->rx_vectors得到rte_mbuf指针后,vlib_buffer_from_rte_mbuf再换算成vlib_buffer指针
- 使用vlib_get_buffer_index函数得到每个vlib_buffer指针相对于buffer_mem_start的offset值
即作了归一化后的包索引值,将指针值表示成索引值
这些包索引值将保存在to_next所指向的next_frame中的vector中
2.2.1.4. 验证处理结果
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0);
当next0 != next_index时,说明该包被正确处理,该宏将do nothing
否则,说明本来该包应去next_index但是发生错误,使得next0 != next_index。该宏会将该错误包索引pi0发往到next0实际的下一个结点
2.2.1.5. vlib_pending_frame_t的添加
完成包处理后下一结点的frame已填充好包索引信息,说明可以进行调度处理需要添加到vlib_pending_frame_t待处理帧管理表中
vlib_put_next_frame(vm, node, next_index, n_left_to_next);
主要登记的信息包括:
下一结点frame索引、下一结点runtime_index、下一结点next_frame_index