实验三 控制平面实验(Mininet)

一、实验目的

二、实验内容

1、网络性能测试

2、Mininet测量路径损耗率

(1)构建存在路径损耗的网络

(2)测量路径损耗率

3、分析实用性

(1)准确性

(2)可靠性

(3)可扩展性

三、实验总结


一、实验目的

1、学习在Mininet中使用Python进行自定义拓扑的实现,并会设置交换机和主机之间丢包率、延迟以及链路的带宽,从而对主机的性能进行测试,通过本实验,可以学习到以下知识:

  • ① 设置丢包率、延迟以及链路的带宽;

  • ② 使用iperf测试主机间的带宽性能。

2、学习使用Mininet模拟网络环境,通过在不同节点间发送和接收数据包,测量网络中各个路径的损耗率。同时,探究基于Mininet的路径损耗率测量方法,并分析其实用性。

二、实验内容

1、网络性能测试

在Mininet中,可以通过设置带宽,延迟和丢包等参数来模拟不同的网络条件和拥塞控制机制,进而进行网络性能测试,从而优化网络拓扑和协议设计。

构建的网络拓扑如下:

 然后用python脚本构建如上网络拓扑,该拓扑为Single类的拓扑,呈星型,有一个交换机多个主机,可通过SingleSwitchTopo直接实现

(1)导入类模块

from mininet.topo import Topo
from mininet.topo import SingleSwitchTopo
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel

(2)网络拓扑构建

为更好配置网络拓扑参数,重写类SingleSwitchTopo,在类中实现为主机配置cpu资源,链路设置带宽、时延等。

class SingleSwitchTopo(Topo):
    def __init__(self, n=2, **opts):
        Topo.__init__(self, **opts)
        switch = self.addSwitch('s1') # 添加s1交换机
        for h in range(n):
            host = self.addHost('h%s' % (h + 1), cpu=.5/n)  #每个主机占50/n%的CPU,限制每个主机处理数据的能力
            self.addLink(host, switch, bw=10, delay='5ms', loss=0, max_queue_size=1000, use_htb=True)

然后就可以构建Single类拓扑,并进行网络性能测试:

def perfTest():
    topo = SingleSwitchTopo(n=4)
    net = Mininet(topo=topo,host=CPULimitedHost, link=TCLink) # 创建网络拓扑
    net.start() # 启动网络拓扑
    print ("Dumping host connections")
    dumpNodeConnections(net.hosts) # 打印节点之间的连接关系
    print ("Testing network connectivity")
    net.pingAll() # 所有主机之间相互ping
    print ("Testing bandwidth between h2 and h3")
    h2,h3 = net.get('h2','h3') # 测试主机2与主机3之间的带宽
    net.iperf((h2,h3)) 
    net.stop()

输出的网络配置信息如下:添加了四台主机hosts,每套主机都被分配相同的CPU时间片,有一台交换机,为链路的两个方向都进行了配置:每个链路都有一个延迟为5ms、丢包率为0.00000%的10.00Mbit的带宽限制。

 net.start()调用,网络拓扑配置调用,开始性能测试过程:

 完成测试之后net.stop()被调用,设备停机:

2、Mininet测量路径损耗率

 路径的损耗率是指在在网络中传输数据时,数据包在从源节点到目标节点的过程中丢失或损坏的比例。可以使用Mininet模拟网络环境,通过在不同节点间发送和接收数据包,测量网络中各个路径的损耗率。

(1)构建存在路径损耗的网络

  • 导入类模块
from mininet.net import Mininet
from mininet.node import Node
from mininet.link import TCLink
from mininet.log import setLogLevel,info
from threading import Timer
from mininet.util import quietRun # 用于在Mininet环境中运行命令
from time import sleep
  •  构建网络

        首先创建出网络节点,并为每个节点命名

info( "*** Creating nodes\n" )
controller = Node( 'c0', inNamespace=False ) # 远程控制器
switch = Node( 's0', inNamespace=False ) # 交换机
switch1 = Node( 's1', inNamespace=False )
h0 = Node( 'h0' ) # 主机
h1 = Node( 'h1' )

然后构建出各个节点之间的关系,创建链路,某条链路的配置信息如下:

