summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2014-02-04 13:27:52 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-02-04 18:41:32 +0900
commit5bfc8255badd8fd9765d2c9d777201726e307d1e (patch)
tree35f955d8a7db67caa4670f5cdc8121dc788e0310
parent03a9196e4366458c436fe29dade25b4ff78c54c3 (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.py346
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):