Open vSwitch Datapath淺析


下圖所示是Open vSwitch的組成(摘自Open vSwitch官網):

 

它分為Kernel部分和User部分。

安裝驅動

Kerenl部分是從Linux 2.6.32開始何如內核,默認是編譯為一個KO,位於/lib/modules/`uname –r`/kernel/net/openvswitch/openvswitch.ko。

 

應用open vswitch首先要做的就是install這個kernel module。需要注意,GRE Tunneling的支持需要gre.ko, VXLAN的支持需要vxlan.ko, 這兩個KO都位於/lib/modules/`uname –r`/kernel/路徑下。

user部分是有兩個daemon,一個是ovs-vswitchd,用來管理datapath,另外一個是ovsdb-server,用來維護一個數據庫。

初始化dbserver

在install好openvswitch.ko后,我們接着需要初始化這個ovsdb-server:

123

opendb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \            --remote=Open_vSwitch,Open_vSwitch,manager_option \            --pidfile --detach

此時會生成一個數據庫文件(/usr/local/etc/conf.db),該dbserver會將網絡狀態信息給記錄到conf.db里面。這些網絡狀態使得open vswitch能夠適應網絡的動態變化,比如可以用來追蹤VM的遷移。 
這個dbserver還可以通過TCP的6632端口跟遠端的openflow server進行通信,這個openflow server可以通過remote這個參數來指定。

啟動ovs-vswitchd

接下來就需要啟動ovs-vswitchd:

ovs-vswitchd —pidfile —detach

整個OVS的核心就是這個ovs-vswitchd。 
這樣子open vswich就在PC上運行起來了。

構建網絡拓撲

我們來構建如下圖所示的一個網絡拓撲:

 

首先需要增加一個bridge(br0)

ovs-vsctl add-br br0

執行這個命令后,

1. 將br0記錄到ovsdb里面

2. ovs-vswitchd創建一個新的bridge

3. ovs-vswitchd通過netlink這種方式,發相應的cmd給kernel,執行對應的handler來生成一個datapath以及和其相關的一些結構體。 
每個bridge都對應於一個datapath結構體。

接着來將網絡結構設備連接到該bridge

ovs-ctl add-port br0 eth1

執行這個命令后, 
1. 將該信息記錄到ovsdb 
2. ovs-vswitchd在bridge上新增一個端口,並將其設置為混雜模式(NETDEV_PROMISC),設置為混雜模式的目的是為了接收非本機MAC地址的包 
3. ovs-vswitchd通過netlink調用到kernel端的handler,此時:

1. 找到“eth1”對應的net\_device     

2.  把該net\_device的handler替換為ovs的handler,這樣net\_device的進包就不會進入普通的內核處理流程,而是由OVS接收過來處理。    

3. 產生一個新的vport結構體    

整個過程如下圖所示:

 


至此,就初始化完成了kernel module的主要結構體datapath/vport/flow_table。這些主要結構體的關系如下圖所示:

 

設置openflow server

下面這個命令可以用來設置遠端用來和ovs-vswitchd通信的openflow server:

ovs-vsctl set-controller br0 tcp:XXX.XXX.XXX.XXX:6633

如下圖所示:

 


根據不同的設備類型,ovs實現了不同的vport以作支持。目前OVS共支持了6種vport:

1234567

A. Network device : tap & system deviceB. Network device implemented by datapath: internal deviceinternal device存在的目的是為了給bridge分配IP地址。C. GRE tunnelD. GRE64 tunnelE. VXLAN tunnelF. LISP tunnel

以ping為例子來看下包處理流程

VM0來ping VM1. 
當vm0以ping發送一個ICMP報文給OVS時,OVS會依次進行如下處理:

1. ping 
VM0發送報文到tap0, tap0和br0的一個端口相連。br0的端口對應一個vport結構體。

2. ovs receive 
ovs執行tap0的receive handler,(即在前面執行ovs-ctl add-port br0 eth1 tag=XXX時注冊的那個handler) 
tag=XXX就是vlan,通過vlan來實現網絡隔離的功能。

3. flow key 
從sk_buff中解析出來L2~L4的信息生成一個flow_key. 
flow可以理解為一個以太網包所包含的頭部信息的集合,在一個flow table里面的一個flow必須是唯一的,它是包含L2/L3/L4這些頭部的一個細粒度的實體。一個TCP連接由兩個flow組成,每個方向上有一個。

 


4. flow lookup 
使用該key來執行flow_lookup, 去跟kernel module里面維護的flow table進行比較。 
首先去跟 flow_table里的 mask_cache數組進行比較, mask_cache里面只有 sk_buff的 hash值所以很快速; 
接着再去跟 mask_array這個數組進行比較,這個數組里面存放是的 sw_flow_key, 查找相對慢一些。 
如果在 mask_array里面匹配到了這個 flow,就會把該 sk_buff的 hash值給放到 mask_cache里面。 
在 kenerl里的這部分比較稱之為 ovs的 fast path

 


5. flow action 
如果在kernel中查找到了對應的flow entry,就去執行對應的flow action。 
這些action是告訴datapath怎么去處理flow里面的這些packets。 
action也可以為空,即丟棄這些packets。 
datapath的這些action跟openflow定義的action是一致的。 
6. send upcall 
如果沒有match到,就執行upcall通過netlink的方式給ovs-vswitchd發送OVS_PACKET_CMD_MISS命令。 
UPCALL會包含整個packet,雖然不必要拷貝整個的packet給user space,可以做一些優化,但是由於只是拷貝first packet(比如TCP SYN),所以這種優化意義不大,而且有時候可能真的會用到整個packet。 
ovs-vswitch一次只處理一個upcall,為了能夠讓每一個port產生的upcall都能夠得到即使處理,datapath是采用的round robin這種方式來讓每個port發送upcall。 
UPCALL發送出去后,dadapath的處理就結束了。 
一個普通的UPCALL結構如下圖所示。

 


7. handle upcall 
ovs-vswitchd執行read_upcalls來讀取upcall。 
read_upcalls的主要處理流程如下圖所示。

 


Hash bucket的數據結構是hmap,如下圖所示

 


8. flow table match 在userspace維護着openflowtable。對hmap里面的flow以wildcard的方式來與openflowtable匹配。 
Openflowtable的匹配過程大致如下圖。

 


9. MAC learning 
在open vswitch里面配置MAC learning功能

12345

ovs-ofctl add-flow br0 \  "table=2 actions=learn(table=10, NXM_OF_VLAN_TCI[0..11], \    NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], \    load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15]), \      resubmit(,3)“

 

 轉載地址:http://laoar.net/blog/2015/04/27/open-vswitch/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM