1. 程式人生 > 實用技巧 >WPF介面開發太難?DevExpress教你搞定CRUD操作

WPF介面開發太難?DevExpress教你搞定CRUD操作

實驗 3:Mininet 實驗——測量路徑的損耗率 一、實驗目的 在實驗 2 的基礎上進一步熟悉 Mininet 自定義拓撲指令碼,以及與損耗率相關的設定;初步瞭解 Mininet 安裝時自帶的 POX 控制器指令碼編寫,測試路徑損耗率。 二、實驗任務 h0 向 h1 傳送資料包,由於在 Mininet 指令碼中設定了連線損耗率,在傳輸過程中會丟失一些包,本次實驗的目的是展示如何通過控制器計算路徑損耗速率(h0-s0-s1-h1)。這裡假設控制器預先知道網路拓撲。控制器將向 s0 和 s1 傳送flow_stats_request,當控制器接收到來自 s0 的 response 時,將特定流的資料包數儲存在 input_pkts 中,當控制器接收到來自 s1 的 response 時,將接收到特定流的資料包數儲存在 output_pkts 中,差值就是丟失的資料包數量。基於上述拓撲,編寫 Mininet 指令碼,設定特定的交換機間的路徑損耗速率,然後編寫 POX 控制器指令碼,實現對路徑的損耗率的測量。 三、實驗步驟
1. 實驗環境 安裝了 Ubuntu 18.04.5 Desktop amd64 的虛擬機器 2. 實驗過程 SDNLAB 實驗參考資料:https://www.sdnlab.com/15100.html (1)新建並編輯 pox 指令碼 flow_stats.py:
#cd pox
#touch flow_stats.py

(2)編輯檔案flow_stats.py,內容如下:

#!/usr/bin/python
# Copyright 2012 William Yu
# [email protected]
#
# This file is part of POX.
#
# POX is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License 
as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # POX is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License
for more details. # # You should have received a copy of the GNU General Public License # along with POX. If not, see <http://www.gnu.org/licenses/>. # """ This is a demonstration file created to show how to obtain flow and port statistics from OpenFlow 1.0-enabled switches. The flow statistics handler contains a summary of web-only traffic. """ # standard includes 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 # include as part of the betta branch from pox.openflow.of_json import * from pox.lib.recoco import Timer import time log = core.getLogger() 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 # handler for timer function that sends the requests to all the # switches connected to the controller. 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)) # handler to display flow statistics received in JSON format # structure of event.stats is defined by ofp_flow_stats() def _handle_flowstats_received (event): #stats = flow_stats_to_list(event.stats) #log.debug("FlowStatsReceived from %s: %s", dpidToStr(event.connection.dpid), stats) global src_dpid, dst_dpid, input_pkts, output_pkts #print "src_dpid=", dpidToStr(src_dpid), "dst_dpid=", dpidToStr(dst_dpid) 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: #print "input: ", f.byte_count, f.packet_count 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: #print "output: ", f.byte_count, f.packet_count output_pkts = f.packet_count if input_pkts !=0: print getTheTime(), "Path Loss Rate =", (input_pkts-output_pkts)*1.0/input_pkts*100, "%" # handler to display port statistics received in JSON format def _handle_portstats_received (event): #print "\n<<<STATS-REPLY: Return PORT stats for Switch", event.connection.dpid,"at ",getTheTime() #for f in event.stats: #if int(f.port_no)<65534: #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 #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 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) 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 msg = of.ofp_flow_mod() msg.priority =1 msg.idle_timeout = 0 msg.match.in_port =1 msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =1 msg.idle_timeout = 0 msg.match.in_port =2 msg.actions.append(of.ofp_action_output(port = of.OFPP_ALL)) event.connection.send(msg) 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.in_port=1
  msg.match.nw_dst = "192.168.123.2"
  msg.actions.append(of.ofp_action_output(port = 2))
  event.connection.send(msg)
 
  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))
  event.connection.send(msg)
    
# main functiont to launch the module
def launch ():
  # attach handsers to listners
  core.openflow.addListenerByName("FlowStatsReceived", 
    _handle_flowstats_received) 
  core.openflow.addListenerByName("PortStatsReceived", 
    _handle_portstats_received) 
  core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
 
  # timer set to execute every five seconds
  Timer(1, _timer_func, recurring=True)
