60 lines
2.3 KiB
Python
60 lines
2.3 KiB
Python
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) |