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代碼流程圖