this patch makes ofctl_rest enable use of OFPTableFeaturesStats message.

Get table features:

  usage)

    URI:    /stats/tablefeatures/<dpid>
    method: GET

  e.g.)

    $ curl -X GET http://localhost:8080/stats/tablefeatures/1
    {
      "1": [
        {
          "metadata_write": 18446744073709552000,
          "config": 0,
          "table_id": 0,
          "metadata_match": 18446744073709552000,
          "max_entries": 4096,
          "properties": [
            {
              "type": "INSTRUCTIONS",
              "instruction_ids": [
               {
               "len": 4,
               "type": 1
               },
               ....
              ]
            },
            ...
          ],
          "name": "table_0"
        },
        {
          "metadata_write": 18446744073709552000,
          "config": 0,
          "table_id": 1,
          "metadata_match": 18446744073709552000,
          "max_entries": 4096,
          "properties": [
            {
              "type": "INSTRUCTIONS",
              "instruction_ids": [
               {
               "len": 4,
               "type": 1
               },
               ....
              ]
            },
            ...
          ],
          "name": "table_1"
        },
        ...
      ]
    }

Signed-off-by: Minoru TAKAHASHI <[email protected]>
---
 ryu/app/ofctl_rest.py | 33 ++++++++++++++++++
 ryu/lib/ofctl_v1_3.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 129 insertions(+)

diff --git a/ryu/app/ofctl_rest.py b/ryu/app/ofctl_rest.py
index d9a8f4a..e459b79 100644
--- a/ryu/app/ofctl_rest.py
+++ b/ryu/app/ofctl_rest.py
@@ -68,6 +68,9 @@ supported_ofctl = {
 # get table stats of the switch
 # GET /stats/table/<dpid>
 #
+# get table features stats of the switch
+# GET /stats/tablefeatures/<dpid>
+#
 # get ports stats of the switch
 # GET /stats/port/<dpid>
 #
@@ -270,6 +273,30 @@ class StatsController(ControllerBase):
         body = json.dumps(ports)
         return Response(content_type='application/json', body=body)
 
+    def get_table_features(self, req, dpid, **_kwargs):
+
+        if type(dpid) == str and not dpid.isdigit():
+            LOG.debug('invalid dpid %s', dpid)
+            return Response(status=400)
+
+        dp = self.dpset.get(int(dpid))
+
+        if dp is None:
+            return Response(status=404)
+
+        _ofp_version = dp.ofproto.OFP_VERSION
+
+        _ofctl = supported_ofctl.get(_ofp_version, None)
+        if _ofctl is not None:
+            ports = _ofctl.get_table_features(dp, self.waiters)
+
+        else:
+            LOG.debug('Unsupported OF protocol')
+            return Response(status=501)
+
+        body = json.dumps(ports)
+        return Response(content_type='application/json', body=body)
+
     def get_port_stats(self, req, dpid, **_kwargs):
 
         if type(dpid) == str and not dpid.isdigit():
@@ -773,6 +800,11 @@ class RestStatsApi(app_manager.RyuApp):
                        controller=StatsController, action='get_table_stats',
                        conditions=dict(method=['GET']))
 
