OVS網橋建立和連線管理
前言
Open vSwitch作為一個被廣泛應用的虛擬交換機,除了完成流表匹配、資料轉發等功能外,其自身對網橋的建立更新和連線管理也尤為重要,這是其高效能的保障。本文按照原始碼的行文思路,從網橋的建立、配置、更新到主動、被動連線管理,依次進行梳理學習。
重要結構體:
本文將按照下圖主線進行分析。其中,會提到一系列有關聯的結構體bridge、ofproto、connmgr、ofconn、rconn、vconn,其附屬關係也如圖中所示:
bridge、ofproto、connmgr等前三個結構體都是對於一個網橋而言,且分別和網橋都是一對一關係,互相之間也是一對一關係。從connmgr開始是和連線例項相關,一個connmgr對應多個ofconn(如一個網橋連線多個控制器,則需要建立相應多個ofconn例項;和ofctl等工具連線時也要建立ofconn例項);一個ofconn對應一個rconn;一個rconn對應多個vconn(因為和控制器建立連線外,可能還會實現snoop功能,即監測並複製互動的of訊息,則一個rconn會對應一個vconn和一個vconn結構體型別的陣列monitor。這樣看來,vconn並非連線兩個實體,可稱為虛擬連線)。
每個結構體具體含義在後面分析中會逐一說明,這裡只需要對其有一個大體關係的瞭解,方便後面分析中保持一個清晰的思路。
一 從Main開始,建立ovs-vswitchd服務端
為了保障思路的完整性,從main函式快速引入(ovs-vswitchd.c),然後進入到網橋建立階段。
1、 main函式中,先通過引數解析得到unixctl_path和remote:
1 |
remote
=
parse_options
(
argc
,
argv
,
&
unixctl_path
) |
ovs有兩大程序vswitchd和ovsdb-server,remote用於這兩個程序的IPC,即程序間socket通訊。remote其實是一個socket檔案地址,由 ovsdb-server服務端繫結監聽時產生,作用類似於網路socket的Ip+Port地址,remote格式如unix:/usr/local/var/run/openvswitch/db.sock。後面建立網橋時會使用。
2、 通過下面命令建立vswitch unixctl服務端,個人理解這個是用於以後ovs vswitch的管理工具,如ofctl等連線的服務端:
1 | retval = unixctl_server_create ( unixctl_path , & unixctl ) ; |
3、 同時會啟動守護程序,最終一些守護程序會退出:
1 | daemonize_start ( ) |
4、 之後,初始化網橋,主要是初始化網橋bridge模型,通過remote地址,來從OVSDB服務端獲取配置資訊來實現網橋初始化配置:
1 | bridge_init ( remote ) ; |
這裡會遇到一個IDL概念。關於IDL,即介面定義語言,一般用於RPC(遠端過程呼叫)。這裡可以理解為用於vswitch和OVSDB服務之間的互動呼叫,一些資訊就需要不斷從OVSDB獲取,如網橋資訊。
5 最後,則通過while迴圈進入正式工作狀態(主要呼叫函式bridge_run(),進入網橋建立階段)。這裡會反覆迴圈,直到服務需要停止時,才退出ovs-vswitchd服務端。
1 | bridge_run ( ) ; |
二 bridge_run():網橋建立、配置和更新(vswitchd/bridge.c)
OVSDB包含三級結構,表table、記錄record和屬性columm。例如,在bridge表中,每一個record就是一個網橋例項的資訊集合,其中uuid和datapath_id等就是這條record的屬性。Open_vSwitch表(ovs資訊表)是肯定有的,屬於根表,一般有且只有一個record,屬性有uuid、版本、系統版本和網橋bridges(當無網橋時則為空[])。當然,這些都是可以通過ovs-vsctl list 表名
(如Open_vSwitch、bridge等表)來查詢其具體內容。
在ovs原始碼中,以結構體名為ovsrec_開頭的就是表結構體,如果例項化了表就是一項紀錄record。因此,在bridge_run()裡,通過ovsrec_open_vswitch_first(idl)和介面idl得到根表open_vswitch(*cfg,即結構體ovsrec_open_vswitch)。其實一個cfg就是跟表的一個record,cfg裡的成員也就是屬性columm(比如版本屬性)。
在bridge_run()中,主要工作依次如下:
1、初始化網橋的ofproto庫:主要呼叫bridge_init_ofproto()->ofproto_init(),且這個函式只執行一次,通過靜態變數initialized控制。
這裡重要的是,註冊了變數ofproto_dpif_class(結構體ofproto_class,ofproto-dpif.c),這是ofproto的執行函式庫的集合。註冊函式為ofproto_class_register(&ofproto_dpif_class),將ofproto_dpif_class賦值給ofproto_classes[i]。個人理解,i只可能為0(n_ofproto_classes只能為1),即ofproto_classes[0]就是ofproto_dpif_class(即ofproto的函式庫)。ofproto_dpif_class很有用,比如含有ofproto的執行、流表項的插入等操作函式,之後會用到。
當然,註冊了ofproto庫,即ofproto_dpif_class之後,才可以建立ofproto。結構體ofproto代表一個OpenFlow交換機,之後會在bridge_reconfigure()中呼叫ofproto_create()建立ofproto。
2、執行網橋:bridge_run_(),主進行兩項工作,第一是通過函式ofproto_type_run(type)讓每一個型別的datapath執行,第二是呼叫ofproto_run(br->ofproto)讓每一個bridge的ofproto執行,ofproto的執行細節在後面三中著重分析。