Experiment 3: Mininet experiment - measuring the loss rate of the path

1, Experimental purpose
On the basis of Experiment 2, further familiar with Mininet custom topology script and settings related to loss rate; Preliminarily understand the script writing of POX controller when Mininet is installed, and test the path loss rate.

2, Experimental task

h0 sends packets to H1. Because the connection loss rate is set in the Mininet script, some packets will be lost during transmission. The purpose of this experiment is to show how to calculate the path loss rate (h0- s0-s1-h1) through the controller. Here, it is assumed that the controller knows the network topology in advance.
The controller will send flow to s0 and s1_ stats_ Request: when the controller receives the response from s0, it saves the number of packets of a specific stream in input_ In PKTS, when the controller receives the response from s1, the number of specific streams will be received
The number of packets is saved in output_ In PKTS, the difference is the number of lost packets. Based on the above topology, the Mininet script is written to set the path loss rate between specific switches, and then the POX controller script is written to measure the path loss rate.

3, Experimental steps

  1. Experimental environment
    Virtual machine with Ubuntu 18.04.5 Desktop amd64 installed
  2. Experimental process
    SDNLAB experiment reference: https://www.sdnlab.com/15100.html
    (1) Create and edit the pox script flowstat py:
    In the pox installation directory (the complete installation of Mininet includes pox), execute the following command to run the pox script
    $ ./pox.py flowstat

    floatstat.py Code:
# Copyright 2012 William Yu
# wyu@ateneo.edu
# 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
# 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))
    hrs = str(flock.tm_hour)
  if int(flock.tm_min)<10:
    mins = "0%s" % (str(flock.tm_min))
    mins = str(flock.tm_min)
  if int(flock.tm_sec)<10:
    secs = "0%s" % (str(flock.tm_sec))
    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():
  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("") 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("") 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))
  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))
  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 = ""
  msg.actions.append(of.ofp_action_output(port = 2))
  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 = ""
  msg.actions.append(of.ofp_action_output(port = 1))
# main functiont to launch the module
def launch ():
  # attach handsers to listners
  core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
  # timer set to execute every five seconds
  Timer(1, _timer_func, recurring=True)

Now let's look at flowstat Key code of Py:
Starting from line 7, let h0 ping h1 to monitor the link between s0 and s1.
⚫ If the packet header (0x0800) of the Ethernet type is matched, and the destination IP address of the packet is (compared with the script of Mininet later, it is found to be h1), and the data plane device id connected to the controller is s0 (h0 ping h1, the packet on the link s0-s1 flows from s0 to s1, s0 is the source and s1 is the destination), execute input_pkts = f.packet_count to store the number of packets into input_pkts;
⚫ Similarly, if the data plane device id connected to the controller is s1, execute output_pkts = f.packet_count to store the number of packets in output_pkts.
⚫ Finally, find the input_pkts and output_ The difference of PKTS. Generally, the difference is positive, indicating that there is loss of data packets on the link.
(2) Edit Mininet script mymininet3 py
Refer to the topology diagram, create and edit the Mininet script mymininet3 Py, because the controller is installed on the machine, the controller address in the reference code needs to be modified to
Set the packet loss rate of the link between s0 and s1 to 0

mymininet3.py Code:

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
    info( "*** Configuring hosts\n" )
    h0.setIP( '' )
    h1.setIP( '' )
    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:' )
    switch1.cmd( 'ovs-vsctl set-controller dp1 tcp:' )
    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' )
    switch1.cmd( 'ovs-vsctl del-br dp1' )
    info( '\n' )
if __name__ == '__main__':
    setLogLevel( 'info' )
    info( '*** Scratch network demo (kernel datapath)\n' )

Then execute the command to run the Mininet script mymininet3 py
$ sudo python mymininet3.py
The operation results are as follows

ping is measured every 1 second by default, and the result of ping will display a packet loss rate, which is calculated according to the percentage of the number of failed pings in the total number of times. In the figure above, the packet loss rate is 0 because it has been pinged 20 times and can be connected every time.
Observe the real-time status update of pox side
The average packet loss rate is 0. The result conforms to the loss rate set in the Mininet script. It may also have a negative value. It can be considered that there is no packet loss.

If the packet loss rate of the link between s0 and s1 in the modified code is 10.

Rerun the Mininet script mymininet3 Py, ICMP during 20 second ping_ Seq is
On June 18 and 19, the three ping s failed, so the packet loss rate is calculated as 15%

When the POX end is retested, it will be found that there is packet loss, but the actual measured packet loss rate will fluctuate, and the overall performance of the link is limited.

Posted by techgearfree on Tue, 17 May 2022 11:16:36 +0300