from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import MAIN_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.ofproto import ofproto_v1_0 from ryu.lib.mac import haddr_to_bin from ryu.lib.packet import packet from ryu.lib.packet import ethernet from ryu.lib.packet import ether_types class L2Switch(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION] def __init__(self, *args, **kwargs): super(L2Switch, self).__init__(*args, **kwargs) self.mac_to_port = dict() def add_flow(self, datapath, in_port, dst, src, actions): ofp = datapath.ofproto match = datapath.ofproto_parser.OFPMatch( in_port=in_port, dl_dst=haddr_to_bin(dst), dl_src=haddr_to_bin(src)) mod = datapath.ofproto_parser.OFPFlowMod( datapath=datapath, match=match, cookie=0, command=ofp.OFPFC_ADD, idle_timeout=3, hard_timeout=9, priority=ofp.OFP_DEFAULT_PRIORITY, flags=ofp.OFPFF_SEND_FLOW_REM, actions=actions) datapath.send_msg(mod) @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def packet_in_handler(self, ev): msg = ev.msg dp = msg.datapath ofp = dp.ofproto ofp_parser = dp.ofproto_parser # adding some verbose messages pkt = packet.Packet(msg.data) eth = pkt.get_protocol(ethernet.ethernet) self.logger.info("src mac-port: %s-%s", eth.src, msg.in_port) self.logger.info("dst mac: %s", eth.dst) # end verbose # learn mac address for later if dp.id not in self.mac_to_port: self.mac_to_port[dp.id] = dict() self.mac_to_port[dp.id][eth.src] = msg.in_port # use previous knowledge (if available) out_port = self.mac_to_port.get(dp.id, dict()).get(eth.dst, ofp.OFPP_FLOOD) # send the package actions = [ofp_parser.OFPActionOutput(out_port)] out = ofp_parser.OFPPacketOut( datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) dp.send_msg(out) # save path in routing table for later if out_port != ofp.OFPP_FLOOD: self.add_flow(dp, msg.in_port, eth.dst, eth.src, actions)