linkopts1=dict(bw=100, delay='1ms', loss=10)
'''
bw 带宽为100
delay 延时为1ms
loss 丢包率,表明该链路存在一定程度的丢包
'''

 链路完整配置如下:

info( "*** Creating links\n" )
linkopts0=dict(bw=100, delay='1ms', loss=0)
linkopts1=dict(bw=100, delay='1ms', loss=10)
link0=TCLink( h0, switch, **linkopts0) # h0-switch
link1 = TCLink( switch, switch1, **linkopts1) # switch-switch1   
link2 = TCLink( h1, switch1, **linkopts0) # h1-switch1

# 配置链路接口的MAC地址,本质是在配置交换机接口的MAC地址
link0.intf2.setMAC("0:0:0:0:0:1")
link1.intf1.setMAC("0:0:0:0:0:2")
link1.intf2.setMAC("0:1:0:0:0:1") 
link2.intf2.setMAC("0:1:0:0:0:2")

 配置主机的IP地址

info( "*** Configuring hosts\n" )
h0.setIP( '192.168.123.1/24' )
h1.setIP( '192.168.123.2/24' )

 在Mininet网络拓扑节点上可以执行命令,通过cmd函数发送命令等待输出,通过在交换机上执行创建网桥的命令,可以实现网络的分割,将一个物理网络划分成两个虚拟网络。如下两个交换机都进行了网络分割:

info( "*** Starting network using Open vSwitch\n" )
switch.cmd( 'ovs-vsctl del-br dp0' )
switch.cmd( 'ovs-vsctl add-br dp0' )
switch1.cmd( 'ovs-vsctl del-br dp1' )
switch1.cmd( 'ovs-vsctl add-br dp1' )

配置控制器:

controller.cmd( cname + ' ' + cargs + '&' )  # 将指定名称cname的控制器启动,&表示控制器在后台运行   

 配置交换机:

首先将之前配置好的链路接口加入到交换机的端口当中,使得交换机能够与其他主机或者交换机正常相连。

# 将之间配置的接口与交换机对应上,使得交换机能与主机相连
for intf in switch.intfs.values(): 
    print (intf)
    print (switch.cmd( 'ovs-vsctl add-port dp0 %s' % intf ))
for intf in switch1.intfs.values():
    print (intf)
    print (switch1.cmd( 'ovs-vsctl add-port dp1 %s' % intf ))

 为SDN网络,需要将交换机与控制器相连,需要注意的是这里的需要填的是本机的IP地址(POX控制器运行在本机上),可以通过ip address show查看:

 然后通过如下代码可以在交换机中执行启动命令,让交换机与控制器相连:

switch.cmd( 'ovs-vsctl set-controller dp0 tcp:10.0.2.15:6633' ) 
switch1.cmd( 'ovs-vsctl set-controller dp1 tcp:10.0.2.15:6633' )

然后等待连接:

info( '*** Waiting for switch to connect to controller' )
while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
    sleep( 1 )
    info( '.' )
info( '\n' )

以上就完成了网络的配置过程,接下来进行网络的性能测试:

在主机0上对主机1执行ping指令,-c 20表示发送了20次ping请求,-Q 0x64指定了服务质量。

h0.cmdPrint( 'ping -Q 0x64 -c 20 ' + h1.IP() )

由于对主机以及链路性能做出了限定,该网络产生了30%的包丢失率。

完成性能测试之后,停止网络运行:

info( "*** Stopping network\n" )
controller.cmd( 'kill %' + cname )
switch.cmd( 'ovs-vsctl del-br dp0' )
switch.deleteIntfs()
switch1.cmd( 'ovs-vsctl del-br dp1' )
switch1.deleteIntfs()
info( '\n' )
(2)测量路径损耗率

 在SDN环境下,控制器不仅可以用来下发流表来控制交换机的转发行为,还可以利用控制器测量路径的损耗率。使用开源的SDN控制器POX来进行SDN网络的管理、监控以及测试。

  • 导入类模块
from pox.core import core
from pox.lib.util import dpidToStr
import pox.openflow.libopenflow_01 as of
from pox.lib.addresses import IPAddr, EthAddr
from pox.openflow.of_json import *
from pox.lib.recoco import Timer
import time
  • 初始化部分
