OpenFlow協(xié)議抓包實(shí)驗(yàn)
1 操作步驟
本實(shí)驗(yàn)采用opendaylight控制器和mininet冠蒋,使用mininet連接opendaylight论颅。連接后pingall測試連接是否成功袋励,測試完連通性后進(jìn)行抓包實(shí)驗(yàn)乙嘀。
打開wireshark抓包:
sudo wireshark
2 OpenFlow1.0協(xié)議解析
控制器通過Openflow管理、控制交換機(jī)预伺,分析wireshark抓到的OpenFlow包就可以大體推測控制器與交換機(jī)通信的流程订咸。雖然沒有進(jìn)行任何操作曼尊,但是一旦交換機(jī)連接控制器,wireshark就能捕捉到很多OpenFlow包脏嚷。依次是hello消息骆撇、feature消息,stats消息父叙,以及packet_in和packet_out神郊。
2.1 Hello
控制器與交換機(jī)建立連接時(shí)由其中某一方發(fā)起Hello消息,雙方協(xié)調(diào)協(xié)議版本號(hào)趾唱。Hello消息只有of包頭涌乳,沒有主體部分。而of頭部結(jié)果如下:
/* Header on all OpenFlow packets. */
struct ofp_header {
uint8_t version; /* OFP_VERSION. */
uint8_t type; /* One of the OFPT_ constants. */
uint16_t length; /* Length including this ofp_header. */
uint32_t xid; /* Transaction id associated with this packet.
Replies use the same id as was in the request
to facilitate pairing. */
};
OFP_ASSERT(sizeof(struct ofp_header) == 8);
Hello消息如下:
- Version:OpenFlow版本甜癞,低位為版本號(hào)夕晓,如上所示。
- Type:OpenFlow消息類型悠咱,主要包括:
注:
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號(hào)一致吁朦。如feature_request和對(duì)應(yīng)的feature_reply就使用同一個(gè)Transaction id,但是兩個(gè)hello消息的Transaction id并不相同渡贾,不過據(jù)實(shí)驗(yàn)結(jié)果看兩個(gè)id一般是兩個(gè)相鄰的數(shù)字逗宜。并且packet_in的transaction id都為0。
2.2 Feature消息
TLS會(huì)話一建立空骚,控制器就會(huì)向交換機(jī)發(fā)送一個(gè)ofpt_feature_request消息纺讲,該消息只有of包頭,如下所示囤屹。交換機(jī)會(huì)回復(fù)一條ofpt_feature_reply消息熬甚。
ofpt_feature_request如圖:(有時(shí)候會(huì)發(fā)現(xiàn)一個(gè)數(shù)據(jù)包中有多個(gè)request,并且后面會(huì)有一一對(duì)應(yīng)的reply包肋坚。)
ofpt_feature_reply如圖:
ofpt_feature_reply消息結(jié)構(gòu)如下:
注:
/* Switch features. */
struct ofp_switch_features {
struct ofp_header header;
uint64_t datapath_id; /* Datapath unique ID. The lower 48-bits are for a MAC address, while the upper 16-bits are implementer-defined. */
uint32_t n_buffers; /* Max packets buffered at once. */
uint8_t n_tables; /* Number of tables supported by datapath. */
uint8_t pad[3]; /* Align to 64-bits. */
/* Features. */
uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */
uint32_t actions; /* Bitmap of supported "ofp_action_type"s. */
/* Port info.*/
struct ofp_phy_port ports[0]; /* Port definitions. The number of ports is inferred from the length field in the header. */
};
OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
- datapath_id:數(shù)據(jù)通道獨(dú)一無二的標(biāo)識(shí)符乡括,低48位是一個(gè)MAC地址,而高16位是自定義的智厌。例如诲泌,用高16位代表VLAN ID區(qū)別一個(gè)物理交換機(jī)中的多個(gè)虛擬交換機(jī)。
- n_buffers:一次最多緩存的數(shù)據(jù)包數(shù)量铣鹏。
- n_tables:表示交換機(jī)支持的流表數(shù)量敷扫。而每個(gè)流表可以設(shè)置不同的通配符和不同數(shù)量的流表項(xiàng)〕闲叮控制器和交換機(jī)第一次通信的時(shí)候葵第,控制器會(huì)從feature_reply消息中找出交換機(jī)支持多少流表绘迁,如果控制器還想了解大小、類型和流表查詢的順序卒密,就發(fā)送一個(gè)ofpst_table stats請(qǐng)求脊髓,交換機(jī)必須按照數(shù)據(jù)包遍歷流表的順序把這些流表回復(fù)給控制器,并且精確匹配流表排在通配流表前栅受。
- capabilities:所支持的功能,該字段使用以下flags:
注:
/* Capabilities supported by the datapath. */
enum ofp_capabilities {
OFPC_FLOW_STATS = 1 << 0, /* Flow statistics. */
OFPC_TABLE_STATS = 1 << 1, /* Table statistics. */
OFPC_PORT_STATS = 1 << 2, /* Port statistics. */
OFPC_STP = 1 << 3, /* 802.1d spanning tree. */
OFPC_RESERVED = 1 << 4, /* Reserved, must be zero. */
OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */
OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */
OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP pkts. */
};
- actions:該bitmask表示交換機(jī)所支持的actions恭朗,“required”action必須支持屏镊,vendor action不應(yīng)該通過該bitmask顯示,actions根據(jù)ofp_action_type的值決定需要左移幾位痰腮。
- ports[0]:以數(shù)組的形式羅列出該系統(tǒng)中支持OpenFlow的物理端口而芥。數(shù)據(jù)長度可以根據(jù)OpenFlow頭部中的length推測出來。
2.3 Packet_in消息
當(dāng)交換機(jī)碰到新數(shù)據(jù)包不知道如何處理膀值,或者action要求發(fā)送給控制器棍丐,那么交換機(jī)就會(huì)用packet_in消息發(fā)送給控制器。一般將數(shù)據(jù)包緩存在交換機(jī)中沧踏,將有效的數(shù)據(jù)包信息(默認(rèn)的128字節(jié)歌逢,如果原因是 “send to controller” action,那么長度由action_out的max_len決定翘狱;如果是原因table miss秘案,那么長度由set_config消息中的miss_send_len決定。)和緩存id發(fā)送給控制器潦匈,不過阱高,如果交換機(jī)不支持緩存或者內(nèi)存用光了,那么就把整個(gè)數(shù)據(jù)包放在數(shù)據(jù)部分發(fā)給控制器茬缩,并且緩存id為-1赤惊。
Packet_in消息如下:
Packet_in消息結(jié)構(gòu)如下:
/* Packet received on port (datapath -> controller). */
struct ofp_packet_in {
struct ofp_header header;
uint32_t buffer_id; /* ID assigned by datapath. */
uint16_t total_len; /* Full length of frame. */
uint16_t in_port; /* Port on which frame was received. */
uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
uint8_t pad;
uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word,
so the IP header is 32-bit aligned. The amount of data is inferred from the length field in the header. Because of padding, offsetof(struct ofp_packet_in, data) == sizeof(struct ofp_packet_in) - 2. */
};
OFP_ASSERT(sizeof(struct ofp_packet_in) == 20);
- buffer_id:數(shù)據(jù)通道分配的緩存id,標(biāo)志數(shù)據(jù)包存在交換機(jī)中的位置凰锡,如果沒有緩存在交換機(jī)中則buffer_id則為-1未舟。
- total_len:整個(gè)數(shù)據(jù)幀的長度。
- in_port:接收數(shù)據(jù)幀的端口掂为。
- reason:將數(shù)據(jù)包發(fā)送給控制器的原因处面,一般有倆原因,一是沒有匹配到流表項(xiàng)菩掏,二是動(dòng)作要求發(fā)給控制器魂角。
2.4 Packet_out消息
當(dāng)控制器希望交換機(jī)發(fā)送某個(gè)數(shù)據(jù)包,就使用packet_out消息智绸。Packet_out消息如下所示:
Packet_out消息結(jié)構(gòu)如下:
/* Send packet (controller -> datapath). */
struct ofp_packet_out {
struct ofp_header header;
uint32_t buffer_id; /* ID assigned by datapath (-1 if none). */
uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */
uint16_t actions_len; /* Size of action array in bytes. */
struct ofp_action_header actions[0]; /* Actions. */
/* uint8_t data[0]; */ /* Packet data. The length is inferred
from the length field in the header.
(Only meaningful if buffer_id == -1.) */
};
OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
buffer_id:與packet_in中給的一樣野揪,如果為-1就表明數(shù)據(jù)包附在數(shù)據(jù)數(shù)組中访忿。
2.5 Configuration消息
控制器可以發(fā)送OFPT_SET_CONFIG / OFPT_GET_CONFIG_REQUEST消息設(shè)置/查詢交換機(jī)配置參數(shù),交換機(jī)只需響應(yīng)OFPT_GET_CONFIG_REQUEST消息即可斯稳。
OFPT_SET_CONFIG消息如下所示:
OFPT_GET_CONFIG_REQUEST消息沒有消息主體海铆,OFPT_SET_CONFIG 、OFPT_GET_CONFIG_reply的消息結(jié)構(gòu)如下所示:
/* Switch configuration. */
struct ofp_switch_config {
struct ofp_header header;
uint16_t flags; /* OFPC_* flags. */
uint16_t miss_send_len; /* Max bytes of new flow that datapath should
send to the controller. */
};
OFP_ASSERT(sizeof(struct ofp_switch_config) == 12);
- Flags:配置類型flags挣惰,主要包括:
注:
enum ofp_config_flags {
/* Handling of IP fragments. */
OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */
OFPC_FRAG_DROP = 1, /* Drop fragments. */
OFPC_FRAG_REASM = 2, /* Reassemble (only if OFPC_IP_REASM set). */
OFPC_FRAG_MASK = 3
};
- miss_send_len:決定發(fā)送給控制器的數(shù)據(jù)包長度卧斟,如果該字段為0,則交換機(jī)發(fā)送一個(gè)大小為0的packet_in消息憎茂。
2.6 Stats消息
交換機(jī)和控制器連接后珍语,控制器會(huì)不斷發(fā)送stats消息詢問交換機(jī)的狀態(tài),就好像兩個(gè)打電話的人竖幔,一方不斷詢問“你在嗎板乙?”另一方不斷回答“在呀!”抓到的stats消息如下所示:
ofp_stats_request和ofp_stats_reply消息結(jié)構(gòu)相同拳氢,都使用以下結(jié)構(gòu):
注:
struct ofp_stats_request {
struct ofp_header header;
uint16_t type; /* One of the OFPST_* constants. */
uint16_t flags; /* OFPSF_REQ_* flags (none yet defined). */
uint8_t body[0]; /* Body of the request. */
};
OFP_ASSERT(sizeof(struct ofp_stats_request) == 12);
- Type:該字段決定傳遞的信息的類型并且怎樣解釋body部分募逞。主要包括:
注:
enum ofp_stats_types {
/* Description of this OpenFlow switch.
* The request body is empty.
* The reply body is struct ofp_desc_stats. */
OFPST_DESC,
/* Individual flow statistics.
* The request body is struct ofp_flow_stats_request.
* The reply body is an array of struct ofp_flow_stats. */
OFPST_FLOW,
/* Aggregate flow statistics.
* The request body is struct ofp_aggregate_stats_request.
* The reply body is struct ofp_aggregate_stats_reply. */
OFPST_AGGREGATE,
/* Flow table statistics.
* The request body is empty.
* The reply body is an array of struct ofp_table_stats. */
OFPST_TABLE,
/* Physical port statistics.
* The request body is struct ofp_port_stats_request.
* The reply body is an array of struct ofp_port_stats. */
OFPST_PORT,
/* Queue statistics for a port
* The request body defines the port
* The reply body is an array of struct ofp_queue_stats */
OFPST_QUEUE,
/* Vendor extension.
* The request and reply bodies begin with a 32-bit vendor ID, which takes
* the same form as in "struct ofp_vendor_header". The request and reply
* bodies are otherwise vendor-defined. */
OFPST_VENDOR = 0xffff
};
- Flags:ofp_stats_request的flag字段目前還沒有定義,而reply消息的flag字段只有一個(gè)值0x0001馋评,該值表示后面是否還有更多的reply放接。
2.7 Flow_mod
控制器與交換機(jī)建立連接后,控制器會(huì)自發(fā)給交換機(jī)發(fā)送一組flow_mod消息留特,抓到的消息如下:
flow_mod消息結(jié)構(gòu):
/* Flow setup and teardown (controller -> datapath). */
struct ofp_flow_mod {
struct ofp_header header;
struct ofp_match match; /* Fields to match */
uint64_t cookie; /* Opaque controller-issued identifier. */
/* Flow actions. */
uint16_t command; /* One of OFPFC_*. */
uint16_t idle_timeout; /* Idle time before discarding (seconds). */
uint16_t hard_timeout; /* Max time before discarding (seconds). */
uint16_t priority; /* Priority level of flow entry. */
uint32_t buffer_id; /* Buffered packet to apply to (or -1).
Not meaningful for OFPFC_DELETE*. */
uint16_t out_port; /* For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_NONE indicates no restriction. */
uint16_t flags; /* One of OFPFF_*. */
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
- Cookie: 控制器設(shè)置的不透明數(shù)據(jù)透乾。當(dāng)command為OFPFC_MODIFY或OFPFC_MODIFY_STRICT時(shí),匹配了的流表項(xiàng)需要適當(dāng)?shù)母耤ookie字段磕秤。
- Command可能會(huì)是
注:
enum ofp_flow_mod_command {
OFPFC_ADD, /* New flow. */
OFPFC_MODIFY, /* Modify all matching flows. */
OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */
OFPFC_DELETE, /* Delete all matching flows. */
OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */
};
- idle_timeout和hard_timeout控制流表項(xiàng)的生命周期乳乌。當(dāng)idle_timeout為x(x不為0)并且hard_timeout為0時(shí),流表項(xiàng)在x秒收不到數(shù)據(jù)包后就到期市咆。當(dāng)idle_timeout為0并且hard_timeout為x時(shí)汉操,x秒后無論收不收得到數(shù)據(jù)包流表項(xiàng)都到期。當(dāng)idle_timeout為x(x不為0)并且hard_timeout為y(y不為0)時(shí)蒙兰,x秒收不到數(shù)據(jù)包或者y秒后磷瘤,哪個(gè)期限先到就按哪個(gè)算。當(dāng)idle_timeout和hard_timeout都為0時(shí)搜变,表明這個(gè)流表項(xiàng)是永恒的采缚,除非用OFPFC_DELETE刪除,否則不會(huì)到期挠他。
- priority:priority只和含通配字段的流表項(xiàng)有關(guān)扳抽。Priority值越大,表明流表優(yōu)先級(jí)越高。交換機(jī)必須將優(yōu)先級(jí)最高的通配流表項(xiàng)放在編號(hào)最低的通配流表中贸呢。無論流表是什么配置镰烧,交換機(jī)需要確保精確流表項(xiàng)排在通配流表項(xiàng)之前。
- buffer_id:標(biāo)志由packet_in消息發(fā)送的數(shù)據(jù)包存儲(chǔ)的地方楞陷。
- out_port:delete和delete_strict消息利用該字段確定作用域怔鳖,而add、modify固蛾、modify_strict消息會(huì)自動(dòng)忽略該字段结执。如果out_port為ofpp_none則表明禁用output端口過濾功能,否則就相當(dāng)于添加了一個(gè)額外的匹配限制條件艾凯。連0也是有效端口id献幔,表示約束條件是必須有關(guān)于該端口的output動(dòng)作。而ofp_match和優(yōu)先級(jí)等條件依舊生效览芳,該字段只是添加了一個(gè)額外的約束。
- flags:flags主要包括:
注:
enum ofp_flow_mod_flags {
OFPFF_SEND_FLOW_REM = 1 << 0, /* Send flow removed message when flow
* expires or is deleted. */
OFPFF_CHECK_OVERLAP = 1 << 1, /* Check for overlapping entries first. */
OFPFF_EMERG = 1 << 2 /* Remark this is for emergency. */
};
(1)鸿竖、設(shè)置OFPFF_SEND_FLOW_REM標(biāo)識(shí)表示當(dāng)流表項(xiàng)到期時(shí)交換機(jī)發(fā)送一條flow removed消息沧竟,一般默認(rèn)情況下交換機(jī)是不會(huì)為新添加的流表項(xiàng)發(fā)送flow removed消息的。
(2)缚忧、OFPFF_CHECK_OVERLAP生效表明交換機(jī)必須檢查是否有優(yōu)先級(jí)沖突的流表項(xiàng)悟泵,如果沖突,則flow mod無效并且回復(fù)錯(cuò)誤提醒闪水。
(3糕非、)OFPFF_EMERG為1則代表該流表項(xiàng)是緊急流表項(xiàng),當(dāng)交換機(jī)與控制器斷開連接時(shí)就利用該表項(xiàng)轉(zhuǎn)發(fā)數(shù)據(jù)包球榆。