SDN实验(八)——网络时延探测

  • 一、原理
  • 二、程序设计
    • 1、构建网络拓扑
    • 2、获取控制器到每个交换机的往返时延
    • 3、获取LLDP时延
    • 4、整体代码
  • 三、实验验证
    • 1、运行Ryu控制器
    • 2、运行网络拓扑
    • 3、查看结果

一、原理

  网络时延探测,主要利用LLDP的知识原理进行,也就是利用了Ryu自带的switches模块的数据,获取到了LLDP数据发送时的时间戳,然后和收到的时间戳进行相减,得到了LLDP数据包从控制器下发到交换机1,然后从交换机1到交换机2,再上报给控制器的时延T1,同理可得到反向的时延T2。此外,控制器到交换机的往返时延,此部分时延可由echo报文测试,分别为Ta,Tb。最后链路的前向后向平均时延T=(T1+T2-Ta-Tb)/2。

  所以网络时延探测主要有3步:(1) echo报文; (2) LLDP报文;(3) 运算。本文先主要讲述如何利用echo得到控制器到交换机的时延和LLDP时延,运算部分以及基于链路质量的数据转发后续更新。

二、程序设计

1、构建网络拓扑

  使用miniedit构建拓扑如下所示:

#!/usr/bin/env pythonfrom mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSKernelSwitch, UserSwitch
from mininet.node import IVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import TCLink, Intf
from subprocess import calldef myNetwork():net = Mininet( topo=None,build=False,ipBase='10.0.0.0/8')info( '*** Adding controller\n' )c0=net.addController(name='c0',controller=RemoteController,protocol='tcp',port=6633)info( '*** Add switches\n')s1 = net.addSwitch('s1', cls=OVSKernelSwitch, dpid='0000000000000001')s2 = net.addSwitch('s2', cls=OVSKernelSwitch, dpid='0000000000000002')s3 = net.addSwitch('s3', cls=OVSKernelSwitch, dpid='0000000000000003')s4 = net.addSwitch('s4', cls=OVSKernelSwitch, dpid='0000000000000004')info( '*** Add hosts\n')h1 = net.addHost('h1', cls=Host, ip='10.0.0.1', defaultRoute=None)h2 = net.addHost('h2', cls=Host, ip='10.0.0.2', defaultRoute=None)h3 = net.addHost('h3', cls=Host, ip='10.0.0.3', defaultRoute=None)h4 = net.addHost('h4', cls=Host, ip='10.0.0.4', defaultRoute=None)info( '*** Add links\n')net.addLink(s1, s2)net.addLink(s2, s3)net.addLink(s3, s4)net.addLink(s1, h1)net.addLink(s2, h2)net.addLink(s3, h3)net.addLink(s4, h4)info( '*** Starting network\n')net.build()info( '*** Starting controllers\n')for controller in net.controllers:controller.start()info( '*** Starting switches\n')net.get('s1').start([c0])net.get('s2').start([c0])net.get('s3').start([c0])net.get('s4').start([c0])info( '*** Post configure switches and hosts\n')CLI(net)net.stop()if __name__ == '__main__':setLogLevel( 'info' )myNetwork()

2、获取控制器到每个交换机的往返时延

  这种时延的探测方法主要是控制器通过向交换机发送echo报文,同时记录此时的时间戳,然后交换机收到echo报文之后,就会给控制器返回echo响应报文,当控制器收到响应报文之后,用当前的系统时间减去时间戳,即得到了控制器到交换机的往返时延。具体的代码如下:

    # 由控制器向交换机发送echo报文,同时记录此时时间def send_echo_request(self):# 循环遍历交换机,逐一向存在的交换机发送echo探测报文for datapath in self.dpidSwitch.values():parser = datapath.ofproto_parserecho_req = parser.OFPEchoRequest(datapath, data=bytes("%.12f" % time.time(), encoding="utf8"))  # 获取当前时间datapath.send_msg(echo_req)# 每隔0.5秒向下一个交换机发送echo报文,防止回送报文同时到达控制器hub.sleep(0.5)# 交换机向控制器的echo请求回应报文,收到此报文时,控制器通过当前时间-时间戳,计算出往返时延@set_ev_cls(ofp_event.EventOFPEchoReply, [MAIN_DISPATCHER, CONFIG_DISPATCHER, HANDSHAKE_DISPATCHER])def echo_reply_handler(self, ev):now_timestamp = time.time()try:echo_delay = now_timestamp - eval(ev.msg.data)# 将交换机对应的echo时延写入字典保存起来self.echoDelay[ev.msg.datapath.id] = echo_delayprint('*******************echo delay*****************')print(self.echoDelay)except Exception as error:print(error)return