log = core.getLogger() # 初始化记录日志信息的对象
# 初始化网络的参数0
src_dpid = 0		# 源交换机
dst_dpid = 0		# 目标交换机
input_pkts = 0      # 输入数据包数量
output_pkts = 0		# 输出数据包数量
  • 为了便于记录日志,需要有一个能够获取当前时间的函数
def getTheTime():  #fuction to create a timestamp
  flock = time.localtime()
  then = "[%s-%s-%s" %(str(flock.tm_year),str(flock.tm_mon),str(flock.tm_mday))
  
# 设置特定现实格式
  if int(flock.tm_hour)<10: # 时
    hrs = "0%s" % (str(flock.tm_hour))
  else:
    hrs = str(flock.tm_hour)
  if int(flock.tm_min)<10:  # 分
    mins = "0%s" % (str(flock.tm_min))
  else:
    mins = str(flock.tm_min)
  if int(flock.tm_sec)<10:	# 秒
    secs = "0%s" % (str(flock.tm_sec))
  else:
    secs = str(flock.tm_sec)
  then +="]%s.%s.%s" % (hrs,mins,secs)
  return then
  • 控制器与每个交换机相连,它需要从交换机处获取网络信息
def _timer_func ():
  	for connection in core.openflow._connections.values(): # 遍历所有交换机与控制器的连接,控制器向每个交换机请求流表统计信息以及端口统计信息
    	connection.send(of.ofp_stats_request(body=of.ofp_flow_stats_request()))
    	connection.send(of.ofp_stats_request(body=of.ofp_port_stats_request()))
  	log.debug("Sent %i flow/port stats request(s)", len(core.openflow._connections))
  •  交换机收到控制器的请求之后会进行响应,控制器需要处理交换机的响应:处理流表统计信息和端口统计信息,并利用这些信息计算出从源主机到目的主机的路径丢包率(仍为从主机0向主机1发送ping请求),流表统计信息通常包括匹配字段、匹配计数器、动作计数器和匹配命中率。  
def _handle_flowstats_received (event):
   global src_dpid, dst_dpid, input_pkts, output_pkts
# 目的地均为为192.168.123.2
   for f in event.stats:
     if f.match.dl_type==0x0800 and f.match.nw_dst==IPAddr("192.168.123.2") and f.match.nw_tos==0x64 and event.connection.dpid==src_dpid: # 源交换机

       input_pkts = f.packet_count
     if f.match.dl_type==0x0800 and f.match.nw_dst==IPAddr("192.168.123.2") and f.match.nw_tos==0x64 and event.connection.dpid==dst_dpid: # 目的交换机

       output_pkts = f.packet_count
       if input_pkts !=0:
         print (getTheTime(), "Path Loss Rate =", (input_pkts-output_pkts)*1.0/input_pkts*100, "%")

 得到进入某个链路的input_pkts和输出某个链路的output_pkts之后,通过(input_pkts-output_pkts)*1.0/input_pkts*100就可以得到路径上的丢包率。

def _handle_portstats_received (event):
  stats = flow_stats_to_list(event.stats)
  log.debug("PortStatsReceived from %s: %s", dpidToStr(event.connection.dpid), stats)

端口统计信息恢复转换格式之后直接打印。

  • 交换机会主动向控制器发起连接,控制器在收到连接请求之后需要进行处理:控制器南向接口下发流表到交换机
def _handle_ConnectionUp (event):
  global src_dpid, dst_dpid
  print("ConnectionUp: ", dpidToStr(event.connection.dpid)) # 获取连接的交换机的ID,并打印
  for m in event.connection.features.ports: # 遍历交换机的端口,确定源交换机以及目的交换机
    if m.name == "s0-eth0": 	# 源
      src_dpid = event.connection.dpid
    elif m.name == "s1-eth0": 	# 目的
      dst_dpid = event.connection.dpid

随后进行流表表项的设置:

其中一二条都只需要匹配交换机的入端口,三四条需要进行IP、交换机端口、网络服务类型的匹配。

