热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SDN实验Ryu的应用开发(五)网络拓扑发现

一:实验简介(一)网络拓扑信息:其中1,2,3表示该交换机对应的端口号!!!(二)用邻接矩阵展示其中左侧列S1,S2,S3,S4表示出节点,,上面S1,S2,S3,S4表示入节点

一:实验简介

(一)网络拓扑信息:

技术图片


其中1,2,3表示该交换机对应的端口号!!!


(二)用邻接矩阵展示

技术图片


其中左侧列S1,S2,S3,S4表示出节点,----->,上面S1,S2,S3,S4表示入节点。


(m,1),m表示出节点的端口--->入节点,1表示两个节点有连接!


(三)主机信息展示

技术图片 


二:代码实现 

(一)导入模块


from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER,DEAD_DISPATCHER #只是表示datapath数据路径的状态
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
from ryu.lib.packet import packet,ethernet
from ryu.topology import event,switches
from ryu.topology.api import get_switch,get_link,get_host


(二)数据结构


class TopoDetect(app_manager.RyuApp):
OFP_VERSIONS
= [ofproto_v1_3.OFP_VERSION]
def __init__(self,
*args,**kwargs):
super(TopoDetect,self).__init__(
*args,**kwargs)
self.topology_api_app
= self #用于保持对象本身,后面get_switch等方法需要(我们也可以直接传入self)
self.link_list = None #保存所有的link信息,由get_link获得
self.switch_list = None #保存所有的switch信息,由get_switch获得
self.host_list = None #保存所有的host信息,由get_host获得
self.dpid2id = {} #获取交换机dpid,以及自定义id--->{dpid:id}
self.id2dpid = {} #对应上面的self.dpid2id,翻转即可,因为我们使用id进行建立邻接矩阵,这两个结构方便查找
self.dpid2switch = {} #保存dpid和对应的交换机全部信息---->通过矩阵获得id,然后获得dpid,最后获得交换机对象信息
self.ip2host = {} #根据ip,保存主机对象信息--->{ip:host}
self.ip2switch = {} #根据ip,获取当前主机是连接到哪个交换机--->{ip:dpid}
self.net_size = 0 #记录交换机个数(网络拓扑大小)
self.net_topo =
[] #用于保存邻接矩阵

self.monitor_thread
= hub.spawn(self._monitor) #协程实现定时检测网络拓扑


(三)实现基本openflow消息处理


@set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
def switch_feature_handle(self,ev):
"""
datapath中有配置消息到达
"""
#print("------------------switch_feature_handle")
msg
= ev.msg
datapath
= msg.datapath
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
match
= ofp_parser.OFPMatch()
actions
= [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath
=datapath,priority=0,match=match,actiOns=actions,extra_info="config infomation arrived!!")
def add_flow(self,datapath,priority,match,actions,idle_timeout
=0,hard_timeout=0,extra_info=None):
#print(
"------------------add_flow:")
if extra_info != None:
print(extra_info)
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
inst
= [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]
mod
= ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
idle_timeout
=idle_timeout,
hard_timeout
=hard_timeout,
match
=match,instructiOns=inst)
datapath.send_msg(mod);
@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
#print(
"------------------packet_in_handler")
msg
= ev.msg
datapath
= msg.datapath
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
dpid
= datapath.id
in_port
= msg.match[in_port]
pkt
= packet.Packet(msg.data)
eth_pkt
= pkt.get_protocol(ethernet.ethernet)
dst
= eth_pkt.dst
src
= eth_pkt.src
#self.logger.info(
"------------------Controller %s get packet, Mac address from: %s send to: %s , send from datapath: %s,in port is: %s"
# ,dpid,src,dst,dpid,in_port)
#self.get_topology(None)


注意:对于packet_in消息,我们没有处理,所以整个网络(交换机之间的链路)是无法工作通信的,


但是各个交换机可以与控制器通信(switch_feature_handle实现),主机也可以和边缘交换机通信,


所以控制器可以获取网络拓扑信息!!! 


(四)实现拓扑发现功能


def _monitor(self):
"""
协程实现伪并发,探测拓扑状态
"""
while True:
#print(
"------------------_monitor")
self.get_topology(None)
try:
self.show_topology()
except Exception
as err:
print(
"Please use cmd: pingall to detect topology and wait a moment")
hub.sleep(
5) #5秒一次
events
= [event.EventSwitchEnter, event.EventSwitchLeave,
event.EventSwitchReconnected,
event.EventPortAdd, event.EventPortDelete,
event.EventPortModify,
event.EventLinkAdd, event.EventLinkDelete,
event.EventHostAdd]
@set_ev_cls(events)
def get_topology(self,ev):
print(
"-----------------get_topology")
#获取所有的交换机、链路、主机信息
self.switch_list
= get_switch(self.topology_api_app) #1.只要交换机与控制器联通,就可以获取
self.link_list = get_link(self.topology_api_app) #2.在ryu启动时,加上--observe-links即可用于拓扑发现
self.host_list = get_host(self.topology_api_app) #3
.需要使用pingall,主机通过与边缘交换机连接,才能告诉控制器

#获取交换机字典id2dpid{id:dpid} dpid2switch{dpid:
switch object}
for i,switch in enumerate(self.switch_list):
self.id2dpid[i]
= switch.dp.id
self.dpid2id[
switch.dp.id] = i
self.dpid2switch[
switch.dp.id] = switch
#获取主机信息字典ip2host{ipv4:host
object} ip2switch{ipv4:dpid}
for i,host in enumerate(self.host_list):
self.ip2switch[
"%s"%host.ipv4] = host.port.dpid
self.ip2host[
"%s"%host.ipv4] = host
#根据链路信息,开始获取拓扑信息
self.net_size
= len(self.id2dpid) #表示网络中交换机个数
for i in range(self.net_size):
self.net_topo.append([
0]*self.net_size)
for link in self.link_list:
src_dpid
= link.src.dpid
src_port
= link.src.port_no
dst_dpid
= link.dst.dpid
dst_port
= link.dst.port_no
sid
= self.dpid2id[src_dpid]
did
= self.dpid2id[dst_dpid]
self.net_topo[sid][did]
= (src_port,1) #注意:这里1表示存在链路,后面可以修改为时延
self.net_topo[did][sid]
= (dst_port,1)
def show_topology(self):
print(
"-----------------show_topology")
print(
"----------switch network----------")
line_info
= " "
for i in range(self.net_size):
line_info
+="s%d "%self.id2dpid[i]
print(line_info)
for i in range(self.net_size):
line_info
= "s%d "%self.id2dpid[i]
for j in range(self.net_size):
if self.net_topo[i][j] == 0:
line_info
+="0 "
else:
line_info
+="(%d,%d) "%self.net_topo[i][j]
print(line_info)
print(
"----------host 2 switch----------")
for key,val in self.ip2switch.items():
print(
"%s---s%d"%(key,val))


(五)全部代码


技术图片技术图片

from ryu.base import app_manager
from ryu.ofproto import ofproto_v1_3
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER,DEAD_DISPATCHER #只是表示datapath数据路径的状态
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
from ryu.lib.packet import packet,ethernet
from ryu.topology import event,switches
from ryu.topology.api import get_switch,get_link,get_host
class TopoDetect(app_manager.RyuApp):
OFP_VERSIONS
= [ofproto_v1_3.OFP_VERSION]
def __init__(self,
*args,**kwargs):
super(TopoDetect,self).__init__(
*args,**kwargs)
self.topology_api_app
= self
self.link_list
= None
self.switch_list
= None
self.host_list
= None
self.dpid2id
= {}
self.id2dpid
= {}
self.dpid2switch
= {}
self.ip2host
= {}
self.ip2switch
= {}
self.net_size
= 0
self.net_topo
= []

self.monitor_thread
= hub.spawn(self._monitor)
def _monitor(self):
"""
协程实现伪并发,探测拓扑状态
"""
while True:
#print(
"------------------_monitor")
self.get_topology(None)
try:
self.show_topology()
except Exception
as err:
print(
"Please use cmd: pingall to detect topology and wait a moment")
hub.sleep(
5) #5秒一次
@set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
def switch_feature_handle(self,ev):
"""
datapath中有配置消息到达
"""
#print("------------------switch_feature_handle")
msg
= ev.msg
datapath
= msg.datapath
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
match
= ofp_parser.OFPMatch()
actions
= [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath
=datapath,priority=0,match=match,actiOns=actions,extra_info="config infomation arrived!!")
def add_flow(self,datapath,priority,match,actions,idle_timeout
=0,hard_timeout=0,extra_info=None):
#print(
"------------------add_flow:")
if extra_info != None:
print(extra_info)
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
inst
= [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]
mod
= ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
idle_timeout
=idle_timeout,
hard_timeout
=hard_timeout,
match
=match,instructiOns=inst)
datapath.send_msg(mod);
@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
#print(
"------------------packet_in_handler")
msg
= ev.msg
datapath
= msg.datapath
ofproto
= datapath.ofproto
ofp_parser
= datapath.ofproto_parser
dpid
= datapath.id
in_port
= msg.match[in_port]
pkt
= packet.Packet(msg.data)
eth_pkt
= pkt.get_protocol(ethernet.ethernet)
dst
= eth_pkt.dst
src
= eth_pkt.src
#self.logger.info(
"------------------Controller %s get packet, Mac address from: %s send to: %s , send from datapath: %s,in port is: %s"
# ,dpid,src,dst,dpid,in_port)
#self.get_topology(None)
events
= [event.EventSwitchEnter, event.EventSwitchLeave,
event.EventSwitchReconnected,
event.EventPortAdd, event.EventPortDelete,
event.EventPortModify,
event.EventLinkAdd, event.EventLinkDelete,
event.EventHostAdd]
@set_ev_cls(events)
def get_topology(self,ev):
print(
"-----------------get_topology")
#获取所有的交换机、链路、主机信息
self.switch_list
= get_switch(self.topology_api_app) #1.只要交换机与控制器联通,就可以获取
self.link_list
= get_link(self.topology_api_app) #2.在ryu启动时,加上--observe-links即可用于拓扑发现
self.host_list
= get_host(self.topology_api_app) #3.需要使用pingall,主机通过与边缘交换机连接,才能告诉控制器

#获取交换机字典id2dpid{id:dpid} dpid2switch{dpid:
switch object}
for i,switch in enumerate(self.switch_list):
self.id2dpid[i]
= switch.dp.id
self.dpid2id[
switch.dp.id] = i
self.dpid2switch[
switch.dp.id] = switch
#获取主机信息字典ip2host{ipv4:host
object} ip2switch{ipv4:dpid}
for i,host in enumerate(self.host_list):
self.ip2switch[
"%s"%host.ipv4] = host.port.dpid
self.ip2host[
"%s"%host.ipv4] = host
#根据链路信息,开始获取拓扑信息
self.net_size
= len(self.id2dpid) #表示网络中交换机个数
for i in range(self.net_size):
self.net_topo.append([
0]*self.net_size)
for link in self.link_list:
src_dpid
= link.src.dpid
src_port
= link.src.port_no
dst_dpid
= link.dst.dpid
dst_port
= link.dst.port_no
sid
= self.dpid2id[src_dpid]
did
= self.dpid2id[dst_dpid]
self.net_topo[sid][did]
= (src_port,1) #注意:这里1表示存在链路,后面可以修改为时延
self.net_topo[did][sid]
= (dst_port,1)

#print(
"+++++++++++allSwitch:")
#
for i,switch in enumerate(allSwitch): #switch中含有datapath和port对象
# print(
"===%d datapath:"%i)
# print(
switch.dp,switch.dp.id)
# print(
"===%d ports: dpid portno name hwaddr:"%i)
# print(
switch.ports)
#
for port in switch.ports:
# print(port.dpid,port.port_no,port.name,port.hw_addr)
#
===0 datapath:
#
object at 0x7f8275748940> 1
#
===0 ports: dpid portno name hwaddr:
#[
object at 0x7f8275862c50>, object at 0x7f8275862da0>]
#
1 1 bs1-eth1 ae:22:48:41:18:1d
#
1 2 bs1-eth2 8a:71:db:bd:a1:86

