summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYAMAMOTO Takashi <yamamoto@valinux.co.jp>2013-10-28 17:08:10 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2013-10-28 23:02:49 +0900
commit5769688e32dfe0a28bb148abd5f7670b10624b40 (patch)
treec9888c55c738b51e1c42ab36c64f4a6302ec9ac1
parentf138351288f10f8fb4a9308cbda91a7b5d126d66 (diff)
of13: implement table features request/reply
Signed-off-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/ofproto/ofproto_v1_3_parser.py321
1 files changed, 306 insertions, 15 deletions
diff --git a/ryu/ofproto/ofproto_v1_3_parser.py b/ryu/ofproto/ofproto_v1_3_parser.py
index d3db3fbe..50e69923 100644
--- a/ryu/ofproto/ofproto_v1_3_parser.py
+++ b/ryu/ofproto/ofproto_v1_3_parser.py
@@ -4733,13 +4733,308 @@ class OFPTableFeaturesStats(StringifyMixin):
) = struct.unpack_from(ofproto_v1_3.OFP_TABLE_FEATURES_PACK_STR,
buf, offset)
table_features.name = name.rstrip('\0')
- offset += ofproto_v1_3.OFP_TABLE_FEATURES_SIZE
- # TODO: parse ofp_table_feature_prop_header
- table_features.properties = []
+ props = []
+ rest = buf[offset + ofproto_v1_3.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_v1_3.OFP_TABLE_FEATURES_SIZE + len(bin_props)
+
+ buf = bytearray()
+ msg_pack_into(ofproto_v1_3.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(StringifyMixin):
+ _PACK_STR = '!HH' # type, length
+ _TYPES = {} # OFPTFPT_ -> class
+
+ def __init__(self, type_, length=None):
+ self.type = type_
+ self.length = length
+
+ @classmethod
+ def register_type(cls, type_):
+ def _register_type(subcls):
+ cls._TYPES[type_] = subcls
+ return subcls
+ return _register_type
+
+ @classmethod
+ def parse(cls, buf):
+ (type_, length,) = struct.unpack_from(cls._PACK_STR, buffer(buf), 0)
+ bin_prop = buf[struct.calcsize(cls._PACK_STR):length]
+ rest = buf[utils.round_up(length, 8):]
+ try:
+ subcls = cls._TYPES[type_]
+ except KeyError:
+ subcls = OFPTableFeaturePropUnknown
+ kwargs = subcls._parse_prop(bin_prop)
+ kwargs['type_'] = type_
+ kwargs['length'] = length
+ return subcls(**kwargs), rest
+
+ def serialize(self):
+ # fixup
+ bin_prop = self._serialize_prop()
+ self.length = struct.calcsize(self._PACK_STR) + len(bin_prop)
+
+ buf = bytearray()
+ msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
+ pad_len = utils.round_up(self.length, 8) - self.length
+ return buf + bin_prop + pad_len * '\0'
+
+
+class OFPTableFeaturePropUnknown(OFPTableFeatureProp):
+ def __init__(self, type_, length=None, data=None):
+ super(OFPTableFeaturePropUnknown, self).__init__(type_, length)
+ self.data = data
+
+ @classmethod
+ def _parse_prop(cls, buf):
+ return {'data': buf}
+
+ def _serialize_prop(self):
+ return self.data
+
+
+# Implementation note: While OpenFlow 1.3.2 shares the same ofp_instruction
+# for flow_mod and table_features, we have separate classes. We named this
+# class to match with OpenFlow 1.4's name. (ofp_instruction_id)
+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_v1_3.OFPTFPT_INSTRUCTIONS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_INSTRUCTIONS_MISS)
+class OFPTableFeaturePropInstructions(OFPTableFeatureProp):
+ def __init__(self, type_, instruction_ids=[], length=None):
+ super(OFPTableFeaturePropInstructions, self).__init__(type_, length)
+ self.instruction_ids = instruction_ids
+
+ @classmethod
+ def _parse_prop(cls, buf):
+ rest = buf
+ ids = []
+ while rest:
+ i, rest = OFPInstructionId.parse(rest)
+ ids.append(i)
+ return {
+ 'instruction_ids': ids,
+ }
+
+ def _serialize_prop(self):
+ bin_ids = bytearray()
+ for i in self.instruction_ids:
+ bin_ids += i.serialize()
+ return bin_ids
+
+
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_NEXT_TABLES)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_NEXT_TABLES_MISS)
+class OFPTableFeaturePropNextTables(OFPTableFeatureProp):
+ _TABLE_ID_PACK_STR = '!B'
+
+ def __init__(self, type_, table_ids=[], length=None):
+ super(OFPTableFeaturePropNextTables, self).__init__(type_, length)
+ self.table_ids = table_ids
+
+ @classmethod
+ def _parse_prop(cls, buf):
+ 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 {
+ 'table_ids': ids,
+ }
+
+ def _serialize_prop(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: 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):
+ # XXX
+ # ofp_action_header should have trailing pad bytes.
+ # however, i guess it's a specification bug as:
+ # - the spec explicitly says non-experimenter actions are 4 bytes
+ # - linc/of_protocol doesn't use them
+ # - OpenFlow 1.4 changed to use a separate structure
+ _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_v1_3.OFPTFPT_WRITE_ACTIONS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_WRITE_ACTIONS_MISS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_APPLY_ACTIONS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_APPLY_ACTIONS_MISS)
+class OFPTableFeaturePropActions(OFPTableFeatureProp):
+ def __init__(self, type_, action_ids=[], length=None):
+ super(OFPTableFeaturePropActions, self).__init__(type_, length)
+ self.action_ids = action_ids
+
+ @classmethod
+ def _parse_prop(cls, buf):
+ rest = buf
+ ids = []
+ while rest:
+ i, rest = OFPActionId.parse(rest)
+ ids.append(i)
+ return {
+ 'action_ids': ids,
+ }
+
+ def _serialize_prop(self):
+ bin_ids = bytearray()
+ for i in self.action_ids:
+ bin_ids += i.serialize()
+ 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.
+# 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_v1_3.oxm_to_user(oxm >> 9, None, None)
+ hasmask = ofproto_v1_3.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_v1_3.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_v1_3.OFPTFPT_MATCH)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_WILDCARDS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_WRITE_SETFIELD)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_WRITE_SETFIELD_MISS)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_APPLY_SETFIELD)
+@OFPTableFeatureProp.register_type(ofproto_v1_3.OFPTFPT_APPLY_SETFIELD_MISS)
+class OFPTableFeaturePropOxm(OFPTableFeatureProp):
+ def __init__(self, type_, oxm_ids=[], length=None):
+ super(OFPTableFeaturePropOxm, self).__init__(type_, length)
+ self.oxm_ids = oxm_ids
+
+ @classmethod
+ def _parse_prop(cls, buf):
+ rest = buf
+ ids = []
+ while rest:
+ i, rest = OFPOxmId.parse(rest)
+ ids.append(i)
+ return {
+ 'oxm_ids': ids,
+ }
+
+ def _serialize_prop(self):
+ bin_ids = bytearray()
+ for i in self.oxm_ids:
+ bin_ids += i.serialize()
+ return bin_ids
+
+
+# XXX ofproto_v1_3.OFPTFPT_EXPERIMENTER
+# XXX ofproto_v1_3.OFPTFPT_EXPERIMENTER_MISS
+
@_set_stats_type(ofproto_v1_3.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
@_set_msg_type(ofproto_v1_3.OFPT_MULTIPART_REQUEST)
@@ -4751,21 +5046,17 @@ class OFPTableFeaturesStatsRequest(OFPMultipartRequest):
This message is currently unimplemented.
"""
- def __init__(self, datapath, flags, length, table_id, name,
- metadata_match, metadata_write, config, max_entries,
- properties, type_=None):
+ def __init__(self, datapath, flags,
+ body=[],
+ properties=[], type_=None):
super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags)
- self.length = length
- 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.body = body
def _serialize_stats_body(self):
- # TODO
- pass
+ bin_body = bytearray()
+ for p in self.body:
+ bin_body += p.serialize()
+ self.buf += bin_body
@OFPMultipartReply.register_stats_type()