# 1
msg = of.ofp_flow_mod() # 用于设置流表项的数据结构
msg.priority =1			# 优先级,值越小优先级越低,这里设置为1,为最低优先级
msg.idle_timeout = 0	# 空闲时就关闭连接
msg.match.in_port =1	# 交换机入端口为1
msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL)) # OFPP_ALL表示发送到所有端口,泛洪
event.connection.send(msg) # 将该流表条目发送给交换机
# 2
msg = of.ofp_flow_mod()
msg.priority =1
msg.idle_timeout = 0
msg.match.in_port =2	# # 交换机入端口为2
msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL))
event.connection.send(msg)
# 3
msg = of.ofp_flow_mod()  
msg.priority =10		# 优先级高于前两条
msg.idle_timeout = 0
msg.hard_timeout = 0
msg.match.dl_type = 0x0800 # IPv4
msg.match.nw_tos = 0x64    # 网络服务类型
msg.match.in_port=1		   # 入端口
msg.match.nw_dst = "192.168.123.2" # 目的IP
msg.actions.append(of.ofp_action_output(port = 2)) # 转发到端口2
event.connection.send(msg)
# 4
msg = of.ofp_flow_mod()
msg.priority =10
msg.idle_timeout = 0
msg.hard_timeout = 0
msg.match.dl_type = 0x0800
msg.match.nw_tos = 0x64
msg.match.nw_dst = "192.168.123.1"
msg.actions.append(of.ofp_action_output(port = 1)) # 转发到端口1
event.connection.send(msg)

 由于该网络拓扑比较简单,所以两个交换机配置的流表是相同的(可以保证正确转发)。

  • 还需要设置监听器和定时器来保证控制器能够准确收到交换器发送的消息
def launch ():
  core.openflow.addListenerByName("FlowStatsReceived", 
    _handle_flowstats_received)  # 收到流表统计信息
  core.openflow.addListenerByName("PortStatsReceived", 
    _handle_portstats_received)  # 收到端口统计信息
  core.openflow.addListenerByName("ConnectionUp", 
  _handle_ConnectionUp)			 # 收到交换机连接请求
 
  Timer(1, _timer_func, recurring=True) # 定时器保证每个一段时间控制器检查是否有收到事件,若有则回调相应的处理函数_timer_func会向交换机请求状态信息

以上就完成了SDN控制器POX的设置,它完成了流表的下发,接收交换机的连接请求以及计算路径丢包率等工作。

可以看到控制器通连接到了两个交换机,它们的mac地址分别是00-00-00-00-00-01和00-01-00-00-00-01。对比控制器计算的损失率和ping计算的损失率,二者存在一定的误差,控制器没能检测到主机发送的所有包,也没能检测到所有的丢失情况。

3、分析实用性

(1)准确性

Mininet提供了一个虚拟网络环境,可以模拟真实网络中的拓扑结构和链路特性。通过在Mininet中设置合适的网络参数和路径损耗模型,可以模拟出较为真实的路径损耗情况。但是由于控制器只与交换机、路由器等处在网络核心的设备相连,如果从端系统到网络核心设备这之间发生了大量的丢包,那么就可能检测不到。

(2)可靠性

Mininet提供了一套完整的网络模拟环境,可以模拟和测试不同的网络场景和协议行为。具有一定的可靠性。

(3)可扩展性

使用Mininet可以构建各种类型的网络拓扑,模拟复杂的网络环境,但是随着网络规模的增大,Mininet性能可能会受到限制,大规模网络的模拟可能会导致资源消耗较大,影响测量的实时性和准确性。

三、实验总结

在实验的第一部分学习了使用Mininet的使用,能够使用Mininet构建网络拓扑并进行所构建网络拓扑的性能测试。

在实验的第二部分完成了网络拓扑图和SDN控制器(POX)的构建,网络中的交换机接收网络控制器下发的流表完成数据转发的工作,网络控制器接收网络中的状态信息计算出路径损耗率。在该部分中进一步理解了SDN控制平面与数据平面分离的思想,学习到了SDN控制平面与数据平面交互的过程,以及SDN控制平面如何利用网络中的信息实现对应的网络控制应用测量路径损耗率。

  • 38
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值