#print(
"+++++++++++allLink:")
#
for link in self.link_list:
# print(link.src,link.dst)
#
+++++++++++allLink:
#Port
2, port_no=2, LIVE> Port1, port_no=2, LIVE>
#Port
1, port_no=2, LIVE> Port2, port_no=2, LIVE>
#print(
"+++++++++++allHost:")
#
for host in self.host_list:
# print(
"%s %s %s"%(host.ipv4,host.mac,host.port))
#
+++++++++++allHost:
#[
10.0.0.2] 5e:20:b8:90:dd:0e Port2, port_no=1, LIVE>
#[
10.0.0.1] 6e:a0:c2:a0:f0:2a Port1, port_no=1, LIVE>
def show_topology(self):
print(
"-----------------show_topology")
print(
"----------switch network----------")
line_info
= " "
for i in range(self.net_size):
line_info
+="s%d "%self.id2dpid[i]
print(line_info)
for i in range(self.net_size):
line_info
= "s%d "%self.id2dpid[i]
for j in range(self.net_size):
if self.net_topo[i][j] == 0:
line_info
+="0 "
else:
line_info
+="(%d,%d) "%self.net_topo[i][j]
print(line_info)
print(
"----------host 2 switch----------")
for key,val in self.ip2switch.items():
print(
"%s---s%d"%(key,val))


View Code

三:实验验证

(一)启动Ryu控制器


ryu-manager TopoDetect.py --verbose --observe-links


其中--observe-links用于拓扑发现,添加之后用于链路的信息获取!!

技术图片


(二)启动mininet


sudo mn --topo=linear,4 --switch=ovsk --cOntroller=remote --link=tc

技术图片


注意:需要在mininet中使用pingall,才能使得交换机获得host存在,从而使得控制器获取host消息!!

技术图片


(三)结果显示

技术图片

 

SDN实验---Ryu的应用开发(五)网络拓扑发现



推荐阅读
  • Cookie学习小结
    Cookie学习小结 ... [详细]
  • packagecom.panchan.tsmese.utils;importjava.lang.reflect.ParameterizedType;importjava.lang. ... [详细]
  • 蒜头君的倒水问题(矩阵快速幂优化)
    蒜头君将两杯热水分别倒入两个杯子中,每杯水的初始量分别为a毫升和b毫升。为了使水冷却,蒜头君采用了一种特殊的方式,即每次将第一杯中的x%的水倒入第二杯,同时将第二杯中的y%的水倒入第一杯。这种操作会重复进行k次,最终求出两杯水中各自的水量。 ... [详细]
  • 本文介绍了Java编程语言的基础知识,包括其历史背景、主要特性以及如何安装和配置JDK。此外,还详细讲解了如何编写和运行第一个Java程序,并简要介绍了Eclipse集成开发环境的安装和使用。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • Python多线程详解与示例
    本文介绍了Python中的多线程编程,包括僵尸进程和孤儿进程的概念,并提供了具体的代码示例。同时,详细解释了0号进程和1号进程在系统中的作用。 ... [详细]
  • NX二次开发:UFUN点收集器UF_UI_select_point_collection详解
    本文介绍了如何在NX中使用UFUN库进行点收集器的二次开发,包括必要的头文件包含、初始化和选择点集合的具体实现。 ... [详细]
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
  • LDAP服务器配置与管理
    本文介绍如何通过安装和配置SSSD服务来统一管理用户账户信息,并实现其他系统的登录调用。通过图形化交互界面配置LDAP服务器,确保用户账户信息的集中管理和安全访问。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 本文介绍了如何查看PHP网站及其源码的方法,包括环境搭建、本地测试、源码查看和在线查找等步骤。 ... [详细]
  • CSS 百分比单位的取值依据是什么
    本文详细探讨了 CSS 中百分比单位的取值依据,包括不同定位方式下的包含块概念及其应用。通过具体的示例和代码,帮助读者更好地理解和掌握这一知识点。 ... [详细]
  • 本文介绍了多种开源数据库及其核心数据结构和算法,包括MySQL的B+树、MVCC和WAL,MongoDB的tokuDB和cola,boltDB的追加仅树和mmap,levelDB的LSM树,以及内存缓存中的一致性哈希。 ... [详细]
  • Excel 数据分析基础
    Excel 是数据分析中最基本且强大的工具之一,具备多种实用功能和操作方法。本文将简要介绍 Excel 的不同版本及其兼容性问题,并探讨在处理大数据时的替代方案。 ... [详细]
author-avatar
隐之王语录
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有