summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIWAMOTO Toshihiro <iwamoto@valinux.co.jp>2016-10-07 16:37:58 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-10-12 09:08:52 +0900
commit6aa4adb0707ed89727b43a17f371b41110132ab5 (patch)
tree8c9636ec2a55c1e1d4b62bf39621ea9e51fb7bb0
parentb9a9f81ff0bbc5aa09711f6533af28a357ad8818 (diff)
ofproto_v1_3_parser: Raise OFPTruncatedMessage exception on truncated messages
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 <iwamoto@valinux.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/exception.py13
-rw-r--r--ryu/ofproto/ofproto_parser.py15
-rw-r--r--ryu/ofproto/ofproto_v1_3_parser.py71
3 files changed, 79 insertions, 20 deletions
diff --git a/ryu/exception.py b/ryu/exception.py
index 0a1e72ce..1be4ba12 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 670878d8..b68c5382 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 99c4a47b..c298c998 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):