OpenFlow通信流程解讀


1 前言

接觸了這么久的SDN,OpenFlow協議前前后后也讀過好多遍,但是一直沒有時間總結一下自己的一些見解。現在有時間了,就寫一寫自己對OpenFlow協議通信流程的一些理解。

2 SDN中Switch和controller

在SDN中很重要的兩個實體是Switch跟Controller。Controller在網絡中相當於上帝,可以知道網絡中所有的消息,可以給交換機下發指令。Switch就是一個實現Controller指令的實體,只不過這個交換機跟傳統的交換機不一樣,他的轉發規則由流表指定,而流表由控制器發送。

2.1 switch組成與傳統交換機的差異

switch組成

switch由一個Secure Channel和一個flow table組成,of1.3之后table變成多級流表,有256級。而of1.0中table只在table0中。

  • Secure Channel是與控制器通信的模塊,switch和controller之間的連接時通過socket連接實現。
  • Flow table里面存放這數據的轉發規則,是switch的交換轉發模塊。數據進入switch之后,在table中尋找對應的flow進行匹配,並執行相應的action,若無匹配的flow則產生packet_in(后面有講)

of中sw與傳統交換機的差異

  • 匹配層次高達4層,可以匹配到端口,而傳統交換機只是2層的設備。
  • 運行of協議,實現許多路由器的功能,比如組播。
  • 求補充!!(如果你知道,請告訴我,非常感謝!)

OpenFlow的switch可以從以下方式獲得

  • 實體of交換機,目前市場上有一些廠商已經制造出of交換機,但是普遍反映價格較貴!性能最好。
  • 在實體機上安裝OVS,OVS可以使計算機變成一個OpenFlow交換機。性能相對穩定。
  • 使用Mininet模擬環境。可以搭建許多交換機,任意拓撲,搭建拓撲具體教程本博客有一篇。性能依賴虛擬機的性能。

2.2 controller組成

控制器有許多種,不同的語言,如python寫的pox、ryu,如java寫的Floodlight等等。從功能層面controller分為以下幾個模塊:

  • 底層通信模塊:OpenFlow中目前controller與switch之間使用的是socket連接,所以控制器底層的通信是socket。
  • OpenFlow協議。socket收到的數據的處理規則需按照OpenFlow協議去處理。
  • 上層應用:根據OpenFlow協議處理后的數據,開發上層應用,比如pox中就l2_learning、l3_learning等應用。更多的應用需要用戶自己去開發。

3 OpenFlow通信流程

以下教程環境為:Mininet+自編簡單控制器+scapy封裝

3.1 建立連接

首先啟動Mininet,Mininet會自行啟動一個default拓撲,你也可以自己建立你的拓撲。sw建立完成之后,會像controllerIP:controllerport發送數據。

controller啟動之后,監聽指定端口,默認6633,但是好像以后的都改了,因為該端口被其他協議占用。

3次握手之后,建立連接,這個是底層的通信,是整一套系統的基礎設施。

3.2 OFPT_HELLO

創建socket之后,sw跟controller會彼此發送hello數據包。

  • 目的:協議協商。
  • 內容:本方支持的最高版本的協議
  • 成果:使用雙方都支持的最低版本協議。
  • 成功:建立連接
  • 失敗:OFPT_ERROR (TYPE:OFPT_HELLO_FAILED,CODE =0),終止連接。

3.3 OFPT_ERROR

說到OFPT_ERROR,我們不妨先了解一下。

錯誤類型如上所示。對應的type還會有對應的code。所以報錯的格式為:

如 TYPE:0 CODE:0為:OFPHFC_INCOMPATIBLE

具體對應的關系,請自行查看OF協議。

3.4 OFPT_ECHO

  • 分類:對稱信息 OFPT_ECHO_REQUEST, OFPT_ECHO_REPLY
  • 作用:查詢連接狀態,確保通信通暢。

當沒有其他的數據包進行交換時,controller會定期循環給sw發送OFPT_ECHO_REQUEST。

3.5 OFPT_FEATURES

當sw跟controller完成連接之后,控制器會向交換機下發OFPT_FEATYRES_REQUEST的數據包,目的是請求交換機的信息。

  • 發送時間:連接建立完成之后
  • 發送數據:OFPT_FEATURES_REQUEST
  • 對稱數據:OFPT_FEATURES_REPLY
  • 目的:獲取交換機的信息

OFPT_FEATURES_REQUEST

  • TYPE=5
  • Without data

OFPT_FEATURES_REPLY

  • TYPE =6
  • [0:8]為header
  • [8:32]長度24byte為sw的features
  • [32:]長度與端口數成正比,存放port的信息。每一個port信息長度為48byte。

以上的結構是交換機的features,緊跟在后面的是端口的結構:

