預備知識
- 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
此時的網絡拓撲結構如下圖:

檢視交換機 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 的流表資訊,如何作用到資料包的轉發,則需要在後續的學習中找到答案。