3、获取LLDP时延

  获取几个交换机LLDP的逻辑一样,均需要使用到switches模块的数据。计算LLDP时延的处理逻辑如下代码所示。首先从Packet_in中解析LLDP数据包,获得源DPID,源端口。然后根据发送端口的数据获取到portdata中的发送时间戳数据,并用当下的系统时间减去发送时间戳,得到时延,最后将其保存到字典中。

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)def packet_in_handler(self, ev):  # 处理到达的LLDP报文,从而获得LLDP时延msg = ev.msgtry:src_dpid, src_outport = LLDPPacket.lldp_parse(msg.data)  # 获取两个相邻交换机的源交换机dpid和port_no(与目的交换机相连的端口)dst_dpid = msg.datapath.id  # 获取目的交换机(第二个),因为来到控制器的消息是由第二个(目的)交换机上传过来的if self.switches is None:self.switches = lookup_service_brick("switches")  # 获取交换机模块实例# 获得key(Port类实例)和data(PortData类实例)for port in self.switches.ports.keys():  # 开始获取对应交换机端口的发送时间戳if src_dpid == port.dpid and src_outport == port.port_no:  # 匹配keyport_data = self.switches.ports[port]  # 获取满足key条件的values值PortData实例,内部保存了发送LLDP报文时的timestamp信息timestamp = port_data.timestampif timestamp:delay = time.time() - timestampself._save_delay_data(src=src_dpid, dst=dst_dpid, src_port=src_outport, lldp_dealy=delay)except Exception as error:print(error)returndef _save_delay_data(self, src, dst, src_port, lldp_dealy):key = "%s-%s-%s" % (src, src_port, dst)self.src_dstDelay[key] = lldp_dealyprint('------------------lldp delay--------------------')print(self.src_dstDelay)

4、整体代码

