Support meter in FlowMod instructions and support MeterMod, MeterStats, 
MeterFeatures.

see following examples.

FlowMod with the meter instruction:

    flow = {'match': {},
            'actions': [{'type': 'METER',
                         'meter_id': 1}]
    curl -X POST -d '{"dpid": 1, "match": {}, "actions": [{"type": "METER", 
"meter_id": 1}]}' http://localhost:8080/stats/flowentry/add


MeterMod:

    meter = {'meter_id': 1,
             'flags': 'KBPS',
             'bands': [{'type': 'DROP',
                        'rate': 1000}]}
    curl -X POST -d '{"dpid": 1, "meter_id": 1, "flags": "KBPS", "bands": 
[{"type": "DROP", "rate": 1000}]}' http://localhost:8080/stats/meterentry/add

    NOTE: flags: 'KBPS', 'PKTPS', 'BURST', 'STATS'
          type: 'DROP', 'REMARK', 'EXPERIMENTER'


MeterStats:

    curl http://localhost:8080/stats/meter/1


MetetFeatures:

    curl http://localhost:8080/stats/meterfeatures/1


Signed-off-by: Yuichi Ito <[email protected]>
---
 ryu/app/ofctl_rest.py |   86 ++++++++++++++++++++++++++++++++++++++++++++++
 ryu/lib/ofctl_v1_3.py |   90 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 176 insertions(+)

diff --git a/ryu/app/ofctl_rest.py b/ryu/app/ofctl_rest.py
index 9840b0f..907bed5 100644
--- a/ryu/app/ofctl_rest.py
+++ b/ryu/app/ofctl_rest.py
@@ -48,6 +48,12 @@ LOG = logging.getLogger('ryu.app.ofctl_rest')
 # get ports stats of the switch
 # GET /stats/port/<dpid>
 #
+# get meter features stats of the switch
+# GET /stats/meterfeatures/<dpid>
+#
+# get meters stats of the switch
+# GET /stats/meter/<dpid>
+#
 ## Update the switch stats
 #
 # add a flow entry
@@ -62,6 +68,14 @@ LOG = logging.getLogger('ryu.app.ofctl_rest')
 # delete all flow entries of the switch
 # DELETE /stats/flowentry/clear/<dpid>
 #
+# add a meter entry
+# POST /stats/meterentry/add
+#
+# modify a meter entry
+# POST /stats/meterentry/modify
+#
+# delete a meter entry
+# POST /stats/meterentry/delete


 class StatsController(ControllerBase):
@@ -123,6 +137,34 @@ class StatsController(ControllerBase):
         body = json.dumps(ports)
         return (Response(content_type='application/json', body=body))

+    def get_meter_features(self, req, dpid, **_kwargs):
+        dp = self.dpset.get(int(dpid))
+        if dp is None:
+            return Response(status=404)
+
+        if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
+            meters = ofctl_v1_3.get_meter_features(dp, self.waiters)
+        else:
+            LOG.debug('Unsupported OF protocol')
+            return Response(status=501)
+
+        body = json.dumps(meters)
+        return (Response(content_type='application/json', body=body))
+
+    def get_meter_stats(self, req, dpid, **_kwargs):
+        dp = self.dpset.get(int(dpid))
+        if dp is None:
+            return Response(status=404)
+
+        if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
+            meters = ofctl_v1_3.get_meter_stats(dp, self.waiters)
+        else:
+            LOG.debug('Unsupported OF protocol')
+            return Response(status=501)
+
+        body = json.dumps(meters)
+        return (Response(content_type='application/json', body=body))
+
     def mod_flow_entry(self, req, cmd, **_kwargs):
         try:
             flow = eval(req.body)
@@ -169,6 +211,35 @@ class StatsController(ControllerBase):

         return Response(status=200)

+    def mod_meter_entry(self, req, cmd, **_kwargs):
+        try:
+            flow = eval(req.body)
+        except SyntaxError:
+            LOG.debug('invalid syntax %s', req.body)
+            return Response(status=400)
+
+        dpid = flow.get('dpid')
+        dp = self.dpset.get(int(dpid))
+        if dp is None:
+            return Response(status=404)
+
+        if cmd == 'add':
+            cmd = dp.ofproto.OFPMC_ADD
+        elif cmd == 'modify':
+            cmd = dp.ofproto.OFPMC_MODIFY
+        elif cmd == 'delete':
+            cmd = dp.ofproto.OFPMC_DELETE
+        else:
+            return Response(status=404)
+
+        if dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
+            ofctl_v1_3.mod_meter_entry(dp, flow, cmd)
+        else:
+            LOG.debug('Unsupported OF protocol')
+            return Response(status=501)
+
+        return Response(status=200)
+

 class RestStatsApi(app_manager.RyuApp):
     OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
@@ -210,6 +281,16 @@ class RestStatsApi(app_manager.RyuApp):
                        controller=StatsController, action='get_port_stats',
                        conditions=dict(method=['GET']))

