OVS源碼--vswitchd啓動(二十)

Vswitchd是ovs中運行在用戶空間的守護進程, 實現ovs主要的功能邏輯, 本文將着重分析其啓動過程。

數據結構

bridge/port/iface/ofproto/ofport

在數通領域, 交換機和橋很多時候可以是在說一個東西, 它工作在二層, 可以添加多個端口, 從一個端口上收到的報文會根據MAC表從其他某個端口轉發出去. 在ovs中, 它也還是一個東西, 不過ovs用兩個數據結構描述它們: 交換機(ofproto)與橋(bridge). 它們在ovs中是一一對應的, 也就是說一個bridge就有一個對應的ofproto. 相比而言, bridge更貼近用戶, ofproto跟底層聯繫更多. 想想添加一個橋的命令是 ovs-vsctl add-br 就可見一斑了.
交換機需要添加端口才能具有實際作用, ovs用port和ofprot描述端口, 前者對應bridge, 更貼近用戶配置, 而後者對應ofproto,更貼近底層. ovs還有一個結構叫iface, 一般而言, 一個port包含一個iface, 但存在一種聚合(bond)的情況, 我們可以把多個iface捆在一起, 將它們一併歸納到一個port.此時port和iface就是一對多的關係了.

以下爲前面提到的幾個數據結構之間的聯繫
在這裏插入圖片描述

vswitchd啓動

入口

vswitchd 進程的入口在ovs-vswitchd.c ,下面我們將主要關注主幹流程的分析,而忽略其中的一些旁枝末節

int main(int argc, char *argv[])
{
     remote = parse_options(argc, argv, &unixctl_path)
     bridge_init(remote);
     while (!existing){
           bridge_run();     
           bridge_wait();
           poll_block();
     }
     .....exit();
     return 0;
}

初始化 bridge 模塊

bridge 模塊的初始化在 bridge_init 中完成, bridge_init主要的動作是連接數據庫ovsdb, 並從中讀取配置信息.

void bridge_init(const char *remote)
{
    idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true, true);
 
    ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
    ......
}

注意, 像ovsrec_open_vswitch_col_cur_cfg這樣的全局變量的定義是編譯時自動生成的, 從官方下載的代碼中最初是沒有它的定義的.

運行 bridge 模塊

bridge 模塊的初始化在 bridge_run 中進行

void bridge_run(void)
{
    cfg = ovsrec_open_vswitch_first(idl);
    bridge_init_ofproto(cfg);
    bridge_run__();
    if (ovsdb_idl_get_seqno(idl) != idl_seqno || if_notifier_changed(ifnotifier))
    {
        bridge_reconfigure(cfg ? cfg : &null_cfg)
    }
    ...
}

首先讀取數據庫ovsdb中的配置到cfg, 此時, cfg中就有了諸如用戶創建了多少個bridge, 每個bridge中有多少個port, iface等信息.

在bridge_init_ofproto中, 會進行ofproto library初始化, 之前提到了, bridge更靠近用戶配置, ofproto更靠近底層, 這裏就是進行底層庫的初始化

void ofproto_init(const struct shash *iface_hints)
{
    ofproto_class_register(&ofproto_dpif_class);
    .....
    for (i = 0; i < n_ofproto_classes; i++) {
        ofproto_classes[i]->init(&init_ofp_ports);
    }
}

ofproto library首先進行ofproto class類的註冊, ovs當前僅支持一種類, 即ofproto_dpif_class, 所以後面調用init, 實際上也只會調用ofproto_dpif_class->init().
觀察ofproto的數據結構中 的前幾項

struct ofproto{
   const struct ofproto_class *ofproto_class;
   char *type;             /* Datapath type */ 
   char *name;             /* Datapath name */
   ...
}

其中, ofproto_class即爲生產者的class, 在當前ovs中, 只會指向ofproto_dpif_class, type爲ofproto的類型, 也可稱爲provider, 當前的ofproto_dpif_class有兩種provider , 記錄在dpif_classes中, 它的來源是base_dpif_classes[]

static const struct dpif_class *base_dpif_classes[] = {
  &dpif_netlink_class,
  &dpif_netdev_class,
} 

可以把dpif_classes看成一張註冊表, 裏面有兩個條目
在這裏插入圖片描述
ofproto_dpif_class實現的enumerate_types方法可以列舉當前支持的datapath的類型, 在當前的ovs實現中,是"system"和"netdev"

再來看 bridge_run__(void)

static void bridge_run__(void)
{
    ofproto_enumerate_types(&types);
    SSET_FOR_EACH(type, &types){
        ofproto_type_run(type);
    }
    HMAP_FOR_EACH(br, node, &all_bridges){
       ofproto_run(br->ofproto);
    }
}

首先bridge_run__將當前支持的type列舉出來, 再逐個調用ofproto_type_run ,最終調用到ofproto_dpif_class->type_run(),這裏在第一次運行時, 由於all_dpif_backers爲空,所以就直接返回了.
然後, bridge_run__對all_bridges上記錄的每個bridge調用ofproto_run, 同樣在第一次運行在這裏時all_bridges爲空, 所以也不會有實際的動作.

原文鏈接:https://blog.csdn.net/chenmo187J3X1/article/details/83242809

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章