import timefrom ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER, CONFIG_DISPATCHER, HANDSHAKE_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
from ryu.ofproto import ofproto_v1_3
from ryu.topology.switches import LLDPPacket
from ryu.base.app_manager import lookup_service_brick# 导入这些主要是为了让网络链路中产生LLDP数据包,只有产生了LLDP数据报,才能进行LLDP时延探测
from ryu.topology.api import get_switch, get_link, get_hostclass DelayDetector(app_manager.RyuApp):OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]def __init__(self, *args, **kwargs):super(DelayDetector, self).__init__(*args, *kwargs)self.name = 'delay_detector'self.switches = lookup_service_brick('switches')# 存储网络拓扑的交换机idself.dpidSwitch = {}# 存储echo往返时延self.echoDelay = {}# 存储LLDP时延self.src_dstDelay = {}# 实现协程,进行时延的周期探测self.detector_thread = hub.spawn(self.detector)# 每隔3秒进行控制器向交换机发送一次echo报文,用以获取往返时延def detector(self):while True:self.send_echo_request()hub.sleep(3)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)@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)def switch_features_handler(self, ev):msg = ev.msgdatapath = msg.datapathofp = datapath.ofprotoofp_parser = datapath.ofproto_parser# add table-missmatch = ofp_parser.OFPMatch()actions = [ofp_parser.OFPActionOutput(ofp.OFPP_CONTROLLER, ofp.OFPCML_NO_BUFFER)]self.add_flow(datapath=datapath, priority=0, match=match, actions=actions)@set_ev_cls(ofp_event.EventOFPStateChange, [MAIN_DISPATCHER, DEAD_DISPATCHER])def state_change_handler(self, ev):datapath = ev.datapathif ev.state == MAIN_DISPATCHER:if not datapath.id in self.dpidSwitch:self.dpidSwitch[datapath.id] = datapathelif ev.state == DEAD_DISPATCHER:if datapath.id in self.dpidSwitch:del self.dpidSwitch[datapath.id]# 由控制器向交换机发送echo报文,同时记录此时时间def send_echo_request(self):# 循环遍历交换机,逐一向存在的交换机发送echo探测报文for datapath in self.dpidSwitch.values():parser = datapath.ofproto_parserecho_req = parser.OFPEchoRequest(datapath, data=bytes("%.12f" % time.time(), encoding="utf8"))  # 获取当前时间datapath.send_msg(echo_req)# 每隔0.5秒向下一个交换机发送echo报文,防止回送报文同时到达控制器hub.sleep(0.5)# 交换机向控制器的echo请求回应报文,收到此报文时,控制器通过当前时间-时间戳,计算出往返时延@set_ev_cls(ofp_event.EventOFPEchoReply, [MAIN_DISPATCHER, CONFIG_DISPATCHER, HANDSHAKE_DISPATCHER])def echo_reply_handler(self, ev):now_timestamp = time.time()try:echo_delay = now_timestamp - eval(ev.msg.data)# 将交换机对应的echo时延写入字典保存起来self.echoDelay[ev.msg.datapath.id] = echo_delayprint('*******************echo delay*****************')print(self.echoDelay)except Exception as error:print(error)return@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)def packet_in_handler(self, ev):  # 处理到达的LLDP报文,从而获得LLDP时延msg = ev.msgtry:src_dpid, src_outport = LLDPPacket.lldp_parse(msg.data)  # 获取两个相邻交换机的源交换机dpid和port_no(与目的交换机相连的端口)dst_dpid = msg.datapath.id  # 获取目的交换机(第二个),因为来到控制器的消息是由第二个(目的)交换机上传过来的if self.switches is None:self.switches = lookup_service_brick("switches")  # 获取交换机模块实例# 获得key(Port类实例)和data(PortData类实例)for port in self.switches.ports.keys():  # 开始获取对应交换机端口的发送时间戳if src_dpid == port.dpid and src_outport == port.port_no:  # 匹配keyport_data = self.switches.ports[port]  # 获取满足key条件的values值PortData实例,内部保存了发送LLDP报文时的timestamp信息timestamp = port_data.timestampif timestamp:delay = time.time() - timestampself._save_delay_data(src=src_dpid, dst=dst_dpid, src_port=src_outport, lldp_dealy=delay)except Exception as error:print(error)returndef _save_delay_data(self, src, dst, src_port, lldp_dealy):key = "%s-%s-%s" % (src, src_port, dst)self.src_dstDelay[key] = lldp_dealyprint('------------------lldp delay--------------------')print(self.src_dstDelay)

三、实验验证

1、运行Ryu控制器

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

2、运行网络拓扑

sudo python3 delay_detector.py

3、查看结果

  可以看到,当拓扑开始运行后,控制器后台在不断输出数据:

  以上结果中,{1: 0.0004951953887939453, 2: 0.00040435791015625, 3: 0.0005011558532714844, 4: 0.00046634674072265625}表示控制器到交换机s1、s2、s3、s4的往返时延;{‘2-1-1’: 0.0009016990661621094, ‘1-1-2’: 0.0007228851318359375, ‘3-1-2’: 0.0007128715515136719, ‘4-1-3’: 0.0010399818420410156, ‘2-2-3’: 0.0008199214935302734, ‘3-2-4’: 0.0008656978607177734}表示c0-s1-s2-c0、c0-s2-s1-c0、c0-s2-s3-c0、c0-s3-s2-c0、c0-s3-s4-c0、c0-s4-s3-c0这六种LLDP时延。

