天天看點

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

 OpenFlow1.0協定解析

控制器通過Openflow管理、控制交換機,分析wireshark抓到的OpenFlow包就可以大體推測控制器與交換機通信的流程。雖然沒有進行任何操作,但是一旦交換機連接配接控制器,wireshark就能捕捉到很多OpenFlow包。依次是hello消息、feature消息,stats消息,以及packet_in和packet_out。

1 Hello

控制器與交換機建立連接配接時由其中某一方發起Hello消息,雙方協調協定版本号。Hello消息隻有of標頭,沒有主體部分。而of頭部結果如下:

/* 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版本,低位為版本号,如上所示。

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号一緻。如feature_request和對應的feature_reply就使用同一個Transaction id,但是兩個hello消息的Transaction id并不相同,不過據實驗結果看兩個id一般是兩個相鄰的數字。并且packet_in的transaction id都為0。

2 Feature消息

TLS會話一建立,控制器就會向交換機發送一個ofpt_feature_request消息,該消息隻有of標頭,如下所示。交換機會回複一條ofpt_feature_reply消息。

ofpt_feature_request如圖:(有時候會發現一個資料包中有多個request,并且後面會有一一對應的reply包。)

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

ofpt_feature_reply如圖:

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

ofpt_feature_reply消息結構如下:

注:

/* 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:資料通道獨一無二的辨別符,低48位是一個MAC位址,而高16位是自定義的。例如,用高16位代表VLAN ID差別一個實體交換機中的多個虛拟交換機。

n_buffers:一次最多緩存的資料包數量。

n_tables:表示交換機支援的流表數量。而每個流表可以設定不同的通配符和不同數量的流表項。控制器和交換機第一次通信的時候,控制器會從feature_reply消息中找出交換機支援多少流表,如果控制器還想了解大小、類型和流表查詢的順序,就發送一個ofpst_table stats請求,交換機必須按照資料包周遊流表的順序把這些流表回複給控制器,并且精确比對流表排在通配流表前。

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表示交換機所支援的actions,“required”action必須支援,vendor action不應該通過該bitmask顯示,actions根據ofp_action_type的值決定需要左移幾位。

ports[0]:以數組的形式羅列出該系統中支援OpenFlow的實體端口。資料長度可以根據OpenFlow頭部中的length推測出來。

3 Packet_in消息

當交換機碰到新資料包不知道如何處理,或者action要求發送給控制器,那麼交換機就會用packet_in消息發送給控制器。一般将資料包緩存在交換機中,将有效的資料包資訊(預設的128位元組,如果原因是 “send to controller” action,那麼長度由action_out的max_len決定;如果是原因table miss,那麼長度由set_config消息中的miss_send_len決定。)和緩存id發送給控制器,不過,如果交換機不支援緩存或者記憶體用光了,那麼就把整個資料包放在資料部分發給控制器,并且緩存id為-1。

Packet_in消息如下:

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析
OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

Packet_in消息結構如下:

/* 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:資料通道配置設定的緩存id,标志資料包存在交換機中的位置,如果沒有緩存在交換機中則buffer_id則為-1。

total_len:整個資料幀的長度。

in_port:接收資料幀的端口。

reason:将資料包發送給控制器的原因,一般有倆原因,一是沒有比對到流表項,二是動作要求發給控制器。

4 Packet_out消息

當控制器希望交換機發送某個資料包,就使用packet_out消息。Packet_out消息如下所示:

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

Packet_out消息結構如下:

/* 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就表明資料包附在資料數組中。

5 Configuration消息

控制器可以發送OFPT_SET_CONFIG / OFPT_GET_CONFIG_REQUEST消息設定/查詢交換機配置參數,交換機隻需響應OFPT_GET_CONFIG_REQUEST消息即可。

OFPT_SET_CONFIG消息如下所示:

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

OFPT_GET_CONFIG_REQUEST消息沒有消息主體,OFPT_SET_CONFIG 、OFPT_GET_CONFIG_reply的消息結構如下所示:

/* 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:決定發送給控制器的資料包長度,如果該字段為0,則交換機發送一個大小為0的packet_in消息。

6 Stats消息

交換機和控制器連接配接後,控制器會不斷發送stats消息詢問交換機的狀态,就好像兩個打電話的人,一方不斷詢問“你在嗎?”另一方不斷回答“在呀!”抓到的stats消息如下所示:

OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析
OpenFlow好文集錦-OpenFlow1.0協定解析  OpenFlow1.0協定解析

ofp_stats_request和ofp_stats_reply消息結構相同,都使用以下結構:

注:

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字段隻有一個值0x0001,該值表示後面是否還有更多的reply。

7 Flow_mod

控制器與交換機建立連接配接後,控制器會自發給交換機發送一組flow_mod消息,抓到的消息如下:

flow_mod消息結構:

/* 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: 控制器設定的不透明資料。當command為OFPFC_MODIFY或OFPFC_MODIFY_STRICT時,比對了的流表項需要适當的更新cookie字段。

Command可能會是

注:

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控制流表項的生命周期。當idle_timeout為x(x不為0)并且hard_timeout為0時,流表項在x秒收不到資料包後就到期。當idle_timeout為0并且hard_timeout為x時,x秒後無論收不收得到資料包流表項都到期。當idle_timeout為x(x不為0)并且hard_timeout為y(y不為0)時,x秒收不到資料包或者y秒後,哪個期限先到就按哪個算。當idle_timeout和hard_timeout都為0時,表明這個流表項是永恒的,除非用OFPFC_DELETE删除,否則不會到期。

priority:priority隻和含通配字段的流表項有關。Priority值越大,表明流表優先級越高。交換機必須将優先級最高的通配流表項放在編号最低的通配流表中。無論流表是什麼配置,交換機需要確定精确流表項排在通配流表項之前。

buffer_id:标志由packet_in消息發送的資料包存儲的地方。

out_port:delete和delete_strict消息利用該字段确定作用域,而add、modify、modify_strict消息會自動忽略該字段。如果out_port為ofpp_none則表明禁用output端口過濾功能,否則就相當于添加了一個額外的比對限制條件。連0也是有效端口id,表示限制條件是必須有關于該端口的output動作。而ofp_match和優先級等條件依舊生效,該字段隻是添加了一個額外的限制。

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)、設定OFPFF_SEND_FLOW_REM辨別表示當流表項到期時交換機發送一條flow removed消息,一般預設情況下交換機是不會為新添加的流表項發送flow removed消息的。

(2)、OFPFF_CHECK_OVERLAP生效表明交換機必須檢查是否有優先級沖突的流表項,如果沖突,則flow mod無效并且回複錯誤提醒。

(3、)OFPFF_EMERG為1則代表該流表項是緊急流表項,當交換機與控制器斷開連接配接時就利用該表項轉發資料包。

收集自 http://www.jianshu.com/p/e660508f1c5d