Dijkstra Algorithm implementation in RYU
[Script: dijkstra_ryu.py]
# Copyright (C) 2011 Nippon Telegraph and
Telephone Corporation. # # Licensed under the Apache License,
Version 2.0 (the "License"); # you may not use this file except in
compliance with the License. # You may obtain a copy of the License at # #
http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or
agreed to in writing, software # distributed under the License is
distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or # implied. # See the License for the specific language
governing permissions and # limitations under the License. from ryu.base import app_manager from ryu.controller import mac_to_port from ryu.controller import ofp_event from ryu.controller.handler import CONFIG_DISPATCHER,
MAIN_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.ofproto import ofproto_v1_3 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 from ryu.lib import mac from ryu.topology.api
import get_switch, get_link from ryu.app.wsgi import ControllerBase from ryu.topology import event, switches from collections import defaultdict #switches switches = [] #mymac[srcmac]->(switch, port) mymac={} #adjacency map [sw1][sw2]->port
from sw1 to sw2 adjacency=defaultdict(lambda:defaultdict(lambda:None)) def minimum_distance(distance, Q): min = float('Inf') node = 0 for v in Q: if distance[v] < min: min =
distance[v] node = v return node def get_path (src,dst,first_port,final_port): #Dijkstra's
algorithm print "get_path
is called, src=",src," dst=",dst, " first_port=", first_port, " final_port=",
final_port distance = {} previous = {} for dpid in
switches: distance[dpid] = float('Inf') previous[dpid] = None distance[src]=0 Q=set(switches) print "Q=", Q while len(Q)>0: u = minimum_distance(distance, Q) Q.remove(u) for p in switches: if
adjacency[u][p]!=None: w
= 1 if
distance[u] + w < distance[p]:
distance[p] = distance[u] + w
previous[p] = u r=[] p=dst r.append(p) q=previous[p] while q is not None: if q == src: r.append(q) break p=q r.append(p) q=previous[p] r.reverse() if src==dst: path=[src] else: path=r # Now add the ports r = [] in_port = first_port for s1,s2 in
zip(path[:-1],path[1:]): out_port
= adjacency[s1][s2] r.append((s1,in_port,out_port)) in_port
= adjacency[s2][s1] r.append((dst,in_port,final_port)) return r class ProjectController(app_manager.RyuApp): OFP_VERSIONS =
[ofproto_v1_3.OFP_VERSION] def
__init__(self, *args, **kwargs): super(ProjectController,
self).__init__(*args, **kwargs) self.mac_to_port = {} self.topology_api_app = self self.datapath_list=[] # Handy function that
lists all attributes in the given object def
ls(self,obj): print("\n".join([x for
x in dir(obj) if x[0] !=
"_"]))
def
add_flow(self,
datapath, in_port, dst, actions): ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = datapath.ofproto_parser.OFPMatch(
in_port=in_port, eth_dst=dst)
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = datapath.ofproto_parser.OFPFlowMod(
datapath=datapath,
match=match, cookie=0,
command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
instructions=inst) datapath.send_msg(mod) def
install_path(self, p, ev, src_mac, dst_mac): print
"install_path is called"
#print
"p=", p, " src_mac=", src_mac, " dst_mac=",
dst_mac msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto parser =
datapath.ofproto_parser for sw, in_port, out_port in p:
#print src_mac,"->", dst_mac, "via ", sw,
" in_port=", in_port,
" out_port=", out_port
match=parser.OFPMatch(in_port=in_port, eth_src=src_mac, eth_dst=dst_mac)
actions=[parser.OFPActionOutput(out_port)]
datapath=self.datapath_list[int(sw)-1] inst
= [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS , actions)] mod = datapath.ofproto_parser.OFPFlowMod(
datapath=datapath,
match=match, idle_timeout=0, hard_timeout=0,
priority=1, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPSwitchFeatures
, CONFIG_DISPATCHER) def
switch_features_handler(self , ev): print "switch_features_handler
is called" datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser
match = parser.OFPMatch() actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)] inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS , actions)] mod = datapath.ofproto_parser.OFPFlowMod(
datapath=datapath,
match=match, cookie=0,
command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=0, 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
parser = datapath.ofproto_parser in_port = msg.match['in_port'] pkt = packet.Packet(msg.data)
eth = pkt.get_protocol(ethernet.ethernet)
#print "eth.ethertype=",
eth.ethertype #avodi broadcast from LLDP if
eth.ethertype==35020:
return dst = eth.dst src = eth.src dpid = datapath.id self.mac_to_port.setdefault(dpid, {}) if
src not in mymac.keys():
mymac[src]=( dpid, in_port)
#print "mymac=", mymac if
dst in mymac.keys():
p = get_path(mymac[src][0], mymac[dst][0], mymac[src][1], mymac[dst][1])
print p
self.install_path(p,
ev, src, dst)
out_port = p[0][2]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)] #
install a flow to avoid packet_in next time if
out_port
!= ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_src=src, eth_dst=dst)
data=None if
msg.buffer_id==ofproto.OFP_NO_BUFFER:
data=msg.data
out = parser.OFPPacketOut(
datapath=datapath,
buffer_id=msg.buffer_id,
in_port=in_port,
actions=actions, data=data) datapath.send_msg(out)
@set_ev_cls(event.EventSwitchEnter) def
get_topology_data(self, ev):
global switches switch_list = get_switch(self.topology_api_app,
None)
switches=[switch.dp.id for switch in switch_list] self.datapath_list=[switch.dp for switch in switch_list]
#print "self.datapath_list=",
self.datapath_list
print "switches=", switches links_list = get_link(self.topology_api_app, None)
mylinks=[(link.src.dpid,link.dst.dpid,link.src.port_no,link.dst.port_no)
for link in links_list]
for s1,s2,port1,port2 in mylinks:
adjacency[s1][s2]=port1
adjacency[s2][s1]=port2
#print s1,s2,port1,port2
|
[execution]
Reference
https://sourceforge.net/p/ryu/mailman/message/34289918/
Dr. Chih-Heng Ke
Department of Computer Science and
Information Engineering, National Quemoy University, Kinmen, Taiwan
Email: smallko@gmail.com