ofp_handler: Output human readable error msg ev log

Currently, the error message event log which is output by ofp_handler.py
is difficult to understand what is wrong in the previous OpenFlow request
message.
This patch improves the readability of this output to find out errors.

*** Output Example ***
EventOFPErrorMsg received.
version=0x4, msg_type=0x1, msg_len=0x4c, xid=0xecc7f07b
 `-- msg_type: OFPT_ERROR(1)
OFPErrorMsg(type=0x4, code=0x9, data=b'\x04\x0e\x00\x58\xec\xc7\xf0\x7b\x00\x0
0\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x2b\x67\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x0
0\x01\x00\x0c\x80\x00\x18\x04\xc0\xa8\x00\x01\x00\x00\x00\x00')
 |-- type: OFPET_BAD_MATCH(4)
 |-- code: OFPBMC_BAD_PREREQ(9)
 `-- data: version=0x4, msg_type=0xe, msg_len=0x58, xid=0xecc7f07b
     `-- msg_type: OFPT_FLOW_MOD(14)

Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Yusuke Iwase 2015-09-09 10:19:20 +09:00 committed by FUJITA Tomonori
parent f5932480c5
commit b6e280172a
7 changed files with 164 additions and 2 deletions

View File

@ -31,6 +31,7 @@ from ryu.controller.controller import OpenFlowController
from ryu.controller.handler import set_ev_handler
from ryu.controller.handler import HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER,\
MAIN_DISPATCHER
from ryu.ofproto import ofproto_parser
# The state transition: HANDSHAKE -> CONFIG -> MAIN
@ -249,5 +250,23 @@ class OFPHandler(ryu.base.app_manager.RyuApp):
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def error_msg_handler(self, ev):
msg = ev.msg
self.logger.debug('error msg ev %s type 0x%x code 0x%x %s',
msg, msg.type, msg.code, utils.hex_array(msg.data))
ofp = msg.datapath.ofproto
(version, msg_type, msg_len, xid) = ofproto_parser.header(msg.data)
self.logger.debug('EventOFPErrorMsg received.')
self.logger.debug(
'version=%s, msg_type=%s, msg_len=%s, xid=%s', hex(msg.version),
hex(msg.msg_type), hex(msg.msg_len), hex(msg.xid))
self.logger.debug(
' `-- msg_type: %s', ofp.ofp_msg_type_to_str(msg.msg_type))
self.logger.debug(
"OFPErrorMsg(type=%s, code=%s, data=b'%s')", hex(msg.type),
hex(msg.code), utils.binary_str(msg.data))
self.logger.debug(
' |-- type: %s', ofp.ofp_error_type_to_str(msg.type))
self.logger.debug(
' |-- code: %s', ofp.ofp_error_code_to_str(msg.type, msg.code))
self.logger.debug(
' `-- data: version=%s, msg_type=%s, msg_len=%s, xid=%s',
hex(version), hex(msg_type), hex(msg_len), hex(xid))
self.logger.debug(
' `-- msg_type: %s', ofp.ofp_msg_type_to_str(msg_type))

View File

@ -0,0 +1,123 @@
# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
def generate(modname):
import sys
import functools
mod = sys.modules[modname]
def add_attr(k, v):
setattr(mod, k, v)
add_attr('ofp_msg_type_to_str',
functools.partial(_msg_type_to_str, mod))
add_attr('ofp_error_type_to_str',
functools.partial(_error_type_to_str, mod))
add_attr('ofp_error_code_to_str',
functools.partial(_error_code_to_str, mod))
add_attr('ofp_error_to_jsondict',
functools.partial(_error_to_jsondict, mod))
def _get_value_name(mod, value, pattern):
for k, v in mod.__dict__.items():
if k.startswith(pattern):
if v == value:
return k
return 'Unknown'
def _msg_type_to_str(mod, type_):
"""
This method is registered as ofp_msg_type_to_str(type_) method
into ryu.ofproto.ofproto_v1_* modules.
And this method returns the message type as a string value for given
'type' defined in ofp_type enum.
Example::
>>> ofproto.ofp_msg_type_to_str(14)
'OFPT_FLOW_MOD(14)'
"""
return '%s(%d)' % (_get_value_name(mod, type_, 'OFPT_'), type_)
def _error_type_to_str(mod, type_):
"""
This method is registered as ofp_error_type_to_str(type_) method
into ryu.ofproto.ofproto_v1_* modules.
And this method returns the error type as a string value for given
'type' defined in ofp_error_msg structure.
Example::
>>> ofproto.ofp_error_type_to_str(4)
'OFPET_BAD_MATCH(4)'
"""
return '%s(%d)' % (_get_value_name(mod, type_, 'OFPET_'), type_)
def _get_error_names(mod, type_, code):
t_name = _get_value_name(mod, type_, 'OFPET_')
if t_name == 'Unknown':
return 'Unknown', 'Unknown'
# Construct error code name pattern
# e.g.) "OFPET_BAD_MATCH" -> "OFPBMC_"
if t_name == 'OFPET_FLOW_MONITOR_FAILED':
c_name_p = 'OFPMOFC_'
else:
c_name_p = 'OFP'
for m in re.findall("_(.)", t_name):
c_name_p += m.upper()
c_name_p += 'C_'
c_name = _get_value_name(mod, code, c_name_p)
return t_name, c_name
def _error_code_to_str(mod, type_, code):
"""
This method is registered as ofp_error_code_to_str(type_, code) method
into ryu.ofproto.ofproto_v1_* modules.
And this method returns the error code as a string value for given
'type' and 'code' defined in ofp_error_msg structure.
Example::
>>> ofproto.ofp_error_code_to_str(4, 9)
'OFPBMC_BAD_PREREQ(9)'
"""
(_, c_name) = _get_error_names(mod, type_, code)
return '%s(%d)' % (c_name, code)
def _error_to_jsondict(mod, type_, code):
"""
This method is registered as ofp_error_to_jsondict(type_, code) method
into ryu.ofproto.ofproto_v1_* modules.
And this method returns ofp_error_msg as a json format for given
'type' and 'code' defined in ofp_error_msg structure.
Example::
>>> ofproto.ofp_error_to_jsondict(4, 9)
{'code': 'OFPBMC_BAD_PREREQ(9)', 'type': 'OFPET_BAD_MATCH(4)'}
"""
(t_name, c_name) = _get_error_names(mod, type_, code)
return {'type': '%s(%d)' % (t_name, type_),
'code': '%s(%d)' % (c_name, code)}

