1:集线器原理—设计解决方案
一个数据包从port1进入,会被复制,泛洪转发到其他所有端口发出
2:部署实施—Ryu控制器API学习和使用(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_features_handler(self,ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
match = ofp_parser.OFPMatch()
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath,0,match,actions,"default flow entry")
def add_flow(self,datapath,priority,match,actions,remind_content):
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
match=match,instructions=inst);
print("install to datapath,"+remind_content)
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']
print("get packet in, install flow entry,and lookback parket to datapath")
match = ofp_parser.OFPMatch();
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]
self.add_flow(datapath,1,match,actions,"hub flow entry")
out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=msg.buffer_id,
in_port=in_port,actions=actions)
datapath.send_msg(out);
(二)启动控制器
ryu-manager hub.py --verbose #进入目录,在hub.py文件目录下 --verbose显示调试信息
(三)启动Mininet进行连接测试
sudo mn --topo=linear,4 --controller=remote
openvswitch交换机与Ryu控制器连接,控制器下发默认流表,提示信息install to datapath,default flow entry
(三)使用pingall命令,使得主机向交换机发送数据包—从而实现交换机上传数据包到控制器,实现流表获取
获取提示信息get packet in, install flow entry,and lookback parket to datapath
3: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):
'''明确控制器所用OpenFlow版本'''
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_features_handler(self,ev):
'''
在Ryu控制器上,我们需要写一个函数去处理openvswitch的连接
CONFIG_DISPATCHER : Version negotiated and sent features-request message
'''
#对事件进行解析
datapath = ev.msg.datapath #从连接中获取数据平面的datapath数据结构
ofproto = datapath.ofproto #获取OpenFlow协议信息
ofp_parser = datapath.ofproto_parser #获取协议解析
#解析完成
'''在连接建立成功以后,需要控制器下发一个默认流表
来指挥所有匹配不到交换机的数据,把他上传到控制器上
'''
#install the table-miss flow entry
match = ofp_parser.OFPMatch() #匹配域
#OFPActionOutput将数据包发送出去,
#第一个参数OFPP_CONTROLLER是接收端口,
#第二个是数据包在交换机上缓存buffer_id,由于我们将数据包全部传送到控制器,所以不在交换机上缓存
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath,0,match,actions,"default flow entry") #默认缺省流表项,设置优先级最低即可
'''
数据平面 是由若干网元(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,remind_content):
'''构建流表项 : add a flow entry, install it into datapath
datapath:表示给哪一个逻辑设备下发流表
priority:表示优先级
match,actions:匹配域和动作
'''
#datapath属性
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
#在OpenFlow1.3版本中定义了instruct指令集(交换机内部的一些操作)
#construct a flow msg and send it
inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
match=match,instructions=inst);
print("install to datapath,"+remind_content)
#发送出去
datapath.send_msg(mod);
'''接收数据
Ryu控制器通过装饰器去注册监听某些事件,去处理这些事件。
从而实现从数据平面的消息上传到控制器,再从控制器平面到应用平面,应用程序去处理事件,再逐跳返回到openvswitch
'''
'''要处理这个事件,需要先去注册监听他
EventOFPPacketIn: 是我们要监听的事件
MAIN_DISPATCHER : 是什么状态下,去监听该事件---Switch-features message received and sent set-config message
'''
@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
'''Hub集线器类,所实现的功能:
1.接收从OpenVSwitch发送过来的数据包
2.将数据包泛洪到Hub中的其他端口中
'''
#解析数据结构
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser
in_port = msg.match['in_port'] #获取源端口
print("get packet in, install flow entry,and lookback parket to datapath")
match = ofp_parser.OFPMatch(); #因为我们是将所有转发,所以不用管匹配,填空表示全部匹配
actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)] #注意:FLOOD是OpenFlow协议保留端口---泛洪使用
#调用add_flow,将流表项发送 ,指导后续数据包转发 install flwo entry to avoid packet in next time
self.add_flow(datapath,1,match,actions,"hub flow entry") #等级稍微比默认流表项高级
#注意:我们将流表项下发了,但是数据包我们这次接收的,并没有处理
#就是再将控制器上的数据包,重新发送给datapath,让他按照流表项处理
#buffer_id是这个数据包,存放在控制器中的缓冲区位置,是在事件中的buffer_id获取
out = ofp_parser.OFPPacketOut(datapath=datapath,buffer_id=msg.buffer_id,
in_port=in_port,actions=actions,data=msg.data)
datapath.send_msg(out);
通信流程:
1.当开始一个Hub集线器时,会先与控制器进行连接,我们需要在Ryu中设置函数去处理连接,设置并下发默认流表———函数switch_features_handler实现
2.当主机之间通信时,主机上传信息到OpenVSwitch交换机,而交换机无法匹配到流表项时,我们设置将数据全部上传给Ryu控制器,我们在控制器端实现Hub集线器的泛洪功能,即设置流表项(match-actions为所有匹配数据包的动作为ofproto.OFPP_FLOOD,并且将该流变下发给原来datapath,同时我们要将之前交换机发送过来的数据包重新发送给交换机(让其按照新的流表项进行处理)——–函数packet_in_handler实现
3.我们将公共函数add_flow,构建流表项并且下发流表提出
版权声明:本文为weixin_45236003原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。