--------------------------------------------------------------------------------------------------
Openvswitch是一個優秀的開源軟件交換機,支持主流的交換機功能,比如二層交換、網絡隔離、QoS、流量監控等,而其最大的特點就是支持openflow,openflow定義了靈活的數據包處理規范。其所支持的所有協議如STP/LACP/BOND等最后都是落腳到流表。 同時OvS 提供ofproto dpif 編程接口,支持硬件交換機(后面有介紹)。
OvS豐富的功能和穩定性使得其被部署在各種生產環境中,加上雲計算的快速發展,OvS成為了雲網絡里的關鍵組件。
一、OvS 在SDN網絡中的位置
OvS 通過openflow流表可以實現各種網絡功能,並且通過openflow protocol可以方便的實現控制+轉發分離的SDN方案。
OvS 在雲環境中概圖(圖片來源互聯網)如下
二、OvS 各組件關系
ovs-vswitchd:主要模塊,實現內核datapath upcall 處理以及ofproto 查表,同時是dpdk datapath處理程序。
ovsdb-server:數據庫服務程序, 使用目前普遍認可的ovsdb 協議。
ovs-vsctl:網橋、接口等的創建、刪除、設置、查詢等。
ovs-dpctl:配置vswitch內核模塊
ovs-appctl:發送命令消息到ovs-vswithchd, 查看不同模塊狀態
ovs-ofctl:下發流表信息。該命令可以配置其他openflow 交換機(采用openflow 協議)
三、OvS datapath以及查找算法
OvS 支持內核datapath以及dpdk datapath。在兩種datapath模式中,內核模塊和ovs-vswithd是主要的處理程序。同時兩種datapath 前兩級的查表實現不同,但是第三級都使用相同的ofproto 查詢(這里我們只做簡單介紹)。
一直以來,流Cache是提高查表性能的有效手段,已經被廣泛應用於報文查表加速。它將數據平面的轉發路徑分為快速路徑(即流Cache)和慢速路徑,利用流量局部特性,使得大部分報文命中快速路徑中的表項,從而提高轉發性能。OVS也采用了流Cache設計思路。
OVS當前版本kernel datapath采用Megaflow Cache+Microflow Cache的流Cache組織形式,仍保留了Microflow Cache作為一級Cache,即報文進入后首先查這一級Cache。只不過這個Microflow Cache含義與原來的Microflow Cache不同。原來的Microflow Cache是一個實際存在的精確Hash表,但是最新版本中的Microflow Cache不是一個表,而是一個索引值,指向的是最近一次查Megaflow Cache表項。那么報文的首次查表就不需要進行線性地鏈式搜索,可直接對應到其中一張Megaflow的元組表。SDNLAB已經有文章對此進行了詳細分析,見https://www.sdnlab.com/15713.html
OVS + DPDK 查找算法和kernel datapath 查找有所不同,OVS DPDK查找詳見 https://software.intel.com/en-us/articles/ovs-dpdk-datapath-classifier
四、OvS 代碼架構
ovsdb-server 接收配置信息,同步到ovs-vswithd ,同時獲取ovs-vswithd 狀態信息。
ovs-vswitchd ovsdb-server讀取數據庫信息,並將信息下發到ofproto,同時ovs-vswithd也會將ofproto中的status and statistical信息通過ovsdb-server寫入到數據庫中。
ofproto通過網絡和OpenFlow 控制器通信。通過"ofproto provider”和軟件交換機以及硬件交換機通信。目前openvswitch只支持ofproto-dpif,但是用戶可以很容易的實現其他ofproto provider
ofproto provider 支持兩種dpif,ofproto-dpif 實現自己的數據結構,但是對上層呈現為ofproto結構體,其具體實現細節對上不可見。
netdev 對網絡設備(如Ethernet)的抽象,該層基於netdev provider實現。如果linux平台的system,tap,internal,以及dpdk的dpdk,dpdkr,dpdkvhostuser,dpdkvhostuserclient等。
創建ovs bridge流程分析:
1.通過ovs-vsctl 創建網橋,將創建參數發送給ovsdb-server,ovsdb-server將數據寫入數據庫。
2.ovs-vswitchd從ovsdb-server中讀取創建網橋的信息,在ovs-vswithd層創建一個bridge結構體信息
3.然后將brdige信息應用到ofproto層,在ofproto層通過ofproto_create創建網橋,ofproto_create通過用戶指定的網橋類型查找包含該類型的ofproto provider(目前只支持一個ofproto provider)。
查找后創建ofproto結構體(該結構體也表示一個bridge),並通過ofproto provider 構造函數創建ofproto provider的私有信息。
4.ofproto-dpif 層,構造函數完成如下:ofproto-dpif會為相同類型的ofproto創建一個backer結構體,所有類型的ofproto的backer使用全局列表表示。ofproto-dpif通過backer關聯dpif。同時backer關聯upcall處理線程
netdev沒有實現upcall注冊函數,所以對應的backer線程實際上不做任何處理,但依然會有該處理線程。netlink 通過backer啟動的線程實現處理upcall數據包的處理。
vswitchd是ovs中最核心的組件,openflow的相關邏輯都在vswitchd里實現,一般來說ovs分為datapath, vswitchd以及ovsdb三個部分,datapath一般是和具體是數據面平台相關的,比如白盒交換機,或者linux內核等。ovsdb用於存儲vswitch本身的配置信息,比如端口,拓撲,規則等。vswitchd本身是分層的結構,最上層daemon主要用於和ovsdb通信,做配置的下發和更新等,中間層ofproto,用於和openflow控制器通信,以及通過ofproto_class暴露了ofproto provider接口,不同平台上openflow的具體實現就通過ofproto_class統一。
Open vSwitch實現了兩種dpif。lib/dpif-netlink.c 特定Linux實現的dpif,該dpif與Open vSwith實現的內核模塊通信。內核模塊執行所有的交換工作,將內核態不匹配的數據包發送到用戶態。dpif封裝調用內核接口。lib/dpif-netdev.c 是一種通用的 dpif 實現。該dpif就是Open vSwith在用戶態的實現。數據包的交換不會進入內核。struct dpif_class是datapath interface實現的工廠接口類,用於和實際的datapath, e.g. openvswitch.ko, 或者userspace datapath交互。目前已有的兩個dpif的實現是dpif-netlink和dpif-netdev,前者是基於內核datapath的dpif實現,后者基於用戶態datapath。代碼可以在lib/dpif-netlink.c以及lib/dpif-netdev.c里找到。
五、OvS 開發實踐貢獻代碼之前
開發OvS 代碼之前,我們需要了解如下信息
1.郵件列表,所有的郵件列表:我們一般使用discuss作為平時問題的討論,dev作為提patch。https://mail.openvswitch.org/mailman/listinfo
2.編碼風格,如果你為OvS用戶態程序提供的patch,那么你需要遵循用戶態編碼風格。如果你是為內核datapath 編寫的patch 你需要遵循內核編碼風格。這兩種是不同的風格。http://docs.openvswitch.org/en/latest/internals/contributing/coding-style/
3.Commit Message,在提交代碼時,盡量把你遇到的問題,復現方法以及你的patch如何解決該問題的等, 描寫的詳盡。這不僅能夠讓其他人更好的理解,同時縮短接收patch時間,國內外有時差。
4.patchwork 在這里,你能夠看到其他人提交的patch,同時每個patch 處於什么狀態。http://patchwork.ozlabs.org/project/openvswitch/list/
六、OvS 開發實踐之二層網絡功能
OvS 支持各種二層網絡功能,比如LACP,STP,RSTP,MAC 學習,MCAST等,如果這些協議出現問題,可以通過如下的開發過程,定位,開發。ovs-vswithd 結構分析,開發OvS 最重要的就是分析ovs-vswithd
OvS 模塊的初始化
主要是模塊使用的數據結構體的初始化非協議,如lacp、bond、cfm、stp、rstp都在bridge_init調用初始化
ovs-vswithd 循環處理架構
這里只是列出的基本重要的架構,其他部分讀者可以進一步分析
bridge_run__ 循環處理一些必要的操作,如stp、rstp、mcast處理等,同時ovs-ofctl 下發openflow,也是在這里處理。bridge_reconfigure 主要完成根據數據以及當前進程信息,創建、更新、刪除必要的網橋、接口、端口以及其他協議的配置等。最終這些操作為應用到ofproto 層、ofproto dpif 層、run_stats_update、run_status_update、run_system_stats 更新openvswitch數據庫狀態信息netdev_run netdev_linux_run監控網卡狀態並更新。
以STP 某個功能為例,例如之前的一個bug,OvS 不會檢查stp port 所處的狀態。如果已經加入的port 開啟的stp功能,用戶使用ifconfig 禁止網卡狀態,那么理論上OvS 應該停止通過該端口發送數據包括BPDU。但是OvS 並沒有做這方便的檢查。同時如果ifconfig up了該網卡,那么重新進入stp 狀態,以及stp 各個狀態的改變。
社區最后接收了該bug的修復,patch 如下:https://github.com/openvswitch/ovs/commit/52182c5f50198d0f985b10677e47a9ac49ee709b
添加鏈路狀態監測函數:
在必要的地方調用
該補丁,在bridge_run__ stp_run中調用狀態檢查,並根據port 狀態對stp進行響應的處理。(網卡狀態的更新檢查統一在netdev_run中盡心,這里我們使用最后的檢查的結果做判斷)同時該補丁也bridge_reconfigure bridge_configure_spanning_tree設置port時調用該函數。如果是對其他協議的bug,修復過程其實類似。
七、OvS 開發實踐之unixctl
ovs-vswithd 支持ovs-appctl 很多命令,通過該方式,我們可以開發很多有用的功能,如查看ovs-vswithd 運行狀態,數據包處理狀態,內存使用情況,PMD線程情況。
OvS unixctl的初始化
在ovs-vswithd 初始化的時候通過unixctl_server_create函數創建unixctl 服務。命令ovs-appctl和注冊的服務通信。
OvS unixctl 命令注冊
我們可以通過unixctl_command_register 注冊unixctl 提供個命令服務,如ovs-vswithd 退出函數 unixctl_command_register("exit", "", 0, 0, ovs_vswitchd_exit, &exiting)
OvS unixctl 命令運行
ovs-vswithd 在循環中通過調用unixctl_server_run 執行用戶下發的命令。
前段時間開發的rstp/show 命令,該命令能夠查看rstp 協議在各個交換機中的狀態,顯示格式和思科交換機類似。在開發該功能時考慮如下 :
1.使用重陷入鎖還是使用內部函數。在實現該命令時需要調用其他函數,但是之前使用的鎖不允許重入,但是如果更改rstp 使用鎖的方式,需要更改大量的代碼(聲明,函數修飾)。
因此最后改成添加內部幫助函數。
2.rstp port name。之前rstp port不支持name 顯示,因此為了更清晰的顯示信息。我們需要在結構體中添加name 成員。
在整個rstp port 整個聲明周期(如rstp port的創建,刪除,使用,修改等),我們需要處理好name。獨立的patch 如下 https://github.com/openvswitch/ovs/commit/8d2f8375c7f7ee3e36877ba20f4e4cc5b47841d3
添加必要屬性
設置port name函數rstp_port_set_port_name__
最后需要在rstp_add_port 初始化port name, 在rstp_port_unref 刪除port name,同時在rstp 模塊添加必要的內部函數,實現如下(具體很簡單,大家可以review)https://github.com/openvswitch/ovs/commit/066f0ab4a07d2edc07dedcf006224df7fa00a9b1
最后實現rstp/show命令https://github.com/openvswitch/ovs/commit/cc3a32f3b6891168cee98812e8f5e3d8a5a52c98
最終命令效果
Q&A
Q:我有ovs通過vmware的wmnet橋接的,但是把橋接網卡設置成trunk后就不通了,能幫忙分析下么,ovs是安裝在centos7上的,cent是安裝在vmware上的
A:這個好細節,你可以通過tcpdump 檢查,每個節點是否 都有數據包,看看哪里丟包。ovs 你可以看看ovs flow表 看看哪個flow drop的該數據包。
Q:之前提到的ovs-dpdk的datapath,請問能講解一下ofproto是如何把流表分發給多個PMD的呢?
A:ovs 不管哪個datapath 都是三級cache,最后一個是ofproto,dpcls miss之后才去ofproto 所以對應的dpcls 才會有,之后emc 查找去對應的dpcls 去找,一個pmd 線程可能多個dpcls
Q:ovs流表匹配采用什么算法?對精確匹配字段,前綴匹配字段,和范圍匹配字段的匹配有區別對待?
A:ovs kernel datapath 使用Megaflow Cache + Microflow Cache,dpdk 和kernel 第一層cache 都是精准匹配,后面是通配的。如果是有區別,就是查找前后的區別。大家可以review dpdk 和kernel 的實現算法。
Q:能介紹一下ovs -dpdk在openstack里的應用嗎?
A:ovs-dpdk 在openstack 並沒有應用到實際的生產環境,如果有,也是小部分現在。不過這個是趨勢。
Q:相同優先級 match條件都一樣的兩條流表 怎么決定匹配到哪一條
A:這個會對 表的優先級排序的,找到的肯定是優先級高的。
Q:流表中的in port 和虛機端口有什么關系嗎?
A:沒有