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>
This commit is contained in:
Simon Horman 2014-02-04 13:27:52 +09:00 committed by FUJITA Tomonori
parent 03a9196e43
commit 5bfc8255ba

View File

@ -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):