基于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不会那么陌生。

基于RYU的拓扑发现的更多相关文章

  1. 基于SNMP的路由拓扑发现算法收集

    一.三层(网络层)发现 算法来源:王娟娟.基于SNMP的网络拓扑发现算法研究.武汉科技大学硕士学位论文,2008 数据结构: 待检路由设备网关链表:存放指定深度内待检路由设备的网关信息,处理后删除. ...

  2. OpenFlow 1.3 控制器与交换机的交互,以及拓扑发现

    前言 最近纠结于控制器如何发现拓扑,于是就翻起了OpenFlow 1.3进行查看,以及一些相关协议 OF 1.3 安全通道,即交互消息 OpenFlow Switch Specification 1. ...

  3. 提高SDN控制器拓扑发现性能

    原文由我发表在sdnlab.com.原文链接:http://www.sdnlab.com/15425.html SDN网络的一大特点就是资源由控制器集中管理,控制器管理网络,最基本的当然需要知道网络的 ...

  4. 基于Ryu REST API的VLAN实现

    目录 0.预备知识 1.实验内容 2.编写脚本addflow.sh一步实现流表下发 3.使用api查看流表 4.实验结果 0.预备知识 ryu控制器的API文档:ryu.app.ofctl_rest ...

  5. 两款商业拓扑发现软件siteview和ElementSentry的比较

    今天在公司试用了一下两款商业拓扑发现软件游龙科技的siteview和速方软件ElementSentry. 条目/产品 速方软件ElementSentryv5.0 游龙科技Siteview NNM v3 ...

  6. prometheus 基于DNS的目标发现

    prometheus 基于DNS的目标发现 DNS服务发现依赖于查询A.AAAA或SRV DNS记录. 1.基于 SRV 记录发现 scrape_configs: - job_name: 'webap ...

  7. prometheus — 基于文件的服务发现

    基于文件的服务发现方式不需要依赖其他平台与第三方服务,用户只需将要新的target信息以yaml或json文件格式添加到target文件中 ,prometheus会定期从指定文件中读取target信息 ...

  8. prometheus 基于文件的目标发现

    prometheus 基于文件的目标发现 1.创建目录 cd /usr/local/prometheus/conf mkdir -pv targets/{nodes,docker} 2.修改prome ...

  9. 基于Ryu的服务器实现及相关请求访问处理

    基于Ryu的服务器实现及相关请求访问处理 前言及问题描述 近期又遇到了一个非常棘手的问题,由于Ryu是通过Python语言开发的,通过Ryu的wsgi的方式建立服务器,无法解析PHP,通过多次方法解决 ...

随机推荐

  1. 【jquery】 在异步加载的元素上绑定事件

    最近因为工作关系又重新回归到了jquery的怀抱,发现很多jquery的一些细节处理的部分都忘记了.这里记录一下最近在做项目时频繁遇到的一个问题:给异步加载的元素添加事件绑定. 问题发生的前提是项目前 ...

  2. python第四十三课——封装性

    1.面向对象的三大特性:封装性.继承性.多态性 封装: 封装使用的领悟: 1).生活层面:食品.快递.计算机.明星... 2).计算机层面: ①.模块.类.函数... ②.属性数据的封装与隐藏 权限修 ...

  3. docker tomcat jvm 使用 visualVM监控

    1.  建立基础镜像 FROM centos MAINTAINER fengjian <fengjian@senyint.com> ENV TZ "Asia/Shanghai&q ...

  4. pyspider爬取数据存入redis--2.测试数据库连通性

    直接上代码 #!/usr/bin/env python # -*- encoding: utf-8 -*- # Created on 2017-10-27 09:56:50 # Project: re ...

  5. WorldWind源码剖析系列:地形瓦片类TerrainTile和地形瓦片服务类TerrainTileService

    地形瓦片类TerrainTile 用来抽象封装用户漫游中所请求的地形瓦片数据类型. 地形瓦片服务类TerrainTileService提供了从BIL(Binary Interleaved by Lin ...

  6. (转)LVS+Keepalived使用总结 vip丢失

    /sbin/ifconfig lo: $vip broadcast $vip netmask 255.255.255.255 up /sbin/ifconfig lo: 172.16.254.63 b ...

  7. 1.4《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——编辑命令

    在编辑模式中,命令行包括几个重复之前命令的功能.这些以及其他很多命令功能时常设计键盘上的特殊键,所以给出Table 1作为参考,给出了许多键在典型的Macintosh键盘上的标记符号.若你的键盘不太一 ...

  8. 7、mysql高级特性

    7.1.分区表 7.1.1 分区表的原理 7.1.2分区表的类型 7.1.3如何使用分区表 7.1.4什么情况下出问题 7.1.5查询优化 使用explain 来分析sql使用的分区表 7.1.6合并 ...

  9. 一、InnoDB引擎

    一.InnoDB的历史 MYSQL的5.1版本的时候还是使用旧的innoDB,当时orale公司推出的新的innoDB引擎, 但是需要以插件的形式编译,叫innoDB plugin : 知道MYSQL ...

  10. C语言如何向系统接要存

    C语言如何向系统接要存,就有这么三种方式: 1.向栈要. 2.向堆要. 3.向数据段要. 这一下就扯出了三种内存空间,内存空间的本质是一样的,一个地址对应一个方框,方框里可以放数据.但是为了更好的去 ...