一:实现最短跳数转发

(一)原理

推文:迪杰斯特拉算法弗洛伊德算法

二:代码实现

(一)全部代码

from ryu.base import app_manager
from ryu.controller.handler import set_ev_cls
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER
from ryu.lib.packet import packet,ethernet
from ryu.topology import event
from ryu.topology.api import get_switch,get_link
from ryu.ofproto import ofproto_v1_3 import networkx as nx class MyShortestForwarding(app_manager.RyuApp):
'''
class to achive shortest path to forward, based on minimum hop count
'''
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self,*args,**kwargs):
super(MyShortestForwarding,self).__init__(*args,**kwargs) #set data structor for topo construction
self.network = nx.DiGraph() #store the dj graph
self.paths = {} #store the shortest path
self.topology_api_app = self @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
def switch_features_handler(self,ev):
'''
manage the initial link between switch and controller
'''
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser match = ofp_parser.OFPMatch() #for all packet first arrive, match it successful, send it ro controller
actions = [ofp_parser.OFPActionOutput(
ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER
)] self.add_flow(datapath, , match, actions) def add_flow(self,datapath,priority,match,actions):
'''
fulfil the function to add flow entry to switch
'''
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,match=match,instructions=inst) datapath.send_msg(mod) @set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
'''
manage the packet which comes from switch
'''
#first get event infomation
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser in_port = msg.match['in_port']
dpid = datapath.id #second get ethernet protocol message
pkt = packet.Packet(msg.data)
eth_pkt = pkt.get_protocol(ethernet.ethernet) eth_src = eth_pkt.src #note: mac info willn`t change in network
eth_dst = eth_pkt.dst out_port = self.get_out_port(datapath,eth_src,eth_dst,in_port)
actions = [ofp_parser.OFPActionOutput(out_port)] if out_port != ofproto.OFPP_FLOOD:
match = ofp_parser.OFPMatch(in_port=in_port,eth_dst=eth_dst)
self.add_flow(datapath,,match,actions) out = ofp_parser.OFPPacketOut(
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions,data=msg.data
) datapath.send_msg(out) @set_ev_cls(event.EventSwitchEnter,[CONFIG_DISPATCHER,MAIN_DISPATCHER]) #event is not from openflow protocol, is come from switchs` state changed, just like: link to controller at the first time or send packet to controller
def get_topology(self,ev):
'''
get network topo construction, save info in the dict
''' #store nodes info into the Graph
switch_list = get_switch(self.topology_api_app,None) #------------need to get info,by debug
switches = [switch.dp.id for switch in switch_list]
self.network.add_nodes_from(switches) #store links info into the Graph
link_list = get_link(self.topology_api_app,None)
#port_no, in_port ---------------need to debug, get diffirent from both
links = [(link.src.dpid,link.dst.dpid,{'attr_dict':{'port':link.dst.port_no}}) for link in link_list] #add edge, need src,dst,weigtht
self.network.add_edges_from(links) links = [(link.dst.dpid,link.src.dpid,{'attr_dict':{'port':link.dst.port_no}}) for link in link_list]
self.network.add_edges_from(links) def get_out_port(self,datapath,src,dst,in_port):
'''
datapath: is current datapath info
src,dst: both are the host info
in_port: is current datapath in_port
'''
dpid = datapath.id #the first :Doesn`t find src host at graph
if src not in self.network:
self.network.add_node(src)
self.network.add_edge(dpid, src, attr_dict={'port':in_port})
self.network.add_edge(src, dpid)
self.paths.setdefault(src, {}) #second: search the shortest path, from src to dst host
if dst in self.network:
if dst not in self.paths[src]: #if not cache src to dst path,then to find it
path = nx.shortest_path(self.network,src,dst)
self.paths[src][dst]=path path = self.paths[src][dst]
next_hop = path[path.index(dpid)+]
#print("1ooooooooooooooooooo")
#print(self.network[dpid][next_hop])
out_port = self.network[dpid][next_hop]['attr_dict']['port']
#print("2ooooooooooooooooooo")
#print(out_port) #get path info
#print("6666666666 find dst")
print(path)
else:
out_port = datapath.ofproto.OFPP_FLOOD #By flood, to find dst, when dst get packet, dst will send a new back,the graph will record dst info
#print("8888888888 not find dst")
return out_port

(二)注意:由于各种版本的不同,导致我们使用函数的时候可能有所不同,需要我们自己去调试

1.安装networkx模块,若是下载太慢或者出错,换国内源:在末尾加上-i https://pypi.tuna.tsinghua.edu.cn/simple

pip3 install networkx
pip3 install multiqc

2.出现self.network.add_edge(dpid, src, {'port':in_port})使用时,会出现参数太多

self.network.add_edge(dpid, src, attr_dict={'port':in_port})  attr_dict是对我们提供的扩展成熟

3.学会代码调试和思考

三:代码讲解

(一)不变代码:实现初始连接处理和公共函数--下发流表

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
def switch_features_handler(self,ev):
'''
manage the initial link between switch and controller
'''
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser match = ofp_parser.OFPMatch() #for all packet first arrive, match it successful, send it ro controller
actions = [ofp_parser.OFPActionOutput(
ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER
)] self.add_flow(datapath, , match, actions) def add_flow(self,datapath,priority,match,actions):
'''
fulfil the function to add flow entry to switch
'''
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,match=match,instructions=inst) datapath.send_msg(mod)

(二)实现获取网络拓扑结构

class MyShortestForwarding(app_manager.RyuApp):
'''
class to achive shortest path to forward, based on minimum hop count
'''
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] def __init__(self,*args,**kwargs):
super(MyShortestForwarding,self).__init__(*args,**kwargs) #set data structor for topo construction
self.network = nx.DiGraph() #store the dj graph  设置图结构存储信息
self.paths = {} #store the shortest path
self.topology_api_app =
self @set_ev_cls(event.EventSwitchEnter,[CONFIG_DISPATCHER,MAIN_DISPATCHER]) #event is not from openflow protocol, is come from switchs` state changed, just like: link to controller at the first time or send packet to controller
def get_topology(self,ev):
'''
get network topo construction, save info in the dict  由于监听交换机信息进入,触发,注意事件不在flow协议类,在from ryu.topology import event中
''' #store nodes info into the Graph
switch_list = get_switch(self.topology_api_app,None) #------------need to get info,by debug
switches = [switch.dp.id for switch in switch_list]
self.network.add_nodes_from(switches) #store links info into the Graph
link_list = get_link(self.topology_api_app,None)
#port_no, in_port ---------------need to debug, get diffirent from both
links = [(link.src.dpid,link.dst.dpid,{'attr_dict':{'port':link.dst.port_no}}) for link in link_list] #add edge, need src,dst,weigtht
self.network.add_edges_from(links) links = [(link.dst.dpid,link.src.dpid,{'attr_dict':{'port':link.dst.port_no}}) for link in link_list]
self.network.add_edges_from(links)

补充:event.EventSwitchEnter---由于监听交换机信息进入,触发,注意事件不在flow协议类,在from ryu.topology import event中

(三)实现下一跳端口获取(根据图获取最短路径,从中获取信息)

    def get_out_port(self,datapath,src,dst,in_port):
'''
datapath: is current datapath info
src,dst: both are the host info
in_port: is current datapath in_port
'''
dpid = datapath.id #the first :Doesn`t find src host at graph
if src not in self.network:    #根据src主机是否在网络中,决定是否新添加进入
self.network.add_node(src)
self.network.add_edge(dpid, src, attr_dict={'port'
:in_port})
self.network.add_edge(src, dpid)
self.paths.setdefault(src, {})  #设置数据结构:用于保存每个源主机到各个目的主机的最短路径{src1:{dst1:[],dst2:[],dst3:[]....},src2:{dst1:[],dst2:[],dst3:[]....},}
#second: search the shortest path, from src to dst host
if dst in self.network:
if dst not in self.paths[src]: #if not cache src to dst path,then to find it
path = nx.shortest_path(self.network,src,dst)
self.paths[src][dst]=
path path = self.paths[src][dst]
next_hop = path[path.index(dpid)+1
]  #根据数据结构获取下一跳datapath信息
#print("1ooooooooooooooooooo")
#print(self.network[dpid][next_hop])
out_port = self.network[dpid][next_hop]['attr_dict']['port']  #根据该id和下一跳id去获取出端口,进行数据转发
#print("2ooooooooooooooooooo")
#print(out_port) #get path info
#print("6666666666 find dst")
print(path)
else:  #否则是泛洪处理
out_port = datapath.ofproto.OFPP_FLOOD #By flood, to find dst, when dst get packet, dst will send a new back,the graph will record dst info
#print("8888888888 not find dst")
return out_port

(四)实现包接收,计算最短路径,按照最短路径进行动作下发《重点》

    @set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
'''
manage the packet which comes from switch
'''
#first get event infomation
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
ofp_parser = datapath.ofproto_parser in_port = msg.match['in_port']
dpid =
datapath.id #second get ethernet protocol message
pkt = packet.Packet(msg.data)
eth_pkt = pkt.get_protocol(ethernet.ethernet) eth_src = eth_pkt.src #note: mac info willn`t change in network
eth_dst =
eth_pkt.dst out_port = self.get_out_port(datapath,eth_src,eth_dst,in_port)  #这里进行获取下一跳端口
actions = [ofp_parser.OFPActionOutput(out_port)]
if out_port != ofproto.OFPP_FLOOD:
match = ofp_parser.OFPMatch(in_port=in_port,eth_dst=eth_dst)
self.add_flow(datapath,,match,actions) out = ofp_parser.OFPPacketOut(
datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,
actions=actions,data=msg.data
) datapath.send_msg(out)

三:实验演示:注意开启顺序,否则可能导致其他错误

(一)启动Ryu控制器  observe-links命令会导致控制器在运行期间 会不间断地发送LLDP数据包进行链路探测

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

(二)启动Mininet

sudo mn --topo=tree,, --controller=remote --mac

(三)Ryu查看信息

