任務目的
1、 掌握OpenFlow交換機發送Packet-in消息過程及其消息格式。
2、 掌握OpenFlow控制器發送Packet-out消息過程及其消息格式。
實驗原理
Packet-In
使用Packet-In消息的目的是為了將到達OpenFlow交換機的數據包發送至OpenFlow控制器。以下2種情況即可發送Packet-In消息。
不存在與流表項一致的項目時(Table-miss),OFPR_NO_MATCH
匹配的流表項中記載的行動為“發送至OpenFlow控制器”時,OFPR_ACTION
發送Packet-In消息時OpenFlow交換機分為兩種情況,一種是緩存數據包,一種是不緩存數據包。如果不通過OpenFlow交換機緩存數據包,那么Packet-In消息的buffer_id字段設置為-1,將整個數據包發送至OpenFlow控制器。
如果通過OpenFlow交換機緩存數據包,那么以通過SET_CONFIG消息設置的miss_send_len為最大值的數據包數據將發送至OpenFlow控制器。
miss_send_len的默認值為128。未實施SET_CONFIG消息的交換時,使用該默認值。

| 字段 | 比特數 | 內容 |
| buffer_id | 32 | 表示OpenFlow交換機中保存的數據包的緩存id |
| Total_len | 16 | 幀的長度 |
| in_port | 16 | 接受幀的端口 |
| reason | 8 | 發送Packet-in消息的原因 |
| pad | 8 | 用於調整對齊的填充 |
| data | 任意 | 包含以太網幀的數據時使用的字段。 |
Packet-Out
Packet-Out消息是從OpenFlow控制器向OpenFlow交換機發送的消息,是包含數據包發送命令的消息”。
若OpenFlow交換機的緩存中已存在數據包,而OpenFlow控制器發出“發送該數據包”的命令時,該消息指定了表示相應數據包的buffer_id。使用Packet-Out消息還可將OpenFlow控制器創建的數據包發送至OpenFlow交換機。此時,buffer_id置為-1,在Packet-Out消息的最后添加數據包數據。

| 字段 | 比特數 | 內容 |
| buffer_id | 32 | 表示OpenFlow交換機中保存的數據包的緩存id |
| in_port | 16 | 數據包的輸入端口 |
| actions_len | 16 | 行動信息的長度 |
制器與OpenFlow交換機在連接建立過程中會存在拓撲發現的環節,該環節會密集出現Packe-in/out消息,其交互流程如下:

1、 SDN控制器通過構造Packet-out消息,向交換機s1的三個端口分別發送上圖所示的LLDP數據包。
2、 控制器向交換機s1下發流表,流表規則為:將從Controller端口收到的LLDP數據包從規定端口發送出去。
3、 控制器向交換機s2下發流表,流表規則為:將從非Controller接收到LLDP數據包發送給控制器。
4、 當LLDP數據包到達交換機s2,會觸發Packet-in消息發往控制器。控制器通過解析LLDP數據包,得到鏈路的源交換機,源接口(s1,port1)。通過收到的Packet-in消息知道目的交換機(s2)。
5、 同理,當SDN控制器向交換機s2發送Packet-out消息時,可以得知鏈路源交換機,源接口(s2,port3)。通過收到的Packet-in消息知道目的交換機(s1)。如此,控制器便發現了s1與s2之間的完整鏈路。
對於存在多個交換機的網絡,上述分析過程一樣成立。
實驗步驟
步驟 1
登錄控制器,切換至root用戶。輸入如下命令,啟動RYU相關應用。
ryu-manager --verbose --observe-links ryu.topology.switches ryu.app.rest_topology ryu.app.ofctl_rest ryu.app.simple_switch_13
步驟 2
再打開新的命令窗口,切換到root用戶。執行wireshark命令啟動Wireshark,抓包enp0s17
步驟 3
登錄Mininet所在的主機,切換至root用戶。執行命令mn —controller=remote,ip=30.0.1.3, port=6633 —switch=ovsk,protocols=OpenFlow13 —topo=linear,2,如下圖所示。
步驟 4
執行命令links
步驟 5
登錄控制器,停止Wireshark,觀察數據包列表,可以看出控制器與交換機的基本交互流程。

Packet in/out消息詳解
步驟1 登錄Mininet所在的主機,查看交換機s1的流表信息(s2同理):
ovs-ofctl dump-flows -O OpenFlow13 s1
root@mininet:~# ovs-ofctl dump-flows -O OpenFlow13 s1
cookie=0x0, duration=495.916s, table=0, n_packets=552, n_bytes=33120, priority=65535,dl_dst=01:80:c2:00:00:0e,dl_type=0x88cc actions=CONTROLLER:65535
cookie=0x0, duration=495.923s, table=0, n_packets=50, n_bytes=4923, priority=0 actions=CONTROLLER:65535
紅色標記的流表項中:dl_type=0x88cc表示LLDP幀,dl_dst=01:80:c2:00:00:0e表示目的MAC地址為局域網組播地址,actions=CONTROLLER:65535表示行動為發往控制器的65535端口,意味着輸入到交換機中的LLDP組播幀都會發送到控制器。
步驟2 在控制器Wireshark抓取的數據包中,尋找包含LLDP包的Packet-out消息並雙擊,詳細信息展示如下。

可以看出,該控制器與OpenFlow交換機協商的OpenFlow版本為1.3版本,消息類型為Packet-out。由紅色標記部分信息可以看出Packet-out消息中包含LLDP幀,動作為從交換機的端口2發出,以此來檢測網絡拓撲結構。
步驟3 在控制器Wireshark抓取的數據包中,尋找包含LLDP包的Packet-in消息並雙擊,詳細信息展示如下。

當LLDP幀被發送至相鄰的交換機后,與事先設置好的流表項進行匹配(紅色標記表示Packet-in消息觸發原因為:匹配的流表項的行動為“發往控制器”),通過Packet-in消息封裝LLDP幀,把消息發送到控制器。
步驟4 在控制器中重啟Wireshark,准備抓取Packet-in消息。
步驟5 在Mininet主機中,刪除交換機s1的流表,同時快速進行Ping操作。
$ sh ovs-ofctl del-flows s1 -O OpenFlow13
$ sh ovs-ofctl dump-flows s1 -O OpenFlow13
$ h1 ping h2

步驟6 在控制器中查看Wireshark,添加過濾條件icmp,尋找觸發原因為“OFPR_NO_MATCH”的Packet-in消息並雙擊。該消息的詳細情況如下。

由於OpenFlow交換機中不存在流表項,故發送到OpenFlow交換機的ICMP包無法匹配流表,只好封裝並上傳到控制器。紅色標記表明該Packet-in消息觸發原因為:不存在匹配的流表項(OFPR_NO_MATCH)。
