最近,做到一个实验,需要每隔一段时间,就改变数据的传输路径,如下图所示,主机之间的数据传输需要经过s1和s2两个交换机,交换机之间的链路有两条,实验是在这两条链路之间每隔10秒切换一次,也就是相当于ECMP的轮询算法(当然,若想以流为单位切换链路,比如说:上一个流经链路1下一条流经链路2,这种方式的轮询利用集线器的程序改变一下就可以实现)。

  • 轮询,即各个流在多条路径之间轮询传输。

拓扑的端口对应关系:

接下来,重点说明程序如何写,不再赘述一些关于拓扑构建和轮询的一些概念。

一、程序

SDN架构下的网络数据传输均是通过流表进行的,也就是说,要想在两条链路之间进行切换,就需要对流表进行改变,这里的思想:

  1. 获取SDN交换机对象和SDN交换机的dpid,也就是s1和s2;
  2. 向s1,s2添加流表项,规则为走上面一条链路;
  3. 设定的时间间隔后,删除s1,s2的流表项,重新添加流表项,规则为走下面一条链路;
  4. 循环执行2,3过程。

首先,创建RRSwitchChange类,进行初始化,并初始化交换机字典,用来存储SDN交换机对象和id。

class RRSwitchChange(app_manager.RyuApp):def __init__(self, *args, **kwargs):super(RRSwitchChange, self).__init__(*args, **kwargs)# 用于存储交换机对象self.datapaths = {}

接下来,向类中添加增加和删除流表项的方法。

    # 删除流表项的方法,方法直接清除交换机的所有流表项def del_flow(self, datapath, match):ofp = datapath.ofprotoofp_parser = datapath.ofproto_parserreq = ofp_parser.OFPFlowMod(datapath=datapath,command=ofp.OFPFC_DELETE,out_port=ofp.OFPP_ANY,out_group=ofp.OFPG_ANY,match=match)datapath.send_msg(req)# 添加流表项的方法def add_flow(self, datapath, priority, match, actions):ofp = datapath.ofprotoofp_parser = datapath.ofproto_parsercommand = ofp.OFPFC_ADDinst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]req = ofp_parser.OFPFlowMod(datapath=datapath, command=command,priority=priority, match=match, instructions=inst)datapath.send_msg(req)

同时,由于删除和添加流表项的多项操作均相同,也就是如果单纯的调用添加和删除流表项的方法会显得程序冗余杂乱,所以,这里本实验添加了一个方法match_flow(),用于简化添加和删除流表项的重复调用的冗余操作。

    def match_flow(self, dpid, in_port, out_port, priority, add_del):ofp_parser = self.datapaths[dpid].ofproto_parserofp = self.datapaths[dpid].ofprotoactions = [ofp_parser.OFPActionOutput(out_port)]# add_del变量用来判断是该执行删除还是添加操作,如果是1则执行添加,如果为0执行删除if add_del == 1:match = ofp_parser.OFPMatch(in_port=in_port)self.add_flow(datapath=self.datapaths[dpid], priority=priority, match=match, actions=actions)if add_del == 0:match = ofp_parser.OFPMatch()self.del_flow(datapath=self.datapaths[dpid], match=match)

接下来,是整个程序的关键部分,即处理流表的删除与添加的函数。

    def rr_link_change(self):# flag用于标记每一段时间间隔的流表项下发规则# 例如flag=1表示走上面一条链路,flag=2表示走下面一条链路flag = 1# 一致循环的执行流表项的清除添加工作while True:print('datapath:', self.datapaths)try:if flag == 1:print('flag:', flag)flag = 2# 添加流表项之前先删除交换机s1,s2中存在的流表项self.match_flow(dpid=1, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=2, in_port=1, out_port=1, priority=1, add_del=0)# 向交换机s1中添加流表项self.match_flow(dpid=1, in_port=1, out_port=2, priority=1, add_del=1)self.match_flow(dpid=1, in_port=2, out_port=1, priority=1, add_del=1)# 向交换机s2中添加流表项self.match_flow(dpid=2, in_port=1, out_port=2, priority=1, add_del=1)self.match_flow(dpid=2, in_port=2, out_port=1, priority=1, add_del=1)elif flag == 2:print('flag:', flag)flag = 1self.match_flow(dpid=1, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=2, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=1, in_port=1, out_port=3, priority=1, add_del=1)self.match_flow(dpid=1, in_port=3, out_port=1, priority=1, add_del=1)self.match_flow(dpid=2, in_port=1, out_port=3, priority=1, add_del=1)self.match_flow(dpid=2, in_port=3, out_port=1, priority=1, add_del=1)except Exception as info:print('info:', info)hub.sleep(10) # 间隔10秒切换一次

