diff options
author | Simon Horman <horms@verge.net.au> | 2014-02-04 13:27:52 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-02-04 18:41:32 +0900 |
commit | 5bfc8255badd8fd9765d2c9d777201726e307d1e (patch) | |
tree | 35f955d8a7db67caa4670f5cdc8121dc788e0310 | |
parent | 03a9196e4366458c436fe29dade25b4ff78c54c3 (diff) |
of14: Add table features stats request and reply message support
Signed-off-by: Simon Horman <horms@verge.net.au>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/ofproto/ofproto_v1_4_parser.py | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/ryu/ofproto/ofproto_v1_4_parser.py b/ryu/ofproto/ofproto_v1_4_parser.py index 567051c6..52ff6d8b 100644 --- a/ryu/ofproto/ofproto_v1_4_parser.py +++ b/ryu/ofproto/ofproto_v1_4_parser.py @@ -1800,6 +1800,352 @@ class OFPDescStatsReply(OFPMultipartReply): super(OFPDescStatsReply, self).__init__(datapath, **kwargs) +class OFPTableFeaturesStats(StringifyMixin): + + _TYPE = { + 'utf-8': [ + # OF spec is unclear about the encoding of name. + # we assumes UTF-8. + 'name', + ] + } + + def __init__(self, table_id=None, name=None, metadata_match=None, + metadata_write=None, config=None, max_entries=None, + properties=None, length=None): + super(OFPTableFeaturesStats, self).__init__() + self.length = None + self.table_id = table_id + self.name = name + self.metadata_match = metadata_match + self.metadata_write = metadata_write + self.config = config + self.max_entries = max_entries + self.properties = properties + + @classmethod + def parser(cls, buf, offset): + table_features = cls() + (table_features.length, table_features.table_id, + name, table_features.metadata_match, + table_features.metadata_write, table_features.config, + table_features.max_entries + ) = struct.unpack_from(ofproto.OFP_TABLE_FEATURES_PACK_STR, + buf, offset) + table_features.name = name.rstrip('\0') + + props = [] + rest = buf[offset + ofproto.OFP_TABLE_FEATURES_SIZE: + offset + table_features.length] + while rest: + p, rest = OFPTableFeatureProp.parse(rest) + props.append(p) + table_features.properties = props + + return table_features + + def serialize(self): + # fixup + bin_props = bytearray() + for p in self.properties: + bin_props += p.serialize() + self.length = ofproto.OFP_TABLE_FEATURES_SIZE + len(bin_props) + + buf = bytearray() + msg_pack_into(ofproto.OFP_TABLE_FEATURES_PACK_STR, buf, 0, + self.length, self.table_id, self.name, + self.metadata_match, self.metadata_write, + self.config, self.max_entries) + return buf + bin_props + + +class OFPTableFeatureProp(OFPPropBase): + _TYPES = {} + + @classmethod + def get_rest(cls, buf): + (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0) + offset = struct.calcsize(cls._PACK_STR) + return buf[offset:length] + + def serialize(self): + # Body + # serialize_body should be implemented by subclass + body = bytearray() + body += self.serialize_body() + + # fixup + self.length = len(body) + struct.calcsize(self._PACK_STR) + + # Header + buf = bytearray() + msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length) + buf += body + + # Pad + pad_len = utils.round_up(self.length, 8) - self.length + ofproto_parser.msg_pack_into("%dx" % pad_len, buf, len(buf)) + + return buf + + +class OFPInstructionId(StringifyMixin): + _PACK_STR = '!HH' # type, len + + def __init__(self, type_, len_=None): + self.type = type_ + self.len = len_ + # XXX experimenter + + @classmethod + def parse(cls, buf): + (type_, len_,) = struct.unpack_from(cls._PACK_STR, buffer(buf), 0) + rest = buf[len_:] + return cls(type_=type_, len_=len_), rest + + def serialize(self): + # fixup + self.len = struct.calcsize(self._PACK_STR) + + buf = bytearray() + msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len) + return buf + + +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS_MISS) +class OFPTableFeaturePropInstructions(OFPTableFeatureProp): + def __init__(self, type_=None, length=None, instruction_ids=[]): + super(OFPTableFeaturePropInstructions, self).__init__(type_, length) + self.instruction_ids = instruction_ids + + @classmethod + def parser(cls, buf): + rest = cls.get_rest(buf) + ids = [] + while rest: + i, rest = OFPInstructionId.parse(rest) + ids.append(i) + return cls(instruction_ids=ids) + + def serialize_body(self): + bin_ids = bytearray() + for i in self.instruction_ids: + bin_ids += i.serialize() + + return bin_ids + + +# Implementation note: While OpenFlow 1.3.2 shares the same ofp_action_header +# for flow_mod and table_features, we have separate classes. We named this +# class to match with OpenFlow 1.4's name. (ofp_action_id) +class OFPActionId(StringifyMixin): + _PACK_STR = '!HH' # type, len + + def __init__(self, type_, len_=None): + self.type = type_ + self.len = len_ + # XXX experimenter + + @classmethod + def parse(cls, buf): + (type_, len_,) = struct.unpack_from(cls._PACK_STR, buffer(buf), 0) + rest = buf[len_:] + return cls(type_=type_, len_=len_), rest + + def serialize(self): + # fixup + self.len = struct.calcsize(self._PACK_STR) + + buf = bytearray() + msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len) + return buf + + +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS_MISS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS_MISS) +class OFPTableFeaturePropActions(OFPTableFeatureProp): + def __init__(self, type_=None, length=None, action_ids=[]): + super(OFPTableFeaturePropActions, self).__init__(type_, length) + self.action_ids = action_ids + + @classmethod + def parser(cls, buf): + rest = cls.get_rest(buf) + ids = [] + while rest: + i, rest = OFPActionId.parse(rest) + ids.append(i) + return cls(action_ids=ids) + + def serialize_body(self): + bin_ids = bytearray() + for i in self.action_ids: + bin_ids += i.serialize() + return bin_ids + + +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES_MISS) +class OFPTableFeaturePropNextTables(OFPTableFeatureProp): + _TABLE_ID_PACK_STR = '!B' + + def __init__(self, type_=None, length=None, table_ids=[]): + super(OFPTableFeaturePropNextTables, self).__init__(type_, length) + self.table_ids = table_ids + + @classmethod + def parser(cls, buf): + rest = cls.get_rest(buf) + ids = [] + while rest: + (i,) = struct.unpack_from(cls._TABLE_ID_PACK_STR, buffer(rest), 0) + rest = rest[struct.calcsize(cls._TABLE_ID_PACK_STR):] + ids.append(i) + return cls(table_ids=ids) + + def serialize_body(self): + bin_ids = bytearray() + for i in self.table_ids: + bin_id = bytearray() + msg_pack_into(self._TABLE_ID_PACK_STR, bin_id, 0, i) + bin_ids += bin_id + return bin_ids + + +# Implementation note: OFPOxmId is specific to this implementation. +# It does not have a corresponding structure in the specification. +# (the specification uses plain uint32_t for them.) +# +# i have taken a look at some of software switch implementations +# but they all look broken or incomplete. according to the spec, +# oxm_hasmask should be 1 if a switch supports masking for the type. +# the right value for oxm_length is not clear from the spec. +# update: OpenFlow 1.3.3 "clarified" that oxm_length here is the payload +# length. it's still unclear if it should be doubled for hasmask or not, +# though. +# ofsoftswitch13 +# oxm_hasmask always 0 +# oxm_length same as ofp_match etc (as without mask) +# linc/of_protocol +# oxm_hasmask always 0 +# oxm_length always 0 +# ovs: +# table-feature is not implemented +class OFPOxmId(StringifyMixin): + _PACK_STR = '!I' # oxm header + + _TYPE = { + 'ascii': [ + 'type', + ], + } + + def __init__(self, type_, hasmask=False, length=None): + self.type = type_ + self.hasmask = hasmask + self.length = length + # XXX experimenter + + @classmethod + def parse(cls, buf): + (oxm,) = struct.unpack_from(cls._PACK_STR, buffer(buf), 0) + (type_, _v) = ofproto.oxm_to_user(oxm >> 9, None, None) + hasmask = ofproto.oxm_tlv_header_extract_hasmask(oxm) + length = oxm & 0xff # XXX see the comment on OFPOxmId + rest = buf[4:] # XXX see the comment on OFPOxmId + return cls(type_=type_, hasmask=hasmask, length=length), rest + + def serialize(self): + # fixup + self.length = 0 # XXX see the comment on OFPOxmId + + (n, _v, _m) = ofproto.oxm_from_user(self.type, None) + oxm = (n << 9) | (self.hasmask << 8) | self.length + buf = bytearray() + msg_pack_into(self._PACK_STR, buf, 0, oxm) + return buf + + +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_MATCH) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WILDCARDS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD_MISS) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD) +@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD_MISS) +class OFPTableFeaturePropOxm(OFPTableFeatureProp): + def __init__(self, type_=None, length=None, oxm_ids=[]): + super(OFPTableFeaturePropOxm, self).__init__(type_, length) + self.oxm_ids = oxm_ids + + @classmethod + def parser(cls, buf): + rest = cls.get_rest(buf) + ids = [] + while rest: + i, rest = OFPOxmId.parse(rest) + ids.append(i) + return cls(oxm_ids=ids) + + def serialize_body(self): + bin_ids = bytearray() + for i in self.oxm_ids: + bin_ids += i.serialize() + return bin_ids + + +@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats) +@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST) +class OFPTableFeaturesStatsRequest(OFPMultipartRequest): + """ + Table features statistics request message + + The controller uses this message to query table features. + + ================ ====================================================== + Attribute Description + ================ ====================================================== + body List of ``OFPTableFeaturesStats`` instances. + The default is []. + ================ ====================================================== + """ + def __init__(self, datapath, flags=0, body=[], type_=None): + super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags) + self.body = body + + def _serialize_stats_body(self): + bin_body = bytearray() + for p in self.body: + bin_body += p.serialize() + self.buf += bin_body + + +@OFPMultipartReply.register_stats_type() +@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats) +@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY) +class OFPTableFeaturesStatsReply(OFPMultipartReply): + """ + Table features statistics reply message + + The switch responds with this message to a table features statistics + request. + + This implmentation is still incomplete. + Namely, this implementation does not parse ``properties`` list and + always reports it empty. + + ================ ====================================================== + Attribute Description + ================ ====================================================== + body List of ``OFPTableFeaturesStats`` instance + ================ ====================================================== + """ + def __init__(self, datapath, type_=None, **kwargs): + super(OFPTableFeaturesStatsReply, self).__init__(datapath, **kwargs) + + @_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort) @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST) class OFPPortDescStatsRequest(OFPMultipartRequest): |