Mininet系列实验(四):基于Mininet测量路径的损耗率

1 实验目的

熟悉Mininet自定义拓扑脚本的编写与损耗率的设定;

熟悉编写POX脚本,测量路径损耗速率

2 实验原理

在SDN环境中,控制器可以通过对交换机下发流表操作来控制交换机的转发行为,此外,还可以利用控制器测量路径的损耗率。在本实验中,基于Mininet脚本,设置特定的交换机间的路径损耗速率,然后编写POX脚本,实现对路径的损耗率的测量

3 实验内容

这是本实验的拓扑图,在该环境下,h0向h1发送数据包,由于在mininet脚本中设置了连接损耗率,在传输过程中会丢失一些包,本次实验的目的是展示如何通过控制器计算路径损耗速率(h0-s0-s1-h1)。这里假设控制器预先知道网络拓扑,所以没有显示发现网络的代码以及其他相关代码。控制器将向s0和s1发送flow_stats_request,当控制器接收到来自s0的response时,将特定流的数据包数保存在input_pkts中,当控制器接收到来自s1的response时,将接收到特定流的数据包数保存在output_pkts中,差值就是丢失的数据包数量。

应用POX基于Mininet测量路径的损耗率 图1

 搭建环境:本实验需要安装POX和支持OpenFlow1.3协议的Mininet。POX的安装教程如下:

Https://blog.csdn.net/shallynever/article/details/48522941

关于python中的logging以及相关函数的使用说明:

https://www.jb51.net/article/126681.htm

1.1 在装有mininet的虚拟机上创建脚本mymininet.py

 
cd mininet
 
gedit mymininet.py

 

1.2  编辑脚本(稍微解释了一下)

  1  
  2 #!/usr/bin/python
  3  
  4 #coding:utf-8
  5  
  6  
  7  
  8 # 调用关于mininet和time的一些模块
  9  
 10 from mininet.net import Mininet
 11  
 12 from mininet.node import Node
 13  
 14 from mininet.link import TCLink
 15  
 16 from mininet.log import setLogLevel, info
 17  
 18 from threading import Timer
 19  
 20 from mininet.util import quietRun
 21  
 22 from time import sleep
 23  
 24  
 25  
 26 #定义mynet函数
 27  
 28 def myNet(cname='controller', cargs='-v ptcp:'):
 29  
 30 #通过使用OVS抓取来创建网络
 31  
 32  
 33  
 34 #诊断信息然后开始创建节点,其中有控制器C0和交换机s0,s1,还有主机h0,h1
 35  
 36 info( "*** Creating nodes\n" )
 37  
 38 controller = Node( 'c0', inNamespace=False )
 39  
 40 switch = Node( 's0', inNamespace=False )
 41  
 42 switch1 = Node( 's1', inNamespace=False )
 43  
 44 h0 = Node( 'h0' )
 45  
 46 h1 = Node( 'h1' )
 47  
 48  
 49  
 50 #诊断以后开始创建链路(这一块不是很懂)
 51  
 52 info( "*** Creating links\n" )
 53  
 54  
 55  
 56 #这是链路选项设置,丢包以及延迟还有带宽等等
 57  
 58 linkopts0=dict(bw=100, delay='1ms', loss=0)
 59  
 60 linkopts1=dict(bw=100, delay='1ms', loss=10)
 61  
 62  
 63  
 64 #链路0,1,2分别表示h0和s0,s0和s1,h1和s1的链路并调用以上两行的参数
 65  
 66 link0=TCLink( h0, switch, **linkopts0)
 67  
 68 link1 = TCLink( switch, switch1, **linkopts1)
 69  
 70 link2 = TCLink( h1, switch1, **linkopts0)
 71  
 72  
 73  
 74 #MAC地址设置:按照拓扑图来设置的,这一块有些不理解,个人理解为,链路0,2只需要设置一个能连上
 75  
 76 #s0/s1的端口就行,而1需要左边的s0端口和右边的s1端口
 77  
 78 link0.intf2.setMAC("0:0:0:0:0:1")
 79  
 80 link1.intf1.setMAC("0:0:0:0:0:2")
 81  
 82 link1.intf2.setMAC("0:1:0:0:0:1")
 83  
 84 link2.intf2.setMAC("0:1:0:0:0:2")
 85  
 86  
 87  
 88 #诊断后设置主机ip
 89  
 90 info( "*** Configuring hosts\n" )
 91  
 92 h0.setIP( '192.168.123.1/24' )
 93  
 94 h1.setIP( '192.168.123.2/24' )
 95  
 96  
 97  
 98 #通过使用OVS开始网络连接,然后单引号里的意思是搭建和删除桥梁
 99  
