自学习交换机
交换机的自学习在传统网络中是一项非常重要的数据链路层功能。该功能确保转发表能够动态变化,以适应不同的流、实现相应的转发目标。
SDN中交换机的自学习与TCP/IP协议的第二层交换机工作模式类似,总的来说,我们需要对经过交换机的流安装相应的流表,达到转发的目标,主要步骤有以下几个:
1、交换机收到数据包,此时没有安装相应规则,故需要产生packet_in消息给控制器;
2、控制器对数据包进行解析,并指示交换机如何处理这个数据包(在未安装规则的情况下,交换机解析数据包的源端口,并将对该数据包进行泛洪,已确定究竟哪个端口能够到达目的MAC);
3、当数据包被目的MAC主机接收之后,返回应答消息,再次经过交换机的时候,由于源端口变为了第(1)步中的目的端口,目的端口变成了第(1)步中的源端口(即反方向发送应答数据包)所以此时交换机仍然不知道怎么做,上报控制器确定目的端口和源端口;
此时控制器发现该应答的源端口即为第1步中的目的端口,就知道了这两个端口之间的对应关系,于是下发流表。
代码实现
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
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
class Learning_switch(app_manager.RyuApp):
# Example Switch
OFP_VERSIONS=[ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(Learning_switch, self).__init__(*args, **kwargs)
self.mac_to_port={}
@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
# get datapath id to identify openflow switch
dpid=datapath.id #dpid=datapath id
self.mac_to_port.setdefault(dpid,{})
# save info
# parser and analyse 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=msg.match['in_port']
self.logger.info("packet in %s %s %s %s",dpid,src,dst,in_port)
# learn the relationship between source mac address and ports to avoid Flood next time
self.mac_to_port[dpid][src]=in_port
# if the dst mac address exists, decide which port to send the packet
# otherwise Flood (Don't know which port lead to the dest port)
if dst in self.mac_to_port[dpid]:
out_port=self.mac_to_port[dpid][dst]
else:
out_port=ofproto.OFPP_FLOOD
# build actions
actions=[ofp_parser.OFPActionOutput(out_port)]
# install a new flow rule
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)
来源:https://edu.sdnlab.com/training/376.html(SDNLAB-未来网络学院)