Topology Recognition with Ryu

  • 14 Replies
  • 19691 Views
*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Topology Recognition with Ryu
« on: August 02, 2016, 01:14:28 PM »
Hi,

Im a student at RMIT in Melbourne working with the Zodiac FX and Ryu. I connected the simple switch application from the Ryu examples and did some own experiments with the Ryu controller (basically installing static flows and some adoptions of the learning switch code). The Zodiak FX worked out of the box with this controllers.

At the moment I try setting up a small topology recognition controller by following this https://sdn-lab.com/2014/12/31/topology-discovery-with-ryu/ tutorial. I managed to successfully start and connect the controller to the switch (controller is connected to port 4) by
$ryu-manager --observe-links topo_learner.py
but no matter what I do (connect different devices (mostly Rapberry Pis) to the ports, calling different API functions of Ryu's topology api) the link lists and switch lists are always empty..

Is the Zodiac FX capable of returning topology information to the controller? And if yes, how can I do this?

I appreciate any help!
Cheers,
Ben

*

Paul Zanna

  • Moderator
  • Sr. Member
  • *****
  • 370
    • View Profile
    • Northbound Networks
Re: Topology Recognition with Ryu
« Reply #1 on: August 02, 2016, 02:00:48 PM »
Hi Ben,

Topology information is created by the controller using mac addresses from packet in messages so it isn't really dependant on a particular switch feature. If the simple switch app is working ok then packet ins are being processed by the controller to create the flows for the layer 2 switch function. Given that it doesn't even show anything in the switch list sounds like it's an issue with the RYU app code or is the command line switch in the wrong place? The example show the observe-links switch after the app name "ryu-manager sp.py --observe-links".

You could also try it with Mininet to rule out a code issue.

Regards,
Paul 

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #2 on: August 08, 2016, 02:30:06 PM »
Hi Paul,

Thank you for the very fast answer! :-) Sorry for my late response, but I had to
spend some time on other things, before I had the time to test your advice.

1) $ ryu-manager --help
shows, that you should put your app list first and additional commands like
(observe-links or verbose) afterwards. Actually I tried both positions, neither
of them worked (same empty output for links).

2) I also tried OVS and mininet like described here:
http://sdnhub.org/tutorials/ryu/

I pinged from host 1 to host 3 (worked), although the link list is empty.

ben@Benovo:~/masterthesis/ryu_code$ ryu-manager simple_switch_13.py --observe-links
loading app simple_switch_13.py
loading app ryu.topology.switches
loading app ryu.controller.ofp_handler
instantiating app ryu.topology.switches of Switches
instantiating app simple_switch_13.py of SimpleSwitch13
instantiating app ryu.controller.ofp_handler of OFPHandler
switches:  [1]
links_list:  []
links []
packet in 1 00:00:00:00:00:01 ff:ff:ff:ff:ff:ff 1
packet in 1 00:00:00:00:00:03 00:00:00:00:00:01 3
packet in 1 00:00:00:00:00:01 00:00:00:00:00:03 1


This indicates that "my" code is not working properly.
You can see the modified simple_switch_13.py code next:


# 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 CONFIG_DISPATCHER, MAIN_DISPATCHER
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

from ryu.topology.api import get_link, get_switch
from ryu.topology import event, switches

class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.mac_to_port = {}
    #    self.topology_api_app = self

    @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)

    def add_flow(self, datapath, priority, match, actions, buffer_id=None):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]
        if buffer_id:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst)
        else:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)

        datapath.send_msg(mod)

    @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)
        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_protocols(ethernet.ethernet)[0]

        if eth.ethertype == ether_types.ETH_TYPE_LLDP:
            # ignore lldp packet
            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)

        # learn a mac address to avoid FLOOD next time.
        self.mac_to_port[dpid][src] = in_port

        if dst in self.mac_to_port[dpid]:
            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
        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
            # verify if we have a valid buffer_id, if yes avoid to send both
            # flow_mod & packet_out
            if msg.buffer_id != ofproto.OFP_NO_BUFFER:
                self.add_flow(datapath, 1, match, actions, msg.buffer_id)
                return
            else:
                self.add_flow(datapath, 1, match, actions)
            self.get_topology_data(ev)  ## changed!!
        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):
        switch_list = get_switch(self, None) #.topology_api_app
        switches=[switch.dp.id for switch in switch_list]
        print "switches: ", switches

        links_list = get_link(self, switches[0]) #.topology_api_app ,None
        links=[(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list]
        print "links_list: ", links_list #[0]
        print "links", links



3) I also tried the Ryu code, that the writer of the tutorial provides on github
(https://github.com/castroflavio/ryu/blob/master/ryu/app/shortestpath.py). I
changed the virtual switch to use OpenFlow 1.0, as the code is written for
OpenFlow 1.0. This results also in an empty output..

ben@Benovo:~/masterthesis/ryu_code$ ryu-manager shortestpath.py --observe-links
loading app shortestpath.py
Generating grammar tables from /usr/lib/python2.7/lib2to3/Grammar.txt
Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
loading app ryu.topology.switches
loading app ryu.controller.ofp_handler
instantiating app ryu.topology.switches of Switches
instantiating app topo_tutorial.py of ProjectController
instantiating app ryu.controller.ofp_handler of OFPHandler
**********List of links
[]

I have no idea, what to do next..
Any help is appreciated!

Best regards,
Ben
« Last Edit: August 09, 2016, 01:36:02 PM by schneiben »

*

Paul Zanna

  • Moderator
  • Sr. Member
  • *****
  • 370
    • View Profile
    • Northbound Networks
Re: Topology Recognition with Ryu
« Reply #3 on: August 10, 2016, 09:33:28 AM »
Hi Ben,

Let me take a look and I'll get back to you soon.

Regards,
Paul

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #4 on: August 18, 2016, 07:05:18 PM »
Update:

If I call the get_host method provided by the topology api, I get some information about the hosts back. So this seems to work  :)