SDN实验---Ryu的应用开发(四)基于跳数的最短路径转发原理的更多相关文章

  1. SDN实验---Ryu的应用开发(二)Learning Switch

    一:自学习交换机(二层MAC交换机)的编程思路 (一)明确问题 如何实现软件定义的自学习交换机? (二)设计解决方案 通过控制器来实现自学习交换算法,然后指导数据平面实现交换机操作 (三)确定具体的技 ...

  2. SDN实验---Ryu的应用开发(三)流量监控

    一:实现流量监控 (一)流量监控原理 其中控制器向交换机周期下发获取统计消息,请求交换机消息------是主动下发过程 流速公式:是(t1时刻的流量-t0时刻的流量)/(t1-t0) 剩余带宽公式:链 ...

  3. SDN实验---Ryu的应用开发(四)北向接口RESTAPI

    一:推文 软件定义网络基础---REST API概述 软件定义网络基础---REST API的设计规范 二:掌握Ryu基本RESTAPI使用方法 (一)Ryu的RESTAPI (二) REST应用样例 ...

  4. SDN实验---Ryu的应用开发(一)Hub实现

    补充: (一)Ubuntu下安装Notepadqq 背景:为什么安装Notepadqq Notepad++ 不仅有语法高亮度显示,也有语法折叠功能,并且支持宏以及扩充基本功能的外挂模组.但是可惜的是N ...

  5. SDN实验---Ryu的安装

    一:Ryu是主流SDN开源控制器之一 (一)推文(摘录自) https://ryu.readthedocs.io/en/latest/ https://www.sdnlab.com/1785.html ...

  6. SDN实验---Ryu的源码分析

    一:安装Pycharm https://www.cnblogs.com/huozf/p/9304396.html(有可取之处) https://www.jetbrains.com/idea/buy/# ...

  7. SDN实验---Mininet实验(玩转流表)

    一:实验目的 (一)案例目的 (二)实验内容 (三)网络拓扑结构 二:OpenFlow流表实验准备 (一)使用Python设置网络拓扑 --- tree_topo.py from mininet.to ...

  8. 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)

    通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...

  9. 实验四实验报告————Android基础开发

    实验四实验报告----Android基础开发 任务一 关于R类 关于apk文件 实验成果 任务二 活动声明周期 实验成果 任务三 关于PendingIntent类 实验成果 任务四 关于布局 实验成果 ...

随机推荐

  1. 【转】大众点评CAT开源监控系统剖析

    https://www.cnblogs.com/yeahwell/p/cat.html 参考文档: 大众点评的实时监控系统分析(一) CAT_source_analyze 透过CAT,来看分布式实时监 ...

  2. LoarRunner脚本录制-Port Mapping

    使用LR录制脚本时经常会因为内外网访问限制,或浏览器兼容等问题,导致无法正常录制脚本. 这里简单介绍一下使用LR端口映射的方式进行脚本录制,与之前介绍的<Jmeter脚本录制--HTTP代理服务 ...

  3. php的选择排序

    往前. <?php /** * 选择排序 * 工作原理是每次从待排序的元素中的第一个元素设置为最小值, * 遍历每一个没有排序过的元素,如果元素小于现在的最小值, * 就将这个元素设置成为最小值 ...

  4. 用于Python扩展包的非官方Windows二进制文件

    https://www.lfd.uci.edu/~gohlke/pythonlibs/ Index by date: peewee aiohttp indexed_gzip pygit2 pymatg ...

  5. 项目Beta冲刺(团队5/7)

    项目Beta冲刺(团队) --5/7 作业要求: 项目Beta冲刺(团队) 1.团队信息 团队名 :男上加男 成员信息 : 队员学号 队员姓名 个人博客地址 备注 221600427 Alicesft ...

  6. Optional类的基本使用(没怎么看)

    参考:https://www.runoob.com/java/java8-optional-class.html java8中引入了一个新类:Optional,用于日常编码中对空指针异常进行限制和处理 ...

  7. Linux中的磁盘练习

    查看磁盘接口类型 ide dh[a-z] scsi sd[a-z] 添加磁盘 先添加一个磁盘 cd /dev/ ls sd* 可以看到先添加的磁盘 磁盘分区 .fdisk /dev/sdb n (添加 ...

  8. Dinner Bet Gym - 101174D (期望dp)

    Problem D: Dinner Bet \[ Time Limit: 1.5 s \quad Memory Limit: 256 MiB \] 题意 题意是两个人在玩游戏,一共有\(n\)张牌,这 ...

  9. 10-网页,网站,微信公众号基础入门(使用微信自带配置选项实现Airkiss配网)

    https://www.cnblogs.com/yangfengwu/p/11066036.html 如果提交失败多提交两次,只要上一节可以,,这一节一定可以的 如果没有设备 这个是我的二维码 咱就测 ...

  10. P3327 [SDOI2015]约数个数和 莫比乌斯反演

    P3327 [SDOI2015]约数个数和 莫比乌斯反演 链接 luogu 思路 第一个式子我也不会,luogu有个证明,自己感悟吧. \[d(ij)=\sum\limits_{x|i}\sum\li ...