100 info( "*** Starting network using Open vSwitch\n" )
101  
102 switch.cmd( 'ovs-vsctl del-br dp0' )
103  
104 switch.cmd( 'ovs-vsctl add-br dp0' )
105  
106 switch1.cmd( 'ovs-vsctl del-br dp1' )
107  
108 switch1.cmd( 'ovs-vsctl add-br dp1' )
109  
110  
111  
112 #控制器的设置不是很懂
113  
114 controller.cmd( cname + ' ' + cargs + '&' )
115  
116  
117  
118 #打印出每个交换机的链路信息
119  
120 for intf in switch.intfs.values():
121  
122 print intf
123  
124 print switch.cmd( 'ovs-vsctl add-port dp0 %s' % intf )
125  
126 for intf in switch1.intfs.values():
127  
128 print intf
129  
130 print switch1.cmd( 'ovs-vsctl add-port dp1 %s' % intf )
131  
132  
133  
134 # 控制器和交换机同属根命名空间所以我们可以通过环回接口连接,对了,10.0.0.13是别的up主的主机
135  
136 # ip,需要用自己的,因为控制器是你自己的
137  
138 switch.cmd( 'ovs-vsctl set-controller dp0 tcp:10.0.0.13:6633' )
139  
140 switch1.cmd( 'ovs-vsctl set-controller dp1 tcp:10.0.0.13:6633' )
141  
142  
143  
144 #诊断并等待交换机连接上控制器,在连接完成前会一秒一个点
145  
146 info( '*** Waiting for switch to connect to controller' )
147  
148 while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
149  
150 sleep( 1 )
151  
152 info( '.' )
153  
154 info( '\n' )
155  
156  
157  
158 #运行测试20次h0和h1的传输情况
159  
160 #info( "*** Running test\n" )
161  
162 h0.cmdPrint( 'ping -Q 0x64 -c 20 ' + h1.IP() )
163  
164  
165  
166 #休息一秒后关闭网络:删除“桥梁”
167  
168 sleep( 1 )
169  
170 info( "*** Stopping network\n" )
171  
172 controller.cmd( 'kill %' + cname )
173  
174 switch.cmd( 'ovs-vsctl del-br dp0' )
175  
176 switch.deleteIntfs()
177  
178 switch1.cmd( 'ovs-vsctl del-br dp1' )
179  
180 switch1.deleteIntfs()
181  
182 info( '\n' )
183  
184  
185  
186 #主函数,看不懂,意思应当是如果是个主函数就设定info的等级然后开始获取网络demo然后运行
187  
188 #mynet()函数
189  
190 if __name__ == '__main__':
191  
192 setLogLevel( 'info' )
193  
194 info( '*** Scratch network demo (kernel datapath)\n' )
195  
196 Mininet.init()
197  
198 myNet()

 

2.1 我们在pox文件里面创建脚本

 
cd pox
 
gedit flow_stats.py

 

