天天看点

SDN之基于Ryu控制器的自学习交换机实现自学习交换机代码实现

自学习交换机

交换机的自学习在传统网络中是一项非常重要的数据链路层功能。该功能确保转发表能够动态变化,以适应不同的流、实现相应的转发目标。

SDN中交换机的自学习与TCP/IP协议的第二层交换机工作模式类似,总的来说,我们需要对经过交换机的流安装相应的流表,达到转发的目标,主要步骤有以下几个:

1、交换机收到数据包,此时没有安装相应规则,故需要产生packet_in消息给控制器;

2、控制器对数据包进行解析,并指示交换机如何处理这个数据包(在未安装规则的情况下,交换机解析数据包的源端口,并将对该数据包进行泛洪,已确定究竟哪个端口能够到达目的MAC);

3、当数据包被目的MAC主机接收之后,返回应答消息,再次经过交换机的时候,由于源端口变为了第(1)步中的目的端口,目的端口变成了第(1)步中的源端口(即反方向发送应答数据包)所以此时交换机仍然不知道怎么做,上报控制器确定目的端口和源端口;

此时控制器发现该应答的源端口即为第1步中的目的端口,就知道了这两个端口之间的对应关系,于是下发流表。

SDN之基于Ryu控制器的自学习交换机实现自学习交换机代码实现

代码实现

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-未来网络学院)

继续阅读