Measure the Path Loss Rate

 

[Introduction]

   In this example, I will show how to measure the path loss rate in the POX controller. The example topology is shown as below.

 

h0 --- s0 --- s1 --- h1

 

h0 will send packets to h1 via s0 and s1. The packets transmitted over the link between s0 and s1 may be lost due to the link loss rate setting in the mininet script. The goal of this example is to show how to calculate the path loss rate (h0-s0-s1-h1) in the controller. So I have made some assumptions. The controller knows the network topology in advance and therefore I don’t show how to discover the network code and other related codes. Just keep this example as simple as possible. The controller will send flow_stats_request to s0 and s1. When the controller gets the response from s0, it will keep the number of packets for a specific flow in input_pkts valuable. When the controller gets the response from s1, it will keep the number of packets received for a specific flow in output_pkts valuable. The difference is the lost packets.

 

[mininet10.py]

#!/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=10)

    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()

 

[flow_stats.py: controller program]

#!/usr/bin/python

# 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

# 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)

 

[Execution]

 

 

The results from controller:

 

We can see the results from the above the figure that the path loss rate is equal to 10%. This value is the link loss rate setting in the link between s0 and s1 in mymininet10.py.

 

Dr. Chih-Heng Ke (smallko@gmail.com)

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.