交換機和端口的配置信息在整一個通信過程起着至關的作用,因為所有關於的操作都需要從features里面提取相關的信息,如dpid、port_no,等在整個通信過程中多次被用到的重要數據。所以,對這兩個數據結構了然於心,對於研究OpenFlow來說,至關重要。每一次交換機連到控制器,都會收到控制器的features_request,當sw將自己的features回復給控制器之后,控制器就對交換機有了一個全面的了解,從而為后面的控制提供的控制信息。

3.6 OFPT_PACKET_IN

在控制器獲取完交換機的特性之后,交換機開始處理數據。

對於進入交換機而沒有匹配流表,不知道如何操作的數據包,交換機會將其封裝在packet_in中發給controller。包含在packet_in中的數據可能是很多種類型,arp和icmp是最常見的類型。

當然產生packet_in的原因不止一種,產生packet_in的原因主要有一下兩種:

  • OFPR_NO_MATCH
  • OFPR_ACTION

無法匹配的數據包會產生packet_in,action也可以指定將數據包發給packet_in,也就是說我們可以利用這一點,將需要的數據包發給控制器。

packet_in事件之后,一般會觸發兩類事件:

  • packet_out
  • flow_mod

如果是廣播包,如arp,控制器一般會將其包裝起來,封裝成packet_out數據包,將其發給交換機,讓其flood,flood操作是將數據包往除去in_port以外的所有端口發送數據包。

3.7 OFPT_PACKET_OUT

很多人不是特別了解packet_out的作用。

  • 作用:通過控制器發送交換機希望發送的數據
  • 例子:arp在廣播的時候,在ofsw中不能直接將arp廣播,需要上報控制器,控制器下發packet_out,指定交換機對該數據包做泛洪操作。

PS:前一個版本此處有誤:特此聲明。packet_out的作用在與指導交換機做flood操作,並把ARP包廣播出去,packet_out本身並不攜帶arp數據包。

3.8 OFPT_FLOW_MOD

OFPT_FLOW_MOD是整個OpenFlow協議中最重要的數據結構,沒有之一。

OFPT_FLOW_MOD由header+match+flow_mod+action[]組成。為了操作簡單,以下的結構是將wildcards和match分開的形式,形成兩個結構,在編程的時候能更方便一些。由於這個數據包很重要,所以,我將把這個數據包仔細拆分解讀。

OFP_HEADER

header是所有數據包的報頭,有三個參數:

  • type:類型
  • length:整個數據包的長度
  • xid:數據包的編號

比如ofp_flow_mod的type就是14,具體的哪一種數據的類型將在文章最后給出。length最基本長度為72,每一個action長度為8。所以長度必定為8的倍數才是一個正確的數據長度。

WILDCARDS

這是從match域提取出來的前32bit。

在of1.0中這里的0,1意義跟我們平時接觸的如子網掩碼等意義相反,如OFPFW_NW_DST_MASK=0則表示全匹配目標IP。如果為63,則表示不匹配IP。為什么拿這個舉例?原因就在於,他的長度是6bit,最大是63,需要將數值轉變成對應2進制數值才是我們想要的匹配規則,且注意,1是忽略,0是匹配。如果wildcards全0,則表示由match精確指定,即所有12元組都匹配。

當然高興的是,在1.3的時候,這個邏輯改成了正常的與邏輯。即1為使能匹配,0為默認不匹配。

MATCH

這個數據結構會出現在機會所有重要的數據包中,因為他存的就是控制信息。

如有packet_in引發的下發流表,則match部分應對應填上對應的數據,這樣下發的流表才是正確的。

但是在下發的時候還需要注意許多細節,比如:

  • 並不是所有的數據包都有vlan_tag。如0x0800就是純IP,並沒有攜帶vlan_tag,所以填充式應根據packet_in的具體情況填充。
  • 並不是所有的數據都有四層端口,所以四層的源端口,目的端口都不是任何時候都能由packet_in去填充的。不去管就好了,默認的會填充一個默認值,匹配的時候不去匹配4層端口就沒有問題。

FLOW_MOD

這里面的信息也是至關重要的。

command里面的類型決定了flow_mod的操作是添加,修改還是刪除等。類型如下

例如:如果要添加一條新流,command=0。

兩個時間參數idle_timeout & idle_timeout:

  • idle_timeout:如值為10,則某條流在10秒之內沒有被匹配,則刪除,可以稱之為活躍時間吧。
  • hard_timeout:如值為30,則30秒到達的時候,一定刪除這條流,即使他還活躍,即被匹配。

priority

priority是流的優先級的字段,字數越大則優先級越高,存放在號數越小的table中。

buffer_id

