天天看點

RYU 控制器初探

預備知識

  • RYU 控制器是衆多 SDN 控制器中的一員,使用 Python 編寫,對開發者非常友好。RYU 控制器的官方文檔、API 文檔和源碼連結:
  • 在 OpenFlow 中,資料是以流的形式進行處理的。流表是針對特定資料流的政策表,用于決定資料流的流向。OpenFlow 官方文檔:​​本文的實驗基于 OpenFlow 1.3 版本。

流表檢視與比對示例

使用 ryu-manager 執行 GitHub 上的 ryu 官方的控制器例程,來建立 SDN 控制器:

sdn@debian:~$ sudo ryu-manager ryu/ryu/app/simple_switch_13.py 
loading app ryu/ryu/app/simple_switch_13.py
loading app ryu.controller.ofp_handler
instantiating app ryu/ryu/app/simple_switch_13.py of SimpleSwitch13
instantiating app ryu.controller.ofp_handler of OFPHandler
      

使用 mininet 連接配接 RYU 控制器,并建立隻有一個交換機和兩個主機的簡單的網絡拓撲:

sdn@debian:~$ sudo mn --controller=remote
*** Creating network
*** Adding controller
Connecting to remote controller at 127.0.0.1:6653
*** Adding hosts:
h1 h2 
*** Adding switches:
s1 
*** Adding links:
(h1, s1) (h2, s1) 
*** Configuring hosts
h1 h2 
*** Starting controller
c0 
*** Starting 1 switches
s1 ...
*** Starting CLI:
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0
c0
      

此時的網絡拓撲結構如下圖:

RYU 控制器初探

檢視交換機 s1 的流表資訊,此時 s1 中隻有一條流表項:

mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
cookie=0x0, duration=40.319s, table=0, n_packets=16, n_bytes=1272, priority=0 actions=CONTROLLER:65535
      

​actions=CONTROLLER:65535​

​ 是交換機的 Table-miss 流表項,該流表項的比對域為通配,即比對任何封包,優先級為 0(優先級最低)。也就是說,當收到的資料包沒有比對到任意一條流表項時,則将該資料包發送給 controller,且限制資料包最大長度為 65535 位元組。

在 mininet 中執行 ​

​pingall​

​,來測試 h1、h2 的聯通性:

mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 
h2 -> h1 
*** Results: 0% dropped (2/2 received)
      

再檢視 s1 的流表資訊:

mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
cookie=0x0, duration=39.658s, table=0, n_packets=3, n_bytes=238, priority=1,in_port="s1-eth2",dl_src=62:cc:b8:e8:2f:6b,dl_dst=d2:12:9f:77:82:71 actions=output:"s1-eth1"
cookie=0x0, duration=39.655s, table=0, n_packets=2, n_bytes=140, priority=1,in_port="s1-eth1",dl_src=d2:12:9f:77:82:71,dl_dst=62:cc:b8:e8:2f:6b actions=output:"s1-eth2"
cookie=0x0, duration=198.655s, table=0, n_packets=23, n_bytes=1734, priority=0 actions=CONTROLLER:65535

      

此時 s1 中新增了兩條流表項:

cookie=0x0, duration=39.658s, table=0, n_packets=3, n_bytes=238, priority=1,in_port="s1-eth2",dl_src=62:cc:b8:e8:2f:6b,dl_dst=d2:12:9f:77:82:71 actions=output:"s1-eth1"
cookie=0x0, duration=39.655s, table=0, n_packets=2, n_bytes=140, priority=1,in_port="s1-eth1",dl_src=d2:12:9f:77:82:71,dl_dst=62:cc:b8:e8:2f:6b actions=output:"s1-eth2"

      

​in_port="s1-eth2",dl_src=62:cc:b8:e8:2f:6b,dl_dst=d2:12:9f:77:82:71 actions=output:"s1-eth1"​

​ 訓示 s1,當端口 ​

​s1-eth2​

​ 接收到源 MAC 為 ​

​62:cc:b8:e8:2f:6b​

​,目标 MAC 為 ​

​d2:12:9f:77:82:71​

​ 的資料包時,則将該資料包發送到與端口 ​

​s1-eth1​

​ 連接配接的主機。而 h1 和 h2 的 MAC 位址,正好分别是 ​

​d2:12:9f:77:82:71​

​ 和 ​

​62:cc:b8:e8:2f:6b​

​:

mininet> h1 ifconfig h1-eth0
h1-eth0: flags=4163<up,broadcast,running,multicast>  mtu 1500
        inet 10.0.0.1  netmask 255.0.0.0  broadcast 10.255.255.255
        inet6 fe80::d012:9fff:fe77:8271  prefixlen 64  scopeid 0x20<link>
        ether d2:12:9f:77:82:71  txqueuelen 1000  (Ethernet)
        RX packets 35  bytes 3498 (3.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 16  bytes 1216 (1.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

mininet> h2 ifconfig h2-eth0
h2-eth0: flags=4163<up,broadcast,running,multicast>  mtu 1500
        inet 10.0.0.2  netmask 255.0.0.0  broadcast 10.255.255.255
        inet6 fe80::60cc:b8ff:fee8:2f6b  prefixlen 64  scopeid 0x20<link>
        ether 62:cc:b8:e8:2f:6b  txqueuelen 1000  (Ethernet)
        RX packets 35  bytes 3498 (3.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 16  bytes 1216 (1.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      

換而言之,​

​in_port="s1-eth2",dl_src=62:cc:b8:e8:2f:6b,dl_dst=d2:12:9f:77:82:71 actions=output:"s1-eth1"​

​s1-eth2​

​ 接收到 h2 發送給 h1 的資料包時,則将該資料包發送到與端口 ​

​s1-eth1​

​ 連接配接的主機,也就是 h1:

mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0
c0
      

​in_port="s1-eth1",dl_src=d2:12:9f:77:82:71,dl_dst=62:cc:b8:e8:2f:6b actions=output:"s1-eth2"​

​ 同理,不再贅述。

上述例子僅簡單示範了 OpenFlow 流表的檢視與比對,細節請參考官方文檔

流表項如何下發

流表項由 SDN 控制器生成并發送給 SDN 交換機。SDN 交換機維護了流表項,用于決定資料包的流向。由于本文的 SDN 控制器 RYU 與交換機之間使用的南向接口是 OpenFlow,是以接下來的内容依舊是基于 OpenFlow 進行分析。

TCP 握手

在 OpenFlow 中,控制平面與資料平面的傳輸協定是 TCP。

在上節中,使用 ryu-manager 執行官方例程來啟動 RYU 控制器後,控制器監聽在本地的 6653 端口:

tcp        0      0 0.0.0.0:6653            0.0.0.0:*               LISTEN      6264/python         
      

在 mininet 中連接配接 RYU 控制器時,控制器與交換機的 TCP 握手如下:

16:42:18.461536 IP localhost.51678 > localhost.6653: Flags [S], seq 1969037218, win 43690, options [mss 65495,sackOK,TS val 2494429579 ecr 0,nop,wscale 9], length 0
16:42:18.461556 IP localhost.6653 > localhost.51678: Flags [S.], seq 1946739924, ack 1969037219, win 43690, options [mss 65495,sackOK,TS val 2494429579 ecr 2494429579,nop,wscale 9], length 0
16:42:18.461574 IP localhost.51678 > localhost.6653: Flags [.], ack 1946739925, win 86, options [nop,nop,TS val 2494429579 ecr 2494429579], length 0
      

OpenFlow 版本協商

TCP 三次握手完成後,RYU 控制器與交換機互相發送 OFPT_HELLO 封包(省略其他無關的封包,如 TCP ACK 封包段和重傳封包段)。HELLO 封包用于協商 OpenFLow 版本。通過協商後,通信雙方決定使用的 OpenFlow 版本号為 1.3.0:

Frame 4: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51676, Seq: 1, Ack: 1, Len: 8
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_HELLO (0)
    Length: 8
    Transaction ID: 3155619061
Frame 12: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51678, Seq: 1, Ack: 1, Len: 8
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_HELLO (0)
    Length: 8
    Transaction ID: 1369246796
      

擷取交換機的功能特性

在完成 OpenFlow 版本協商後,控制器需要根據交換機的功能特性,來完成相關配置。是以,RYU 控制器往交換機發送一個 OFPT_FEATURES_REQUEST 封包,以擷取交換機的相關特性。作為響應,交換機回以一個 OFPT_FEATURES_REPLY 封包,其中包含了 datapath_id(在 OpenFlow 中,datapath 用于描述一個與控制器相連後的交換機)、n_buffers(單次資料包的接收最大緩沖)、n_tables(該交換機所能支援的流表數目)等資訊:

Frame 22: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51678, Seq: 9, Ack: 249, Len: 8
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_FEATURES_REQUEST (5)
    Length: 8
    Transaction ID: 1369246797

Frame 23: 98 bytes on wire (784 bits), 98 bytes captured (784 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 51678, Dst Port: 6653, Seq: 249, Ack: 17, Len: 32
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_FEATURES_REPLY (6)
    Length: 32
    Transaction ID: 1369246797
    datapath_id: 0x0000000000000001
    n_buffers: 0
    n_tables: 254
    auxiliary_id: 0
    Pad: 0
    capabilities: 0x0000004f
        .... .... .... .... .... .... .... ...1 = OFPC_FLOW_STATS: True
        .... .... .... .... .... .... .... ..1. = OFPC_TABLE_STATS: True
        .... .... .... .... .... .... .... .1.. = OFPC_PORT_STATS: True
        .... .... .... .... .... .... .... 1... = OFPC_GROUP_STATS: True
        .... .... .... .... .... .... ..0. .... = OFPC_IP_REASM: False
        .... .... .... .... .... .... .1.. .... = OFPC_QUEUE_STATS: True
        .... .... .... .... .... ...0 .... .... = OFPC_PORT_BLOCKED: False
    Reserved: 0x00000000
      

交換機發送端口狀态資訊

當交換機增删改端口時,需要發送 OFPT_PORT_STATUS 封包,以此通知控制器:

Frame 16: 146 bytes on wire (1168 bits), 146 bytes captured (1168 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 51678, Dst Port: 6653, Seq: 9, Ack: 9, Len: 80
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_PORT_STATUS (12)
    Length: 80
    Transaction ID: 0
    Reason: OFPPR_MODIFY (2)
    Pad: 00000000000000
    Port
        Port no: 2
        Pad: 00000000
        Hw addr: 1e:09:45:71:69:a6 (1e:09:45:71:69:a6)
        Pad: 0000
        Name: s1-eth2
    (略)
      

修改交換機的流表項資訊

控制器通過往交換機發送 OFPT_FLOW_MOD 封包,來調整交換機的流表。同時,在初始化階段,控制器往交換機發送了一條 Match 字段為空、資料最大長度為 65535 的 OFPT_FLOW_MOD 封包,可見這條封包就是用于設定交換機的 Table-miss 流表項:

Frame 26: 146 bytes on wire (1168 bits), 146 bytes captured (1168 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51678, Seq: 33, Ack: 489, Len: 80
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_FLOW_MOD (14)
    Length: 80
    Transaction ID: 1369246799
    Cookie: 0x0000000000000000
    Cookie mask: 0x0000000000000000
    Table ID: 0
    Command: OFPFC_ADD (0)
    Idle timeout: 0
    Hard timeout: 0
    Priority: 0
    Buffer ID: OFP_NO_BUFFER (4294967295)
    Out port: 0
    Out group: 0
    Flags: 0x0000
        .... .... .... ...0 = Send flow removed: False
        .... .... .... ..0. = Check overlap: False
        .... .... .... .0.. = Reset counts: False
        .... .... .... 0... = Don't count packets: False
        .... .... ...0 .... = Don't count bytes: False
    Pad: 0000
    Match
        Type: OFPMT_OXM (1)
        Length: 4
        Pad: 00000000
    Instruction
        Type: OFPIT_APPLY_ACTIONS (4)
        Length: 24
        Pad: 00000000
        Action
            Type: OFPAT_OUTPUT (0)
            Length: 16
            Port: OFPP_CONTROLLER (4294967293)
            Max length: OFPCML_NO_BUFFER (65535)
            Pad: 000000000000
      

PACKET_IN 和 PACKET_OUT 封包

上文提到,交換機在初始階段隻有一條預設流表項:

mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------
cookie=0x0, duration=161.361s, table=0, n_packets=19, n_bytes=1466, priority=0 actions=CONTROLLER:65535
      

是以, 當交換機收到主機發的第一個資料包時(如,在 mininet 執行 ​

​h1 ping h2​

​),會通過 PACKET_IN 封包, 将該資料包轉發到控制器,

Frame 4: 150 bytes on wire (1200 bits), 150 bytes captured (1200 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 51750, Dst Port: 6653, Seq: 9, Ack: 9, Len: 84
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_PACKET_IN (10)
    Length: 84
    Transaction ID: 0
    Buffer ID: OFP_NO_BUFFER (4294967295)
    Total length: 42
    Reason: OFPR_NO_MATCH (0)
    Table ID: 0
    Cookie: 0x0000000000000000
    Match
        (略)
      

控制器收到 PACKET_IN 封包,會根據程式邏輯(本文中就是 ryu/ryu/app/simple_switch_13.py 中的處理邏輯),生成相應的流表項,然後以 PACKET_OUT 封包,将流表項傳回給交換機:

Frame 5: 148 bytes on wire (1184 bits), 148 bytes captured (1184 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51750, Seq: 9, Ack: 93, Len: 82
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_PACKET_OUT (13)
    Length: 82
    Transaction ID: 3977916314
    Buffer ID: OFP_NO_BUFFER (4294967295)
    In port: 1
    Actions length: 16
    Pad: 000000000000
    Action
        (略)
      

交換機收到 PACKET_OUT 封包後,将流表項應用于資料包的轉發。

ECHO 封包

控制器與交換機之間,通過 ECHO 封包來保持連接配接的活性:

Frame 1: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 51750, Dst Port: 6653, Seq: 1, Ack: 1, Len: 8
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_ECHO_REQUEST (2)
    Length: 8
    Transaction ID: 0

Frame 2: 74 bytes on wire (592 bits), 74 bytes captured (592 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 6653, Dst Port: 51750, Seq: 1, Ack: 9, Len: 8
OpenFlow 1.3
    Version: 1.3 (0x04)
    Type: OFPT_ECHO_REPLY (3)
    Length: 8
    Transaction ID: 0
      

總結

RYU 控制器是 SDN 軟體定義網絡中的重要一環,使用 OpenFlow 協定作為南向接口來與交換機進行通信。RYU 對開發者而言是非常友好和容易了解的。至于交換機接收到 RYU 的流表資訊,如何作用到資料包的轉發,則需要在後續的學習中找到答案。