To be a better coder
分类: LINUX
2019-09-17 09:32:31
OpenFlow控制器是通过安全通道和OpenFlow交换机进行通信的,安全通道由控制面网络建立,不受OpenFlow交换机中的流表项的影响。在OpenFlow中,安全通道通过TLS来实现,控制器与交换机之间通过服务器证书和客户机证书进行认证。在一些OpenFlow版本中(1.1及以上),控制器和交换机之间的连接有时也会通过TCP明文来实现。
OpenFlow控制器启动后,对指定端口进行监听,默认的TCP端口为6633,后更改为6653。通过三次握手后,连接建立。
OpenFlow消息由64比特(8字节)组成,所有的OpenFlow消息都是从OpenFlow头开始,图2-1为OpenFlow头格式。
字段 | 比特数 | 内容 |
---|---|---|
version | 8 | OpenFlow的协议版本号 |
type | 8 | 消息类型(见2.1) |
length | 16 | 该头中包含的八位字节数 |
xid | 32 | 分配给数据包的id |
表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消息 |
OpenFlow交换机与OpenFlow控制器建立安全通道后,会相互发送hello包。hello消息仅有OpenFlow头构成。且由交换机连向路由器。
目的:用于OpenFlow协议版本的协商。
内容:发送双方各自支持的最高版本协议。
结果:选择双方支持的最低协议版本。
成功:建立连接。
失败:发送OFPT_ERROR,终止连接。
通过互发hello消息建立连接后,执行控制器和交换机之间的握手过程。控制器通过握手过程了解交换机的相关配置信息,即可以对交换机进行控制。
type=6
Features响应消息格式(如图2-2所示)
各个字段的含义
字段 | 比特数 | 内容 |
---|---|---|
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回复给控制器后,控制器就会对交换机有了全面的了解,从而为交换机提供控制信息。
为了将到达OpenFlow交换机的数据包发送至控制器,使用Packet-In消息,当存在:
可发送Packet-In消息,包含在Packet-In中的数据可能是很多种类型,ARP和ICMP为最常见类型。
如果是广播包,控制器就会将其包装,封装成Packet-Out数据包,将其发送给交换机,让其进行泛洪处理(flood),即将数据包发往除in_port之外的所有端口。
作用:通过控制器发送交换机希望发送的数据
例子:当一个没有匹配上流表项的数据上报控制器时,控制器可以下发packet_out,指定交换机对该数据包做泛洪或丢弃动作。
若OpenFlow交换机的缓存中已存在数据包,而OpenFlow控制器发出发送数据包的命令时,该消息指定表示响应数据包的buffer_id。使用Packet-out还可以将OpenFlow控制器创建的数据包发送给交换机,此时,buffer_id设置为-1.在Packet-out消息后添加数据包数据。
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)
见2.消息中OpenFlow头结构。
这个数据结构会出现在几乎所有重要的数据包中,因为他存的就是控制信息。
如有packet_in引发的下发流表,则match部分应对应填上对应的数据,这样下发的流表才是正确的。
但是在下发的时候还需要注意许多细节,比如:
在of1.0中这里的0,1意义跟我们平时接触的如子网掩码等意义相反,如OFPFW_NW_DST_MASK=0则表示全匹配目标IP。如果为63,则表示不匹配IP。在1.3的时候,这个逻辑改成了正常的与逻辑。即1为使能匹配,0为默认不匹配。
因匹配字段在1.2版本之后变化较大,请自行查看OpenFlow协议。
Flow-Mod消息的行动信息结构如图2-3所示:
相关代码如下:
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类型如下:
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-mod的flags置为1,则在该流表失效后会回复控制器OFPT_LFOW_REMOVED消息。结构如图2-4所示:
作用:在流失效的时候回复控制器,并携带若干统计数据。
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消息的作用是通知出现了某种错误,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"}
交换机在收到OFPT_BARRIER_REQUEST的时候,会回复控制器一个OFPT_BARRIER_REPLY。控制器收到回复之后,确认flow-mod设置流表成功,可以发送Packet-out消息。