...
 
Commits (3)
......@@ -23,6 +23,8 @@ class SPBSwitchApp(app_manager.RyuApp):
self.net = Topology()
self.verbose = False
# Flow Handler
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
......@@ -45,7 +47,7 @@ class SPBSwitchApp(app_manager.RyuApp):
mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
dp.send_msg(mod)
# Handle Packages
# Packet Handler
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
......@@ -64,13 +66,12 @@ class SPBSwitchApp(app_manager.RyuApp):
# learn (src, first_hop), (first_hop, src, port)
#####################################################
if not self.net.has_node(src):
self._print_event(
"ENDPOINT",
"Endpoint {0} injected a packet for {1} on Switch {2} at Port {3}".format(
src, dst, dpid, in_port
), ev
)
self._print_event(
"ENDPOINT",
"Endpoint {0} injected a packet for {1} on Switch {2} at Port {3}".format(
src, dst, dpid, in_port
), ev
)
self.net.add_edge(dpid, src, ev.msg.match['in_port'])
self.net.add_edge(src, dpid, 0)
......@@ -106,6 +107,8 @@ class SPBSwitchApp(app_manager.RyuApp):
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id, in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
# Packet Filter
def _filter(self, ev):
reason = ""
apply_filter = False
......@@ -133,6 +136,8 @@ class SPBSwitchApp(app_manager.RyuApp):
self._print_event("FILTER", reason, ev)
return apply_filter
# Misc
def _print_event(self, actor, reason, event):
out = "[{0}] {1}".format(actor, reason)
self.logger.info(out)
......
......@@ -7,6 +7,8 @@ from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
import json
class SimpleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
......@@ -15,6 +17,10 @@ class SimpleSwitch13(app_manager.RyuApp):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.ryu_packet_events = LogWriter('/output/ryu.packet.log')
# Flow Handler
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
......@@ -38,12 +44,28 @@ class SimpleSwitch13(app_manager.RyuApp):
mod = parser.OFPFlowMod(datapath=dp, priority=priority, match=match, instructions=inst)
dp.send_msg(mod)
def del_flow(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
for dst in self.mac_to_port[datapath.id].keys():
match = parser.OFPMatch(eth_dst=dst)
mod = parser.OFPFlowMod(
datapath,
command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY,
out_group=ofproto.OFPG_ANY,
priority=1,
match=match
)
datapath.send_msg(mod)
# Packet Handler
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
# If you hit this you might want to increase
# the "miss_send_length" of your switch
if ev.msg.msg_len < ev.msg.total_len:
self.logger.debug("Packet truncated: only %s of %s bytes", ev.msg.msg_len, ev.msg.total_len)
if self._filter(ev):
return
datapath = ev.msg.datapath
ofproto = ev.msg.datapath.ofproto
......@@ -53,15 +75,12 @@ class SimpleSwitch13(app_manager.RyuApp):
pkt = packet.Packet(ev.msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
return
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("[Packet In] %s %s %s %s", dpid, src, dst, in_port)
self.ryu_packet_events.write("[Packet In] %s %s %s %s".format(dpid, src, dst, in_port))
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
......@@ -88,3 +107,57 @@ class SimpleSwitch13(app_manager.RyuApp):
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id, in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
# Packet Filter
def _filter(self, ev):
reason = ""
apply_filter = False
# Rule: filter truncated packets
if ev.msg.msg_len < ev.msg.total_len:
reason = "Packet truncated"
apply_filter = True
pkt = packet.Packet(ev.msg.data)
# Rule: filter non Ethernet packet
if not pkt.get_protocol(ethernet.ethernet):
reason = "non-ethernet Packet"
apply_filter = True
eth = pkt.get_protocols(ethernet.ethernet)[0]
# Rule: filter LLDP
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
reason = "LLDP Packet"
apply_filter = True
if self.verbose and apply_filter:
self._print_event("FILTER", reason, ev)
return apply_filter
# Misc
def _print_event(self, actor, reason, event):
out = "[{0}] {1}".format(actor, reason)
self.logger.info(out)
class LogWriter(object):
def __init__(self, name='ryu.log', enable=True):
self.CRLF = "\r\n"
self.file = name
self.enabled = enable
def write(self, data):
if not self.enabled:
return True
try:
with open(self.file, 'a') as f:
f.write(json.dumps(data) + self.CRLF)
return True
except Exception:
return False
......@@ -11,8 +11,6 @@ from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.app import simple_switch_13
import json
class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
......@@ -23,31 +21,26 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
self.mac_to_port = {}
self.stp = kwargs['stplib']
self.ryu_events = LogWriter('/output/ryu.event.log')
self.ryu_stp_events = LogWriter('/output/ryu.stp.event.log')
self.ryu_packet_events = LogWriter('/output/ryu.packet.log')
self.ryu_packet_events = simple_switch_13.LogWriter('/output/ryu.packet.log')
self.ryu_events = simple_switch_13.LogWriter('/output/ryu.event.log')
self.ryu_stp_events = simple_switch_13.LogWriter('/output/ryu.stp.event.log')
self.verbose = False
# Sample of stplib config.
config = {dpid_lib.str_to_dpid('0000a0369f6bc904'):
{'bridge': {'priority': 0x8000}},
dpid_lib.str_to_dpid('0000a0369f6bc944'):
{'bridge': {'priority': 0x9000}},
dpid_lib.str_to_dpid('0000a0369f6bc8c8'):
{'bridge': {'priority': 0xa000}}}
self._stp_config(None)
# STP
def _stp_config(self, config=None):
if config is None:
# Sample of stplib config
config = {
dpid_lib.str_to_dpid('0000a0369f6bc904'): {'bridge': {'priority': 0x8000}},
dpid_lib.str_to_dpid('0000a0369f6bc944'): {'bridge': {'priority': 0x9000}},
dpid_lib.str_to_dpid('0000a0369f6bc8c8'): {'bridge': {'priority': 0xa000}}
}
self.stp.set_config(config)
def delete_flow(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
for dst in self.mac_to_port[datapath.id].keys():
match = parser.OFPMatch(eth_dst=dst)
mod = parser.OFPFlowMod(
datapath, command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
priority=1, match=match)
datapath.send_msg(mod)
# Packet Handler
@set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
......@@ -59,11 +52,14 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
parser = ev.msg.datapath.ofproto_parser
buffer_id = ev.msg.buffer_id
in_port = ev.msg.match['in_port']
dpid = ev.msg.datapath.id
eth = packet.Packet(ev.msg.data).get_protocol(ethernet.ethernet)
src = eth.src
pkt = packet.Packet(ev.msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.ryu_packet_events.write("[Packet In] %s %s %s %s".format(dpid, src, dst, in_port))
# learn a mac address to avoid FLOOD next time.
......@@ -73,7 +69,6 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
......@@ -87,51 +82,13 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
self.add_flow(datapath, 1, match, actions)
data = None
if ev.msg.buffer_id == ofproto.OFP_NO_BUFFER:
if buffer_id == ofproto.OFP_NO_BUFFER:
data = ev.msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id, in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
def _filter(self, ev):
# No Rule: filter if Reason one of..
ofproto = ev.msg.datapath.ofproto
if ev.msg.reason == ofproto.OFPR_NO_MATCH:
reason = 'NO MATCH'
elif ev.msg.reason == ofproto.OFPR_ACTION:
reason = 'ACTION'
elif ev.msg.reason == ofproto.OFPR_INVALID_TTL:
reason = 'INVALID TTL'
else:
reason = 'unknown'
# Rule: filter truncated packets
if ev.msg.msg_len < ev.msg.total_len:
if self.verbose:
self._print_event("FILTER", "Packet truncated", ev)
return True
pkt = packet.Packet(ev.msg.data)
# Rule: filter non Ethernet packet
if not pkt.get_protocol(ethernet.ethernet):
if self.verbose:
self._print_event("FILTER", "non-ethernet Packet", ev)
return True
eth = pkt.get_protocols(ethernet.ethernet)[0]
# Rule: filter LLDP
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
if self.verbose:
self._print_event("FILTER", "LLDP Packet", ev)
return True
return False
def _print_event(self, actor, reason, event):
out = "[{0}] {1}".format(actor, reason)
self.logger.info(out)
# Topology
@set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
def _topology_change_handler(self, ev):
......@@ -140,7 +97,7 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
self.ryu_events.write('Topology change {} - flushing MAC table.'.format(dpid_str))
if dp.id in self.mac_to_port:
self.delete_flow(dp)
self.del_flow(dp)
del self.mac_to_port[dp.id]
@set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
......@@ -174,23 +131,3 @@ class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
def ev_switch_del_handler(self, ev):
dpid = dpid_lib.dpid_to_str(ev.switch.dp.id)
self.ryu_events.write('Switch down {0}'.format(dpid))
class LogWriter(object):
def __init__(self, name='ryu.log', enable=True):
self.CRLF = "\r\n"
self.file = name
self.enabled = enable
def write(self, data):
if not self.enabled:
return True
try:
with open(self.file, 'a') as f:
f.write(json.dumps(data) + self.CRLF)
return True
except Exception:
return False