最后,需要将方法 rr_link_change()进行调用,同时由于上述步骤用到了交换机的对象,所以需要获取交换机,将其写入字典中,这里使用交换机状态变化的函数,获取完成后在初始化中调用 rr_link_change()进行流表项的下发,为了持续的执行方法,而且不对程序的其他部分产生影响,这里利用协程进行方法的执行,代码如下。

    @set_ev_cls(ofp_event.EventOFPStateChange, [MAIN_DISPATCHER, DEAD_DISPATCHER])def _state_change_handler(self, ev):datapath = ev.datapathif ev.state == MAIN_DISPATCHER:if datapath.id not in self.datapaths:self.datapaths[datapath.id] = datapathelif ev.state == DEAD_DISPATCHER:if datapath.id in self.datapaths:del self.datapaths[datapath.id]
    def __init__(self, *args, **kwargs):super(RRSwitchChange, self).__init__(*args, **kwargs)self.datapaths = {}self.link_change = hub.spawn(self.rr_link_change)

至此,程序编写完成,接下来,在Ubuntu终端命令行执行程序。

二、实验

实验拓扑如下:

在程序执行前,查看s1和s2的流表项,流表项为空。接下来,输入命令执行程序,如下图所示。

然后,查看s1和s2的流表项,可以间隔时间查一次,就可以发现流表项每隔10秒更改一次,如下所示。

此时,h1 ping h2,就可以正常的进行通信了。

3、代码附录

from ryu.controller import ofp_event
from ryu.lib import hub
from ryu.base import app_manager
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_clsclass RRSwitchChange(app_manager.RyuApp):def __init__(self, *args, **kwargs):super(RRSwitchChange, self).__init__(*args, **kwargs)self.datapaths = {}self.link_change = hub.spawn(self.rr_link_change)@set_ev_cls(ofp_event.EventOFPStateChange, [MAIN_DISPATCHER, DEAD_DISPATCHER])def _state_change_handler(self, ev):datapath = ev.datapathif ev.state == MAIN_DISPATCHER:if datapath.id not in self.datapaths:self.datapaths[datapath.id] = datapathelif ev.state == DEAD_DISPATCHER:if datapath.id in self.datapaths:del self.datapaths[datapath.id]def rr_link_change(self):flag = 1while True:print('datapath:', self.datapaths)try:if flag == 1:print('flag:', flag)flag = 2self.match_flow(dpid=1, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=2, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=1, in_port=1, out_port=2, priority=1, add_del=1)self.match_flow(dpid=1, in_port=2, out_port=1, priority=1, add_del=1)self.match_flow(dpid=2, in_port=1, out_port=2, priority=1, add_del=1)self.match_flow(dpid=2, in_port=2, out_port=1, priority=1, add_del=1)elif flag == 2:print('flag:', flag)flag = 1self.match_flow(dpid=1, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=2, in_port=1, out_port=1, priority=1, add_del=0)self.match_flow(dpid=1, in_port=1, out_port=3, priority=1, add_del=1)self.match_flow(dpid=1, in_port=3, out_port=1, priority=1, add_del=1)self.match_flow(dpid=2, in_port=1, out_port=3, priority=1, add_del=1)self.match_flow(dpid=2, in_port=3, out_port=1, priority=1, add_del=1)except Exception as info:print('info:', info)hub.sleep(10)def match_flow(self, dpid, in_port, out_port, priority, add_del):ofp_parser = self.datapaths[dpid].ofproto_parserofp = self.datapaths[dpid].ofprotoactions = [ofp_parser.OFPActionOutput(out_port)]if add_del == 1:match = ofp_parser.OFPMatch(in_port=in_port)self.add_flow(datapath=self.datapaths[dpid], priority=priority, match=match, actions=actions)if add_del == 0:match = ofp_parser.OFPMatch()self.del_flow(datapath=self.datapaths[dpid], match=match)def del_flow(self, datapath, match):ofp = datapath.ofprotoofp_parser = datapath.ofproto_parserreq = ofp_parser.OFPFlowMod(datapath=datapath,command=ofp.OFPFC_DELETE,out_port=ofp.OFPP_ANY,out_group=ofp.OFPG_ANY,match=match)datapath.send_msg(req)def add_flow(self, datapath, priority, match, actions):ofp = datapath.ofprotoofp_parser = datapath.ofproto_parsercommand = ofp.OFPFC_ADDinst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions)]req = ofp_parser.OFPFlowMod(datapath=datapath, command=command,priority=priority, match=match, instructions=inst)datapath.send_msg(req)

github地址:https://github.com/Yang-Jianlin/ryu/blob/master/ryu/app/rr_switch_link_yjl.py

如有问题,请各位留言或者私信指出,谢谢啦。