View File

@ -20,6 +20,8 @@ OpenFlow 1.0 definitions.
from struct import calcsize
from ryu.ofproto import ofproto_utils
MAX_XID = 0xffffffff
@ -492,6 +494,9 @@ OFP_QUEUE_PROP_MIN_RATE_SIZE = 16
assert (calcsize(OFP_QUEUE_PROP_MIN_RATE_PACK_STR) +
OFP_QUEUE_PROP_HEADER_SIZE == OFP_QUEUE_PROP_MIN_RATE_SIZE)
# generate utility methods
ofproto_utils.generate(__name__)
def nxm_header__(vendor, field, hasmask, length):
return (vendor << 16) | (field << 9) | (hasmask << 8) | length

View File

@ -19,6 +19,7 @@ OpenFlow 1.2 definitions.
"""
from ryu.lib import type_desc
from ryu.ofproto import ofproto_utils
from ryu.ofproto import oxm_fields
from struct import calcsize
@ -831,6 +832,8 @@ oxm_types = [
oxm_fields.generate(__name__)
# generate utility methods
ofproto_utils.generate(__name__)
# define constants
OFP_VERSION = 0x03

View File

@ -19,6 +19,7 @@ OpenFlow 1.3 definitions.
"""
from ryu.lib import type_desc
from ryu.ofproto import ofproto_utils
from ryu.ofproto import oxm_fields
from struct import calcsize
@ -1229,6 +1230,9 @@ OFP_PROP_EXPERIMENTER_SIZE = 12
assert (calcsize(OFP_PROP_EXPERIMENTER_PACK_STR) ==
OFP_PROP_EXPERIMENTER_SIZE)
# generate utility methods
ofproto_utils.generate(__name__)
# define constants
OFP_VERSION = 0x04
OFP_TCP_PORT = 6633

View File

@ -19,6 +19,7 @@ OpenFlow 1.4 definitions.
"""
from ryu.lib import type_desc
from ryu.ofproto import ofproto_utils
from ryu.ofproto import oxm_fields
from struct import calcsize
@ -1482,6 +1483,9 @@ OFP_PROP_EXPERIMENTER_SIZE = 12
assert (calcsize(OFP_PROP_EXPERIMENTER_PACK_STR) ==
OFP_PROP_EXPERIMENTER_SIZE)
# generate utility methods
ofproto_utils.generate(__name__)
# define constants
OFP_VERSION = 0x05
OFP_TCP_PORT = 6653

View File

@ -19,6 +19,7 @@ OpenFlow 1.5 definitions.
"""
from ryu.lib import type_desc
from ryu.ofproto import ofproto_utils
from ryu.ofproto import oxm_fields
from ryu.ofproto import oxs_fields
@ -1818,6 +1819,9 @@ OFP_PROP_EXPERIMENTER_SIZE = 12
assert (calcsize(OFP_PROP_EXPERIMENTER_PACK_STR) ==
OFP_PROP_EXPERIMENTER_SIZE)
# generate utility methods
ofproto_utils.generate(__name__)
# define constants
OFP_VERSION = 0x06
OFP_TCP_PORT = 6653