OpenFlow控制器与OpenFlow交换机之间的通信
1.建立安全通道
OpenFlow控制器是通过安全通道和OpenFlow交换机进行通信的,安全通道由控制面网络建立,不受OpenFlow交换机中的流表项的影响。在OpenFlow中,安全通道通过TLS来实现,控制器与交换机之间通过服务器证书和客户机证书进行认证。在一些OpenFlow版本中(1.1及以上),控制器和交换机之间的连接有时也会通过TCP明文来实现。
OpenFlow控制器启动后,对指定端口进行监听,默认的TCP端口为6633,后更改为6653。通过三次握手后,连接建立。
2.消息
OpenFlow消息由64比特(8字节)组成,所有的OpenFlow消息都是从OpenFlow头开始,图2-1为OpenFlow头格式。
图2-1.png
- 各字段及其含义
字段 | 比特数 | 内容 |
---|---|---|
version | 8 | OpenFlow的协议版本号 |
type | 8 | 消息类型(见2.1) |
length | 16 | 该头中包含的八位字节数 |
xid | 32 | 分配给数据包的id |
2.1 OpenFlow消息类型
表2-1(参考1.3版本)
类型 | 名称 |
---|---|
OFPT_HELLO | Hello消息 |
OFPT_ERROR | Error消息 |
OFPT_ECHO_REQUEST | Echo请求消息 |
OFPT_ECHO_REPLY | Echo响应消息 |
OFPT_EXPERIMENTER | Experimenter消息 |
OFPT_FEATURES_REQUEST | Features请求消息 |
OFPT_FEATURES_REPLY | Features响应消息 |
OFPT_GET_CONFIG_REQUEST | GET_CONFIG请求消息 |
OFPT_GET_CONFIG_REPLY | GET_CONFIG响应消息 |
OFPT_SET_CONFIG | SET_CONFIG消息 |
OFPT_PACKET_IN | Packet-In消息 |
OFPT_FLOW_REMOVED | Flow-Remove消息 |
OFPT_PORT_STATUS | Port-Status消息 |
OFPT_PACKET_OUT | Packet-Out消息 |
OFPT_FLOW_MOD | Flow-Mod消息 |
OFPT_GROUP_MOD | GROUP_MOD消息 |
OFPT_PORT_MOD | PORT-MOD消息 |
OFPT_TABLE_MOD | TABLE_MOD消息 |
OFPT_MULTIPART_REQUEST | MULTIPART请求消息 |
OFPT_MULTIPART_REPLY | MULTIPART响应消息 |
OFPT_BARRIER_REQUEST | BARRIER请求消息 |
OFPT_BARRIER_REPLY | BARRIER响应消息 |
OFPT_QUERU_GET_CONFIG_REQUEST | QUERU_GET_CONFIG请求消息 |
OFPT_QUEUE_GET_CONFIG_REPLY | QUERU_GET_CONFIG响应消息 |
OFPT_ROLE_REQUEST | Role请求消息 |
OFPT_ROLE_REPLE | Role响应消息 |
OFPT_GET_ASYNC_REQUEST | GET_ASYNC请求消息 |
OFPT_GET_ASYNC_REPLY | GET_ASYNC响应消息 |
OFPT_SET_ASYNC | SET_ASYNC消息 |
OFPT_METER_MOD | METER消息 |
-
OFPT_HELLO消息
OpenFlow交换机与OpenFlow控制器建立安全通道后,会相互发送hello包。hello消息仅有OpenFlow头构成。且由交换机连向路由器。
-
目的:用于OpenFlow协议版本的协商。
-
内容:发送双方各自支持的最高版本协议。
-
结果:选择双方支持的最低协议版本。
-
成功:建立连接。
-
失败:发送OFPT_ERROR,终止连接。
-
Features消息(握手过程)
通过互发hello消息建立连接后,执行控制器和交换机之间的握手过程。控制器通过握手过程了解交换机的相关配置信息,即可以对交换机进行控制。
- 发送数据:OFPT_FEATURES_REQUEST(Features请求)
- 接收数据:OFPT_FEATURES_REPLY(Features响应)
Features请求消息
- type=5
- 只包含openflow头
Features响应消息
-
type=6
-
Features响应消息格式(如图2-2所示)
图2-2.png -
各个字段的含义
字段 | 比特数 | 内容 |
---|---|---|
datapath_id | 64 | OpenFlow中将各交换机称为datapath,datapath_id是唯一识别datapath的ID |
n_buffers | 32 | 交换机可以同时缓存的数据包的最大个数 |
n_tables | 8 | 交换机中支持的流表数量 |
pad | 24 | 用于64位对其的填充 |
capabilities | 32 | 支持的容量 |
actions | 32 | 支持的行动 |
ports | 长度可变 | OpenFlow1.3之后废除,在此不再介绍 |
对于Features消息,每一次交换机连接到控制器,都会收到控制器的features_request,当交换机将features_reply回复给控制器后,控制器就会对交换机有了全面的了解,从而为交换机提供控制信息。
-
OFPT_PACKET_IN消息
为了将到达OpenFlow交换机的数据包发送至控制器,使用Packet-In消息,当存在:
- 不存在与流表项一致,即没有流表进行匹配时(Table-miss)
- 匹配的流表项存在发送至控制器的行为时
可发送Packet-In消息,包含在Packet-In中的数据可能是很多种类型,ARP和ICMP为最常见类型。
如果是广播包,控制器就会将其包装,封装成Packet-Out数据包,将其发送给交换机,让其进行泛洪处理(flood),即将数据包发往除in_port之外的所有端口。
-
OFPT_PACKET_OUT消息
-
作用:通过控制器发送交换机希望发送的数据
-
例子:当一个没有匹配上流表项的数据上报控制器时,控制器可以下发packet_out,指定交换机对该数据包做泛洪或丢弃动作。
若OpenFlow交换机的缓存中已存在数据包,而OpenFlow控制器发出发送数据包的命令时,该消息指定表示响应数据包的buffer_id。使用Packet-out还可以将OpenFlow控制器创建的数据包发送给交换机,此时,buffer_id设置为-1.在Packet-out消息后添加数据包数据。
-
OFPT_FLOW_MOD消息
Flow-Mod消息是由OpenFlow控制器对OpenFlow交换机设置流表项的消息。可对流表项进行添加、删除、变更设置等操作。Flow-Mod消息具体命令种类如下:
名称 | 内容 |
---|---|
OFPFC_ADD | 添加流表项 |
OFPFC_MODIFY | 变更匹配的流表项设置(OpenFlow1.2版本以上删除此项) |
OFPFC_MODIFY_STRICT | 仅变更完全匹配的流表项设置 |
OFPFC_DELETE | 删除匹配的流表项 |
OFPFC_DELETE_STRICT | 仅删除完全匹配的流表项 |
ofp_flow_mod_command = { 0: "OFPFC_ADD", # New flow
1: "OFPFC_MODIFY", # Modify all matching flows
2: "OFPFC_MODIFY_STRICT", # Modify entry strictly matching wildcards
3: "OFPFC_DELETE", # Delete all matching flows
4: "OFPFC_DELETE_STRICT"} # Strictly match wildcards and priority
OFPT_FLOW_MOD由header+match+flow_mod+action构成。
flow_mod = of.ofp_header(type=14,length=72)/of.ofp_flow_wildcards(OFPFW_NW_TOS=1,
OFPFW_DL_VLAN_PCP=1,
OFPFW_NW_DST_MASK=0,
OFPFW_NW_SRC_MASK=0,
OFPFW_TP_DST=1,
OFPFW_TP_SRC=1,
OFPFW_NW_PROTO=1,
OFPFW_DL_TYPE=1,
OFPFW_DL_VLAN=1,
OFPFW_IN_PORT=1,
OFPFW_DL_DST=1,
OFPFW_DL_SRC=1)\
/of.ofp_match(in_port=msg.payload.payload.payload.in_port,
dl_src=pkt_parsed.src,
dl_dst=pkt_parsed.dst,
dl_type=pkt_parsed.type,
dl_vlan=pkt_parsed.payload.vlan,
nw_tos=pkt_parsed.payload.tos,
nw_proto=pkt_parsed.payload.proto,
nw_src=pkt_parsed.payload.src,
nw_dst=pkt_parsed.payload.dst,
tp_src = 0,
tp_dst = 0)\
/of.ofp_flow_mod(cookie=0,
command=0,
idle_timeout=10,
hard_timeout=30,
out_port=msg.payload.payload.payload.payload.port,
buffer_id=buffer_id,
flags=1)
-
OFP_HEADER
见2.消息中OpenFlow头结构。
-
MATCH(数据包匹配)
这个数据结构会出现在几乎所有重要的数据包中,因为他存的就是控制信息。
如有packet_in引发的下发流表,则match部分应对应填上对应的数据,这样下发的流表才是正确的。
但是在下发的时候还需要注意许多细节,比如:
- 并不是所有的数据包都有vlan_tag。如0x0800就是纯IP,并没有携带vlan_tag,所以填充式应根据packet_in的具体情况填充。
- 并不是所有的数据都有四层端口,所以四层的源端口,目的端口都不是任何时候都能由packet_in去填充的。不去管就好了,默认的会填充一个默认值,匹配的时候不去匹配4层端口就没有问题。
-
WILDCARDS(通配符)
在of1.0中这里的0,1意义跟我们平时接触的如子网掩码等意义相反,如OFPFW_NW_DST_MASK=0则表示全匹配目标IP。如果为63,则表示不匹配IP。在1.3的时候,这个逻辑改成了正常的与逻辑。即1为使能匹配,0为默认不匹配。
因匹配字段在1.2版本之后变化较大,请自行查看OpenFlow协议。
-
Flow-Mod消息的行动信息
Flow-Mod消息的行动信息结构如图2-3所示:
图2-3.png
相关代码如下:
class ofp_flow_mod(Packet):
name = "OpenFlow Flow Modify"
fields_desc=[ BitField("cookie", 0, 64), #Opaque controller-issued identifier
ShortEnumField("command", 0, ofp_flow_mod_command),
ShortField("idle_timeout", 60),
ShortField("hard_timeout", 0),
ShortField("priority", 0),
IntField("buffer_id", 0),
ShortField("out_port", 0),
#flags are important, the 1<<0 bit is OFPFF_SEND_FLOW_REM, send OFPT_FLOW_REMOVED
#1<<1 bit is OFPFF_CHECK_OVERLAP, checking if the entries' field overlaps(among same priority)
#1<<2 bit is OFPFF_EMERG, used only switch disconnected with controller)
ShortField("flags", 0)]
各字段及其含义:
字段 | 比特数 | 内容 |
---|---|---|
command | 16 | 表示Flow-Mod消息动作的ofp_flow_mod_command(具体参看上表具体命令) |
idle_timeout | 16 | 如果与流表项匹配的数据包超过idle_timeout的时间还未到,则删除流表项 |
hard_timeout | 16 | 流表项添加的时间超过hard_timeout则删除 |
priority | 16 | 多个流表项与数据包匹配时的优先级 |
buffer_id | 32 | OpenFlow交换机一侧保存的数据包的缓存ID |
out_port | 16 | 仅在DELETE及DELETE_STRICT命令中使用,该值已指定时,仅删除行动中描述了与该数值一致的输出物理端口的流表项 |
flags | 16 | 标志。 |
actions | 长度可变 | 行动描述部分 |
例如:
如果要添加一条新流,command=0。
两个时间参数idle_timeout & hard_timeout:
idle_timeout: 如值为20,则某条流在20秒之内没有被匹配,则删除。
hard_timeout: 如值为30,则30秒到达的时候,一定删除这条流,即使他还活跃,能被匹配。
priority:
priority是流的优先级的字段,字数越大则优先级越高,存放在号数越小的table中。
buffer_id:
由交换机指定的buffei_id,准确的说是由dpid指定的。如果是手动下发的流,buffer_id应填-1,即0xffff,告诉交换机这个数据包并没有缓存在队列中。
out_port:
指定流的出口,有一些端口是很特殊的,如flood,local等。具体分类如下:
ofp_port = { 0xff00: "OFPP_MAX",
0xfff8: "OFPP_IN_PORT",
0xfff9: "OFPP_TABLE",
0xfffa: "OFPP_NORMAL",
0xfffb: "OFPP_FLOOD",
0xfffc: "OFPP_ALL",
0xfffd: "OFPP_CONTROLLER",
0xfffe: "OFPP_LOCAL",
0xffff: "OFPP_NONE"}
如果不清楚端口是多少,最好填写flood,即0xfffb。
flags: 若无特殊用途,置为1,这样可以让交换机在删除一条流时给交换机上报flow_removed信息。
action:
每一条流都必须指定action,若没有指定,交换机会默认执行drop操作。
- action的两种类型行动。
- 必备行动:Forward,Drop
- 选择行动:Set-Queue,Set-Field等。
具体action类型如下:
ofp_action_type = { 0: "OFPAT_OUTPUT",
1: "OFPAT_SET_VLAN_VID",
2: "OFPAT_SET_VLAN_PCP",
3: "OFPAT_STRIP_VLAN",
4: "OFPAT_SET_DL_SRC",
5: "OFPAT_SET_DL_DST",
6: "OFPAT_SET_NW_SRC",
7: "OFPAT_SET_NW_DST",
8: "OFPAT_SET_NW_TOS",
9: "OFPAT_SET_TP_SRC",
10: "OFPAT_SET_TP_DST",
11: "OFPAT_ENQUEUE"
}
各字段及其含义:
名称 | 内容 |
---|---|
OFPAT_OUTPUT | 输出至交换机物理端口 |
OFPAT_SET_VLAN_VID | 设置802.1Q的VLAN id |
OFPAT_SET_VLAN_PCP | 设置802.1Q的PCP |
OFPAT_STRIP_VLAN | 清除802.1Q的头 |
OFPAT_SET_DL_SRC | 设置发送源以太网地址 |
OFPAT_SET_DL_DST | 设置发送目标以太网地址 |
OFPAT_SET_NW_SRC | 设置发送源IPV4地址 |
OFPAT_SET_NW_DST | 设置发送目标IPV4地址 |
OFPAT_SET_NW_TOS | 设置IPV4的TOS字段 |
OFPAT_SET_TP_SRC | 设置TCP/UDP的发送源端口号或ICMP类型\ |
OFPAT_SET_TP_DST | 设置TCP/UDP的目标端口号或ICMP代码 |
OFPAT_ENQUEUE | 输出至队列 |
-
Flow-Removed消息
如果flow-mod的flags置为1,则在该流表失效后会回复控制器OFPT_LFOW_REMOVED消息。结构如图2-4所示:
图2-4.png
作用:在流失效的时候回复控制器,并携带若干统计数据。
class ofp_flow_removed(Packet):
name = "OpenFlow flow removed"
fields_desc = [ BitField("cookie", 0, 64), #在控制器中使用,与flow-mod消息数值相同。
BitField("priority", 0,16),#流表项的优先级,与flow-mod相同。
BitField("reason", 0, 8),#流表项删除理由。
ByteField("pad", None),#用于32位对齐。
BitField("duration_sec", 0, 32),#流表项有效时间。
BitField("duration_nsec", 0, 32),#流表项有效时间。
BitField("idle_timeout", 0, 16),#idle超时时间。
ByteField("pad", 0),#用于64位对齐。
BitField("packet_count", 0, 64),#与流表项匹配的数据包数。
BitField("byte_count", 0, 64),#匹配的数据包总字节数。
]
-
Error消息
Error消息的作用是通知出现了某种错误,OpenFlow交换机和OpenFlow控制器都可以发送Error消息。
错误消息类型:
名称(type) | 内容 |
---|---|
OFPET_HELLO_FAILED | Hello协议失败 |
OFPET_BAD_REQUEST | 无法解读请求 |
OFPET_BAD_ACTION | 行动的描述中包含错误 |
OFPET_FLOW_MOD_FAILED | 变更流表项时发生错误 |
OFPET_PORT_MOD_FAILED | Port-Mod请求失败 |
OFPET_QUEUE_OP_FAILED | 队列操作失败 |
具体的type与其对应的相关代码:
ofp_hello_failed_code = { 0: "OFPHFC_INCOMPATIBLE",
1: "OFPHFC_EPERM"}
ofp_bad_request_code = { 0: "OFPBRC_BAD_VERSION",
1: "OFPBRC_BAD_TYPE",
2: "OFPBRC_BAD_STAT",
3: "OFPBRC_BAD_VENDOR",
4: "OFPBRC_BAD_SUBTYPE",
5: "OFPBRC_EPERM",
6: "OFPBRC_BAD_LEN",
7: "OFPBRC_BUFFER_EMPTY",
8: "OFPBRC_BUFFER_UNKNOWN"}
ofp_bad_action_code = { 0: "OFPBAC_BAD_TYPE",
1: "OFPBAC_BAD_LEN",
2: "OFPBAC_BAD_VENDOR",
3: "OFPBAC_BAD_VENDOR_TYPE",
4: "OFPBAC_BAD_OUT_PORT",
6: "OFPBAC_BAD_ARGUMENT",
7: "OFPBAC_EPERM", #permissions error
8: "OFPBAC_TOOMANY",
9: "OFPBAC_BAD_QUEUE"}
ofp_flow_mod_failed_code = { 0: "OFPFMFC_ALL_TABLES_FULL",
1: "OFPFMFC_OVERLAP",
2: "OFPFMFC_EPERM",
3: "OFPFMFC_BAD_EMERG_TIMEOUT",
4: "OFPFMFC_BAD_COMMAND",
5: "OFPFMFC_UNSUPPORT"}
ofp_port_mod_failed_code = { 0: "OFPPMFC_BAD_PORT",
1: "OFPPFMC_BAD_HW_ADDR"}
ofp_queue_op_failed_code = { 0: "OFPQOFC_BAD_PORT",
1: "OFPQOFC_BAD_QUEUE"}
-
Barrier消息
交换机在收到OFPT_BARRIER_REQUEST的时候,会回复控制器一个OFPT_BARRIER_REPLY。控制器收到回复之后,确认flow-mod设置流表成功,可以发送Packet-out消息。
-
Echo消息
- 分类:对称信息OFPT_ECHO_REQUEST,OFPT_ECHO_REPLY
- 作用:确认控制器和交换机之间是否连接,检测通信延迟,测量通信带宽等。
- 发送方:交换机和控制器均可发送。
- 构成:OpenFlow头和附加数据。
- 周期:没有数据包交换时,控制器会定期给交换机发送请求消息。
-
参考:
北邮-李呈:OpenFlow通信流程解读
《图解OpenFlow协议》