SDN实验(八)——网络时延探测相关推荐

  1. ryu实例---网络时延探测

    一.前言 前面的博文写到了基于跳数的最短路径的案例实现(ryu实例---基于跳数的最短路径转发_北风-CSDN博客),然而基于跳数的最短路径转发并未考虑网络链路的质量(时延.可用带宽.丢包率...), ...

  2. 实验八网络程序设计(网络编程)_JAVA

    实验目的: (1)掌握网络通信的概念. (2)掌握InetAddress.URL类的使用. (2)掌握JAVA利用 TCP协议和UDP协议进行通信的网络编程方法. 实验内容 1.从键盘输入网址,读取网 ...

  3. 20155235 《网络攻防》 实验八 Web基础

    20155235 <网络攻防> 实验八 Web基础 实验内容 Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表 ...

  4. 基于深度学习的SDN家庭网关加密网络流量分类

    写在前面: 本文翻译供个人研究学习之用,不保证严谨与准确 github链接:https://github.com/WithHades/network_traffic_classification_pa ...

  5. 实验一 网络对抗技术

    实验一 网络侦查与网络扫描     学生姓名 杨益 年级 2015 区队 网络安全与执法六区队 指导教师 高见 实验任务(一) 网络侦查是指黑客为了更加有效地实施攻击而在攻击前或攻击过程中对目标主机的 ...

  6. SDN实验(四)——Learning Switch自学习交换机

    SDN实验(四)--Learning Switch自学习交换机 一.自学习交换机原理 (一)普通交换机实现 (二)SDN交换机实现 二.自学习交换机代码实现 (一)代码 (二)代码讲解 (三)实验 三 ...

  7. SDN实验(六)——SDN流量监控

    SDN实验(六)--SDN流量监控 一.流量监控原理 二.代码实现 (一)代码 (二)讲解 三.实验演示 (一)开启Ryu (二)开启Mininet (三)Ryu显示结果 四.扩展 一.流量监控原理 ...

  8. SDN(软件定义网络)基本概念

    SDN(软件定义网络)基本概念 定义 SDN(Software Defined Network)是"软件定义网络"的缩写,它是一种网络架构和技术,旨在将网络控制器与数据转发分离开来 ...

  9. 实验:网络常见的9个命令

    1.ping命令 ping是个使用频率极高的实用程序,主要用于确定网络的连通性.这对确定网络是否正确连接,以及网络连接的状况十分有用.简单的说,ping就是一个测试程序,如果ping运行正确,大体上就 ...

最新文章

  1. python raw_input 与 input 的区别
  2. 计算机基础2多媒体,《计算机基础》第2章-多媒体技术.pptx
  3. NFS基本配置与NFS客户端自动挂载
  4. SAP Spartacus pagefold学习笔记
  5. 数据思维,让决策更精准
  6. 一行代码让 Python 的运行速度提高100倍
  7. 图片URL转换为base64的两种方式
  8. 【QT C++ TCP通信调试助手】
  9. Verilog语法概述(一)
  10. 3dB等波纹低通滤波器设计(HFSS)
  11. 测试ssd软件哪个好,好物分享:安兔兔SSD测试工具
  12. 每日算法(5)——正整数分解质因数
  13. Unterminated regular expression 和正则表达式
  14. java top virt_Java 进程占用 VIRT 虚拟内存超高的问题研究
  15. 新浪股东批准私有化合并协议;中集车辆创业板成功过会;中国红牛2020年销售额超228亿元​ | 美通企业周刊...
  16. OpenResty 火焰图工具
  17. Win10系统在当前文件夹下打开cmd(命令行)窗口
  18. 童年记忆中的零食商品
  19. NeurlPS2020:Neuron-level Structured Pruning using Polarization Regularizer(polarization正则化技术)
  20. Golang的runtime

热门文章

  1. JavaScript blog式日历控件javascript
  2. POJ1151 Atlantis(线段树,扫描线,离散化,矩形面积并)
  3. 玩《征途》感受——这么多年白玩游戏了 (zt)
  4. android 聚合数据,关于聚合数据调用的问题
  5. 多智能相机视觉系统助力实现智能制造
  6. 毕业三年,同学基本都辞职了
  7. 抖音解析后保存不了,新浪看点秒拍凤凰号修改md5,批量下载去重消重伪原创火山上热门时间,今日头条修改m...
  8. 修改chrome浏览器背景颜色为保护颜色
  9. MySQL查询练习1
  10. 多级分销模块 java_java B2B2C 源码 多级分销Springcloud多租户电子商城系统-hystrix的工作原理...