由交換機指定的buffei_id,准確的說是由dpid指定的。如果是手動下發的流,buffer_id應填-1,即0xffff,告訴交換機這個數據包並沒有緩存在隊列中。

out_port

指定流的出口,但是這個出口並不是直接指導流轉發的,至少我是這么覺得,指導流轉發的出口會在action里面添加,這個端口是為了在flow_removed的時候查詢,並返回控制器的作用。(求糾正!)

有一些端口是很特殊的,如flood、local等。具體分類如下:

如果你不知道端口是多少,最好填flood,也就是0xfffb。

flags

在上面的注釋中也說得比較清楚了。如果沒有特殊用處,請將他置1,因為這樣能讓交換機在刪除一條流的時候給交換機上報flow_removed信息。

3.9 ACTION

action是OpenFlow里面最重要的結構。對,他也是最重要的。每一條流都必須指定必要的action,不然匹配上之后,沒有指定action,交換機會默認執行drop操作。

action有2種類型:

  • 必備行動:Forward and Drop
  • 選擇行動:FLOOD、NALMAL 等

如添加output就是一個必須要添加的action。每一個action最好有一個action_header(),然后再接一個實體。如:

具體的action類型如下:

action不僅僅會出現在flow_mod中,也會出現在如stats_reply中。

3.10 OFPT_BARRIER_REQUEST && REPLY

這個數據包可以的作用很簡單,交換機在收到OFPT_BARRIER_REQUEST的時候,會回復控制器一個OFPT_BARRIER_REPLY。我們默認數據下發的順序不會在傳輸中發生變化,在進入消息隊列之后處理也是按照FIFO進行的,那么只要在flow_mod之后發送這個數據,當收到reply之后,交換機默認flow已經寫成功。也許你會問他只是保證了flow_mod命令執行了,寫入的結果如何並沒有保證,如何確定確實寫入流表了呢?

  • 如果非邏輯錯誤,那么交換機在處理flow_mod的時候會報錯。所以我們會知道寫入結果。
  • 如果是邏輯錯誤,那么會寫進去,但是邏輯錯誤應該是人的問題,所以barrier還是有他的功能的。

3.11 OFPT_FLOW_REMOVED

如果flow_mod的flags填成1,則該流在失效之后會回復控制器一條OFPT_FLOW_REMOVED信息。

  • 結構:header()/wildcards()/match()/flow_removed()
  • 作用:在流失效的時候回復控制器,並攜帶若干統計數據。

其實的duration_sec是流存在的時間,單位為秒,duration_nsec單位為納秒。

3.12 OFPT_STATS_REQUEST && REPLY

以上的數據都是通信過程中必須的部分。還有一些數據包是為了某些目的而設計的,如OFPT_STATS_REQUEST && REPLY可以獲得統計信息,我們可以利用統計信息做的事情就太多了。如:負載平衡, 流量監控等基於流量的操作。

OFPT_STATS_REQUEST

OFPT_STATS_REQUEST類型有很多,回復的類型也很多。

Type

  • 0:請求交換機版本信息,制造商家等信息。
  • 1:單流請求信息
  • 2:多流請求信息
  • 3:流表請求信息
  • 4:端口信息請求
  • 5:隊列請求信息
  • 6:vendor請求信息,有時候沒有定義。

 

 

OFPT_STATS_REPLY

每一種請求信息都會對應一種回復信息。我們只介紹最重要的flow_stats_reply。

  • 結構:header(type=17)/reply_header()/flow_stats/wildcards/match/ flow_stats_data
  • 作用:攜帶流的統計信息,如通過的數據包個數,字節數。

ofp_flow_stats(body[4:8])里面會有的table_id字段表明該流存放在哪一個流表里。flow_stats_data里面有packet_count和byte_count是最有價值的字段,流量統計就是由這兩個字段提供的信息。如想統計某條流的速率:前后兩個reply的字節數相減除以duration_time只差就可以求得速率。由速率我們可以做很多基於流量的app,如流量監控,負載均衡等等。

值得注意的是,在這些數據之后,其實還有一些action,但是目前我還沒有查看這些action到底是干什么用的。

4 后續

寫到這里,我使用到的數據包都寫了一遍,其他的報文其實道理也是一樣的。如OFPT_GET_CONFIG_REQUEST和REPLY,道理應該和stats一樣,只是數據結構不一樣罷了。不再多說。

最后把我們用的一些比較多的信息帖出來讓大家更好的學習。
ERROR
在調試的過程中遇到錯誤是再所難免的,前面也提到了error的結構。這里就貼一下type跟code吧。
Type

相關的code:

謝謝我的兩個師傅richardzhao,kimi帶我走進OpenFlow的世界。整篇文檔均為牧紫星原創,轉載請聲明告知。希望能給你帶來一些幫助。
 


免責聲明!

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



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