2.2 编辑脚本 (中文部分是对程序的解释,未翻译部分是对具体代码的代码解释)

  1  
  2 #!/usr/bin/python
  3  
  4 # Copyright 2012 William Yu
  5  
  6 # wyu@ateneo.edu
  7  
  8 #
  9  
 10 # This file is part of POX.
 11  
 12 #
 13  
 14 # POX is free software: you can redistribute it and/or modify
 15  
 16 # it under the terms of the GNU General Public License as published by
 17  
 18 # the Free Software Foundation, either version 3 of the License, or
 19  
 20 # (at your option) any later version.
 21  
 22 #
 23  
 24 # POX is distributed in the hope that it will be useful,
 25  
 26 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 27  
 28 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 29  
 30 # GNU General Public License for more details.
 31  
 32 #
 33  
 34 # You should have received a copy of the GNU General Public License
 35  
 36 # along with POX. If not, see <http://www.gnu.org/licenses/>.
 37  
 38 #
 39  
 40  
 41  
 42 """
 43  
 44 This is a demonstration file created to show how to obtain flow
 45  
 46 and port statistics from OpenFlow 1.0-enabled switches. The flow
 47  
 48 statistics handler contains a summary of web-only traffic.
 49  
 50 """
 51  
 52  
 53  
 54 # standard includes
 55  
 56 from pox.core import core
 57  
 58 from pox.lib.util import dpidToStr
 59  
 60 import pox.openflow.libopenflow_01 as of
 61  
 62 from pox.lib.addresses import IPAddr, EthAddr
 63  
 64  
 65  
 66 # include as part of the betta branch
 67  
 68 from pox.openflow.of_json import *
 69  
 70 from pox.lib.recoco import Timer
 71  
 72 import time
 73  
 74  
 75  
 76 log = core.getLogger()
 77  
 78 #初始化网络的参数0
 79  
 80 src_dpid = 0
 81  
 82 dst_dpid = 0
 83  
 84 input_pkts = 0
 85  
 86 output_pkts = 0
 87  
 88  
 89  
 90 def getTheTime():
 91  
 92 #设定当地时间的函数
 93  
 94 flock = time.localtime()
 95  
 96 then = "[%s-%s-%s" %(str(flock.tm_year),str(flock.tm_mon),str(flock.tm_mday))
 97  
 98  
 99  
