前言
最近在搞SDN大赛,我们的初赛题目是使用SDN网络实现对SYN Flood 攻击的防御,因此我就开始了SDN的学习之旅,根据旗神的推荐,我们是使用的控制器是RYU,那我们就先看看一个简单的样例吧——simple_switch.py(这个文件在ryu/app/simple_switch_13.py,在不同的版本中,最后的数字是不一样的)。
本文内容分来自于RYUbook这本书,是台湾RYU团队翻译的。
类别的定义和初始化
为了实现Ryu程序,需要继承ryu.base.app_manager.RyuApp这个类,然后将OFP_VERSION设定为OpenFlow 1.3.
之后定义MAC地址表mac_port。
在OpenFlow协议中,有些程序需要定义在OpenFlow交换机和Controller之间的链接,比如握手(handshank),这些东西我们会在后面讲解,暂时先不用管。
1 | class SimpleSwitch13(app_manager.RyuApp): |
事件管理(Event handler)
对于RYU来说,接受到的任何OpenFlow消息都会立即产生一个相对应得事件(Event),而我们的RYU程序需要对这个事件进行相应的处理。
事件管理(Event handler)需要一个事件对象(Event Object)作为参数,并且使用ryu.controller.handler.set_ev_cls修饰(Decorator)函数。不懂得可以去看Python教程了。
set_ev_cls需要指定事件的类别和交换机的状态参数。
事件的类别为ryu.controller.ofp_event.EventOFP+<OpenFlow讯息名称>,例如Pack-in事件,就是EventOFPPacketIn。具体的事件定义,请查看Ryu的API手册。
对于状态来说,需要指定下面的表格中的一项。
| 名称 | 说明 |
|---|---|
| ryu.controller.handler.HANDSHAKE_DISPATCHER | 交换Hello消息 |
| ryu.controller.handler.CONFIG_DISPATCHER | 接收SwitchFeatures消息 |
| ryu.controller.handler.MAIN_DISPATCHER | 一般状态 |
| ryu.controller.handler.DEAD_DISPATCHER | 连接中断 |
添加缺省流(Table-miss Flow Entry)
OpenFlow交换机与Controller握手完成后,会在流表中添加缺省流(Table-miss Flow Entry),为接收Packet-In消息做准备。
1 |
|
ev.msg是用来存储对应事件的OpenFlow消息类的对象,在这个例子中指的是ryu.ofproto.ofproto_v1_3_parser.OFPSwitchFeatures。
msg.datapath是用来存储OpenFlow交换机ryu.controller.controller.Datapath类所对应的对象。
Datapath类是用来处理OpenFlow交换机的重要信息,例如:执行交换机的通讯和触发接收消息的相关事件。
Ryu应用程序使用的主要属性如下:
| 名称 | 说明 |
|---|---|
| id | 连接的OpenFlow交换机的ID |
| ofproto | 表示当前使用的OpenFlow版本的对应ofproto module。目前可用的参数如下: |
| ryu.ofproto.ofproto_v1_0 | |
| ryu.ofproto.ofproto_v1_2 | |
| ryu.ofproto.ofproto_v1_3 | |
| ryu.ofproto.ofproto_v1_4 | |
| ofproto_parser | 和ofproto一样,表示ofproto_parser module。目前可用的参数如下: |
| ryu.ofproto.ofproto_v1_0_parser | |
| ryu.ofproto.ofproto_v1_2_parser | |
| ryu.ofproto.ofproto_v1_3_parser | |
| ryu.ofproto.ofproto_v1_4_parser |
Ryu应用程序中Datapath类的主要方法是send_msg(msg),发送OpenFlow消息。
msg是将要发送的OpenFlow消息,是ryu.ofproto.ofproto_parser.MsgBox的子类。
交换机本身不仅仅使用收到的Switch features消息,还会在事件被处理时添加Table-miss Flow Entry。
1 | def switch_features_handler(self, ev): |
Table-miss Flow Entry的优先级为0(最低),并且这个流表项可以匹配所有的包,而且这个流表项所的动作通常是output action,并且输出端指向Controller。因此,当某个包没有匹配到其他的流表项的时候,就会触发Pack-In事件。
即:当交换机收到Packet后,匹配流表失败,会将这个Packet发送给Table-miss Flow Entry表项所对应的端口,也就是控制器。
Packet-In 消息
为了接收未知包,需要对Packet-In事件管理。
1 |
|
OFPPacketIn类的常用属性如下:
| 名称 | 说明 |
|---|---|
| match | 用来存储接收包的Match信息,是ryu.ofproto.ofproto_v1_3_parser.OFPMatch类 |
| data | 收到的包的二进制数据 |
| total_len | 收到的包的长度 |
| buffer_id | 如果收到的包是在OpenFlow交换机的Buffer中,则需要指定交换机的ID,如果不在Buffer中,则指定为ryu.ofproto.ofproto_v1_3.OFP_NO_BUFFER |
更新MAC地址表
1 | def _packet_in_handler(self, ev): |
判断包的输出端口
若目的MAC地址在MAC地址表中,则应该判断这个包的输出端口;如果不在MAC地址表中,则OUTPUT action类应该指定flooding(OFPP_FLOOD)为输出端口。
1 | def _packet_in_handler(self, ev): |
不同于缺省流表项(Table-miss Flow Entry),在添加新的流表项的时候,需要指明优先级,优先级数值越大,优先级越高。同时还要指明match条件,在样例中,是指定了in_port和目的MAC地址,只要满足这个条件,就会调用这个流。
添加对流的处理
1 | def add_flow(self, datapath, priority, match, actions): |
这一块没怎么看懂,看懂了再更新。。。