+        uri = path + '/meterfeatures/{dpid}'
+        mapper.connect('stats', uri,
+                       controller=StatsController, action='get_meter_features',
+                       conditions=dict(method=['GET']))
+
+        uri = path + '/meter/{dpid}'
+        mapper.connect('stats', uri,
+                       controller=StatsController, action='get_meter_stats',
+                       conditions=dict(method=['GET']))
+
         uri = path + '/flowentry/{cmd}'
         mapper.connect('stats', uri,
                        controller=StatsController, action='mod_flow_entry',
@@ -220,6 +301,11 @@ class RestStatsApi(app_manager.RyuApp):
                        controller=StatsController, action='delete_flow_entry',
                        conditions=dict(method=['DELETE']))

+        uri = path + '/meterentry/{cmd}'
+        mapper.connect('stats', uri,
+                       controller=StatsController, action='mod_meter_entry',
+                       conditions=dict(method=['POST']))
+
     def stats_reply_handler(self, ev):
         msg = ev.msg
         dp = msg.datapath
diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py
index 996f605..7822569 100644
--- a/ryu/lib/ofctl_v1_3.py
+++ b/ryu/lib/ofctl_v1_3.py
@@ -118,6 +118,9 @@ def to_actions(dp, acts):
                              else ofproto_v1_3_parser.UINT64_MAX)
             inst.append(
                 parser.OFPInstructionWriteMetadata(metadata, metadata_mask))
+        elif action_type == 'METER':
+            meter_id = int(a.get('meter_id'))
+            inst.append(parser.OFPInstructionMeter(meter_id))
         else:
             LOG.debug('Unknown action type: %s' % action_type)

@@ -184,6 +187,11 @@ def actions_to_str(instructions):
                    else 'WRITE_METADATA:0x%x' % instruction.metadata)
             actions.append(buf)

+        elif isinstance(instruction,
+                        ofproto_v1_3_parser.OFPInstructionMeter):
+            buf = 'METER:' + str(instruction.meter_id)
+            actions.append(buf)
+
         else:
             continue

@@ -429,6 +437,48 @@ def get_port_stats(dp, waiters):
     return ports


+def get_meter_stats(dp, waiters):
+    stats = dp.ofproto_parser.OFPMeterStatsRequest(
+        dp, 0, dp.ofproto.OFPM_ALL)
+    msgs = []
+    send_stats_request(dp, stats, waiters, msgs)
+
+    meters = []
+    for msg in msgs:
+        for stats in msg.body:
+            bands = []
+            for band in stats.band_stats:
+                b = {'packet_band_count': band.packet_band_count,
+                     'byte_band_count': band.byte_band_count}
+                bands.append(b)
+            s = {'meter_id': stats.meter_id,
+                 'len': stats.len,
+                 'flow_count': stats.flow_count,
+                 'packet_in_count': stats.packet_in_count,
+                 'byte_in_count': stats.byte_in_count,
+                 'band_stats': bands}
+            meters.append(s)
+    meters = {str(dp.id): meters}
+    return meters
+
+
+def get_meter_features(dp, waiters):
+    stats = dp.ofproto_parser.OFPMeterFeaturesStatsRequest(dp, 0)
+    msgs = []
+    send_stats_request(dp, stats, waiters, msgs)
+
+    features = []
+    for msg in msgs:
+        for feature in msg.body:
+            f = {'max_meter': msg.body.max_meter,
+                 'band_type': msg.body.band_type,
+                 'max_bands': msg.body.max_bands,
+                 'max_color': msg.body.max_color}
+            features.append(f)
+    features = {str(dp.id): features}
+    return features
+
+
 def mod_flow_entry(dp, flow, cmd):
     cookie = int(flow.get('cookie', 0))
     cookie_mask = int(flow.get('cookie_mask', 0))
@@ -449,3 +499,43 @@ def mod_flow_entry(dp, flow, cmd):
         flags, match, inst)

     dp.send_msg(flow_mod)
+
+
+def mod_meter_entry(dp, flow, cmd):
+
+    flags_convert = {'KBPS': dp.ofproto.OFPMF_KBPS,
+                     'PKTPS': dp.ofproto.OFPMF_PKTPS,
+                     'BURST': dp.ofproto.OFPMF_BURST,
+                     'STATS': dp.ofproto.OFPMF_STATS}
+
+    flags = flags_convert.get(flow.get('flags'))
+    if not flags:
+        LOG.debug('Unknown flags: %s', flow.get('flags'))
+
+    meter_id = int(flow.get('meter_id', 0))
+
+    bands = []
+    for band in flow.get('bands', []):
+        band_type = band.get('type')
+        rate = int(band.get('rate', 0))
+        burst_size = int(band.get('burst_size', 0))
+        if band_type == 'DROP':
+            bands.append(
+                dp.ofproto_parser.OFPMeterBandDrop(rate, burst_size))
+        elif band_type == 'REMARK':
+            prec_level = int(band.get('prec_level', 0))
+            bands.append(
+                dp.ofproto_parser.OFPMeterBandDscpRemark(
+                    rate, burst_size, prec_level))
+        elif band_type == 'EXPERIMENTER':
+            experimenter = int(band.get('experimenter', 0))
+            bands.append(
+                dp.ofproto_parser.OFPMeterBandExperimenter(
+                    rate, burst_size, experimenter))
+        else:
+            LOG.debug('Unknown band type: %s', band_type)
+
+    meter_mod = dp.ofproto_parser.OFPMeterMod(
+        dp, cmd, flags, meter_id, bands)
+
+    dp.send_msg(meter_mod)
--
1.7.10.4


------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to