Hub实现环境:两台Ubuntu虚拟机、mininet、ryu控制器、pycharm
环境搭建见前几篇文章,有具体的搭建步骤。
对于ryu的开发,推荐ryubook这本工具书。
首先,在Ubuntu上安装pycharm,安装完成后,导入ryu项目,若出现无法修改或者权限问题,则需要通过命令chmod [ u / g / o / a ] [ + / - / = ] [ r / w / x ] file修改文件的权限。
接下来,就解释一下代码的编写:
导入包,将导包放在最前面,主要是刚开始学实在不知道导入哪几个包,未来避免出错,可以将所有的包都导入,可以参考ryubook的交换机的程序。
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
接下来,定义一个类hub,继承app_manager,位于ryu下的base内,版本选择openflow1.3,然后初始化操作。
lass hub(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(hub, self).__init__(*args, **kwargs)
接下来,需要定义packet in函数,用来处理交换机和控制器的流表交互,在执行之前需要先对packetin事件进行监听。
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
# 这几句是对数据结构进行解析,是一种固定的形式,可以记住就行
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
in_port = msg.match['in_port'] # get in port of the packet
# add a flow entry for the packet
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
self.add_flow(datapath, 1, match, actions)
# to output the current packet. for install rules only output later packets
out = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions)
# buffer id: locate the buffered packet
datapath.send_msg(out)
在Ryu控制器上,我们需要写一个函数去处理openvswitch的连接,同时需要开启一个监听,监听交换机事件。
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_feathers_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# install flow table-miss flow entry
match = ofp_parser.OFPMatch()
#OFPActionOutput将数据包发送出去,
#第一个参数OFPP_CONTROLLER是接收端口,
#第二个是数据包在交换机上缓存buffer_id,由于我们将数据包全部传送到控制器,所以不在交换
#机上缓存
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
# 1\OUTPUT PORT, 2\BUFF IN SWITCH?
self.add_flow(datapath, 0, match, actions)
ryu的数据平面是由若干网元(Network Element)组成,每个网元包含一个或多个SDN数据路径(SDN Datapath)。SDN Datapath是逻辑上的网络设备,负责转发和处理数据无控制能力,一个SDN DataPath包含控制数据平面接口(Control Data Plane Interface,CDPI)、代理、转发引擎(Forwarding Engine)表和处理功能(Processing Function)SDN数据面(转发面)的关键技术:对数据面进行抽象建模。对于添加流表,可以将其单独拿出了写一个函数。
def add_flow(self, datapath, priority, match, actions):
# 1\ datapath for the switch, 2\priority for flow entry, 3\match field, 4\action for packet
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# install flow
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst)
datapath.send_msg(mod)
代码完成之后,就是实验的验证。
首先,在装有ryu控制器的虚拟机中,运行Hub,具体的运行步骤如下:即先进入ryu目录下,使用ryu-manager Hub.py运行Hub。
然后,实验验证需要使用mininet进行模拟网络架构,具体的模拟方式见之前的博客,此次实验的拓扑如下。交换机选择ovs,控制器远程连接ryu控制器。
然后,运行拓扑,进行pingall测试,如图显示,Hub可以成功转发数据流。
Hub的完整代码如下:
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
class hub(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(hub, self).__init__(*args, **kwargs)
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_feathers_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# install flow table-miss flow entry
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
# 1\OUTPUT PORT, 2\BUFF IN SWITCH?
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
# 1\ datapath for the switch, 2\priority for flow entry, 3\match field, 4\action for packet
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
# install flow
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath, priority=priority, match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
in_port = msg.match['in_port'] # get in port of the packet
# add a flow entry for the packet
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
self.add_flow(datapath, 1, match, actions)
# to output the current packet. for install rules only output later packets
out = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions)
# buffer id: locate the buffered packet
datapath.send_msg(out)