当前Openflow协议中的消息基本可以满足我们对SDN交换机的管理需要,但是在很多情况下,我们更希望能够与openflow交换机交互自定义的管理消息,这就需要用到openflow的实验消息(experimenter messages)。本文以SDN软件交换机ofsoftswitch13为例,来说明如何实现通过自定义的experimenter消息来与交换机通信。
实际上,ofsoftswitch13中已经有几个实验消息实现的范例,因此我侧重于分析ofsoftswitch13工程中的实现过程。当我们将experimenter消息的处理过程分析清楚后,添加自定义的实验消息就会变得非常简单。总体来说,交换机对openflow消息的处理可以划分为三个过程:
- 一是对收到的openflow消息的解析过程。这个过程实现的功能是将数据包从网络字节序的线格式(wire format)解析为主机字节序的openflow消息格式。
- 二是对消息处理过程。比如对交换机进行配置等。这个过程比较直接,下文就不展开分析了。
- 三是交换机向控制器回复openflow消息的过程。这与第一个过程的步骤几乎是相反的,主要实现的功能是将待发送消息的内容打包为网络字节序的线格式(wire format),然后发送给控制器的过程。
如果弄清楚了上述三个过程的实现,那么实现自定义的experimenter消息的步骤就会变得非常清晰。下面首先说明ofsoftswitch13对自定义的experiment消息的解析流程,以及交换机向控制器回复openflow消息的流程。最后说明自定义experimenter消息的工程实现操作步骤。
自定义exp消息的处理流程
交换机收到openflow消息之后,首先对消息内容进行解析。然后根据解析得到的数据包类型调用相应的处理函数。
exp消息处理函数的调用过程
前文SDN软件交换机中数据包的处理流程对openflow交换机的数据包处理过程进行了分析,文中提到了位于文件oflib/ofl-messages-unpack.c
中的openflow消息的解析函数ofl_msg_unpack()
,交换机对自定义experimenter
消息的解析也正是从该函数开始的。
1 | ofl_err |
从ofl_msg_unpack()
对openflow子类型消息解析函数的调用中,我们可以发现experimenter消息的调用与其他openflow消息的调用有所不同,使用的调用方式是这样的:
1 | exp->msg->unpack(oh, &len, (struct ofl_msg_experimenter **)msg) |
其中exp
是通过函数参数传入的。形参为struct ofl_exp *exp
。传入的值是dp->exp
,见文件udatapath/datapath.c
:
1 | ofl_msg_unpack(buffer->data, buffer->size, &msg, &(sender.xid), dp->exp); |
因此,在函数ofl_msg_unpack()
(位于文件oflib/ofl-messages-unpack.c
)中使用exp->msg->unpack(...)
这种调用方式会等价为ofl_exp_msg_unpack(...)
(位于文件udatapath/datapath.c
)。而函数ofl_exp_msg_unpack(...)
的实现位于文件oflib-exp/ofl-exp.c
中。
exp消息处理的函数指针
在这里补充一下exp消息处理函数指针的初始化位置。exp消息解析函数指针在datapath初始化的时候传给了datapath,参见文件udatapath/datapath.c
中的datapath初始化函数:
1 | struct datapath * |
其中,dp_exp
是在该文件中定义的函数指针结构体,指向exp消息的处理函数:
1 | /* Callbacks for processing experimenter messages in OFLib. */ |
exp消息解析实现
自定义的exp消息实现于文件oflib-exp/ofl-exp.c
中:
1 | ofl_err |
下面以openflow extention queue msg为例讲解exp消息解析的实现。
openflow extention queue msg结构体定义
queue_msg
的结构定义如下,位于oflib-exp/ofl-exp-openflow.h
中:
1 | struct ofl_exp_openflow_msg_header { |
头文件中扩展消息定义如下,如include/openflow/openflow-ext.h`文件:
1 | enum ofp_extension_commands { /* Queue configuration commands */ |
openflow extention queue unpack
案例中的experimenter消息unpack的最终实现位于oflib-exp/ofl-exp-openflow.c
文件中。该函数实现的功能是将交换机收到的原始数据包(以网络字节存储于内存),解析为用户定义的实验消息格式(以主机字节序存储于内存)。
1 | ofl_err |
exp消息的处理
消息解析完成之后,exp消息数据包的形态就由opfbuf
结构解析为了对应的exp结构体。前文SDN软件交换机中数据包的处理流程openflow消息的处理
这一小节中提到,函数handle_control_msg()
会根据消息的不同类型分配给不同的处理函数,实验消息也是其中的一种,由dp_exp_message()
函数进行处理。
从exp处理函数的上层调用接口来看,remote_rconn_run
调用消息解析函数之后,如果解析无误,则继续调用handle_control_msg()
函数对消息内容进行处理。与ofl_msg_unpack()
类似,函数handle_control_msg()
定义于文件udtapath/dp_control.c
中,会根据消息的不同类型分配给不同的处理函数,主要代码入下。
1 | ofl_err handle_control_msg(struct datapath *dp, struct ofl_msg_header *msg, const struct sender *sender) { |
其中需要注意的问题是代码内存块的释放:如果处理exp消息的调用函数发现错误,则需要返回错误代码,并且保持传入的exp消息未有任何改动,由handle_control_msg()
的主调函数(remote_rconn_run()
)放内存;如果exp消息的调用函数处理正常,则需要被调函数(dp_exp_message()
)释放数据包内存。
函数dp_exp_message()
定义于文件udatapath/dp_exp.c
中,该函数根据experimenter消息的ID调用相应的处理函数。如果你自定义了一种新的实验消息,就需要在这里增加对实验消息的处理方式。
1 | ofl_err |
交换机向控制器回复openflow消息流程
交换机在处理控制器下发的实验消息时,经常需要对消息做出回应。比如控制器查询交换机中某个队列的状态时,交换机需要回复队列状态信息。
下面举个例子来说明ofsoftswitch13中交换机的回复流程。
准备消息内容
交换机对控制器的查询消息解析完成后,会将消息转交给对应的处理函数。比如udatapath/dp_control.c
文件中的函数handle_control_echo_request()
会对echo进行回复。
1 | /* Handles echo request messages. */ |
调用发送函数
处理函数准备好返回给交换机的信息后,调用dp_send_message()
函数发送数据包。函数dp_send_message()
位于文件udatapath/datapath.c
文件中。
1 | int |
转换传输格式(pack)
dp_senf_message()
首先需要对传入的消息内容打包为可以直接发送openflow格式数据包,这个步骤通过调用打包函数ofl_msg_pack()
来实现,该函数位于文件oflib/ofl-messages-pack.c
中。
1 | int |
除实验消息外,openflow协议消息的pack函数大多位于文件oflib/ofl-messages-pack.c
中。实验消息的处理函数统一位于oflib-exp
目录。pack函数实现的功能都是将软件交换机中解析用到的格式转化为可以直接进行网络传输的报文格式。仍然以echo
消息的pack为例,其实现过程如下:
1 | static int |
最后在dp_send_messages()
函数中调用send_openflow_buffer(dp, ofpbuf, sender);
即可将消息发送给控制器了。
自定义exp消息的工程实现
工程实现部分主要说明在原有的工程结构下,我们需要修改或增加的文件位置。
增加exp头文件
include/openflow/
在该目录下增加自定义消息的定义,实验消息的ID等。
增加exp消息解析函数
oflib-exp/
在该目录下增加自定义的实验消息的处理函数,主要包括如下四个函数:1
2
3
4
5{ .pack = ofl_exp_msg_pack,
.unpack = ofl_exp_msg_unpack,
.free = ofl_exp_msg_free,
.to_string = ofl_exp_msg_to_string
};oflib-exp/ofl-exp.c
在实验消息入口处注册自定义exp消息解析的入口
增加exp消息处理函数
udatapath/dp_exp.c
增加对自定义exp消息的处理函数,并且在dp_exp_message()
函数中注册自定义exp消息处理的入口
修改makefile文件
include/openflow/automake.mk
在makefile对应位置包含增加的自定义exp头文件oflib-exp/automake.mk
在makefile对应位置包含增加的自定义exp头文件lib/automake.mk
增加对应的oflib-exp
中的编译文件
添加日志模块
oflib-exp/vlog-module.def
增加自定义exp模块名