Apply a meter

[Topology]

 

      H1------S1------H2

We will set a meter in S1 so that the traffic generated from H1 will be limited to 100Kbps before entering S1.

 

p.s if you want to do this lab, please make sure that you have already installed CPqD/ofsoftswitch13. Because the current version of openvswitch (ovs) doesn’t support metering.

 

[Script: simple_switch_13_meter.py]

# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#    http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

# implied.

# See the License for the specific language governing permissions and

# limitations under the License.

 

from ryu.base import app_manager

from ryu.controller import ofp_event

from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER

from ryu.controller.handler import set_ev_cls

from ryu.ofproto import ofproto_v1_3

from ryu.lib.packet import packet

from ryu.lib.packet import ethernet

 

 

class SimpleSwitch13(app_manager.RyuApp):

    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

 

    def __init__(self, *args, **kwargs):

        super(SimpleSwitch13, self).__init__(*args, **kwargs)

        self.mac_to_port = {}

 

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)

    def switch_features_handler(self, ev):

        datapath = ev.msg.datapath

        ofproto = datapath.ofproto

        parser = datapath.ofproto_parser

 

        # install table-miss flow entry

        #

        # We specify NO BUFFER to max_len of the output action due to

        # OVS bug. At this moment, if we specify a lesser number, e.g.,

        # 128, OVS will send Packet-In with invalid buffer_id and

        # truncated packet data. In that case, we cannot output packets

        # correctly.  The bug has been fixed in OVS v2.1.0.

        match = parser.OFPMatch()

        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,

                                          ofproto.OFPCML_NO_BUFFER)]

        self.add_flow(datapath, 0, match, actions)

       

        # add rule for metering in s1

        if ev.msg.datapath.id==1:

          datapath = ev.msg.datapath

          ofproto = datapath.ofproto

          parser = datapath.ofproto_parser

 

          bands = [parser.OFPMeterBandDrop(type_=ofproto.OFPMBT_DROP, len_=0, rate=100, burst_size=10)]

 

          req=parser.OFPMeterMod(datapath=datapath, command=ofproto.OFPMC_ADD, flags=ofproto.OFPMF_KBPS, meter_id=1, bands=bands)

         

          datapath.send_msg(req)

        

          #when the traffic generated from h1 will be applied to meter_id=1

          match = parser.OFPMatch(in_port=1, eth_type=0x0800, ipv4_src="10.0.0.1", ipv4_dst="10.0.0.2")

          actions = [parser.OFPActionOutput(2)]

          inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions), parser.OFPInstructionMeter(1,ofproto.OFPIT_METER)]

          mod = datapath.ofproto_parser.OFPFlowMod(

              datapath=datapath, match=match, cookie=0,

              command=ofproto.OFPFC_ADD, idle_timeout=0,  

              hard_timeout=0, priority=3, instructions=inst)

          datapath.send_msg(mod)

 

    def add_flow(self, datapath, priority, match, actions, buffer_id=None):

        ofproto = datapath.ofproto

        parser = datapath.ofproto_parser

 

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,

                                             actions)]

        if buffer_id:

            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,

                                    priority=priority, match=match,

                                    instructions=inst)

        else:

            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,

                                    match=match, instructions=inst)

        datapath.send_msg(mod)

 

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)

    def _packet_in_handler(self, ev):

        # If you hit this you might want to increase

        # the "miss_send_length" of your switch

        if ev.msg.msg_len < ev.msg.total_len:

            self.logger.debug("packet truncated: only %s of %s bytes",

                              ev.msg.msg_len, ev.msg.total_len)

        msg = ev.msg

        datapath = msg.datapath

        ofproto = datapath.ofproto

        parser = datapath.ofproto_parser

        in_port = msg.match['in_port']

 

        pkt = packet.Packet(msg.data)

        eth = pkt.get_protocols(ethernet.ethernet)[0]

 

        dst = eth.dst

        src = eth.src

 

        dpid = datapath.id

        self.mac_to_port.setdefault(dpid, {})

 

        self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)

 

        # learn a mac address to avoid FLOOD next time.

        self.mac_to_port[dpid][src] = in_port

 

        if dst in self.mac_to_port[dpid]:

            out_port = self.mac_to_port[dpid][dst]

        else:

            out_port = ofproto.OFPP_FLOOD

 

        actions = [parser.OFPActionOutput(out_port)]

 

        # install a flow to avoid packet_in next time

        if out_port != ofproto.OFPP_FLOOD:

            match = parser.OFPMatch(in_port=in_port, eth_dst=dst)

            # verify if we have a valid buffer_id, if yes avoid to send both

            # flow_mod & packet_out

            if msg.buffer_id != ofproto.OFP_NO_BUFFER:

                self.add_flow(datapath, 1, match, actions, msg.buffer_id)

                return

            else:

                self.add_flow(datapath, 1, match, actions)

        data = None

        if msg.buffer_id == ofproto.OFP_NO_BUFFER:

            data = msg.data

 

        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,

                                  in_port=in_port, actions=actions, data=data)

        datapath.send_msg(out)

 

[Execution 1: no meter]

 

Use iperf to test the traffic transmission between h1 and h2.

 

[Execution 2: with a meter]

 

Open anther terminal to check the meter setting.

 

Use iperf to test the traffic transmission between h1 and h2.

 

 

References:

https://github.com/CPqD/ofsoftswitch13/wiki/OpenFlow-1.3-Tutorial

https://github.com/CPqD/ofsoftswitch13/wiki/Dpctl-Flow-Mod-Cases

https://github.com/castroflavio/ryu-of13-metering/blob/master/main.py

https://github.com/osrg/ryu/blob/master/ryu/ofproto/ofproto_v1_3_parser.py

 

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

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.