收到 ofp_stats_reply 數據包,但 POX 框架相關教程很少,沒有解析方法教學。其實可以直接用 print 方法打印出來,POX 在這方面的支持很友好,格式縮進什麼的也很體貼。
如下是 MAC 地址爲 00-00-00-00-00-04,DPID 爲 9 的交換機上報的 ofp_stats_reply 消息:
[00-00-00-00-00-04 9] ofp_stats_reply
[00-00-00-00-00-04 9] header:
[00-00-00-00-00-04 9] version: 1
[00-00-00-00-00-04 9] type: 17 (OFPT_STATS_REPLY)
[00-00-00-00-00-04 9] length: 396
[00-00-00-00-00-04 9] xid: 330
[00-00-00-00-00-04 9] type: 1
[00-00-00-00-00-04 9] flags: 0
[00-00-00-00-00-04 9] body:
[00-00-00-00-00-04 9] length: 96
[00-00-00-00-00-04 9] table_id: 0
[00-00-00-00-00-04 9] match:
[00-00-00-00-00-04 9] wildcards: nw_tos|tp_dst|dl_dst|dl_src|dl_vlan_pcp|dl_vlan|tp_src (1100000000000011001110 = 3000ce)
[00-00-00-00-00-04 9] in_port: 2
[00-00-00-00-00-04 9] dl_type: 0x800
[00-00-00-00-00-04 9] nw_proto: 17
[00-00-00-00-00-04 9] nw_src: 10.0.0.11
[00-00-00-00-00-04 9] nw_dst: 10.0.0.8
[00-00-00-00-00-04 9] duration_sec: 58
[00-00-00-00-00-04 9] duration_nsec: 696000000
[00-00-00-00-00-04 9] priority: 3
[00-00-00-00-00-04 9] idle_timeout: 0
[00-00-00-00-00-04 9] hard_timeout: 0
[00-00-00-00-00-04 9] cookie: 0
[00-00-00-00-00-04 9] packet_count: 0
[00-00-00-00-00-04 9] byte_count: 0
[00-00-00-00-00-04 9] actions:
[00-00-00-00-00-04 9] type: 0
[00-00-00-00-00-04 9] len: 8
[00-00-00-00-00-04 9] port: 4
[00-00-00-00-00-04 9] max_len: 0
[00-00-00-00-00-04 9]
[00-00-00-00-00-04 9] length: 96
[00-00-00-00-00-04 9] table_id: 0
[00-00-00-00-00-04 9] match:
[00-00-00-00-00-04 9] wildcards: nw_tos|tp_dst|dl_dst|dl_src|dl_vlan_pcp|dl_vlan|tp_src (1100000000000011001110 = 3000ce)
[00-00-00-00-00-04 9] in_port: 4
[00-00-00-00-00-04 9] dl_type: 0x800
[00-00-00-00-00-04 9] nw_proto: 17
[00-00-00-00-00-04 9] nw_src: 10.0.0.8
[00-00-00-00-00-04 9] nw_dst: 10.0.0.11
[00-00-00-00-00-04 9] duration_sec: 58
[00-00-00-00-00-04 9] duration_nsec: 656000000
[00-00-00-00-00-04 9] priority: 3
[00-00-00-00-00-04 9] idle_timeout: 0
[00-00-00-00-00-04 9] hard_timeout: 0
[00-00-00-00-00-04 9] cookie: 0
[00-00-00-00-00-04 9] packet_count: 0
[00-00-00-00-00-04 9] byte_count: 0
[00-00-00-00-00-04 9] actions:
[00-00-00-00-00-04 9] type: 0
[00-00-00-00-00-04 9] len: 8
[00-00-00-00-00-04 9] port: 2
[00-00-00-00-00-04 9] max_len: 0
[00-00-00-00-00-04 9]
[00-00-00-00-00-04 9] length: 96
[00-00-00-00-00-04 9] table_id: 0
[00-00-00-00-00-04 9] match:
[00-00-00-00-00-04 9] wildcards: nw_tos|tp_dst|dl_dst|dl_src|dl_vlan_pcp|dl_vlan|tp_src (1100000000000011001110 = 3000ce)
[00-00-00-00-00-04 9] in_port: 4
[00-00-00-00-00-04 9] dl_type: 0x800
[00-00-00-00-00-04 9] nw_proto: 17
[00-00-00-00-00-04 9] nw_src: 10.0.0.19
[00-00-00-00-00-04 9] nw_dst: 10.0.0.12
[00-00-00-00-00-04 9] duration_sec: 58
[00-00-00-00-00-04 9] duration_nsec: 621000000
[00-00-00-00-00-04 9] priority: 3
[00-00-00-00-00-04 9] idle_timeout: 0
[00-00-00-00-00-04 9] hard_timeout: 0
[00-00-00-00-00-04 9] cookie: 0
[00-00-00-00-00-04 9] packet_count: 0
[00-00-00-00-00-04 9] byte_count: 0
[00-00-00-00-00-04 9] actions:
[00-00-00-00-00-04 9] type: 0
[00-00-00-00-00-04 9] len: 8
[00-00-00-00-00-04 9] port: 3
[00-00-00-00-00-04 9] max_len: 0
[00-00-00-00-00-04 9]
[00-00-00-00-00-04 9] length: 96
[00-00-00-00-00-04 9] table_id: 0
[00-00-00-00-00-04 9] match:
[00-00-00-00-00-04 9] wildcards: nw_tos|tp_dst|dl_dst|dl_src|dl_vlan_pcp|dl_vlan|tp_src (1100000000000011001110 = 3000ce)
[00-00-00-00-00-04 9] in_port: 3
[00-00-00-00-00-04 9] dl_type: 0x800
[00-00-00-00-00-04 9] nw_proto: 17
[00-00-00-00-00-04 9] nw_src: 10.0.0.12
[00-00-00-00-00-04 9] nw_dst: 10.0.0.19
[00-00-00-00-00-04 9] duration_sec: 58
[00-00-00-00-00-04 9] duration_nsec: 621000000
[00-00-00-00-00-04 9] priority: 3
[00-00-00-00-00-04 9] idle_timeout: 0
[00-00-00-00-00-04 9] hard_timeout: 0
[00-00-00-00-00-04 9] cookie: 0
[00-00-00-00-00-04 9] packet_count: 0
[00-00-00-00-00-04 9] byte_count: 0
[00-00-00-00-00-04 9] actions:
[00-00-00-00-00-04 9] type: 0
[00-00-00-00-00-04 9] len: 8
[00-00-00-00-00-04 9] port: 4
[00-00-00-00-00-04 9] max_len: 0
數據包主要分爲四部分:
- header
- type
- flags
- body:是一個 list,有多少條流表就包含多少個元素,應使用 for 循環依次解析。
接下來依次分析這四個部分。
header
header 內包含四個字段:
- version:OpenFlow 版本號,上例中爲 1(0x01) 即爲 OpenFlow 1.0 版本,後續版本 1.1、1.2、1.3 的 version 值遞增,即爲 2、3、4。
- type:OpenFlow 消息類型,定義在枚舉類 ofp_type 中,主要包括:
enum ofp_type {
/* Immutable messages. /
OFPT_HELLO, / Symmetric message /
OFPT_ERROR, / Symmetric message /
OFPT_ECHO_REQUEST, / Symmetric message /
OFPT_ECHO_REPLY, / Symmetric message /
OFPT_VENDOR, / Symmetric message /
/ Switch configuration messages. /
OFPT_FEATURES_REQUEST, / Controller/switch message /
OFPT_FEATURES_REPLY, / Controller/switch message /
OFPT_GET_CONFIG_REQUEST, / Controller/switch message /
OFPT_GET_CONFIG_REPLY, / Controller/switch message /
OFPT_SET_CONFIG, / Controller/switch message /
/ Asynchronous messages. /
OFPT_PACKET_IN, / Async message /
OFPT_FLOW_REMOVED, / Async message /
OFPT_PORT_STATUS, / Async message /
/ Controller command messages. /
OFPT_PACKET_OUT, / Controller/switch message /
OFPT_FLOW_MOD, / Controller/switch message /
OFPT_PORT_MOD, / Controller/switch message /
/ Statistics messages. /
OFPT_STATS_REQUEST, / Controller/switch message /
OFPT_STATS_REPLY, / Controller/switch message /
/ Barrier messages. /
OFPT_BARRIER_REQUEST, / Controller/switch message /
OFPT_BARRIER_REPLY, / Controller/switch message /
/ Queue Configuration messages. /
OFPT_QUEUE_GET_CONFIG_REQUEST, / Controller/switch message /
OFPT_QUEUE_GET_CONFIG_REPLY / Controller/switch message */
};
- length:消息總長度,包含頭部,單位爲字節。
- xid:事件 ID,同一事件的 ID一致。如 ofp_stats_request 和對應的 ofp_stats_reply 就使用同一個事件 ID。
type
type 表示這個 ofp_stats_request/ofp_stats_reply 消息請求/迴應的統計類型,決定如何解析 body 字段。類型如表所示:
取值 | 消息類型 | 說明 | 請求 body | 回覆 body |
---|---|---|---|---|
0 | OFPMP_DESC | 整體統計信息 | 空 | ofp_desc_stats(製造商、軟硬件描述、序列號、可讀的數據通道描述) |
1 | OFPMP_FLOW | 單流請求信息 | ofp_aggregate_stats_request(要讀的 TABLE_ID 或 OFPPT_ALL 代表讀所有表) | ofp_aggregate_stats_reply(這個項的長度、TABLE ID、流已生成的時間、超過已生成時間的時間、優先級、硬超時時間、未命中時間、包數目、字節數) |
2 | OFPMP_AGGREGATE | 多流請求信息 | ofp_aggregate_stats_request(要讀的 TABLE_ID) | ofp_aggregate_stats_replay(包數目、字節數、流數目) |
3 | OFPMP_TABLE | 流表請求信息 | 空 | ofp_table_stats(表的標識符、通配符、最大支持的流表項、活躍流表項的數量、被查找表的數量、匹配表的數量) |
4 | FPMP_PORT_STATS | 端口信息請求 | fp_port_stats_request(端口號或 OFPP_ANY 代表所有端口) | ofp_port_stats(收到包的數量、已傳送包的數量、收到的字節數、傳送的字節數、被 RX 丟棄的包數、被 RX 丟棄的包數、接收到錯誤的包數、幀調整的錯誤數量、在 RX 溢出的數據包數、CRC 錯誤數、衝突數量) |
5 | OFPMP_QUEUE | 隊列請求信息 | - | - |
6 | - | vendor 請求信息 | - | - |
本例中的類型號爲 1,代表是單流請求信息。
flags
未定義。
body
已在 type 部分介紹,需按照類型解析。
編程實現 POX 控制器發送 ofp_stats_request 和接收 ofp_stats_reply 並解析
只粘貼相關部分。
def req_for_flow_stats():
tik = 30
while True:
time.sleep(1)
tik = (tik - 1 + 30) % 30
if tik == 0:
allCon = core.openflow.connections
for con in allCon:
con.send(of.ofp_stats_request(body=of.ofp_flow_stats_request()))
class DefaultOpenFlowHandlers (OpenFlowHandlers):
"""
Basic OpenFlow message handling functionality
There is generally a single instance of this class which is shared by all
Connections.
"""
@staticmethod
def handle_STATS_REPLY (con, msg):
e = con.ofnexus.raiseEventNoErrors(RawStatsReply, con, msg)
if e is None or e.halt != True:
con.raiseEventNoErrors(RawStatsReply, con, msg)
con._incoming_stats_reply(msg)
dpid = con.dpid
if msg.type == of.OFPST_FLOW:
for f in msg.body:
print(f)
pkts = f.packet_count
byts = f.byte_count
if input_pkts != 0:
print("[byte, packet]: [", f.byte_count, f.packet_count, "]")
print(dpid, ", Path Loss Rate =", (input_pkts - output_pkts) * 1.0 / input_pkts * 100, "%")
完整實現見LXiao2015's GitHub