通过这几天对openvswitch代码的分析,以及项目的需要,需要对openflow
1.0进行一定的扩展,发现网上没有这方面的教程,虽然在搞懂ovs代码架构,floodlight
controller中利用的事件驱动模型之后,会觉得并不是难事,但是对于刚入门SDN的同学来说,需要一番折腾,这里简单记录一下,希望帮助到其他人。
环境配置:2host
+ 1 OVS + floodlight
软件版本: openvswitch 1.9.0 ,
floodlight0.85
在尝试对ovs中的openflow协议进行扩展之前至少应该理清的是,ovs如何与SDN
controller进行通信,收发of msg的过程,处理of
action的流程,特别是如何解析来自controller的消息;此外因为Floodlight利用的是netty框架,所以还要理解netty事件驱动的原理。接下来增加一个简单的openflow
message以及对应的action ,然后看ovs是否能成功接收来自controller的消息。
在
include/openflow/openflow-1.0.h中扩展of协议,增加我们的消息类型。
(里面的字段根据自己的业务逻辑需要而设置)
struct
ofp10_action_fp_update
{
ovs_be16
type;
ovs_be16
len;
ovs_be32
vector;
};
OFP_ASSERT(sizeof(struct ofp10_action_fp_update) ==
8);
struct ofp_fp_update{
ovs_be32
buffer_id;
/* ID assigned by datapath or UINT32_MAX. */
ovs_be16
in_port;
/* Packet‘s input port (OFPP_NONE if none). */
ovs_be16 other; /*
other fields reserved. */
struct
ofp_action_header actions[0]; /* The action length is
inferred
from the length field in
the
header. */
};
OFP_ASSERT(sizeof(struct ofp_fp_update) ==
8);
2.在 lib/ofp-msg.h
更新ofpraw这个结构体(很重要,因为当ovs收到来自controller的消息之后就会利用ofpraw里面格式化的定义来验证消息的有效性,从而进行后续处理)和ofptype枚举体。需要注意的是对ofpraw的更改一定要遵循固定的格式,注释中讲的很清楚。
enum
ofpraw {
/* Immutable standard messages.
*
* The OpenFlow
standard promises to preserve these messages and their numbers
*
in future versions, so we mark them as <all>, which covers
every OpenFlow
* version numbered 0x01...0xff, rather than as
OF1.0+, which covers only
* OpenFlow versions that we otherwise
implement.
* Without <all> here, then we would fail to
decode "hello" messages that
* announce a version higher than we
understand, even though there still could
* be a version in
common with the peer that we do understand. The
<all>
* keyword is less useful for the other messages,
because our OpenFlow channels
* accept only OpenFlow messages
with a previously negotiated version.
*/
....................................................
/* OFPT 1.0 (13): struct ofp_packet_out, uint8_t[].
*/
OFPRAW_OFPT10_PACKET_OUT,
/* OFPT 1.1+ (13):
struct ofp11_packet_out, uint8_t[]. */
OFPRAW_OFPT11_PACKET_OUT,
/* OFPT 1.0 (20):
struct ofp_fp_update, struct ofp_action_header[].
*/
OFPRAW_OFPT10_FP_UPDATE,
};
enum
ofptype {
/* Immutable messages.
*/
OFPTYPE_HELLO,
/* OFPRAW_OFPT_HELLO. */
OFPTYPE_ERROR,
/* OFPRAW_OFPT_ERROR. */
......................................
/*
Controller command messages. */
OFPTYPE_PACKET_OUT,
/*
OFPRAW_OFPT10_PACKET_OUT.
* OFPRAW_OFPT11_PACKET_OUT. */
OFPTYPE_FLOW_MOD,
/*
OFPRAW_OFPT10_FLOW_MOD.
*
OFPRAW_OFPT11_FLOW_MOD.
* OFPRAW_NXT_FLOW_MOD. */
OFPTYPE_PORT_MOD,
/*
OFPRAW_OFPT10_PORT_MOD.
* OFPRAW_OFPT11_PORT_MOD. */
OFPTYPE_FP_UPDATE,
/* OFPRAW_OFPT10_FP_UPDATE. */
};
在lib/ofp-util.h
中添加相应的数据结构,因为ovs用户空间在解码相应的消息的时候需要针对具体的类型执行相应的动作,所以也要更新
ofp-actions.h
// ofp-util.h
struct ofputil_fp_update
{
struct ofpact
*ofpacts; /* Actions.
*/
size_t
ofpacts_len; /* Size
of ofpacts in bytes. */
};
// 对这个消息编解码辅助函数
enum ofperr
ofputil_decode_fp_update(struct ofputil_fp_update
*,
const struct ofp_header
*,
struct ofpbuf *ofpacts);
struct ofpbuf
*ofputil_encode_fp_update(const struct ofputil_fp_update
*,
enum ofputil_protocol protocol);
// ofp-actions.h
struct
ofpact_fp_update {
struct ofpact
ofpact;
uint32_t vector; /*
自定义*/
};
4. 在 ofproto/ofproto.c (3790)- handle_openflow_()
函数中添加处理该消息的分支,
static enum ofperr
3793
handle_openflow__(struct ofconn *ofconn, const struct ofpbuf
*msg)
3794 {
3795 const struct
ofp_header *oh = msg->data;
3796 enum
ofptype type;
3797 enum ofperr
error;
3798
3799 error =
ofptype_decode(&type, oh);
3800 if
(error) {
3801
return error;
3802
}
3803
3804 switch (type)
{
3805 /*
OpenFlow requests. */
3806 case
OFPTYPE_ECHO_REQUEST:
3807
return handle_echo_request(ofconn,
oh);
3808
3809 case
OFPTYPE_FEATURES_REQUEST:
3810
return handle_features_request(ofconn,
oh);
3811
3812 case
OFPTYPE_GET_CONFIG_REQUEST:
3813
return handle_get_config_request(ofconn,
oh);
3814
3815 case
OFPTYPE_SET_CONFIG:
3816
return handle_set_config(ofconn,
oh);
3817
3818 case
OFPTYPE_PACKET_OUT:
3819
return handle_packet_out(ofconn,
oh);
3820 case
OFPTYPE_FP_UPDATE:
3821
return handle_fp_update(ofconn, oh);
...............................................
}
处理函数自己根据需要来实现,这里仅仅打印日志信息。
static
enum ofperr
handle_fp_update(struct ofconn *ofconn, const struct
ofp_header *oh)
{
//TODO
VLOG_INFO("=====I GOT FP FROM
CONTROLLER ========");
return
0;
}
以上就是ovs上需要考虑的地方,细节处要注意。接下来是Floodlight上面通过构造一个该消息,而后当接收到packet
in 后就将其发送到这个SW上。
在org.openflow.protocol
包中增加我们的消息类,以及相应的方法。
public class OFFPUpdate extends OFMessage
implements OFActionFactoryAware{
public
static int MINIMUM_LENGTH = 16;
public
static int BUFFER_ID_NONE = 0xffffffff;
protected OFActionFactory actionFactory;
protected int bufferId;
protected short
inPort = 0x0000; // not used yet
protected short other;
protected
List<OFAction> actions;
public
OFFPUpdate(){
super();
this.type =
OFType.FP_UPDATE;
this.length = U16.t(MINIMUM_LENGTH);
}
....................................
}
然后再OFType中标示这个新增的消息类。
public
enum OFType {
HELLO
(0, OFHello.class, new Instantiable<OFMessage>()
{
@Override
public OFMessage instantiate()
{
return new
OFHello();
}}),
...........................................................
FP_UPDATE (20,
OFFPUpdate.class, new Instantiable<OFMessage>()
{
@Override
public OFMessage instantiate()
{
return new
OFFPUpdate();
}});
}
在org.openflow.protocol.action中新增对应的action类,因为每次从SDN
controller发送控制类消息时都会设置它的action list。
public class
OFActionFPUpdate extends OFAction implements Cloneable
{
public static int MINIMUM_LENGTH =
8;
protected int vector;
public OFActionFPUpdate()
{
super.setType(OFActionType.FP_UPDATE);
super.setLength((short) MINIMUM_LENGTH);
}
public OFActionFPUpdate(int vector)
{
super();
super.setType(OFActionType.FP_UPDATE);
super.setLength((short)
MINIMUM_LENGTH);
this.vector = vector;
}
...................................
}
最后写一个简单的module
来测试。这里的思路是当收到某个SW发来的packetin消息时,我们就给这个交换机下发一个FPUpdate的消息。主要代码:
OFFPUpdate
fu
=
(OFFPUpdate)
floodlightProvider.getOFMessageFactory()
.getMessage(OFType.FP_UPDATE);
OFActionFPUpdate action = new
OFActionFPUpdate();
action.setVector(0xffffffff); // just for
testing
List<OFAction> actions = new
ArrayList<OFAction>();
actions.add(action);
fu.setBufferId(OFFPUpdate.BUFFER_ID_NONE)
.setInPort((short)0)
.setActions(actions)
.setLengthU(OFFPUpdate.MINIMUM_LENGTH+OFActionFPUpdate.MINIMUM_LENGTH);
try
{
sw.write(fu,
cntx);
}
catch (IOException e)
{
logger.error("Failure writing fp update",
e);
}
通过简单的测试,整个流程是正确的。
对于openvswitch的代码分析,可以看看我之前的文章 OVS源码阅读
对openflow 1.0协议的扩展,布布扣,bubuko.com
原文地址:http://www.cnblogs.com/vonzhou/p/3774498.html