zoukankan      html  css  js  c++  java
  • 基于RYU的拓扑发现

    基于RYU的拓扑发现

    前言

    本次实验是一个基于RYU的拓扑发现功能。参考了呈神的实现方式,并加了一些自己实现方式,做了一些数据结构的改动。

    数据结构

    • link_to_port 字典

      有两种关系:

      一是记录交换机与交换机之间的链接 (src_dpid, src_port_no) => (dst_dpid, dst_port_no)

      一是记录交换机与控制器之间的链接 (dpid, port_no) =>(mac, ip)

    • host_or_switch 字典

      用来记录交换机连的端口连接的为何种类型的设备 (dpid, port_no) =>

      1:交换机

      2:主机

      其他:没有连接

    • switch_port_table 字段

      用来记录交换机的端口 , (dpid) => [1,2,....]

    相关API的使用

    API是基于ryu源代码topology/switches下的使用,并使用了三个api

    • get_switch 获取交换机列表
    • get_link 获取链路信息
    • get_host 获取主机信息

    实验代码

    #-*- coding: UTF-8 -*-
    
    import logging
    from ryu.base import app_manager
    
    from ryu.controller import ofp_event
    from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
    from ryu.controller.handler import CONFIG_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.ofproto import ofproto_v1_0
    from ryu.ofproto import ofproto_v1_2
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet
    from ryu.lib import hub
    from ryu.topology import event, switches
    from ryu.topology.api import get_switch, get_link, get_host
    from ryu import cfg
    
    CONF = cfg.CONF
    
    class test_wpq(app_manager.RyuApp):
    
        OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
                        ofproto_v1_3.OFP_VERSION]
    
        def __init__(self, *args, **kwargs):
            super(test_wpq, self).__init__(*args, **kwargs)
            self.topology_api_app = self
            self.link_to_port = {}
            self.host_or_switch = {}
            self.switch_port_table = {}
            self.name = "wpq"
            self.discover_thread = hub.spawn(self._discover_links)
    
        #A thread to output the information of topology
        def _discover_links(self):
            while True:
                self.get_topology(None)
                try:
                    self.show_topology()
                except Exception as err:
                    print "please input pingall in mininet and wait a memment"
                hub.sleep(5)
    
        #add entry of table-miss
        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_feature_handle(self, ev):
            msg = ev.msg
            print msg
            datapath = msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            self.logger.info("switch %s is connected", datapath.id)
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER)]
            self.add_flow(datapath=datapath, priority=0, actions=actions, match=match)
    
        def add_flow(self, datapath, priority, actions, match, idle_timeout=0, hard_timeout=0):
            ofp = datapath.ofproto
            parser = datapath.ofproto_parser
    
            inst = [parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
                                                 actions)]
    
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    idle_timeout=idle_timeout,
                                    hard_timeout=hard_timeout,
                                    match=match, instructions=inst)
    
            datapath.send_msg(mod)
    
        #fill the port of switch imformation
        def create_map(self, switch_list):
            for sw in switch_list:
                dpid = sw.dp.id
                self.switch_port_table.setdefault(dpid, set())
    
                for p in sw.ports:
                    self.switch_port_table[dpid].add(p.port_no)
    
            # print "--------------交换机端口情况---------------"
            # print self.switch_port_table
    
        #fill the link information
        def create_link_port(self, link_list, host_list):
            for link in link_list:
                src = link.src
                dst = link.dst
                self.link_to_port[(src.dpid, src.port_no)] = (dst.dpid, dst.port_no)
                self.link_to_port[(dst.dpid, dst.port_no)] = (src.dpid, src.port_no)
                self.host_or_switch[(src.dpid, src.port_no)] = 1
                self.host_or_switch[(dst.dpid, dst.port_no)] = 1
    
            for host in host_list:
                port = host.port
                self.link_to_port[(port.dpid, port.port_no)] = (host.mac, host.ipv4)
                self.host_or_switch[(port.dpid, port.port_no)] = 2
    
        #packein message handler (it is useless in this function)
        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def packetin_handler(self, ev):
            # print ev.msg
            msg = ev.msg
            pkt = packet.Packet(msg.data)
            # print pkt.get_protocols
            dpid = msg.datapath.id
            port = msg.match['in_port']
            self.get_topology(None)
    
    
        events = [event.EventSwitchEnter,
                  event.EventSwitchLeave, event.EventPortAdd,
                  event.EventPortDelete, event.EventPortModify,
                  event.EventLinkAdd, event.EventLinkDelete]
        #monitor the change in link information
        @set_ev_cls(events)
        def get_topology(self, ev):
            self.create_map(get_switch(self.topology_api_app))
            # print get_host(self.topology_api_app)
            # print type(get_host(self.topology_api_app))
            self.create_link_port(get_link(self.topology_api_app), get_host(self.topology_api_app))
            # self.show_topology()
    
    
        #some command line output typesetting
        def show_topology(self):
            i = 1
            print ""
            print ""
            print ""
            print "----------------" * 2, "physical topology", "----------------" * 6
            for dpid in self.switch_port_table.keys():
                print "switch%d ----------dpid---------- " % i,
                for port_no in self.switch_port_table[dpid]:
                    print "-----------port %s-----------" % port_no,
                print ""
                print "        ", "%11d" % dpid ,"%12s" % " ",
                # # print self.switch_port_table[dpid]
                try:
                    for port_no in self.switch_port_table[dpid]:
                        if self.host_or_switch[(dpid, port_no)] == 1:
                            print "%10s" % "switch", "%d" % self.link_to_port[(dpid, port_no)][0], "     port %d" % self.link_to_port[(dpid, port_no)][1], "  ",
                        elif self.host_or_switch[(dpid, port_no)] == 2:
                            print "%s" % "host", "mac: %s" % self.link_to_port[(dpid, port_no)][0],
                        else:
                            print "%28s" % "None"
    
                    print ""
                    print "        ", "%23s" % " ",
                    for port_no in self.switch_port_table[dpid]:
                        if self.host_or_switch[(dpid, port_no)] == 2:
                            print " ipv4 :", self.link_to_port[(dpid, port_no)][1],
                        else:
                            print "%28s" % " ",
                    print
                except Exception as error:
                    print "please input pingall in mininet and wait a momment until it's finished"
    
                i = i + 1
    
            print "------------------" * 8
            print ""
            print ""
            print ""
    

    细节点

    这也是我调了半天的一个bug,使用hub.spawnhub.sleep配合的函数,应该可以达到停几秒休息一次的作用,尝试很多无果,后来自己随便建了一个没有消息处理机制的函数进行测试,发现其却能正常运行。究其原因,后面原来是自己没有异常处理。异常处理很重要!!!

    实验效果图

    实验缺陷

    对于不同的终端可能适配不一样,尽量放大到全屏看的比较直观,如果设备多了,这个显示依然是一片模糊,后期将加入一个做成json,做成web可视化

    实验总结

    这个程序有一大部分得感谢呈神的参考,还有其他部分也是自己对python的一些类似循环,字典的一些应用,懂得去debug,对python不会那么陌生。

  • 相关阅读:
    python中多进程+协程的使用以及为什么要用它
    python爬虫——多线程+协程(threading+gevent)
    Python几种并发实现方案的性能比较
    Python threadpool传递参数
    python线程池(threadpool)模块使用笔记
    python下的select模块使用 以及epoll与select、poll的区别
    python中的select模块
    Python中threading的join和setDaemon的区别及用法
    python队列Queue
    和为S的连续正数序列
  • 原文地址:https://www.cnblogs.com/wpqwpq/p/6592508.html
Copyright © 2011-2022 走看看