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

Reply via email to