mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-05-08 22:06:10 +02:00
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:
parent
03a9196e43
commit
5bfc8255ba
@ -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):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user