On Wed, 27 Jun 2012 09:27:05 +0900 Simon Horman <[email protected]> wrote:
> On Tue, Jun 26, 2012 at 10:58:42PM +0900, FUJITA Tomonori wrote: > > DESC, FLOW, AGGREGATE, and TABLE stats are supported now. > > > > Signed-off-by: FUJITA Tomonori <[email protected]> > > Looks good. > > Tested-by: Simon Horman <[email protected]> Thanks, I put two patches together and applied. I believe that Ryu fully supports OF1.2 now. Let's test it! = >From 6a351aa5706ef9a58daaf839639a10ca9552d1c3 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori <[email protected]> Date: Wed, 27 Jun 2012 09:51:01 +0900 Subject: [PATCH] of1.2: add OFPFlowStats support Signed-off-by: FUJITA Tomonori <[email protected]> --- 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 394f392..b9d9062 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 6acf7d2..7710be3 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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) + + [email protected]_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) -- 1.7.4.4 ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
