diff options
author | Minoru TAKAHASHI <takahashi.minoru7@gmail.com> | 2015-10-22 17:31:33 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-10-28 14:44:40 +0900 |
commit | 9a534b46a6ded307ba7de9e5af451df08a815da4 (patch) | |
tree | dc20211e3c3ab358797e1c8c970ffe0e554227f4 | |
parent | f4f24469da44411812f0b5bbf4706194c409ff84 (diff) |
ofctl_rest: support OFPTableStats Message
this patch makes ofctl_rest enable use of OFPTableStats message.
Get table stats:
usage)
URI: /stats/table/<dpid>
method: GET
e.g.)
$ curl -X GET http://localhost:8080/stats/table/1
More infomation about this feature is described in the following URL.
http://ryu.readthedocs.org/en/latest/app/ofctl_rest.html#get-table-stats
Signed-off-by: Minoru TAKAHASHI <takahashi.minoru7@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/app/ofctl_rest.py | 33 | ||||
-rw-r--r-- | ryu/lib/ofctl_v1_0.py | 51 | ||||
-rw-r--r-- | ryu/lib/ofctl_v1_2.py | 125 | ||||
-rw-r--r-- | ryu/lib/ofctl_v1_3.py | 19 |
4 files changed, 228 insertions, 0 deletions
diff --git a/ryu/app/ofctl_rest.py b/ryu/app/ofctl_rest.py index e134cb15..d9a8f4a0 100644 --- a/ryu/app/ofctl_rest.py +++ b/ryu/app/ofctl_rest.py @@ -65,6 +65,9 @@ supported_ofctl = { # get aggregate flows stats of the switch filtered by the fields # POST /stats/aggregateflow/<dpid> # +# get table stats of the switch +# GET /stats/table/<dpid> +# # get ports stats of the switch # GET /stats/port/<dpid> # @@ -243,6 +246,30 @@ class StatsController(ControllerBase): body = json.dumps(flows) return Response(content_type='application/json', body=body) + def get_table_stats(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_stats(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(): @@ -741,6 +768,11 @@ class RestStatsApi(app_manager.RyuApp): action='get_aggregate_flow_stats', conditions=dict(method=['GET', 'POST'])) + uri = path + '/table/{dpid}' + mapper.connect('stats', uri, + controller=StatsController, action='get_table_stats', + conditions=dict(method=['GET'])) + uri = path + '/port/{dpid}' mapper.connect('stats', uri, controller=StatsController, action='get_port_stats', @@ -820,6 +852,7 @@ class RestStatsApi(app_manager.RyuApp): ofp_event.EventOFPDescStatsReply, ofp_event.EventOFPFlowStatsReply, ofp_event.EventOFPAggregateStatsReply, + ofp_event.EventOFPTableStatsReply, ofp_event.EventOFPPortStatsReply, ofp_event.EventOFPQueueStatsReply, ofp_event.EventOFPMeterStatsReply, diff --git a/ryu/lib/ofctl_v1_0.py b/ryu/lib/ofctl_v1_0.py index 939207bc..dc2459d3 100644 --- a/ryu/lib/ofctl_v1_0.py +++ b/ryu/lib/ofctl_v1_0.py @@ -382,6 +382,57 @@ def get_aggregate_flow_stats(dp, waiters, flow={}): return flows +def get_table_stats(dp, waiters): + stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0) + ofp = dp.ofproto + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + match_convert = {ofp.OFPFW_IN_PORT: 'IN_PORT', + ofp.OFPFW_DL_VLAN: 'DL_VLAN', + ofp.OFPFW_DL_SRC: 'DL_SRC', + ofp.OFPFW_DL_DST: 'DL_DST', + ofp.OFPFW_DL_TYPE: 'DL_TYPE', + ofp.OFPFW_NW_PROTO: 'NW_PROTO', + ofp.OFPFW_TP_SRC: 'TP_SRC', + ofp.OFPFW_TP_DST: 'TP_DST', + ofp.OFPFW_NW_SRC_SHIFT: 'NW_SRC_SHIFT', + ofp.OFPFW_NW_SRC_BITS: 'NW_SRC_BITS', + ofp.OFPFW_NW_SRC_MASK: 'NW_SRC_MASK', + ofp.OFPFW_NW_SRC: 'NW_SRC', + ofp.OFPFW_NW_SRC_ALL: 'NW_SRC_ALL', + ofp.OFPFW_NW_DST_SHIFT: 'NW_DST_SHIFT', + ofp.OFPFW_NW_DST_BITS: 'NW_DST_BITS', + ofp.OFPFW_NW_DST_MASK: 'NW_DST_MASK', + ofp.OFPFW_NW_DST: 'NW_DST', + ofp.OFPFW_NW_DST_ALL: 'NW_DST_ALL', + ofp.OFPFW_DL_VLAN_PCP: 'DL_VLAN_PCP', + ofp.OFPFW_NW_TOS: 'NW_TOS', + ofp.OFPFW_ALL: 'ALL', + ofp.OFPFW_ICMP_TYPE: 'ICMP_TYPE', + ofp.OFPFW_ICMP_CODE: 'ICMP_CODE'} + + tables = [] + for msg in msgs: + stats = msg.body + for stat in stats: + wildcards = [] + for k, v in match_convert.items(): + if (1 << k) & stat.wildcards: + wildcards.append(v) + s = {'table_id': stat.table_id, + 'name': stat.name, + 'wildcards': wildcards, + 'max_entries': stat.max_entries, + 'active_count': stat.active_count, + 'lookup_count': stat.lookup_count, + 'matched_count': stat.matched_count} + 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_NONE) diff --git a/ryu/lib/ofctl_v1_2.py b/ryu/lib/ofctl_v1_2.py index d4bad8b8..2f2c91f3 100644 --- a/ryu/lib/ofctl_v1_2.py +++ b/ryu/lib/ofctl_v1_2.py @@ -516,6 +516,131 @@ def get_aggregate_flow_stats(dp, waiters, flow={}): return flows +def get_table_stats(dp, waiters): + stats = dp.ofproto_parser.OFPTableStatsRequest(dp) + ofp = dp.ofproto + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + oxm_type_convert = {ofp.OFPXMT_OFB_IN_PORT: 'IN_PORT', + ofp.OFPXMT_OFB_IN_PHY_PORT: 'IN_PHY_PORT', + ofp.OFPXMT_OFB_METADATA: 'METADATA', + ofp.OFPXMT_OFB_ETH_DST: 'ETH_DST', + ofp.OFPXMT_OFB_ETH_SRC: 'ETH_SRC', + ofp.OFPXMT_OFB_ETH_TYPE: 'ETH_TYPE', + ofp.OFPXMT_OFB_VLAN_VID: 'VLAN_VID', + ofp.OFPXMT_OFB_VLAN_PCP: 'VLAN_PCP', + ofp.OFPXMT_OFB_IP_DSCP: 'IP_DSCP', + ofp.OFPXMT_OFB_IP_ECN: 'IP_ECN', + ofp.OFPXMT_OFB_IP_PROTO: 'IP_PROTO', + ofp.OFPXMT_OFB_IPV4_SRC: 'IPV4_SRC', + ofp.OFPXMT_OFB_IPV4_DST: 'IPV4_DST', + ofp.OFPXMT_OFB_TCP_SRC: 'TCP_SRC', + ofp.OFPXMT_OFB_TCP_DST: 'TCP_DST', + ofp.OFPXMT_OFB_UDP_SRC: 'UDP_SRC', + ofp.OFPXMT_OFB_UDP_DST: 'UDP_DST', + ofp.OFPXMT_OFB_SCTP_SRC: 'SCTP_SRC', + ofp.OFPXMT_OFB_SCTP_DST: 'SCTP_DST', + ofp.OFPXMT_OFB_ICMPV4_TYPE: 'ICMPV4_TYPE', + ofp.OFPXMT_OFB_ICMPV4_CODE: 'ICMPV4_CODE', + ofp.OFPXMT_OFB_ARP_OP: 'ARP_OP', + ofp.OFPXMT_OFB_ARP_SPA: 'ARP_SPA', + ofp.OFPXMT_OFB_ARP_TPA: 'ARP_TPA', + ofp.OFPXMT_OFB_ARP_SHA: 'ARP_SHA', + ofp.OFPXMT_OFB_ARP_THA: 'ARP_THA', + ofp.OFPXMT_OFB_IPV6_SRC: 'IPV6_SRC', + ofp.OFPXMT_OFB_IPV6_DST: 'IPV6_DST', + ofp.OFPXMT_OFB_IPV6_FLABEL: 'IPV6_FLABEL', + ofp.OFPXMT_OFB_ICMPV6_TYPE: 'ICMPV6_TYPE', + ofp.OFPXMT_OFB_ICMPV6_CODE: 'ICMPV6_CODE', + ofp.OFPXMT_OFB_IPV6_ND_TARGET: 'IPV6_ND_TARGET', + ofp.OFPXMT_OFB_IPV6_ND_SLL: 'IPV6_ND_SLL', + ofp.OFPXMT_OFB_IPV6_ND_TLL: 'IPV6_ND_TLL', + ofp.OFPXMT_OFB_MPLS_LABEL: 'MPLS_LABEL', + ofp.OFPXMT_OFB_MPLS_TC: 'MPLS_TC'} + + act_convert = {ofp.OFPAT_OUTPUT: 'OUTPUT', + ofp.OFPAT_COPY_TTL_OUT: 'COPY_TTL_OUT', + ofp.OFPAT_COPY_TTL_IN: 'COPY_TTL_IN', + ofp.OFPAT_SET_MPLS_TTL: 'SET_MPLS_TTL', + ofp.OFPAT_DEC_MPLS_TTL: 'DEC_MPLS_TTL', + ofp.OFPAT_PUSH_VLAN: 'PUSH_VLAN', + ofp.OFPAT_POP_VLAN: 'POP_VLAN', + ofp.OFPAT_PUSH_MPLS: 'PUSH_MPLS', + ofp.OFPAT_POP_MPLS: 'POP_MPLS', + ofp.OFPAT_SET_QUEUE: 'SET_QUEUE', + ofp.OFPAT_GROUP: 'GROUP', + ofp.OFPAT_SET_NW_TTL: 'SET_NW_TTL', + ofp.OFPAT_DEC_NW_TTL: 'DEC_NW_TTL', + ofp.OFPAT_SET_FIELD: 'SET_FIELD'} + + inst_convert = {ofp.OFPIT_GOTO_TABLE: 'GOTO_TABLE', + ofp.OFPIT_WRITE_METADATA: 'WRITE_METADATA', + ofp.OFPIT_WRITE_ACTIONS: 'WRITE_ACTIONS', + ofp.OFPIT_APPLY_ACTIONS: 'APPLY_ACTIONS', + ofp.OFPIT_CLEAR_ACTIONS: 'CLEAR_ACTIONS', + ofp.OFPIT_EXPERIMENTER: 'EXPERIMENTER'} + + table_conf_convert = { + ofp.OFPTC_TABLE_MISS_CONTROLLER: 'TABLE_MISS_CONTROLLER', + ofp.OFPTC_TABLE_MISS_CONTINUE: 'TABLE_MISS_CONTINUE', + ofp.OFPTC_TABLE_MISS_DROP: 'TABLE_MISS_DROP', + ofp.OFPTC_TABLE_MISS_MASK: 'TABLE_MISS_MASK'} + + tables = [] + for msg in msgs: + stats = msg.body + for stat in stats: + match = [] + wildcards = [] + write_setfields = [] + apply_setfields = [] + for k, v in oxm_type_convert.items(): + if (1 << k) & stat.match: + match.append(v) + if (1 << k) & stat.wildcards: + wildcards.append(v) + if (1 << k) & stat.write_setfields: + write_setfields.append(v) + if (1 << k) & stat.apply_setfields: + apply_setfields.append(v) + write_actions = [] + apply_actions = [] + for k, v in act_convert.items(): + if (1 << k) & stat.write_actions: + write_actions.append(v) + if (1 << k) & stat.apply_actions: + apply_actions.append(v) + instructions = [] + for k, v in inst_convert.items(): + if (1 << k) & stat.instructions: + instructions.append(v) + config = [] + for k, v in table_conf_convert.items(): + if (1 << k) & stat.config: + config.append(v) + s = {'table_id': stat.table_id, + 'name': stat.name, + 'match': match, + 'wildcards': wildcards, + 'write_actions': write_actions, + 'apply_actions': apply_actions, + 'write_setfields': write_setfields, + 'apply_setfields': apply_setfields, + 'metadata_match': stat.metadata_match, + 'metadata_write': stat.metadata_write, + 'instructions': instructions, + 'config': config, + 'max_entries': stat.max_entries, + 'active_count': stat.active_count, + 'lookup_count': stat.lookup_count, + 'matched_count': stat.matched_count} + tables.append(s) + desc = {str(dp.id): tables} + + return desc + + def get_port_stats(dp, waiters): stats = dp.ofproto_parser.OFPPortStatsRequest( dp, dp.ofproto.OFPP_ANY, 0) diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py index 10c52101..16ba33e4 100644 --- a/ryu/lib/ofctl_v1_3.py +++ b/ryu/lib/ofctl_v1_3.py @@ -547,6 +547,25 @@ def get_aggregate_flow_stats(dp, waiters, flow={}): return flows +def get_table_stats(dp, waiters): + stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0) + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + tables = [] + for msg in msgs: + stats = msg.body + for stat in stats: + s = {'table_id': stat.table_id, + 'active_count': stat.active_count, + 'lookup_count': stat.lookup_count, + 'matched_count': stat.matched_count} + 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) |