VPP——可编程网络node
众多产业正在提供更加软件化的网络服务,在这个环境中提供网络服务是亟待解决的问题。必需可是不足的是须要更多关注非本地的网络控制平面,须要更灵活、高效的数据以及路径交互平面。编程
VPP所具备的重要特色:灵活性,可维护性和高度的调试性,可提供高性能扩展性和高效IO数组
- vpp节点调度
vpp的函数调用更像是一种各个节点之间相互链接,经过决定下一跳节点的路径在肯定整个代码的执行路径。一样这种方式的函数调用提供了很低的耦合性,因此基于这种方式的二次开发不用太多考虑各个模块之间的相互影响,甚至能够彻底不用考虑,本身定义的节点根据格式给出相应的回调函数来插入自定义的功能,下面是一个简单转发的node调用图。网络
能够看到,在转发的过程当中若是要加入本身的上层业务只须要定义新的节点,将其链接到对应位置,并不会影响到其余部分的封装。多线程
- VPP NODE类型
VLIB_NODE_TYPE_PRE_INPUT:目前只有一个epoll node,对socket相关逻辑提供服务,主要使用在控制业务上。socket
VLIB_NODE_TYPE_INTERNAL:对数据包真正处理业务的node。函数
VLIB_NODE_TYPE_INPUT:收包逻辑node,好比:dpdk,pcap等oop
VLIB_NODE_TYPE_PROCESS:该类型的node能够被挂起也能够被恢复,有独立的分配在heap上的运行栈。相似与在一个线程中实现了多任务的调度机制,主要用来修改vpp node内部参数。性能
- VPP多线程支持
1.单线程优化
全部的控制和矢量数据包的运行都在单线程中完成。
2.只有worker的多线程(使用RSS更方便)
main线程负责控制信息(API,CLI)。
矢量数据包运行在一个或者多个线程上。
3.有io和worker的多线程
main线程负责控制信息(API,CLI)。
IO线程处理接口输入并调度数据包到worker线程。
worker线程作包括TX接口在内的真正的业务。
4.有worker的多线程而且main线程作io
main线程同时作了IO线程所作的事(管理调度worker线程)。
对于线程来讲初始化时按照配置文件循环绑定到指定的核上而且分配其rx和tx队列vnet_hw_interface_assign_rx_thread,能够经过show threads查看状态,show dpdk interface placement查看线程绑定网卡的队列,一样也可使用set dpdk interface placement 网卡 队列 线程,来改变其默认的绑定状态。
关于多线程的代码主要分布在两个部分:
1.在vlib/threads.c中,这部分主要是线程建立,复制一些结构体而且初始化。
2.在vnet/device/dpdk/thread.c中,定义线程名字、功能。
全部的线程都是调用的同一个函数,只须要改变它的结构体中的内容就能够区分,因此基于vpp的开发也不须要考虑线程关系问题。
- VPP代码主体流程分析
vpp/vnet main.c
1.main 首先解析参数,再须要初始化堆,插件的初始化将由他提供。
2.vpe_main_init 初始化各类插件,经过宏函数VLIB_INIT_FUNCTION(X),能够经过遍历单链表、动态连接的方式指定不一样的初始化类型如早期的配置、功能等
3.调用 vilb_unix_main
vilb_unix_mian
- vlib_plugin_early_init (vlib_load_one_plugins) 从配置文件中读取插件的路径而不用从新编译.
- vlib_thread_stack_init 建立主线程的线程栈,对于线程的管理,经过了数组的形式,因此每次使用地址能够直接经过偏移量来找到他
- clib_call_jmp 这里执行了main线程(thread0)的回调函数。
thread0->vlib_main
- cli_time_init 用于多线程时间轮调度
- vlib_register_all_static nodes 一样也是经过遍历单链表的方式对全部的节点分配内存、初始化等等。
- vlib_call_all_init_fountions 这里的初始化不一样于最开始时的初始化,这里是创建节点图,经过函数指针计算矢量,也就是在节点图的下一跳(对于不一样类型的数据包所造成的路径也是不一样的)。
- vlib_buffer_get_or_create_free_list 建立默认的缓冲区,dpdk使用了特定的缓冲区的格式,vpp在其头部添加信息使二者相对隔离,给网络栈和空间存储提供了便利。
- vlib_call_all_config_functions 进入主循环前最后一次进行配置
- 进入 vlib_main_loop
vlib_main_loop
- dispatch_process
- dispatch_node(PRE_INPUT) 目前只有一个epoll node,对socket相关逻辑提供服务,主要使用在控制业务上。能够处理CLI命令以及能够在中断模式和轮询模式中切换。
- dispatch_node(INPUT) 须要从其余容器中得到input方法(dpdk_input),由以前构建好的节点图进行矢量跳转,
- queue_signal_pending 用户能够自行定义信号后会调用回调函数
- 中断模式和时间轮计算
- dispatch_pending_node 因为咱们以前已经定义好了数据包的矢量,如今要作的就是跳转到我收到包后如今要作的事情。(p.s.有对于trace版本的优化以及debug版本显示更多信息,同时也能够在gdb中看出数据包的流
- dispatch_node(INTERNAL)
- node->function 调用节点指定的动做(对于dpdk来讲这里就是发包)
- VPP代码流程图