Learning Switch/自学习交换机
- 明确问题–如何实现软件定义的自学习交换机?
- 设计解决方案–通过控制器来实现自学习交换算法,然后指导数据平面实现交换机操作。
- 确定具体技术方案–控制器选用Ryu,数据平面用Mininet模拟
- 部署实施–在控制器上编程开发集线器应用。创建实验网络为验证方案网络做准备。
- 验证方案–运行、调试、验证程序。
- 优化–验证成功后
集线器是物理层设备,功能是对接受到的数据进行再生整形放大,以扩大传输距离,把所有节点集中在中心节点。没有“学习能力”,发送数据没有针对性,采用广播方式发送,当要向某个节点发送数据的时候,是把数据包发送到相连的所有节点。
交换机:光电信号转发的网络设备,为介入交换机的任意两个网络节点提供独享的电信号通路。
自学习交换机的原理/Learning Switch
交换机的1 3 4端口分别连接主机A C B,交换机里面有两个表,分别是MAC地址表和流表
主机A给交换机发消息说我要找主机B,刚开始流表是默认的,没有可以用来指导处理的信息,这时候交换机就会找控制器,这时候控制机就会记录下来A主机连接在哪个端口在MAC地址表中。这时候控制器也不知道B是谁,那就跟交换机说你泛洪一下,发给其他所有的主机,然后B和C主机都能收到消息。
B收到信息知道A是找它的,C收到发现不是找他的就丢掉信息。然后B发送回复,B先发给交换机,交换机不知道怎么处理,给控制器发信息,控制器发现B找A,A在1端口,这时候还学习了一下B在端口4。现在知道了入端口和出端口,就需要下发一条流表项。流表中记录从端口4进入,目的端口是1.
A继续回复,交换机中只有B到A,还不知道A到B,还需要询问控制器,这时候控制器有A和B的MAC地址信息,所以可以下发流表项信息。之后再进行数据转发的时候就可以不询问控制器,直接在交换机中进行转发操作。
Learning Switch/自学习交换机验证(Ryu控制器的API使用)
from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller.handler import CONFIG_DISPATCHER,MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.controller import ofp_event
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
# 编写自学习交换机程序
class ExampleSwitch(app_manager.RyuApp):
# 获取OpenFlowProtocol版本号
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def _init_(self,*args,**kwargs):
super(ExampleSwitch,self)._init_(*args,**kwargs)
# mac 地址表
self.mac_to_port={}
# 见上一篇2.1博文
def switch_features_handler(self,ev):
datapath = ev.msg.datapath
ofproto = datapath
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)
def add_flow(self,datapath,priority,match,actions):
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,instryction=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
# get datapath id to identify OpenFlow switch
# 一个交换机对应一个dpid
dpid = datapath.id
# 设置mac地址表默认格式
self.mac_to_port.setdefault(dpid,{})
# store the info
# parser and analylize the received packets
# 利用提供的方法进行解析数据
pkt = packet.Packet(msg.data)
# 获取以太网协议
eth_pkt = pkt.get_protocol(ethernet.ethernet)
dst = eth_pkt.dst
src = eth_pkt.src
# 获取 in_port
in_port = msg.match['in_port']
# dpid 交换机的编号
# src 输入主机ip
# dst 输出主机ip
# in_port 输入端口
self.logger.info("packet in %s %s %s %s",dpid,src,dst,in_port)
# learn a mac address to avoid Flood next time
self.mac_to_port[dpid][src] = in_port
# if the dst mac address has already learned.
# decide which port to send the packets, otherwise, flood.
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
# contruct actions
actions=[ofp_parser.OFPActionOutput(out_port)]
# install a flow mod msq
if out_port != ofproto.OFPP_FLOOD:
match = ofp_parser.OFPMatch(in_port=in_port,eth_dst=dst)
# 下发流表项
self.add_flow(datapath,1,match,actions)
# send a packet out
out = ofp_parser.OFPPacketOut(
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions)
datapath.send_msg(out)
- sudo mn --controller=remote
- pingall
- sudo mn --controller=remote --mac