The changed code for the get_topology_data function is shown next:

@set_ev_cls(event.EventSwitchEnter)
    def get_topology_data(self, ev):
        switch_list = get_switch(self, None)
        switches=[switch.dp.id for switch in switch_list]
        print "switches: ", switches

        hosts = get_host(self, None)
        print "hosts", hosts

        links = get_link(self, None)
        print "links", links


This code results in this output:

packet in 123917682136031 b8:27:eb:09:56:bd b8:27:eb:07:2f:04 2
switches:  [123917682136031]
hosts [<ryu.topology.switches.Host object at 0x7fc140f82950>, <ryu.topology.switches.Host object at 0x7fc140f82050>]
links {}


The problem of the empty links remains..

Best regards,
Ben

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #5 on: August 23, 2016, 03:53:12 PM »
Update:

I solved the topology problem without the link information coming directly from the switch.  :)

You can extract the link information from hosts and switches: The hosts have an associated port and the port has a datapath ID (which is basically the ID of the switch - as far as I understood). So you can compare the host_port_datapath to the switch_datapath and get the link information.

But it would still be interesting, why I can not get the link information  ;)

Cheers,
Ben

*

TanvirHuque

  • Newbie
  • *
  • 2
    • View Profile
Re: Topology Recognition with Ryu
« Reply #6 on: August 24, 2016, 12:47:51 PM »
Hi Ben


I am also a PhD student (UNSW), and conducting my research on the SDN controller.
I  want to discuss with you regarding the ryu controller topology discovery, if you feel interest.

Please feel free to email me at < Tanvir.ulhuque@data61.csiro.au >

Thanks
-Tanvir

*

Paul Zanna

  • Moderator
  • Sr. Member
  • *****
  • 370
    • View Profile
    • Northbound Networks
Re: Topology Recognition with Ryu
« Reply #7 on: August 25, 2016, 08:46:30 AM »
Hi Ben,

I'm glad you found a work around to your problem. I'm not sure why RYU is not returning the link information correctly, are you passing the correct values to the get_link function?

Regards,
Paul

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #8 on: August 25, 2016, 02:51:08 PM »
Hi Paul,

