在支持OpenFlow的交換機中包含了若干個Flow table,Flow table能夠用來控制數據包的處理,交換機會執行與flow相匹配的表項中所羅列的動做。html
OpenFlow controller經過使用OpenFlow協議來管理交換機,而且controller也能經過使用OpenFlow協議來獲取交換機上的端口、流量的統計信息或其餘情報,並能夠根據這些信息來調整各端口的流量。cookie
交換機中維護的每一個flow table都包含有不少個條目,這些條目會根據自身的一個優先級從高到底進行排序,優先級最高的條目位於flow table的頂部。網絡
當一個數據包進入到交換機時,先和優先級最高的條目進行匹配,若是匹配成功,那麼就中止繼續匹配動做,去執行該條目中的一組action。若是匹配失敗,則按照優先級高低,繼續匹配下一條。若是flow table中全部的條目都不匹配,這個數據包就會被丟棄或發送到控制器(問題:如何決定是丟棄仍是發送到控制器)。工具
OpenFlow協議的版本已經從1.0更新到了1.5,其中爲了保證OpenFlow能有一個穩定的發展平臺,把1.0和1.3版本做爲其中長期支持的穩定版本。1.0版本功能比較簡單,本次主要學習其中的1.3版本。學習
在OpenFlow中用來控制flow的table主要涉及到flow table和group table,先簡單瞭解一下這兩張table的構成。測試
Flow table中每一個條目中包含的字段如上圖所示,其中每一個字段的含義能夠參考下面的表格。spa
每一個Flow table中的條目(表項)都是由Match Fields和Priority兩個字段來共同惟一標識的。3d
一樣的,上圖列出了Group table中每一個條目包含的字段,其含義參考下表:orm
這裏簡單瞭解一下兩張table的結構,至於table中每一個字段的具體含義和用途咱們先不着急去了解,在後面結合具體的流程來更方便的去理解。htm
在瞭解了上述兩張table後,咱們不由會想:在交換機運行過程當中是如何配合這兩張表來實現流量轉發的呢?
這就不得不提到openflow中的一個重要概念:pipeline processing。什麼是pipeline?若是把每一個table當成一道加工工藝的話,pipeline就能夠當作是一條加工流水線。在這條流水線上,多個flow table按照其數字編號從小到大排列着(table0, table1, table2 …… table N),進入交換機的數據包都是從pipeline的第一個flow table也就是table0開始處理,按照上文描述的那樣,對table0中的條目一條一條開始匹配,若是匹配成功則執行相應的動做(這些動做可能致使從flow table跳到group table中),若果沒有全部條目都沒有成功匹配,則根據table自身的不一樣配置執行相應的處理(Table Miss Flow Entry):
Table Miss Flow Entry是flow table中專門處理沒有成功匹配的數據包的一個條目,它的Match Fields可以匹配任何數據包,而且Priority爲0,也就是會被最後執行。
Table Miss Flow Entry不是必須存在的,當不存在的時候,對沒成功匹配的數據包會執行table中的默認動做。
整個流程形象點的話咱們能夠經過下面這張圖來理解:
這張圖是我從網絡上覆制過來的,相關文章能夠在最後的參考連接中查看。
在這張圖中咱們能夠很形象的看到flow table和group table在數據轉發過程當中的地位。
在使用open vswitch來實際應用open flow以前,咱們有必要先了解一下ovs目前對openflow協議各版本的支持狀況。爲此,我在官網找到了以下這張表(2018年4月):
本文中使用的Open vSwitch版本爲2.5.0,默認支持Open Flow 1.3。
在實際的環境中,基本上都是由controller來操做修改交換機的open flow。本實驗將經過使用ovs-ofctl工具手動來配置修改OVS交換機的open flow。
ovs-ofctl的使用方法能夠參考官方文檔:Open vSwitch Manual : ovs-ofctl
環境構築
# 建立namespace ip netns add ns1 ip netns add ns2 ip netns add ns3 ip netns add ns4 # 建立tap設備 ip link add tap0 type veth peer name tap0_br ip link add tap1 type veth peer name tap1_br ip link add tap2 type veth peer name tap2_br ip link add tap3 type veth peer name tap3_br ip link add tap4 type veth peer name tap4_br ip link add tap5 type veth peer name tap5_br ip link add tap6 type veth peer name tap6_br ip link add tap7 type veth peer name tap7_br # 設置tap設備的namespace ip link set tap0 netns ns1 ip link set tap1 netns ns1 ip link set tap2 netns ns2 ip link set tap3 netns ns2 ip link set tap4 netns ns3 ip link set tap5 netns ns3 ip link set tap6 netns ns4 ip link set tap7 netns ns4 # 建立OVS網橋 ovs-vsctl add-br vswitch0 # 將tap設備另外一端綁到網橋 ovs-vsctl add-port vswitch0 tap0_br ovs-vsctl add-port vswitch0 tap1_br ovs-vsctl add-port vswitch0 tap2_br ovs-vsctl add-port vswitch0 tap3_br ovs-vsctl add-port vswitch0 tap4_br ovs-vsctl add-port vswitch0 tap5_br ovs-vsctl add-port vswitch0 tap6_br ovs-vsctl add-port vswitch0 tap7_br
環境配置
# 啓動tap0和tap3及它們的對端 ip netns exec ns1 ip link set tap0 up ip netns exec ns2 ip link set tap3 up ip link set tap0_br up ip link set tap3_br up # 設置tap0和tap3的ip地址 ip netns exec ns1 ip addr add 192.168.1.100 dev tap0 ip netns exec ns2 ip addr add 192.168.1.200 dev tap3 # 配置路由 ip netns exec ns1 route add -net 192.168.1.0 netmask 255.255.255.0 dev tap0 ip netns exec ns2 route add -net 192.168.1.0 netmask 255.255.255.0 dev tap3 # 測試網絡連通性 ip netns exec ns1 ping 192.168.1.200 >> 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.030 ms >> 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.055 ms
查看tap設備對應的ovs port
# ovs-vsctl list interface tap0_br | grep "ofport " ofport : 1 # ovs-vsctl list interface tap3_br | grep "ofport " ofport : 4
首先查看一下vswitch0上的flow table:
# ovs-ofctl dump-flows vswitch0 cookie=0x0, duration=267197.837s, table=0, n_packets=459, n_bytes=42190, idle_age=387, hard_age=65534, priority=0 actions=NORMAL
發現有一條actions爲NORMAL的流表項,這是默認存在的,用以實現交換機的基本動做。
當咱們把這條flow刪除後發現兩個tap設備之間已沒法ping通:
# ovs-ofctl del-flows vswitch0 # ovs-ofctl dump-flows vswitch0 NXST_FLOW reply (xid=0x4): # ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. ^C --- 192.168.1.200 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 2052ms
簡單的講,若是要實現tap0和tap3之間流量互通,其實就是要交換機將port1上的數據發往port4,port4上的數據發往port1(port1和port4分別是tap0和tap3對應的ovs端口,查看方法見上),因此咱們能夠添加下面兩條flow:
# ovs-ofctl add-flow vswitch0 "priority=1,in_port=1,actions=output:4" # ovs-ofctl add-flow vswitch0 "priority=2,in_port=4,actions=output:1"
當添加完這兩條flow後發現tap0和tap3之間又能相互ping通了
# ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.396 ms 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.050 ms ^C --- 192.168.1.200 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1030ms rtt min/avg/max/mdev = 0.050/0.223/0.396/0.173 ms
能夠看到咱們給這兩個flow設置了優先級分別是1和2,根據上文所講,flow優先級越高,會優先匹配,因此咱們再增長下面的flow來測試:
ovs-ofctl add-flow vswitch0 "priority=3,in_port=1,actions=drop"
這條flow是將全部從port1上的數據所有drop掉,若是成功匹配,則tap0和tap3將再也不互通。
# ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. ^C --- 192.168.1.200 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 2057ms
發現果真ping不通了,這就驗證了上文的描述:優先級越高,優先匹配。
在實驗一的基礎上繼續往下作。
首先清除全部的flow,從新開始配置
# ovs-ofctl del-flows vswitch0
還記得轉發的兩條flow嗎?在實驗一中咱們配置到了table0,如今將他們配置到table1
# ovs-ofctl add-flow vswitch0 "table=1,priority=1,in_port=1,actions=output:4" # ovs-ofctl add-flow vswitch0 "table=1,priority=2,in_port=4,actions=output:1" # ovs-ofctl dump-flows vswitch0 NXST_FLOW reply (xid=0x4): cookie=0x0, duration=3.485s, table=1, n_packets=0, n_bytes=0, idle_age=3, priority=1,in_port=1 actions=output:4 cookie=0x0, duration=3.033s, table=1, n_packets=0, n_bytes=0, idle_age=3, priority=2,in_port=4 actions=output:1
嘗試ping對端設備,發現沒法ping通,由於數據包從table0開始處理,當前table0中沒有匹配的flow,因此數據包被drop掉了。
# ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. ^C --- 192.168.1.200 ping statistics --- 3 packets transmitted, 0 received, 100% packet loss, time 2026ms
如今給table0加上一條將數據包發送到table1處理的flow
# ovs-ofctl add-flow vswitch0 "table=0,actions=goto_table=1"
再次嘗試ping對端的設備,能夠正常ping通
# ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.309 ms 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.050 ms ^C --- 192.168.1.200 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1054ms rtt min/avg/max/mdev = 0.050/0.179/0.309/0.130 ms
繼續使用這個環境,第一步仍是清除全部的flow
# ovs-ofctl del-flows vswitch0
查看交換機上存在的group表,發現當前沒有任何group table。
# ovs-ofctl -O OpenFlow13 dump-groups vswitch0 OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
咱們計劃讓數據包從table0發送到group table處理,再發送到table1處理。
# ovs-ofctl -O OpenFlow13 add-group vswitch0 "group_id=1,type=select,bucket=resubmit(,1)" # ovs-ofctl -O OpenFlow13 dump-groups vswitch0 OFPST_GROUP_DESC reply (OF1.3) (xid=0x2): group_id=1,type=select,bucket=actions=resubmit(,1)
在table0中增長兩條flow,目的是將數據包發送到group table1
# ovs-ofctl -O OpenFlow13 add-flow vswitch0 "table=0,in_port=1,actions=group:1" # ovs-ofctl -O OpenFlow13 add-flow vswitch0 "table=0,in_port=4,actions=group:1"
向table1中增長兩條flow,真正的數據轉發在table1中進行。
# ovs-ofctl add-flow vswitch0 "table=1,priority=1,in_port=1,actions=output:4" # ovs-ofctl add-flow vswitch0 "table=1,priority=2,in_port=4,actions=output:1"
嘗試ping對端,能夠成功ping通,說明數據包被正確處理。
# ip netns exec ns1 ping 192.168.1.200 PING 192.168.1.200 (192.168.1.200) 56(84) bytes of data. 64 bytes from 192.168.1.200: icmp_seq=1 ttl=64 time=0.329 ms 64 bytes from 192.168.1.200: icmp_seq=2 ttl=64 time=0.048 ms ^C --- 192.168.1.200 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1048ms rtt min/avg/max/mdev = 0.048/0.188/0.329/0.141 ms