Hi
I am using RYU-4.23 and Mininet OVS.
I have a 62 Node topology. When I run my RYU application I noticed that RYU
is not able to discover all the datapaths and links everytime I run my
code. And also when I run (link down command ) in mininet CLI,
EventLinkDelete is not getting triggered everytime I did it. Few times I
was actually able to discover the full topology and EventLinkDelete was
also getting triggered.
Can you please suggest why is this so. I have attached codes below.
Thanks!
Taha
from mininet.net import Mininet
from mininet.node import Controller, RemoteController
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from time import sleep
Nodes=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62]
Links=[[1, 2], [1, 3], [3, 4], [3, 5], [6, 7], [6, 8], [4, 9], [10, 9], [10, 11],
[5, 12], [5, 7], [5, 11], [5, 9], [5, 13], [9, 14], [9, 15],
[9, 16], [9, 17], [15, 18], [19, 20], [19, 21], [19, 22],
[23, 24], [23, 25], [25, 26], [25, 20], [25, 27], [28, 29],
[28, 30], [29, 31], [29, 32], [29, 33], [29, 30], [29, 34],
[35, 36], [35, 37], [37, 38], [37, 30], [38, 39], [39, 25],
[25, 30], [30, 40], [30, 26], [30, 33], [30, 41], [30, 42],
[30, 43], [30, 44], [45, 46], [45, 47], [45, 41], [45, 44],
[27, 40], [27, 20], [27, 48], [27, 21], [48, 49], [48, 50],
[32, 26], [41, 47], [16, 33], [16, 51], [16, 52], [16, 21],
[49, 40], [22, 20], [53, 24], [53, 54], [24, 26], [43, 40],
[31, 54], [42, 40], [40, 46], [40, 33], [40, 50], [55, 56],
[55, 21], [34, 33], [51, 57], [51, 21], [56, 33], [21, 57],
[21, 26], [21, 33], [21, 20], [54, 26], [36, 46], [7, 33],
[7, 58], [12, 52], [12, 8], [13, 17], [46, 33], [46, 59],
[46, 58], [59, 58], [58, 33], [33, 60], [33, 8], [8, 61],
[8, 2], [52, 14], [52, 18], [52, 62], [62, 14], [14, 18], [60, 61]]
def emptyNet():
"Create an empty network and add nodes to it."
net = Mininet(controller=RemoteController)
info('*** Adding controller\n')
net.addController('c0', controller=RemoteController, ip='127.0.0.1', port=6633)
info('*** Adding hosts\n')
h = []
for i in Nodes:
host = 'h' + str(i)
h.append(net.addHost(host))
info('*** Adding switch\n')
s = []
for j in Nodes:
switch = 's' + str(j)
s.append(net.addSwitch(switch))
"""print(s)"""
info('*** Creating links\n')
## One host at each switch
for index in range(0,len(Nodes)):
net.addLink(s[index], h[index])
i=0;
for link_pair in Links:
i=i+1;
net.addLink('s'+str(link_pair[0]), 's'+str(link_pair[1]))
print('s'+str(link_pair[0]), 's'+str(link_pair[1]), i)
info('*** Starting network\n')
net.start()
for i in s:
i.cmd('ovs-vsctl set bridge', i ,'protocols=OpenFlow13')
info('*** Running CLI\n')
CLI(net)
#sleep(2)
#net.pingAll()
info('*** Stopping network')
net.stop()
if __name__ == '__main__':
setLogLevel('info')
emptyNet()
# 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 ofp_event
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
import logging
import struct
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER, CONFIG_DISPATCHER
from ryu.lib.packet import ipv4
from ryu.lib import mac
from ryu.lib.packet import arp
from ryu.topology import event, switches
from ryu.topology.api import get_switch, get_link
from ryu.controller import dpset
from ryu.lib import dpid
from ryu.controller import handler
from threading import Timer
class SimpleSwitch14(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'dpset': dpset.DPSet}
def __init__(self, *args, **kwargs):
super(SimpleSwitch14, self).__init__(*args, **kwargs)
self.topology_api_app = self
self.mac_to_port = {}
self.switch_port_table = {}
self.link_to_port = {}
self.interior_ports = {}
self.dpid_port_set = set()
self.ip_mac_table = {}
self.ip_dpidport = {}
self.datapath_list = {}
self.link_ids = {}
self.key = []
self.value = []
self.link_pair={} ## Update the constant value of 16.
self.primary_flow_list=[]
#self.survi_paths = SurvSimReq(self.link_ids,self.datapath_list)
self.survi_paths=0
#self.bu_flow = Backup_Paths(msg, self.link_ids, self.datapath_list)
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# install table-miss flow entry
#
# We specify NO BUFFER to max_len of the output action due to
# OVS bug. At this moment, if we specify a lesser number, e.g.,
# 128, OVS will send Packet-In with invalid buffer_id and
# truncated packet data. In that case, we cannot output packets
# correctly. The bug has been fixed in OVS v2.1.0.
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
###############################End_of_Group_Mod_Action#####################################
@set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
def _state_change_handler(self, ev):
dp = ev.datapath
ofproto = dp.ofproto
parser = dp.ofproto_parser
if ev.state == handler.MAIN_DISPATCHER:
self.datapath_list[dp.id] = dp
self.logger.info("DPIDDDDDDDDDD: {}".format(dp.id))
msg = 'Join SW'
elif ev.state == handler.DEAD_DISPATCHER:
ret = self.datapath_list.pop(dp.id, None)
if ret is None:
msg = 'Leave unknown SW'
else:
msg = 'Leave sw'
self.logger.info('dpid {} {} '.format(msg, self.datapath_list))
self.logger.info("port state change event triggered")
def create_port_map(self, switch_list):
"""
Create interior_port table and access_port table.
"""
for sw in switch_list:
dpid = sw.dp.id
self.switch_port_table.setdefault(dpid, set())
self.interior_ports.setdefault(dpid, set())
for p in sw.ports:
self.switch_port_table[dpid].add(p.port_no)
#self.logger.info('Switch_port_table :{}'.format(self.switch_port_table))
def create_interior_links(self, link_list):
"""
Get links`source port to dst port from link_list,
link_to_port:(src_dpid,dst_dpid)->(src_port,dst_port)
"""
for link in link_list:
src = link.src
dst = link.dst
self.link_to_port[(src.dpid, dst.dpid)] = (src.port_no, dst.port_no)
# Find the access ports and interior ports
if link.src.dpid in self.switches:
self.interior_ports[link.src.dpid].add(link.src.port_no)
if link.dst.dpid in self.switches:
self.interior_ports[link.dst.dpid].add(link.dst.port_no)
if len(self.link_to_port) == 214:
for i in self.link_to_port.keys():
self.key.append(i)
for i in self.link_to_port.values():
self.value.append(i)
for i in range(len(self.link_to_port)):
self.link_ids[i + 1] = self.key[i] + self.value[i]
self.logger.info('Link_ids {}'.format(self.link_ids))
self.logger.info('Link_to_Port {}'.format(self.link_to_port))
self.logger.info('Link_Pair {}'.format(self.link_pair))
def create_access_ports(self):
"""
Get ports without link into access_ports
"""
self.dpid_port_set.clear()
for sw in self.switch_port_table:
all_port_table = self.switch_port_table[sw]
interior_port = self.interior_ports[sw]
for port in list(all_port_table - interior_port):
#self.logger.info('port:{}'.format(port))
dpid_port_pair = (sw, port)
self.dpid_port_set.add(dpid_port_pair)
self.logger.info('Access_ports : {}'.format(self.dpid_port_set))
events = [event.EventSwitchEnter,event.EventSwitchLeave]
@set_ev_cls(events)
def get_switches(self, ev):
"""
Get topology info and store it.
"""
self.logger.info("Switch_Enter : {}".format(ev))
switch_list = get_switch(self.topology_api_app, None)
self.create_port_map(switch_list)
self.switches = self.switch_port_table.keys()
#if len(self.datapath_list) == 62:
#print("Yes Here ")
#self.path_installer()
#self.logger.info("datpath_listttttttttttt {} =".format(self.datapath_list))
@set_ev_cls(event.EventLinkAdd,event.EventLinkDelete)
def get_links(self, ev):
self.logger.info("event : {}".format(ev))
msg = ev.link.to_dict()
self.logger.info("Event Link : {}".format(ev))
links = get_link(self.topology_api_app, None)
self.create_interior_links(links)
self.create_access_ports()
self.logger.info("datapath_list sahi ho ja : {}".format(self.datapath_list))
self.logger.info("********************from get_links*********************")
@set_ev_cls(event.EventLinkDelete)
def port_lost(self, ev):
self.logger.info("*********Event Link Delete port lost Called**************")
msg = ev.link.to_dict()
print("Event Link Delete inside EventLinkDelete",msg)
self.logger.info("datapath_list sahi ho ja : {}".format(self.datapath_list))
'''
bu_flow = shared_back_up_flows.Backup_Paths(msg, self.link_ids, self.datapath_list)
sp_link_fail=self.survi_paths.get_link_fail_Map()
bu_flow.identify_failed_link(sp_link_fail)
sp_bu_paths = self.survi_paths.get_back_up_Paths()
bu_flow.find_backup_paths(sp_bu_paths)
sp_total_paths = self.survi_paths.get_total_Paths()
sp_route_map=self.survi_paths.get_routeMap()
sp_all_flows = self.survi_paths.get_all_Flows()
bu_flow.backup_flow_rule_IDs(sp_total_paths,sp_all_flows)
bu_flow.failed_flow_rule_IDs(sp_total_paths,sp_all_flows)
# Delete
bu_flow.delete_flows_failed_paths()
# Add
bu_flow.add_flows_backup_paths()
# Adding the back_up_flows'''
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
def _build_packet_out(self, datapath, buffer_id, src_port, dst_port, data):
"""
Build packet out object.
"""
actions = []
if dst_port:
actions.append(datapath.ofproto_parser.OFPActionOutput(dst_port))
msg_data = None
if buffer_id == datapath.ofproto.OFP_NO_BUFFER:
if data is None:
return None
msg_data = data
out = datapath.ofproto_parser.OFPPacketOut(
datapath=datapath, buffer_id=buffer_id,
data=msg_data, in_port=src_port, actions=actions)
return out
def _register_host_entry(self, arp_src_ip, arp_src_mac, datapathID, port):
self.ip_mac_table[arp_src_ip] = arp_src_mac
dpid_port = (datapathID, port)
self.ip_dpidport[arp_src_ip] = dpid_port
def arp_forwarding(self, msg, arp_header, from_datapath, ether, ethernet_src, ethernet_dst, in_port):
ofproto = from_datapath.ofproto
arp_src_ip = arp_header.src_ip
arp_dst_ip = arp_header.dst_ip
arp_src_mac = arp_header.src_mac
arp_dst_mac = arp_header.dst_mac
if ethernet_dst == mac.BROADCAST_STR: # Handle ARP broadcast
if self.ip_mac_table.get(arp_src_ip) == None: # No src ip found, so storing it in the table
self.logger.info("****No mac entry found for IP. adding entry.....****")
self._register_host_entry(arp_src_ip, arp_src_mac, from_datapath.id, in_port)
if self.ip_mac_table.get(arp_dst_ip) != None: # dst_ip exist in ip_mac_table, so proxy it
ARP_Reply = packet.Packet()
mac_from_table = self.ip_mac_table.get(arp_dst_ip)
ARP_Reply.add_protocol(
ethernet.ethernet(ethertype=ether.ethertype, dst=ethernet_src, src=mac_from_table))
ARP_Reply.add_protocol(arp.arp(opcode=arp.ARP_REPLY, src_mac=mac_from_table, src_ip=arp_dst_ip,
dst_mac=arp_src_mac, dst_ip=arp_src_ip))
ARP_Reply.serialize()
from_datapath.send_msg(
self._build_packet_out(from_datapath, ofproto.OFP_NO_BUFFER, ofproto.OFPP_CONTROLLER,
in_port, ARP_Reply.data))
self.logger.info("****Found mac entry for IP. Proxy-ing****")
else: # no dst_ip in ip_mac_table, flood
for dpid_port_tup in self.dpid_port_set:
if dpid_port_tup not in self.ip_dpidport.values():
self.logger.info("********Flooding {}***********".format(dpid_port_tup))
datapath = self.datapath_list[dpid_port_tup[0]]
datapath.send_msg(self._build_packet_out(datapath, ofproto.OFP_NO_BUFFER,
ofproto.OFPP_CONTROLLER, dpid_port_tup[1], msg.data))
else: # if ARP packet and its a reply
# self.logger.info('This is ARP reply received at port {} of switch {} from IP {}, ARP Src Mac {}, ethernet src {} to IP {}, ARP Destn Mac {}, ethernet dst {}'.format(
# in_port, from_datapath.id, arp_src_ip, arp_src_mac, ethernet_src, arp_dst_ip, arp_dst_mac, ethernet_dst))
self._register_host_entry(arp_src_ip, arp_src_mac, from_datapath.id, in_port)
dpid_inport = self.ip_dpidport.get(arp_dst_ip)
datapath = self.datapath_list[dpid_inport[0]]
datapath.send_msg(self._build_packet_out(datapath, ofproto.OFP_NO_BUFFER,
ofproto.OFPP_CONTROLLER, dpid_inport[1], msg.data))
self.logger.info(
"*********************************************************************************")
return
#####################################Path_installer######################################
def _send_flow_mod(self, datapath, flow_info, in_port, out_port):
self.logger.info('flow_mod message called')
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
actions = []
actions.append(parser.OFPActionOutput(out_port))
match = parser.OFPMatch(in_port=in_port, eth_type=0x0800, ipv4_src=flow_info[0], ipv4_dst=flow_info[1])
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=1, match=match, instructions=inst)
self.logger.info('mod {}'.format(mod))
datapath.send_msg(mod)
return
### --------------------Installing Primary_Flows-----------------------------------###
### Creating an object of Class SurvSimReq(self)-----------------------------------###
def path_installer(self):
self.survi_paths = SurvSimReq(self.link_ids, self.datapath_list)
sp_link_fail = self.survi_paths.get_link_fail_Map()
flows_req=self.survi_paths.get_all_Flows()
for key, val in flows_req.items():
if key[1]==1:
self.primary_flow_list.append(val)
for i in self.primary_flow_list:
ofproto = i[0].ofproto
parser = i[0].ofproto_parser
actions = []
actions.append(parser.OFPActionOutput(i[4]))
match = parser.OFPMatch(in_port=i[3], eth_type=0x0800, ipv4_src=i[1], ipv4_dst=i[2])
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
mod = parser.OFPFlowMod(datapath=i[0], priority=1, match=match, instructions=inst)
i[0].send_msg(mod)
######################################--End of path_installer################################
@set_ev_cls(ofp_event.EventOFPPacketIn, [MAIN_DISPATCHER, CONFIG_DISPATCHER, DEAD_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)
msg = ev.msg
in_port = msg.match['in_port']
datapath = msg.datapath
pkt = packet.Packet(msg.data)
parser = datapath.ofproto_parser
ethernet_header = pkt.get_protocol(ethernet.ethernet)
ethernet_dst = ethernet_header.dst
ethernet_src = ethernet_header.src
arp_header = pkt.get_protocol(arp.arp)
if ethernet_header.ethertype == ether_types.ETH_TYPE_LLDP: # ignore lldp packet
return
#self.logger.info("DataPath_at the bottom : {}:".format(self.datapath_list))
if ethernet_dst[:5] == "33:33": # ignore IPV6 multicast packet
match = parser.OFPMatch(in_port=in_port, eth_dst=ethernet_dst)
actions = []
self.add_flow(datapath, 1, match, actions)
return
self.logger.info("packet in {} {} {} {}".format(datapath.id, ethernet_src, ethernet_dst, in_port))
if arp_header: # handle arp packets
self.logger.info("******ARP Processing********")
self.arp_forwarding(msg, arp_header, datapath, ethernet_header, ethernet_src, ethernet_dst, in_port)
return
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel