From 6a351aa5706ef9a58daaf839639a10ca9552d1c3 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 27 Jun 2012 09:51:01 +0900 Subject: of1.2: add OFPFlowStats support Signed-off-by: FUJITA Tomonori --- ryu/ofproto/ofproto_v1_2.py | 24 +-- ryu/ofproto/ofproto_v1_2_parser.py | 386 ++++++++++++++++++++++++++++++++++++- 2 files changed, 397 insertions(+), 13 deletions(-) diff --git a/ryu/ofproto/ofproto_v1_2.py b/ryu/ofproto/ofproto_v1_2.py index 394f392c..b9d9062b 100644 --- a/ryu/ofproto/ofproto_v1_2.py +++ b/ryu/ofproto/ofproto_v1_2.py @@ -432,23 +432,25 @@ DESC_STR_LEN_STR = str(DESC_STR_LEN) SERIAL_NUM_LEN = 32 SERIAL_NUM_LEN_STR = str(SERIAL_NUM_LEN) OFP_DESC_STATS_PACK_STR = '!' + \ - DESC_STR_LEN_STR + 'c' + \ - DESC_STR_LEN_STR + 'c' + \ - DESC_STR_LEN_STR + 'c' + \ - SERIAL_NUM_LEN_STR + 'c' + \ - DESC_STR_LEN_STR + 'c' + DESC_STR_LEN_STR + 's' + \ + DESC_STR_LEN_STR + 's' + \ + DESC_STR_LEN_STR + 's' + \ + SERIAL_NUM_LEN_STR + 's' + \ + DESC_STR_LEN_STR + 's' OFP_DESC_STATS_SIZE = 1056 assert calcsize(OFP_DESC_STATS_PACK_STR) == OFP_DESC_STATS_SIZE # struct ofp_flow_stats_request -OFP_FLOW_STATS_REQUEST_PACK_STR = '!B3xII4xQQ' + _OFP_MATCH_PACK_STR +OFP_FLOW_STATS_REQUEST_PACK_STR = '!B3xII4xQQ' OFP_FLOW_STATS_REQUEST_SIZE = 40 -assert calcsize(OFP_FLOW_STATS_REQUEST_PACK_STR) == OFP_FLOW_STATS_REQUEST_SIZE +assert (calcsize(OFP_FLOW_STATS_REQUEST_PACK_STR) + OFP_MATCH_SIZE == + OFP_FLOW_STATS_REQUEST_SIZE) # struct ofp_flow_stats -OFP_FLOW_STATS_PACK_STR = '!HBxIIHHH6xQQQ' + _OFP_MATCH_PACK_STR +OFP_FLOW_STATS_PACK_STR = '!HBxIIHHH6xQQQ' OFP_FLOW_STATS_SIZE = 56 -assert calcsize(OFP_FLOW_STATS_PACK_STR) == OFP_FLOW_STATS_SIZE +assert (calcsize(OFP_FLOW_STATS_PACK_STR) + OFP_MATCH_SIZE == + OFP_FLOW_STATS_SIZE) # struct ofp_aggregate_stats_request OFP_AGGREGATE_STATS_REQUEST_PACK_STR = '!B3xII4xQQ' @@ -467,10 +469,10 @@ OFP_TABLE_STATS_SIZE = 128 OFP_MAX_TABLE_NAME_LEN = 32 OFP_MAX_TABLE_NAME_LEN_STR = str(OFP_MAX_TABLE_NAME_LEN) OFP_TABLE_STATS_PACK_STR = '!B7x' + OFP_MAX_TABLE_NAME_LEN_STR + \ - 'cQQIIQQQQIIIIQQ' + 'sQQIIQQQQIIIIQQ' assert calcsize(OFP_TABLE_STATS_PACK_STR) == OFP_TABLE_STATS_SIZE -# struct ofp_por_stats_request +# struct ofp_port_stats_request OFP_PORT_STATS_REQUEST_PACK_STR = '!I4x' OFP_PORT_STATS_REQUEST_SIZE = 8 assert calcsize(OFP_PORT_STATS_REQUEST_PACK_STR) == OFP_PORT_STATS_REQUEST_SIZE diff --git a/ryu/ofproto/ofproto_v1_2_parser.py b/ryu/ofproto/ofproto_v1_2_parser.py index 6acf7d23..7710be36 100644 --- a/ryu/ofproto/ofproto_v1_2_parser.py +++ b/ryu/ofproto/ofproto_v1_2_parser.py @@ -770,8 +770,390 @@ class OFPTableMod(MsgBase): self.table_id, self.config) -# class OFPStatsRequest -# class OFPStatsReply +class OFPStatsRequest(MsgBase): + def __init__(self, datapath, type_): + super(OFPStatsRequest, self).__init__(datapath) + self.type = type_ + self.flags = 0 + + def _serialize_stats_body(self): + pass + + def _serialize_body(self): + msg_pack_into(ofproto_v1_2.OFP_STATS_REQUEST_PACK_STR, + self.buf, ofproto_v1_2.OFP_HEADER_SIZE, + self.type, self.flags) + + self._serialize_stats_body() + + +@_register_parser +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REPLY) +class OFPStatsReply(MsgBase): + _STATS_TYPES = {} + + @staticmethod + def register_stats_reply_type(type_, body_single_struct=False): + def _register_stats_reply_type(cls): + OFPStatsReply._STATS_TYPES[type_] = cls + cls.cls_body_single_struct = body_single_struct + return cls + return _register_stats_reply_type + + def __init__(self, datapath): + super(OFPStatsReply, self).__init__(datapath) + + @classmethod + def parser(cls, datapath, version, msg_type, msg_len, xid, buf): + msg = super(OFPStatsReply, cls).parser(datapath, version, msg_type, + msg_len, xid, buf) + msg.type, msg.flags = struct.unpack_from( + ofproto_v1_2.OFP_STATS_REPLY_PACK_STR, msg.buf, + ofproto_v1_2.OFP_HEADER_SIZE) + stats_type_cls = cls._STATS_TYPES.get(msg.type) + + offset = ofproto_v1_2.OFP_STATS_REPLY_SIZE + body = [] + while offset < msg_len: + r = stats_type_cls.parser(msg.buf, offset) + body.append(r) + offset += r.length + + if stats_type_cls.cls_body_single_struct: + msg.body = body[0] + else: + msg.bdoy = body + + return msg + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPDescStatsRequest(OFPStatsRequest): + def __init__(self, datapath): + super(OFPDescStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_DESC) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_DESC, + body_single_struct=True) +class OFPDescStats(collections.namedtuple('OFPDescStats', + ('mfr_desc', 'hw_desc', 'sw_desc', 'serial_num', 'dp_desc'))): + @classmethod + def parser(cls, buf, offset): + desc = struct.unpack_from(ofproto_v1_2.OFP_DESC_STATS_PACK_STR, + buf, offset) + stats = cls(*desc) + stats.length = ofproto_v1_2.OFP_DESC_STATS_SIZE + return stats + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPFlowStatsRequest(OFPStatsRequest): + def __init__(self, datapath, table_id, out_port, out_group, + cookie, cookie_mask, match): + super(OFPFlowStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_FLOW) + self.table_id = table_id + self.out_port = out_port + self.out_group = out_group + self.cookie = cookie + self.cookie_mask = cookie_mask + self.match = match + + def _serialize_stats_body(self): + msg_pack_into(ofproto_v1_2.OFP_FLOW_STATS_REQUEST_PACK_STR, + self.buf, ofproto_v1_2.OFP_STATS_REQUEST_SIZE, + self.table_id, self.out_port, self.out_group, + self.cookie, self.cookie_mask) + + offset = (ofproto_v1_2.OFP_STATS_REQUEST_SIZE + + ofproto_v1_2.OFP_FLOW_STATS_REQUEST_SIZE - + ofproto_v1_2.OFP_MATCH_SIZE) + + self.match.serialize(self.buf, offset) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_FLOW) +class OFPFlowStats(object): + def __init__(self, length, table_id, duration_sec, duration_nsec, + priority, idle_timeout, hard_timeout, cookie, packet_count, + byte_count, match): + super(OFPFlowStats, self).__init__() + self.length = length + self.table_id = table_id + self.duration_sec = duration_sec + self.duration_nsec = duration_nsec + self.priority = priority + self.idle_timeout = idle_timeout + self.hard_timeout = hard_timeout + self.cookie = cookie + self.packet_count = packet_count + self.byte_count = byte_count + self.match = match + + @classmethod + def parser(cls, buf, offset): + (length, table_id, duration_sec, + duration_nsec, priority, + idle_timeout, hard_timeout, + cookie, packet_count, byte_count) = struct.unpack_from( + ofproto_v1_2.OFP_FLOW_STATS_PACK_STR, + buf, offset) + offset += (ofproto_v1_2.OFP_FLOW_STATS_SIZE - + ofproto_v1_2.OFP_MATCH_SIZE) + match = OFPMatch.parser(buf, offset) + + return cls(length, table_id, duration_sec, duration_nsec, priority, + idle_timeout, hard_timeout, cookie, packet_count, + byte_count, match) + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPAggregateStatsRequest(OFPStatsRequest): + def __init__(self, datapath, table_id, out_port, out_group, + cookie, cookie_mask, match): + super(OFPAggregateStatsRequest, self).__init__( + datapath, + ofproto_v1_2.OFPST_AGGREGATE) + self.table_id = table_id + self.out_port = out_port + self.out_group = out_group + self.cookie = cookie + self.cookie_mask = cookie_mask + self.match = match + + def _serialize_stats_body(self): + msg_pack_into(ofproto_v1_2.OFP_AGGREGATE_STATS_REQUEST_PACK_STR, + self.buf, + ofproto_v1_2.OFP_STATS_REQUEST_SIZE, + self.table_id, self.out_port, self.out_group, + self.cookie, self.cookie_mask) + + offset = (ofproto_v1_2.OFP_STATS_REQUEST_SIZE + + ofproto_v1_2.OFP_AGGREGATE_STATS_REQUEST_SIZE - + ofproto_v1_2.OFP_MATCH_SIZE) + + self.match.serialize(self.buf, offset) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_AGGREGATE, + body_single_struct=True) +class OFPAggregateStatsReply(collections.namedtuple('OFPAggregateStats', + ('packet_count', 'byte_count', 'flow_count'))): + @classmethod + def parser(cls, buf, offset): + desc = struct.unpack_from( + ofproto_v1_2.OFP_AGGREGATE_STATS_REPLY_PACK_STR, + buf, offset) + stats = cls(*desc) + stats.length = ofproto_v1_2.OFP_AGGREGATE_STATS_REPLY_SIZE + return stats + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPTableStatsRequest(OFPStatsRequest): + def __init__(self, datapath): + super(OFPTableStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_TABLE) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_TABLE) +class OFPTableStats( + collections.namedtuple('OFPTableStats', + ('table_id', 'name', 'match', 'wildcards', + 'write_actions', 'apply_actions', + 'write_setfields', 'apply_setfields', + 'metadata_match', 'metadata_write', + 'instructions', 'config', + 'max_entries', 'active_count', + 'lookup_count', 'matched_count'))): + @classmethod + def parser(cls, buf, offset): + table = struct.unpack_from( + ofproto_v1_2.OFP_TABLE_STATS_PACK_STR, + buf, offset) + stats = cls(*table) + stats.length = ofproto_v1_2.OFP_TABLE_STATS_SIZE + return stats + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPPortStatsRequest(OFPStatsRequest): + def __init__(self, datapath, port_no): + super(OFPPortStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_PORT) + self.port_no = port_no + + def _serialize_stats_body(self): + msg_pack_into(ofproto_v1_2.OFP_PORT_STATS_REQUEST_PACK_STR, + self.buf, ofproto_v1_2.OFP_STATS_REQUEST_SIZE, + self.port_no) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_PORT) +class OFPPortStats( + collections.namedtuple('OFPPortStats', + ('port_no', 'rx_packets', 'tx_packets', + 'rx_byptes', 'tx_bytes', + 'rx_dropped', 'tx_dropped', + 'rx_errors', 'tx_errors', + 'rx_frame_err', 'rx_over_err', + 'rx_crc_err', 'collisions'))): + @classmethod + def parser(cls, buf, offset): + port = struct.unpack_from(ofproto_v1_2.OFP_PORT_STATS_PACK_STR, + buf, offset) + stats = cls(*port) + stats.length = ofproto_v1_2.OFP_PORT_STATS_SIZE + return stats + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPQueueStatsRequest(OFPStatsRequest): + def __init__(self, datapath, port_no, queue_id): + super(OFPQueueStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_QUEUE) + self.port_no = port_no + self.queue_id = queue_id + + def _serialize_stats_body(self): + msg_pack_into(ofproto_v1_2.OFP_QUEUE_STATS_REQUEST_PACK_STR, + self.buf, ofproto_v1_2.OFP_STATS_REQUEST_SIZE, + self.port_no, self.queue_id) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_QUEUE) +class OFPQueueStats( + collections.namedtuple('OFPQueueStats', + ('port_no', 'queue_id', 'tx_bytes', + 'tx_packets', 'tx_errors'))): + @classmethod + def parser(cls, buf, offset): + queue = struct.unpack_from(ofproto_v1_2.OFP_QUEUE_STATS_PACK_STR, + buf, offset) + stats = cls(*queue) + stats.length = ofproto_v1_2.OFP_QUEUE_STATS_SIZE + return stats + + +class OFPBucketCounter(object): + def __init__(self, packet_count, byte_count): + super(OFPBucketCounter, self).__init__() + self.packet_count = packet_count + self.byte_count = byte_count + + @classmethod + def parser(cls, buf, offset): + packet, byte = struct.unpack_from( + ofproto_v1_2.OFP_BUCKET_COUNTER_PACK_STR, + buf, offset) + return cls(packet, byte) + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPGroupStatsRequest(OFPStatsRequest): + def __init__(self, datapath, group_id): + super(OFPGroupStatsRequest, self).__init__(datapath, + ofproto_v1_2.OFPST_GROUP) + self.group_id = group_id + + def _serialize_stats_body(self): + msg_pack_into(ofproto_v1_2.OFP_GROUP_STATS_REQUEST_PACK_STR, + self.buf, ofproto_v1_2.OFP_STATS_REQUEST_SIZE, + self.group_id) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_GROUP) +class OFPGroupStats(object): + def __init__(self, length, group_id, ref_count, packet_count, + byte_count, bucket_counters): + super(OFPGroupStats, self).__init__() + self.length = length + self.group_id = group_id + self.ref_count = ref_count + self.packet_count = packet_count + self.byte_count = byte_count + self.bucket_counters = bucket_counters + + @classmethod + def parser(cls, buf, offset): + (length, group_id, ref_count, packet_count, + byte_count) = struct.unpack_from( + ofproto_v1_2.OFP_GROUP_STATS_PACK_STR, + buf, offset) + + bucket_len = length - ofproto_v1_2.OFP_GROUP_STATS_SIZE + offset += ofproto_v1_2.OFP_GROUP_STATS_SIZE + bucket_counters = [] + while bucket_len > 0: + bucket_counters.append(OFPBucketCounter.parser(buf, offset)) + offset += ofproto_v1_2.OFP_BUCKET_COUNTER_SIZE + bucket_len -= ofproto_v1_2.OFP_BUCKET_COUNTER_SIZE + + return cls(length, group_id, ref_count, packet_count, + byte_count, bucket_counters) + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPGroupDescStatsRequest(OFPStatsRequest): + def __init__(self, datapath): + super(OFPGroupDescStatsRequest, self).__init__( + datapath, + ofproto_v1_2.OFPST_GROUP_DESC) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_GROUP_DESC) +class OFPGroupDescStats(object): + def __init__(self, length, type_, group_id, buckets): + self.length = length + self.type = type_ + self.group_id = group_id + self.buckets = buckets + + @classmethod + def parser(cls, buf, offset): + (length, type_, group_id) = struct.unpack_from( + ofproto_v1_2.OFP_GROUP_DESC_STATS_PACK_STR, + buf, offset) + + bucket_len = length - ofproto_v1_2.OFP_GROUP_DESC_STATS_SIZE + offset += ofproto_v1_2.OFP_GROUP_DESC_STATS_SIZE + buckets = [] + while bucket_len > 0: + buckets.append(OFPBucket.parser(buf, offset)) + offset += ofproto_v1_2.OFP_BUCKET_SIZE + bucket_len -= ofproto_v1_2.OFP_BUCKET_SIZE + + return cls(length, type_, group_id, buckets) + + +@_set_msg_type(ofproto_v1_2.OFPT_STATS_REQUEST) +class OFPGroupFeaturesStatsRequest(OFPStatsRequest): + def __init__(self, datapath): + super(OFPGroupFeaturesStatsRequest, self).__init__( + datapath, + ofproto_v1_2.OFPST_GROUP_FEATURES) + + +@OFPStatsReply.register_stats_reply_type(ofproto_v1_2.OFPST_GROUP_FEATURES, + body_single_struct=True) +class OFPGroupFeaturesStats(object): + def __init__(self, types, capabilities, max_groups, actions): + self.types = types + self.capabilities = capabilities + self.max_groups = max_groups + self.actions = acitons + + @classmethod + def parser(cls, buf, offset): + stats = struct.unpack_from( + ofproto_v1_2.OFP_GROUP_FEATURES_STATS_PACK_STR, buf, offset) + types = stats[0] + capabilities = stats[1] + max_groups = stats[2:6] + acitons = stats[6:10] + + return cls(types, capabilities, max_groups, actions) @_set_msg_type(ofproto_v1_2.OFPT_QUEUE_GET_CONFIG_REQUEST) -- cgit v1.2.3