現在一起看下 flowstat.py 的關鍵程式碼: 第 7 行開始,讓 h0 ping h1,監測 s0 和 s1 之間的鏈路。如果匹配到乙太網型別的包頭(0x0800),並且資料包的目的 IP 地址是192.168.123.2(對照後面 Mininet 的指令碼發現是 h1),並且連線到控制器的資料平面裝置 id 是 s0(h0 ping h1,鏈路 s0-s1 上資料包是從 s0 流向 s1,s0 為源,s1 為目的地),執行 input_pkts = f.packet_count,把資料包數量i設為input_pkts;同理,如果連線到控制器的資料平面裝置 id 是 s1,執行 output_pkts =f.packet_count,把資料包數量存入 output_pkts。最後求 input_pkts 和 output_pkts 的差值。一般情況下差值為正,說明鏈路上資料包有損耗。

(3)在裝有Mininet的虛擬機器裡新建檔案mymininet.py

#touch mymininet.py

(4)編輯檔案mymininet.py,內容如下:

參照拓撲圖,新建並編輯 Mininet 指令碼 mymininet3.py,控制器因為安裝在本機,所以需修改參考資料程式碼中的控制器地址為 127.0.0.1:6633,設定 s0 和 s1 之間鏈路的丟包率為 0。
#!/usr/bin/python
 
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
from time import sleep
 
def myNet(cname='controller', cargs='-v ptcp:'):
    "Create network from scratch using Open vSwitch."
    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' )
    
    info( "*** Creating links\n" )
    linkopts0=dict(bw=100, delay='1ms', loss=0)
    linkopts1=dict(bw=100, delay='1ms', loss=0)
    link0=TCLink( h0, switch, **linkopts0)
    link1 = TCLink( switch, switch1, **linkopts1)     
    link2 = TCLink( h1, switch1, **linkopts0)
    #print link0.intf1, link0.intf2
    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")
 
    info( "*** Configuring hosts\n" )
    h0.setIP( '192.168.123.1/24' )
    h1.setIP( '192.168.123.2/24' )
       
    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 + '&' )     
    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 )
   
    # Note: controller and switch are in root namespace, and we
    # can connect via loopback interface
    switch.cmd( 'ovs-vsctl set-controller dp0 tcp:127.0.0.1:6633' )
    switch1.cmd( 'ovs-vsctl set-controller dp1 tcp:127.0.0.1:6633' )
  
    info( '*** Waiting for switch to connect to controller' )
    while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
        sleep( 1 )
        info( '.' )
    info( '\n' )
 
    #info( "*** Running test\n" )
    h0.cmdPrint( 'ping -Q 0x64 -c 20 ' + h1.IP() )
    
    sleep( 1 ) 
    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' )
 
if __name__ == '__main__':
    setLogLevel( 'info' )
    info( '*** Scratch network demo (kernel datapath)\n' )
    Mininet.init()
    myNet()

(5)執行指令碼flow_stats.py

#./pox.py flow_stats

執行後顯示為

(6)執行指令碼mymininet.py
#./mymininet.py
Ping 預設是每 1 秒鐘測一次,ping 的結果會顯示一個丟包率,這裡的丟包率是根據 ping 不通的次數佔總次數的百分比計算得到的。上圖中由於一共 ping 了 20次,每次都能通,所以丟包率是 0。 觀察 pox 側的實時狀態更新: 平均丟包率為 0,結果符合 Mininet 指令碼中設定的損耗率,也有可能出現負值,可以認為沒有丟包。 如果修改程式碼中 s0 和 s1 之間鏈路的丟包率為 10。
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)
 link1 = TCLink( switch, switch1, **linkopts1) 
 link2 = TCLink( h1, switch1, **linkopts0)
重新執行 Mininet 指令碼 mymininet3.py,20 秒時間的 ping 過程中有 icmp_seq 為2/4/14/16/19/20 共 4 次 ping 不通,所以丟包率計算為 20%。 POX 端重新測試,會發現出現丟包現象,但是實際測量出的丟包率會有浮動,鏈路的效能總體受到了限制。 四、實驗感想及問題解決 這次實驗出了一些波折: 1.在執行指令碼mymininet.py時,沒有把pox一起掛到後面執行,這會導致執行時發生錯誤。 解決方法:先執行pox控制器,再執行指令碼mymininet.py就可以解決。 2.python版本問題,在執行指令碼mymininet.py時,有些時候會報錯版本問題。 解決方法:在.py檔案中的每個printf語句後面內容都用()包住,可完美解決。 3.控制器連線等待時間無限長 解決方法:這類錯誤的產生是IP設定錯誤,控制器因為安裝在本機,所以需修改參考資料程式碼中的控制器地址為 127.0.0.1:6633,如果不小心設定成其他的,自然無法連通,我在這裡卡了好久,所幸仔細看了實驗資料及時糾正了。