ofctl_rest: support OFPAggregateStats message

this patch makes ofctl_rest enable use of OFPAggregateStats message.

Get aggregate flow stats:

  usage)

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

  e.g.)

    $ curl -X GET http://localhost:8080/stats/aggregateflow/1
    {
      "1": [
        {
          "packet_count": 18,
          "byte_count": 756,
          "flow_count": 3
        }
      ]
    }

Get aggregate flow stats filtered by fields:

  usage)

    URI:    /stats/aggregateflow/<dpid>
    method: POST

    the message body is as follows.

        table_id     Table ID (int)
        out_port     Require matching entries to include this as an output port (int)
        out_group    Require matching entries to include this as an output group (int)
        cookie       Require matching entries to contain this cookie value (int)
        cookie_mask  Mask used to restrict the cookie bits that must match (int)
        match        Fields to match (dict)

  e.g.)

    $ curl -X POST -d '{
             "table_id": 0,
             "out_port": 2,
             "cookie": 1,
             "cookie_mask": 1,
             "match":{
                 "in_port":1
             }
         }' http://localhost:8080/stats/aggregateflow/1

Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Yusuke Iwase 2015-01-19 10:56:23 +09:00 committed by FUJITA Tomonori
parent 310e20ee0b
commit a4e9abfcbc
4 changed files with 118 additions and 0 deletions

View File

@ -52,6 +52,12 @@ LOG = logging.getLogger('ryu.app.ofctl_rest')
# get flows stats of the switch filtered by the fields
# POST /stats/flow/<dpid>
#
# get aggregate flows stats of the switch
# GET /stats/aggregateflow/<dpid>
#
# get aggregate flows stats of the switch filtered by the fields
# POST /stats/aggregateflow/<dpid>
#
# get ports stats of the switch
# GET /stats/port/<dpid>
#
@ -181,6 +187,33 @@ class StatsController(ControllerBase):
body = json.dumps(flows)
return (Response(content_type='application/json', body=body))
def get_aggregate_flow_stats(self, req, dpid, **_kwargs):
if req.body == '':
flow = {}
else:
try:
flow = ast.literal_eval(req.body)
except SyntaxError:
LOG.debug('invalid syntax %s', req.body)
return Response(status=400)
dp = self.dpset.get(int(dpid))
if dp is None:
return Response(status=404)
if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
flows = ofctl_v1_0.get_aggregate_flow_stats(dp, self.waiters, flow)
elif dp.ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION:
flows = ofctl_v1_2.get_aggregate_flow_stats(dp, self.waiters, flow)
elif dp.ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
flows = ofctl_v1_3.get_aggregate_flow_stats(dp, self.waiters, flow)
else:
LOG.debug('Unsupported OF protocol')
return Response(status=501)
body = json.dumps(flows)
return Response(content_type='application/json', body=body)
def get_port_stats(self, req, dpid, **_kwargs):
dp = self.dpset.get(int(dpid))
if dp is None:
@ -572,6 +605,12 @@ class RestStatsApi(app_manager.RyuApp):
controller=StatsController, action='get_flow_stats',
conditions=dict(method=['GET', 'POST']))
uri = path + '/aggregateflow/{dpid}'
mapper.connect('stats', uri,
controller=StatsController,
action='get_aggregate_flow_stats',
conditions=dict(method=['GET', 'POST']))
uri = path + '/port/{dpid}'
mapper.connect('stats', uri,
controller=StatsController, action='get_port_stats',
@ -650,6 +689,7 @@ class RestStatsApi(app_manager.RyuApp):
@set_ev_cls([ofp_event.EventOFPStatsReply,
ofp_event.EventOFPDescStatsReply,
ofp_event.EventOFPFlowStatsReply,
ofp_event.EventOFPAggregateStatsReply,
ofp_event.EventOFPPortStatsReply,
ofp_event.EventOFPQueueStatsReply,
ofp_event.EventOFPMeterStatsReply,

View File

@ -322,6 +322,30 @@ def get_flow_stats(dp, waiters, flow={}):
return flows
def get_aggregate_flow_stats(dp, waiters, flow={}):
match = to_match(dp, flow.get('match', {}))
table_id = int(flow.get('table_id', 0xff))
out_port = int(flow.get('out_port', dp.ofproto.OFPP_NONE))
stats = dp.ofproto_parser.OFPAggregateStatsRequest(
dp, 0, match, table_id, out_port)
msgs = []
send_stats_request(dp, stats, waiters, msgs)
flows = []
for msg in msgs:
stats = msg.body
for st in stats:
s = {'packet_count': st.packet_count,
'byte_count': st.byte_count,
'flow_count': st.flow_count}
flows.append(s)
flows = {str(dp.id): flows}
return flows
def get_port_stats(dp, waiters):
stats = dp.ofproto_parser.OFPPortStatsRequest(
dp, 0, dp.ofproto.OFPP_NONE)

View File

@ -465,6 +465,32 @@ def get_flow_stats(dp, waiters, flow={}):
return flows
def get_aggregate_flow_stats(dp, waiters, flow={}):
table_id = int(flow.get('table_id', dp.ofproto.OFPTT_ALL))
out_port = int(flow.get('out_port', dp.ofproto.OFPP_ANY))
out_group = int(flow.get('out_group', dp.ofproto.OFPG_ANY))
cookie = int(flow.get('cookie', 0))
cookie_mask = int(flow.get('cookie_mask', 0))
match = to_match(dp, flow.get('match', {}))
stats = dp.ofproto_parser.OFPAggregateStatsRequest(
dp, table_id, out_port, out_group, cookie, cookie_mask, match)
msgs = []
send_stats_request(dp, stats, waiters, msgs)
flows = []
for msg in msgs:
stats = msg.body
s = {'packet_count': stats.packet_count,
'byte_count': stats.byte_count,
'flow_count': stats.flow_count}
flows.append(s)
flows = {str(dp.id): flows}
return flows
def get_port_stats(dp, waiters):
stats = dp.ofproto_parser.OFPPortStatsRequest(
dp, dp.ofproto.OFPP_ANY, 0)

View File

@ -493,6 +493,34 @@ def get_flow_stats(dp, waiters, flow={}):
return flows
def get_aggregate_flow_stats(dp, waiters, flow={}):
table_id = int(flow.get('table_id', dp.ofproto.OFPTT_ALL))
flags = int(flow.get('flags', 0))
out_port = int(flow.get('out_port', dp.ofproto.OFPP_ANY))
out_group = int(flow.get('out_group', dp.ofproto.OFPG_ANY))
cookie = int(flow.get('cookie', 0))
cookie_mask = int(flow.get('cookie_mask', 0))
match = to_match(dp, flow.get('match', {}))
stats = dp.ofproto_parser.OFPAggregateStatsRequest(
dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
match)
msgs = []
send_stats_request(dp, stats, waiters, msgs)
flows = []
for msg in msgs:
stats = msg.body
s = {'packet_count': stats.packet_count,
'byte_count': stats.byte_count,
'flow_count': stats.flow_count}
flows.append(s)
flows = {str(dp.id): flows}
return flows
def get_port_stats(dp, waiters):
stats = dp.ofproto_parser.OFPPortStatsRequest(
dp, 0, dp.ofproto.OFPP_ANY)