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.