diff options
-rw-r--r-- | ryu/app/ofctl_rest.py | 33 | ||||
-rw-r--r-- | ryu/lib/ofctl_v1_3.py | 96 |
2 files changed, 129 insertions, 0 deletions
diff --git a/ryu/app/ofctl_rest.py b/ryu/app/ofctl_rest.py index d9a8f4a0..e459b790 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 16ba33e4..a3eae1f5 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) |