ryu实例---ECMP的rr(轮询)算法实现相关推荐

  1. 负载均衡轮询算法和服务器性能,SpringCloud-Ribbon负载均衡机制、手写轮询算法

    Ribbon 内置的负载均衡规则 在 com.netflix.loadbalancer 包下有一个接口 IRule,它可以根据特定的算法从服务列表中选取一个要访问的服务,默认使用的是「轮询机制」 Ro ...

  2. 微信红包业务,为什么采用轮询算法?

    目录 前言 基本的负载算法 平滑加权轮询算法 一致性哈希算法 最小活跃数算法 最优响应算法 总结 前言 负载均衡这个概念,几乎在所有支持高可用的技术栈中都存在,例如微服务.分库分表.各大中间件(MQ. ...

  3. 微信红包业务,为什么采用轮询算法?(荣耀典藏版)

    目录 前言 1.基本的负载算法 1.1.轮询算法 1.2.随机算法 1.3.权重算法 2.平滑加权轮询算法 3.一致性哈希算法 3.1.通过其他分发算法实现缓存 3.2.致性哈希核心-哈希环 3.3. ...

  4. java轮训算法_负载均衡轮询算法实现疑问

    import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; /* ...

  5. 负载均衡轮询算法和服务器性能,负载均衡算法

    对于要实现高性能集群,选择好负载均衡器很重要,同时针对不同的业务场景选择合适的负载均衡算法也是非常重要的. 一.负载均衡算法分类 任务平分类 负载均衡系统将收到的任务平均分配给服务器进行处理,这里的& ...

  6. 负载均衡之加权轮询算法

    在介绍加权轮询算法(WeightedRound-Robin)之前,首先介绍一下轮询算法(Round-Robin). 一:轮询算法(Round-Robin) 轮询算法是最简单的一种负载均衡算法.它的原理 ...

  7. 负载均衡--加权轮询算法(Weight Round)

    加权轮询算法:不同的后端服务器,在机器的配置和当前系统的负载方面,可能并不相同.因此,它们的抗压能力也不相同.给配置高.负载低的机器配置更高的权重,让其处理更多的请求:给配置低.负载高的机器分配较低的 ...

  8. 按位实现的队列轮询算法

    由于Nagle所提出的队列轮询算法,实际上是以报文为单位进行公平轮询,进而发送报文,但是没有考虑报文大小不同带来的不公平性,导致使用大报文的连接占用较多的网络带宽.来看一下为解决此问题,理想的按照比特 ...

  9. 【纸上得来终觉浅】RoundRobinRule源码分析后,自己手写了轮询算法

    前言 今天自己查看了RoundRobinRule的源码,通过读源码走断点,大概自己知道了源码中,参数调用,下面我是查阅相关源代码,反正看过源代码以后总感觉纸上得来终觉浅,绝知此事要躬行,然后编写了轮询 ...

最新文章

  1. 基于相机和激光传感器的车顶视觉检测系统
  2. 【控制】《多智能体系统的动力学分析与设计》徐光辉老师-第1章-绪论
  3. 专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)
  4. 上传文件漏洞案例分析
  5. 307. Range Sum Query - Mutable | 307. 区域和检索 - 数组可修改(数据结构:线段树,图文详解)
  6. 最强阿里巴巴历年经典面试题汇总:C++研发岗
  7. Java中高效判断数组中是否包含某个元素
  8. 程序员,你怎么这么忙?为什么天天熬夜加班?
  9. http 请求头回显
  10. postgresal去重_postgresql数据库去重方法
  11. 人工智能畅想——《人工智能简史》读后感
  12. 2.4g和5g要不要合并_路由器2.4g和5g要不要合并?
  13. 【Books系列】2022年:《拼职场》读书笔记
  14. mysql 小于号转义_mybatis sql语句配置大于号小于号的处理
  15. 【瑞吉外卖】学习笔记-day1:项目介绍及后台初识
  16. 需求调研过程管理小议
  17. 【论文评审】怎样审稿?
  18. 往年二本计算机分数线,全国一本、二本院校历年录取分数线汇总
  19. hiho一下 第三周---KMP算法
  20. Hive窗口函数详解

热门文章

  1. js m 数值缩写k_像请问英文版微博的数字后面的k和m分别代表什么意思?
  2. 互联网金融的五个猜想和四大趋势
  3. vs2015 CMake Recast库编译方式
  4. 前端:xadmin 实现二级联动
  5. 托福作文——《十天突破新托福Essay》
  6. android searchview光标,android – 在没有ActionBarSherlock的情况下更改SearchView中的光标颜色...
  7. 清华源安装pymysql
  8. Cisco PT模拟实验(10) 路由器的基本配置
  9. npm安装模块到全局(win10)
  10. 阿里巴巴java方向笔试题 带详细答案