I hope so. The definition for this functions in the topology_api (https://github.com/osrg/ryu/blob/master/ryu/topology/api.py) looks as follows:

def get_switch(app, dpid=None):
    rep = app.send_request(event.EventSwitchRequest(dpid))
    return rep.switches

#....

def get_link(app, dpid=None):
    rep = app.send_request(event.EventLinkRequest(dpid))
    return rep.links


So I have to call get_switch and get_link the same way (as I showed in the post of the 18th August).
When I do this, the list returned by get_link is empty and get_switch returns a list with the switche's datapath IDs. get_all_link also returns an empty list (as it also just calls get_link without datapath IDs as parameters).

Cheers,
Ben

*

Paul Zanna

  • Moderator
  • Sr. Member
  • *****
  • 370
    • View Profile
    • Northbound Networks
Re: Topology Recognition with Ryu
« Reply #9 on: August 26, 2016, 08:12:04 AM »
Hi Ben,

I found these RYU Topo apps if you are interested https://github.com/Ehsan70/RyuApps

Regards,
Paul

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #10 on: August 29, 2016, 10:39:53 PM »
Hi all,

@Paul: Thank you for the link! It helped a lot. The repo contains some md files with tutorialson topology discovery in Ryu.

I finally fixed my link problems after a debugging and troubleshouting weekend.

Summary:

You can start a Ryu app another way: $ ryu run <parameters> <app_list>
(the Ryu team recommends to start their topo app https://github.com/osrg/ryu/blob/master/ryu/app/gui_topology/gui_topology.py like this).

Both ways of starting the app worked for me in the end:
$ ryu run --observe-links topo_disco.py
$ ryu-manager --observe-links topo_disco.py


Ryu considers links as connection between switches and NOT as connection between hosts and switches.. I didn't know that (as I'm an industrial-automation-systems-guy and a network beginner) and tried to receive links from a topology that unfortunately had none :-( my topology was the zodiac fx connected to three hosts (Raspberry Pis) and the controller (on my laptop). Today I tried with 2 zodiacs and a connection between them and it worked!

I was also trying to get the links from mininet with mininet's standard topology, that you receive when typing the following:
$ sudo mn --controller remote
This topology consists of a switch and 2 hosts connected to a remote controller (which has to run on the host that also runs mininet). So also no links at all..

Finally I tried:
$ sudo mn --controller remote --topo tree,depth=2
for another topology (tree with depth 2) and received the link information from Ryu.

Now I can register to events like event.EventSwitchEnter and process the received event as desired. You actually don't need to check the lists returned by get_link(), get_host() and get_switch() everytime any event related to the topology is received. You could also process the object (switch, link, host) directly, like the following example shows:

@set_ev_cls(event.EventSwitchEnter)
def event_switch_enter_handler(self, ev):
   print ev.switch
   # do some fancy stuff with the new switch object here


PS: Is it common in networking, that connections between hosts and switches/forwarding devices are not called links? Wikipedia says that "The link is the physical and logical network component used to interconnect hosts or nodes in the network ...". So I assume links as connection between switches is kind of Ryu specific?

Cheers,
Ben

*

Paul Zanna

  • Moderator
  • Sr. Member
  • *****
  • 370
    • View Profile
    • Northbound Networks
Re: Topology Recognition with Ryu
« Reply #11 on: August 30, 2016, 05:42:50 PM »
Hi Ben,

Thanks for the update and sharing your experiences, no doubt many people will find this thread useful in the future.

Regards,
Paul

*

manizhe

  • Newbie
  • *
  • 2
    • View Profile
Re: Topology Recognition with Ryu
« Reply #12 on: September 10, 2016, 05:04:46 PM »
Hi ,
Im student in isfahan univercity of technology, and im new in ryu and want to get topology with ryu and then perform dijkstra routing for it. i use your code but my out put is not perfect.
we must run topo first in mininet and then run controller app to get ryu topo with code in it?
i dont get link and host information and my output run several time why?
i must to get topo information and then run route algorithm for it :(
thank you for any help
manizhe

*

manizhe

  • Newbie
  • *
  • 2
    • View Profile
Re: Topology Recognition with Ryu
« Reply #13 on: September 10, 2016, 05:32:46 PM »
my output is :
loading app /home/manizhe/simple_switch_13.py
loading app ryu.topology.switches
loading app ryu.controller.ofp_handler
instantiating app /home/manizhe/simple_switch_13.py of SimpleSwitch13
instantiating app ryu.topology.switches of Switches
instantiating app ryu.controller.ofp_handler of OFPHandler
switches:  [3]
hosts []
links {<ryu.topology.switches.Link object at 0x7f47a9a4d390>: 1473492543.469031}
switches:  [1, 2, 3]
hosts []
links {<ryu.topology.switches.Link object at 0x7f47a9a36c90>: 1473492543.470042, <ryu.topology.switches.Link object at 0x7f47a9a36e10>: 1473492543.470895, <ryu.topology.switches.Link object at 0x7f47a9a4d610>: 1473492543.471659, <ryu.topology.switches.Link object at 0x7f47a9a4d390>: 1473492543.469031}
switches:  [1, 2, 3]
hosts []
links {<ryu.topology.switches.Link object at 0x7f47a9a36c90>: 1473492543.470042, <ryu.topology.switches.Link object at 0x7f47a9a36e10>: 1473492543.472178, <ryu.topology.switches.Link object at 0x7f47a9a4d610>: 1473492543.471659, <ryu.topology.switches.Link object at 0x7f47a9a4d390>: 1473492543.469031}

*

schneiben

  • Newbie
  • *
  • 10
    • View Profile
Re: Topology Recognition with Ryu
« Reply #14 on: September 12, 2016, 02:39:30 AM »
Hi Manizhe,

I assume you run mininet with this topology:
sudo mn --controller remote --topo tree,depth=2

Your output looks ok. In fact, Ryu adds the hosts to the topology, when communication happens (that means, when your controller receives a packetin event).

Try to ping your hosts in the simulated network from the mininet command line, for example like this:
h1 ping h2
or
pingall

Cheers,
Ben