OFPT_ERROR_MSG can return truncated messages. Some users want to see them in human-friendly format [1]. Catch exceptions caused by such truncated messages and reraise as OFPTruncatedMessage with incomplete ofpmsg in the exception class.
[1] https://bugs.launchpad.net/dragonflow/+bug/1624826 Signed-off-by: IWAMOTO Toshihiro <iwam...@valinux.co.jp> --- ryu/exception.py | 13 +++++++ ryu/ofproto/ofproto_parser.py | 15 ++++++-- ryu/ofproto/ofproto_v1_3_parser.py | 71 +++++++++++++++++++++++++++++--------- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/ryu/exception.py b/ryu/exception.py index 0a1e72c..1be4ba1 100644 --- a/ryu/exception.py +++ b/ryu/exception.py @@ -39,6 +39,19 @@ class OFPMalformedMessage(RyuException): message = 'malformed message' +class OFPTruncatedMessage(RyuException): + message = 'truncated message: %(orig_ex)s' + + def __init__(self, ofpmsg, residue, original_exception, + msg=None, **kwargs): + self.ofpmsg = ofpmsg + self.residue = residue + self.original_exception = original_exception + kwargs['orig_ex'] = str(original_exception) + + super(OFPTruncatedMessage, self).__init__(msg, **kwargs) + + class NetworkNotFound(RyuException): message = 'no such network id %(network_id)s' diff --git a/ryu/ofproto/ofproto_parser.py b/ryu/ofproto/ofproto_parser.py index 670878d..b68c538 100644 --- a/ryu/ofproto/ofproto_parser.py +++ b/ryu/ofproto/ofproto_parser.py @@ -53,21 +53,30 @@ def register_msg_parser(version): def msg(datapath, version, msg_type, msg_len, xid, buf): - assert len(buf) >= msg_len + exp = None + try: + assert len(buf) >= msg_len + except AssertionError as e: + exp = e msg_parser = _MSG_PARSERS.get(version) if msg_parser is None: raise exception.OFPUnknownVersion(version=version) try: - return msg_parser(datapath, version, msg_type, msg_len, xid, buf) + msg = msg_parser(datapath, version, msg_type, msg_len, xid, buf) + except exception.OFPTruncatedMessage as e: + raise e except: LOG.exception( 'Encountered an error while parsing OpenFlow packet from switch. ' 'This implies the switch sent a malformed OpenFlow packet. ' 'version 0x%02x msg_type %d msg_len %d xid %d buf %s', version, msg_type, msg_len, xid, utils.hex_array(buf)) - return None + msg = None + if exp: + raise exp + return msg def create_list_of_base_attributes(f): diff --git a/ryu/ofproto/ofproto_v1_3_parser.py b/ryu/ofproto/ofproto_v1_3_parser.py index 99c4a47..c298c99 100644 --- a/ryu/ofproto/ofproto_v1_3_parser.py +++ b/ryu/ofproto/ofproto_v1_3_parser.py @@ -49,6 +49,7 @@ from ryu.lib import addrconv from ryu.lib import mac from ryu.lib.pack_utils import msg_pack_into from ryu.lib.packet import packet +from ryu import exception from ryu import utils from ryu.ofproto.ofproto_parser import StringifyMixin, MsgBase from ryu.ofproto import ether @@ -1269,17 +1270,28 @@ class OFPMatch(StringifyMixin): offset += 4 length -= 4 + exc = None + residue = None # XXXcompat - cls.parser_old(match, buf, offset, length) + try: + cls.parser_old(match, buf, offset, length) + except struct.error as e: + exc = e fields = [] - while length > 0: - n, value, mask, field_len = ofproto.oxm_parse(buf, offset) - k, uv = ofproto.oxm_to_user(n, value, mask) - fields.append((k, uv)) - offset += field_len - length -= field_len + try: + while length > 0: + n, value, mask, field_len = ofproto.oxm_parse(buf, offset) + k, uv = ofproto.oxm_to_user(n, value, mask) + fields.append((k, uv)) + offset += field_len + length -= field_len + except struct.error as e: + exc = e + residue = buf[offset:] match._fields2 = fields + if exc is not None: + raise exception.OFPTruncatedMessage(match, residue, exc) return match @staticmethod @@ -2696,14 +2708,31 @@ class OFPFlowMod(MsgBase): ofproto.OFP_HEADER_SIZE) offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE - msg.match = OFPMatch.parser(buf, offset) + try: + msg.match = OFPMatch.parser(buf, offset) + except exception.OFPTruncatedMessage as e: + msg.match = e.ofpmsg + e.ofpmsg = msg + raise e + offset += utils.round_up(msg.match.length, 8) instructions = [] - while offset < msg_len: - i = OFPInstruction.parser(buf, offset) - instructions.append(i) - offset += i.len + try: + while offset < msg_len: + i = OFPInstruction.parser(buf, offset) + instructions.append(i) + offset += i.len + except exception.OFPTruncatedMessage as e: + instructions.append(e.ofpmsg) + msg.instructions = instructions + e.ofpmsg = msg + raise e + except struct.error as e: + msg.instructions = instructions + raise exception.OFPTruncatedMessage(ofpmsg=msg, + residue=buf[offset:], + original_exception=e) msg.instructions = instructions return msg @@ -2830,14 +2859,22 @@ class OFPInstructionActions(OFPInstruction): offset += ofproto.OFP_INSTRUCTION_ACTIONS_SIZE actions = [] actions_len = len_ - ofproto.OFP_INSTRUCTION_ACTIONS_SIZE - while actions_len > 0: - a = OFPAction.parser(buf, offset) - actions.append(a) - actions_len -= a.len - offset += a.len + exc = None + try: + while actions_len > 0: + a = OFPAction.parser(buf, offset) + actions.append(a) + actions_len -= a.len + offset += a.len + except struct.error as e: + exc = e inst = cls(type_, actions) inst.len = len_ + if exc is not None: + raise exception.OFPTruncatedMessage(ofpmsg=inst, + residue=buf[offset:], + original_exception=exc) return inst def serialize(self, buf, offset): -- 2.1.4 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ Ryu-devel mailing list Ryu-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ryu-devel