100 if int(flock.tm_hour)<10:
101  
102 hrs = "0%s" % (str(flock.tm_hour))
103  
104 else:
105  
106 hrs = str(flock.tm_hour)
107  
108 if int(flock.tm_min)<10:
109  
110 mins = "0%s" % (str(flock.tm_min))
111  
112 else:
113  
114 mins = str(flock.tm_min)
115  
116 if int(flock.tm_sec)<10:
117  
118 secs = "0%s" % (str(flock.tm_sec))
119  
120 else:
121  
122 secs = str(flock.tm_sec)
123  
124 then +="]%s.%s.%s" % (hrs,mins,secs)
125  
126 return then
127  
128  
129  
130 # 用于将请求发送到连接到控制器的所有交换机的定时器功能的处理程序
131  
132 def _timer_func ():
133  
134 for connection in core.openflow._connections.values():
135  
136 connection.send(of.ofp_stats_request(body=of.ofp_flow_stats_request()))
137  
138 connection.send(of.ofp_stats_request(body=of.ofp_port_stats_request()))
139  
140 log.debug("Sent %i flow/port stats request(s)", len(core.openflow._connections))
141  
142  
143  
144 # 显示在事件的JSON格式结构中接收到的流统计信息的处理程序由ofp_flow_stats()定义
145  
146 def _handle_flowstats_received (event):
147  
148 #stats = flow_stats_to_list(event.stats)
149  
150 #log.debug("FlowStatsReceived from %s: %s", dpidToStr(event.connection.dpid), stats)
151  
152 global src_dpid, dst_dpid, input_pkts, output_pkts
153  
154 #print "src_dpid=", dpidToStr(src_dpid), "dst_dpid=", dpidToStr(dst_dpid)
155  
156 for f in event.stats:
157  
158 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:
159  
160 #print "input: ", f.byte_count, f.packet_count
161  
162 input_pkts = f.packet_count
163  
164 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:
165  
166 #print "output: ", f.byte_count, f.packet_count
167  
168 output_pkts = f.packet_count
169  
170 if input_pkts !=0:
171  
172 print getTheTime(), "Path Loss Rate =", (input_pkts-output_pkts)*1.0/input_pkts*100, "%"
173  
174  
175  
176 # 处理程序以显示JSON格式接收的端口统计信息
177  
178 def _handle_portstats_received (event):
179  
180 #print "\n<<<STATS-REPLY: Return PORT stats for Switch", event.connection.dpid,"at ",getTheTime()
181  
182 #for f in event.stats:
183  
184 #if int(f.port_no)<65534:
185  
186 #print " PortNo:", f.port_no, " Fwd's Pkts:", f.tx_packets, " Fwd's Bytes:", f.tx_bytes, " Rc'd Pkts:", f.rx_packets, " Rc's Bytes:", f.rx_bytes
187  
188 #print " PortNo:", f.port_no, " TxDrop:", f.tx_dropped, " RxDrop:", f.rx_dropped, " TxErr:", f.tx_errors, " RxErr:", f.rx_errors, " CRC:", f.rx_crc_err, " Coll:", f.collisions
189  
190 stats = flow_stats_to_list(event.stats)
191  
192 log.debug("PortStatsReceived from %s: %s", dpidToStr(event.connection.dpid), stats)
193  
194  
195  
196 def _handle_ConnectionUp (event):
197  
198 global src_dpid, dst_dpid
199  
200 print "ConnectionUp: ", dpidToStr(event.connection.dpid)
201  
202 for m in event.connection.features.ports:
203  
204 if m.name == "s0-eth0":
205  
206 src_dpid = event.connection.dpid
207  
208 elif m.name == "s1-eth0":
209  
210 dst_dpid = event.connection.dpid
211  
212 #设置网络的参数(优先级,时间,端口号)
213  
214 msg = of.ofp_flow_mod()
215  
216 msg.priority =1
217  
218 msg.idle_timeout = 0
219  
220 msg.match.in_port =1
221  
222 msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL))
223  
224 event.connection.send(msg)
225  
226  
227  
228 msg = of.ofp_flow_mod()
229  
230 msg.priority =1
231  
232 msg.idle_timeout = 0
233  
234 msg.match.in_port =2
235  
236 msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL))
237  
238 event.connection.send(msg)
239  
240  
241  
242 msg = of.ofp_flow_mod()
243  
244 msg.priority =10
245  
246 msg.idle_timeout = 0
247  
248 msg.hard_timeout = 0
249  
250 msg.match.dl_type = 0x0800
251  
252 msg.match.nw_tos = 0x64
253  
254 msg.match.in_port=1
255  
256 msg.match.nw_dst = "192.168.123.2"
257  
258 msg.actions.append(of.ofp_action_output(port = 2))
259  
260 event.connection.send(msg)
261  
262  
263  
264 msg = of.ofp_flow_mod()
265  
266 msg.priority =10
267  
268 msg.idle_timeout = 0
269  
270 msg.hard_timeout = 0
271  
272 msg.match.dl_type = 0x0800
273  
274 msg.match.nw_tos = 0x64
275  
276 msg.match.nw_dst = "192.168.123.1"
277  
278 msg.actions.append(of.ofp_action_output(port = 1))
279  
280 event.connection.send(msg)
281  
282  
283  
284 # 启动模块的主函数
285  
286 def launch ():
287  
288 # attach handsers to listners
289  
290 core.openflow.addListenerByName("FlowStatsReceived",
291  
292 _handle_flowstats_received)
293  
294 core.openflow.addListenerByName("PortStatsReceived",
295  
296 _handle_portstats_received)
297  
298 core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
299  
300  
301  
302 # 定时器每5秒执行一次
303  
304 Timer(1, _timer_func, recurring=True)

 

 3 执行两个脚本

此处为mymininet的脚本

此处为flow_stats脚本

总结:

1.能看懂2/3的脚本内容,以及脚本的程序意义

2.明白了pox的安装

3.对网络的了解还是不够深刻

posted @ 2018-09-11 17:32  小李子ZZZ  阅读(1507)  评论(0编辑  收藏  举报