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

Reply via email to