+        uri = path + '/tablefeatures/{dpid}'
+        mapper.connect('stats', uri,
+                       controller=StatsController, action='get_table_features',
+                       conditions=dict(method=['GET']))
+
         uri = path + '/port/{dpid}'
         mapper.connect('stats', uri,
                        controller=StatsController, action='get_port_stats',
@@ -853,6 +885,7 @@ class RestStatsApi(app_manager.RyuApp):
                  ofp_event.EventOFPFlowStatsReply,
                  ofp_event.EventOFPAggregateStatsReply,
                  ofp_event.EventOFPTableStatsReply,
+                 ofp_event.EventOFPTableFeaturesStatsReply,
                  ofp_event.EventOFPPortStatsReply,
                  ofp_event.EventOFPQueueStatsReply,
                  ofp_event.EventOFPMeterStatsReply,
diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py
index 16ba33e..a3eae1f 100644
--- a/ryu/lib/ofctl_v1_3.py
+++ b/ryu/lib/ofctl_v1_3.py
@@ -566,6 +566,102 @@ def get_table_stats(dp, waiters):
     return desc
 
 
+def get_table_features(dp, waiters):
+    stats = dp.ofproto_parser.OFPTableFeaturesStatsRequest(dp, 0, [])
+    msgs = []
+    ofproto = dp.ofproto
+    send_stats_request(dp, stats, waiters, msgs)
+
+    prop_type = {ofproto.OFPTFPT_INSTRUCTIONS: 'INSTRUCTIONS',
+                 ofproto.OFPTFPT_INSTRUCTIONS_MISS: 'INSTRUCTIONS_MISS',
+                 ofproto.OFPTFPT_NEXT_TABLES: 'NEXT_TABLES',
+                 ofproto.OFPTFPT_NEXT_TABLES_MISS: 'NEXT_TABLES_MISS',
+                 ofproto.OFPTFPT_WRITE_ACTIONS: 'WRITE_ACTIONS',
+                 ofproto.OFPTFPT_WRITE_ACTIONS_MISS: 'WRITE_ACTIONS_MISS',
+                 ofproto.OFPTFPT_APPLY_ACTIONS: 'APPLY_ACTIONS',
+                 ofproto.OFPTFPT_APPLY_ACTIONS_MISS: 'APPLY_ACTIONS_MISS',
+                 ofproto.OFPTFPT_MATCH: 'MATCH',
+                 ofproto.OFPTFPT_WILDCARDS: 'WILDCARDS',
+                 ofproto.OFPTFPT_WRITE_SETFIELD: 'WRITE_SETFIELD',
+                 ofproto.OFPTFPT_WRITE_SETFIELD_MISS: 'WRITE_SETFIELD_MISS',
+                 ofproto.OFPTFPT_APPLY_SETFIELD: 'APPLY_SETFIELD',
+                 ofproto.OFPTFPT_APPLY_SETFIELD_MISS: 'APPLY_SETFIELD_MISS',
+                 ofproto.OFPTFPT_EXPERIMENTER: 'EXPERIMENTER',
+                 ofproto.OFPTFPT_EXPERIMENTER_MISS: 'EXPERIMENTER_MISS'
+                 }
+
+    p_type_instructions = [ofproto.OFPTFPT_INSTRUCTIONS,
+                           ofproto.OFPTFPT_INSTRUCTIONS_MISS]
+
+    p_type_next_tables = [ofproto.OFPTFPT_NEXT_TABLES,
+                          ofproto.OFPTFPT_NEXT_TABLES_MISS]
+
+    p_type_actions = [ofproto.OFPTFPT_WRITE_ACTIONS,
+                      ofproto.OFPTFPT_WRITE_ACTIONS_MISS,
+                      ofproto.OFPTFPT_APPLY_ACTIONS,
+                      ofproto.OFPTFPT_APPLY_ACTIONS_MISS]
+
+    p_type_oxms = [ofproto.OFPTFPT_MATCH,
+                   ofproto.OFPTFPT_WILDCARDS,
+                   ofproto.OFPTFPT_WRITE_SETFIELD,
+                   ofproto.OFPTFPT_WRITE_SETFIELD_MISS,
+                   ofproto.OFPTFPT_APPLY_SETFIELD,
+                   ofproto.OFPTFPT_APPLY_SETFIELD_MISS]
+
+    p_type_experimenter = [ofproto.OFPTFPT_EXPERIMENTER,
+                           ofproto.OFPTFPT_EXPERIMENTER_MISS]
+
+    tables = []
+    for msg in msgs:
+        stats = msg.body
+        for stat in stats:
+            properties = []
+            for prop in stat.properties:
+                p = {'type': prop_type.get(prop.type, 'UNKNOWN')}
+                if prop.type in p_type_instructions:
+                    instruction_ids = []
+                    for id in prop.instruction_ids:
+                        i = {'len': id.len,
+                             'type': id.type}
+                        instruction_ids.append(i)
+                    p['instruction_ids'] = instruction_ids
+                elif prop.type in p_type_next_tables:
+                    table_ids = []
+                    for id in prop.table_ids:
+                        table_ids.append(id)
+                    p['table_ids'] = table_ids
+                elif prop.type in p_type_actions:
+                    action_ids = []
+                    for id in prop.action_ids:
+                        i = {'len': id.len,
+                             'type': id.type}
+                        action_ids.append(i)
+                    p['action_ids'] = action_ids
+                elif prop.type in p_type_oxms:
+                    oxm_ids = []
+                    for id in prop.oxm_ids:
+                        i = {'hasmask': id.hasmask,
+                             'length': id.length,
+                             'type': id.type}
+                        oxm_ids.append(i)
+                    p['oxm_ids'] = oxm_ids
+                elif prop.type in p_type_experimenter:
+                    pass
+                properties.append(p)
+            s = {'table_id': stat.table_id,
+                 'name': stat.name,
+                 'metadata_match': stat.metadata_match,
+                 'metadata_write': stat.metadata_write,
+                 'config': stat.config,
+                 'max_entries': stat.max_entries,
+                 'properties': properties,
+                 }
+            tables.append(s)
+    desc = {str(dp.id): tables}
+
+    return desc
+
+
 def get_port_stats(dp, waiters):
     stats = dp.ofproto_parser.OFPPortStatsRequest(
         dp, 0, dp.ofproto.OFPP_ANY)
-- 
1.9.1


------------------------------------------------------------------------------
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to