[ovs-dev] [of1.1 3/3] Better abstract OpenFlow error codes.

Ethan Jackson ethan at nicira.com
Thu Jan 12 23:17:56 UTC 2012


This looks like a big win.  Couple of comments.

My compiler complains about this patch:

ofproto/ofproto.c: In function ‘ofoperation_complete’:
ofproto/ofproto.c:3157:5: error: comparison of unsigned expression >=
0 is always true [-Werror=type-limits]

In ofperr_encode_msg__() the following line:
     pair = &domain->errors[MIN(error - OFPERR_OFS, OFPERR_N_ERRORS)];

I don't think you need the MIN because you know at this point that
'error' is valid and therefore error - OFPERR_OFS is less than
OFPERR_N_ERRORS.

Also in the same function you have a cast without a space following it.

Ethan

On Wed, Dec 14, 2011 at 10:01, Ben Pfaff <blp at nicira.com> wrote:
> This commit switches from using the actual protocol values of error codes
> internally in Open vSwitch, to using abstract values that are translated to
> and from protocol values at message parsing and serialization time.  I
> believe that this makes the code easier to read and to write.
>
> This is also one step along the way toward OpenFlow 1.1 support because
> OpenFlow 1.1 renumbered a bunch of error codes.
> ---
>  build-aux/extract-ofp-errors |  243 ++++++++++++++++++--------
>  include/openflow/openflow.h  |   77 ---------
>  lib/.gitignore               |    2 +-
>  lib/automake.mk              |   13 +-
>  lib/autopath.c               |    5 +-
>  lib/autopath.h               |    4 +-
>  lib/bundle.c                 |   22 ++-
>  lib/bundle.h                 |    5 +-
>  lib/dpif.c                   |   10 +-
>  lib/learn.c                  |   27 ++--
>  lib/learn.h                  |    4 +-
>  lib/learning-switch.c        |    1 +
>  lib/multipath.c              |    7 +-
>  lib/multipath.h              |    6 +-
>  lib/nx-match.c               |   48 ++----
>  lib/nx-match.h               |   16 +-
>  lib/ofp-errors.c             |  286 +++++++++++++++++++++++++++++++
>  lib/ofp-errors.h             |  389 +++++++++++++++++++++++++++++++++++++++++-
>  lib/ofp-print.c              |   40 ++---
>  lib/ofp-util.c               |  363 +++++++++-------------------------------
>  lib/ofp-util.h               |  174 ++-----------------
>  lib/vconn.c                  |   11 +-
>  ofproto/connmgr.c            |   21 +--
>  ofproto/connmgr.h            |    7 +-
>  ofproto/ofproto-dpif.c       |   19 +-
>  ofproto/ofproto-provider.h   |   49 +++---
>  ofproto/ofproto.c            |  145 ++++++++--------
>  ofproto/pktbuf.c             |   13 +-
>  ofproto/pktbuf.h             |    8 +-
>  tests/ofp-print.at           |   57 +++++-
>  tests/ovs-ofctl.at           |   92 +++++-----
>  utilities/ovs-ofctl.c        |    7 +-
>  32 files changed, 1261 insertions(+), 910 deletions(-)
>  create mode 100644 lib/ofp-errors.c
>
> diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
> index c34888f..5c3cd26 100755
> --- a/build-aux/extract-ofp-errors
> +++ b/build-aux/extract-ofp-errors
> @@ -12,6 +12,15 @@ idRe = "[a-zA-Z_][a-zA-Z_0-9]*"
>  tokenRe = "#?" + idRe + "|[0-9]+|."
>  inComment = False
>  inDirective = False
> +
> +def getLine():
> +    global line
> +    global lineNumber
> +    line = inputFile.readline()
> +    lineNumber += 1
> +    if line == "":
> +        fatal("unexpected end of input")
> +
>  def getToken():
>     global token
>     global line
> @@ -58,7 +67,7 @@ def getToken():
>                 return False
>
>  def fatal(msg):
> -    sys.stderr.write("%s:%d: error at \"%s\": %s\n" % (fileName, lineNumber, token, msg))
> +    sys.stderr.write("%s:%d: %s\n" % (fileName, lineNumber, msg))
>     sys.exit(1)
>
>  def skipDirective():
> @@ -124,95 +133,179 @@ This program reads the header files specified on the command line and
>  outputs a C source file for translating OpenFlow error codes into
>  strings, for use as lib/ofp-errors.c in the Open vSwitch source tree.
>
> -This program is specialized for reading include/openflow/openflow.h
> -and include/openflow/nicira-ext.h.  It will not work on arbitrary
> -header files without extensions.''' % {"argv0": argv0}
> +This program is specialized for reading lib/ofp-errors.h.  It will not
> +work on arbitrary header files without extensions.\
> +''' % {"argv0": argv0}
>     sys.exit(0)
>
>  def extract_ofp_errors(filenames):
>     error_types = {}
>
> +    comments = []
> +    names = []
> +    domain = {}
> +    reverse = {}
> +    for domain_name in ("OF1.0", "OF1.1", "NX1.0", "NX1.1"):
> +        domain[domain_name] = {}
> +        reverse[domain_name] = {}
> +
>     global fileName
>     for fileName in filenames:
>         global inputFile
>         global lineNumber
>         inputFile = open(fileName)
>         lineNumber = 0
> -        while getToken():
> -            if token in ("#ifdef", "#ifndef", "#include",
> -                         "#endif", "#elif", "#else", '#define'):
> -                skipDirective()
> -            elif match('enum'):
> -                forceId()
> -                enum_tag = token
> -                getToken()
> -
> -                forceMatch("{")
> -
> -                constants = []
> -                while isId(token):
> -                    constants.append(token)
> -                    getToken()
> -                    if match('='):
> -                        while token != ',' and token != '}':
> -                            getToken()
> -                    match(',')
> -
> -                forceMatch('}')
> -
> -                if enum_tag == "ofp_error_type":
> -                    error_types = {}
> -                    for error_type in constants:
> -                        error_types[error_type] = []
> -                elif enum_tag == 'nx_vendor_code':
> -                    pass
> -                elif enum_tag.endswith('_code'):
> -                    error_type = 'OFPET_%s' % '_'.join(enum_tag.split('_')[1:-1]).upper()
> -                    if error_type not in error_types:
> -                        fatal("enum %s looks like an error code enumeration but %s is unknown" % (enum_tag, error_type))
> -                    error_types[error_type] += constants
> -            elif token in ('struct', 'union'):
> -                getToken()
> -                forceId()
> -                getToken()
> -                forceMatch('{')
> -                while not match('}'):
> -                    getToken()
> -            elif match('OFP_ASSERT') or match('BOOST_STATIC_ASSERT'):
> -                while token != ';':
> -                    getToken()
> -            else:
> -                fatal("parse error")
> +
> +        while True:
> +            getLine()
> +            if re.match('enum ofperr', line):
> +                break
> +
> +        while True:
> +            getLine()
> +            if line.startswith('/*') or not line or line.isspace():
> +                continue
> +            elif re.match('}', line):
> +                break
> +
> +            m = re.match('\s+/\* ((?:.(?!\.  ))+.)\.  (.*)$', line)
> +            if not m:
> +                fatal("unexpected syntax between errors")
> +
> +            dsts, comment = m.groups()
> +
> +            comment.rstrip()
> +            while not comment.endswith('*/'):
> +                getLine()
> +                if line.startswith('/*') or not line or line.isspace():
> +                    fatal("unexpected syntax within error")
> +                comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
> +            comment = comment[:-2].rstrip()
> +
> +            getLine()
> +            m = re.match('\s+(?:OFPERR_((?:OFP|NX)[A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
> +                         line)
> +            if not m:
> +                fatal("syntax error expecting enum value")
> +
> +            enum = m.group(1)
> +
> +            comments.append(comment)
> +            names.append(enum)
> +
> +            for dst in dsts.split(', '):
> +                m = re.match(r'([A-Z0-9.]+)\((\d+)(?:,(\d+))?\)$', dst)
> +                if not m:
> +                    fatal("%s: syntax error in destination" % dst)
> +                targets = m.group(1)
> +                type_ = int(m.group(2))
> +                if m.group(3):
> +                    code = int(m.group(3))
> +                else:
> +                    code = None
> +
> +                target_map = {"OF":    ("OF1.0", "OF1.1"),
> +                              "OF1.0": ("OF1.0",),
> +                              "OF1.1": ("OF1.1",),
> +                              "NX":    ("OF1.0", "OF1.1"),
> +                              "NX1.0": ("OF1.0",),
> +                              "NX1.1": ("OF1.1",)}
> +                if targets not in target_map:
> +                    fatal("%s: unknown error domain" % target)
> +                for target in target_map[targets]:
> +                    if type_ not in domain[target]:
> +                        domain[target][type_] = {}
> +                    if code in domain[target][type_]:
> +                        fatal("%s: duplicate assignment in domain" % dst)
> +                    domain[target][type_][code] = enum
> +                    reverse[target][enum] = (type_, code)
> +
>         inputFile.close()
>
> -    print "/* -*- buffer-read-only: t -*- */"
> -    print "#include <config.h>"
> -    print '#include "ofp-errors.h"'
> -    print "#include <inttypes.h>"
> -    print "#include <stdio.h>"
> -    for fileName in sys.argv[1:]:
> -        print '#include "%s"' % fileName
> -    print '#include "type-props.h"'
> -
> -    for error_type, constants in sorted(error_types.items()):
> -        tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
> -        print_enum(tag, constants, "static ")
> -    print_enum("ofp_error_type", error_types.keys(), "")
> -    print """
> -const char *
> -ofp_error_code_to_string(uint16_t type, uint16_t code)
> -{
> -    switch (type) {\
> -"""
> -    for error_type in error_types:
> -        tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
> -        print "    case %s:" % error_type
> -        print "        return %s_to_string(code);" % tag
>     print """\
> +/* Generated automatically; do not modify!     -*- buffer-read-only: t -*- */
> +
> +#define OFPERR_N_ERRORS %d
> +
> +struct ofperr_domain {
> +    const char *name;
> +    uint8_t version;
> +    enum ofperr (*decode)(uint16_t type, uint16_t code);
> +    enum ofperr (*decode_type)(uint16_t type);
> +    struct pair errors[OFPERR_N_ERRORS];
> +};
> +
> +static const char *error_names[OFPERR_N_ERRORS] = {
> +%s
> +};
> +
> +static const char *error_comments[OFPERR_N_ERRORS] = {
> +%s
> +};\
> +""" % (len(names),
> +       '\n'.join('    "%s",' % name for name in names),
> +       '\n'.join('    "%s",' % re.sub(r'(["\\])', r'\\\1', comment)
> +                 for comment in comments))
> +
> +    def output_domain(map, name, description, version):
> +        print """
> +static enum ofperr
> +%s_decode(uint16_t type, uint16_t code)
> +{
> +    switch ((type << 16) | code) {""" % name
> +        for enum in names:
> +            if enum not in map:
> +                continue
> +            type_, code = map[enum]
> +            if code is None:
> +                continue
> +            print "    case (%d << 16) | %d:" % (type_, code)
> +            print "        return OFPERR_%s;" % enum
> +        print """\
>     }
> -    return NULL;
> -}\
> -"""
> +
> +    return 0;
> +}
> +
> +static enum ofperr
> +%s_decode_type(uint16_t type)
> +{
> +    switch (type) {""" % name
> +        for enum in names:
> +            if enum not in map:
> +                continue
> +            type_, code = map[enum]
> +            if code is not None:
> +                continue
> +            print "    case %d:" % type_
> +            print "        return OFPERR_%s;" % enum
> +        print """\
> +    }
> +
> +    return 0;
> +}"""
> +
> +        print """
> +const struct ofperr_domain %s = {
> +    "%s",
> +    %d,
> +    %s_decode,
> +    %s_decode_type,
> +    {""" % (name, description, version, name, name)
> +        for enum in names:
> +            if enum in map:
> +                type_, code = map[enum]
> +                if code == None:
> +                    code = -1
> +            else:
> +                type_ = code = -1
> +            print "        { %2d, %3d }, /* %s */" % (type_, code, enum)
> +        print """\
> +    },
> +};"""
> +
> +    output_domain(reverse["OF1.0"], "ofperr_of10", "OpenFlow 1.0", 0x01)
> +    output_domain(reverse["OF1.1"], "ofperr_of11", "OpenFlow 1.1", 0x02)
>
>  if __name__ == '__main__':
>     if '--help' in sys.argv:
> diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
> index f260984..f68a140 100644
> --- a/include/openflow/openflow.h
> +++ b/include/openflow/openflow.h
> @@ -603,83 +603,6 @@ struct ofp_flow_removed {
>  };
>  OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
>
> -/* Values for 'type' in ofp_error_message.  These values are immutable: they
> - * will not change in future versions of the protocol (although new values may
> - * be added). */
> -enum ofp_error_type {
> -    OFPET_HELLO_FAILED,         /* Hello protocol failed. */
> -    OFPET_BAD_REQUEST,          /* Request was not understood. */
> -    OFPET_BAD_ACTION,           /* Error in action description. */
> -    OFPET_FLOW_MOD_FAILED,      /* Problem modifying flow entry. */
> -    OFPET_PORT_MOD_FAILED,      /* OFPT_PORT_MOD failed. */
> -    OFPET_QUEUE_OP_FAILED       /* Queue operation failed. */
> -};
> -
> -/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED.  'data' contains an
> - * ASCII text string that may give failure details. */
> -enum ofp_hello_failed_code {
> -    OFPHFC_INCOMPATIBLE,        /* No compatible version. */
> -    OFPHFC_EPERM                /* Permissions error. */
> -};
> -
> -/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST.  'data' contains at least
> - * the first 64 bytes of the failed request. */
> -enum ofp_bad_request_code {
> -    OFPBRC_BAD_VERSION,         /* ofp_header.version not supported. */
> -    OFPBRC_BAD_TYPE,            /* ofp_header.type not supported. */
> -    OFPBRC_BAD_STAT,            /* ofp_stats_msg.type not supported. */
> -    OFPBRC_BAD_VENDOR,          /* Vendor not supported (in ofp_vendor_header
> -                                 * or ofp_stats_msg). */
> -    OFPBRC_BAD_SUBTYPE,         /* Vendor subtype not supported. */
> -    OFPBRC_EPERM,               /* Permissions error. */
> -    OFPBRC_BAD_LEN,             /* Wrong request length for type. */
> -    OFPBRC_BUFFER_EMPTY,        /* Specified buffer has already been used. */
> -    OFPBRC_BUFFER_UNKNOWN       /* Specified buffer does not exist. */
> -};
> -
> -/* ofp_error_msg 'code' values for OFPET_BAD_ACTION.  'data' contains at least
> - * the first 64 bytes of the failed request. */
> -enum ofp_bad_action_code {
> -    OFPBAC_BAD_TYPE,           /* Unknown action type. */
> -    OFPBAC_BAD_LEN,            /* Length problem in actions. */
> -    OFPBAC_BAD_VENDOR,         /* Unknown vendor id specified. */
> -    OFPBAC_BAD_VENDOR_TYPE,    /* Unknown action type for vendor id. */
> -    OFPBAC_BAD_OUT_PORT,       /* Problem validating output action. */
> -    OFPBAC_BAD_ARGUMENT,       /* Bad action argument. */
> -    OFPBAC_EPERM,              /* Permissions error. */
> -    OFPBAC_TOO_MANY,           /* Can't handle this many actions. */
> -    OFPBAC_BAD_QUEUE           /* Problem validating output queue. */
> -};
> -
> -/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED.  'data' contains
> - * at least the first 64 bytes of the failed request. */
> -enum ofp_flow_mod_failed_code {
> -    OFPFMFC_ALL_TABLES_FULL,    /* Flow not added because of full tables. */
> -    OFPFMFC_OVERLAP,            /* Attempted to add overlapping flow with
> -                                 * CHECK_OVERLAP flag set. */
> -    OFPFMFC_EPERM,              /* Permissions error. */
> -    OFPFMFC_BAD_EMERG_TIMEOUT,  /* Flow not added because of non-zero idle/hard
> -                                 * timeout. */
> -    OFPFMFC_BAD_COMMAND,        /* Unknown command. */
> -    OFPFMFC_UNSUPPORTED         /* Unsupported action list - cannot process in
> -                                   the order specified. */
> -};
> -
> -/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED.  'data' contains
> - * at least the first 64 bytes of the failed request. */
> -enum ofp_port_mod_failed_code {
> -    OFPPMFC_BAD_PORT,            /* Specified port does not exist. */
> -    OFPPMFC_BAD_HW_ADDR,         /* Specified hardware address is wrong. */
> -};
> -
> -/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
> - * at least the first 64 bytes of the failed request */
> -enum ofp_queue_op_failed_code {
> -    OFPQOFC_BAD_PORT,           /* Invalid port (or port does not exist). */
> -    OFPQOFC_BAD_QUEUE,          /* Queue does not exist. */
> -    OFPQOFC_EPERM               /* Permissions error. */
> -};
> -
>  /* OFPT_ERROR: Error message (datapath -> controller). */
>  struct ofp_error_msg {
>     struct ofp_header header;
> diff --git a/lib/.gitignore b/lib/.gitignore
> index c5b6cac..6cbaf30 100644
> --- a/lib/.gitignore
> +++ b/lib/.gitignore
> @@ -3,4 +3,4 @@
>  /dhparams.c
>  /dirs.c
>  /coverage-counters.c
> -/ofp-errors.c
> +/ofp-errors.inc
> diff --git a/lib/automake.mk b/lib/automake.mk
> index c0cc906..df27393 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -277,13 +277,12 @@ lib/dirs.c: lib/dirs.c.in Makefile
>             > lib/dirs.c.tmp
>        mv lib/dirs.c.tmp lib/dirs.c
>
> -$(srcdir)/lib/ofp-errors.c: \
> -       include/openflow/openflow.h include/openflow/nicira-ext.h \
> -       build-aux/extract-ofp-errors
> -       cd $(srcdir)/include && \
> -       $(PYTHON) ../build-aux/extract-ofp-errors \
> -               openflow/openflow.h openflow/nicira-ext.h > ../lib/ofp-errors.c
> -EXTRA_DIST += build-aux/extract-ofp-errors
> +$(srcdir)/lib/ofp-errors.inc: \
> +       lib/ofp-errors.h $(srcdir)/build-aux/extract-ofp-errors
> +       $(PYTHON) $(srcdir)/build-aux/extract-ofp-errors \
> +               $(srcdir)/lib/ofp-errors.h > $@.tmp && mv $@.tmp $@
> +lib/ofp-errors.c: lib/ofp-errors.inc
> +EXTRA_DIST += build-aux/extract-ofp-errors lib/ofp-errors.inc
>
>  INSTALL_DATA_LOCAL += lib-install-data-local
>  lib-install-data-local:
> diff --git a/lib/autopath.c b/lib/autopath.c
> index 9a39c6a..321b106 100644
> --- a/lib/autopath.c
> +++ b/lib/autopath.c
> @@ -23,6 +23,7 @@
>
>  #include "flow.h"
>  #include "nx-match.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "openflow/nicira-ext.h"
>  #include "vlog.h"
> @@ -75,7 +76,7 @@ autopath_parse(struct nx_action_autopath *ap, const char *s_)
>     free(s);
>  }
>
> -int
> +enum ofperr
>  autopath_check(const struct nx_action_autopath *ap, const struct flow *flow)
>  {
>     int n_bits = nxm_decode_n_bits(ap->ofs_nbits);
> @@ -84,7 +85,7 @@ autopath_check(const struct nx_action_autopath *ap, const struct flow *flow)
>     if (n_bits < 16) {
>         VLOG_WARN("at least 16 bit destination is required for autopath "
>                   "action.");
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     return nxm_dst_check(ap->dst, ofs, n_bits, flow);
> diff --git a/lib/autopath.h b/lib/autopath.h
> index 98b02b4..19e2d07 100644
> --- a/lib/autopath.h
> +++ b/lib/autopath.h
> @@ -18,6 +18,7 @@
>  #define AUTOPATH_H 1
>
>  #include <stdint.h>
> +#include "ofp-errors.h"
>
>  struct flow;
>  struct nx_action_autopath;
> @@ -29,6 +30,7 @@ struct nx_action_autopath;
>  void autopath_execute(const struct nx_action_autopath *, struct flow *,
>                       uint16_t ofp_port);
>  void autopath_parse(struct nx_action_autopath *, const char *);
> -int autopath_check(const struct nx_action_autopath *, const struct flow *);
> +enum ofperr autopath_check(const struct nx_action_autopath *,
> +                           const struct flow *);
>
>  #endif /* autopath.h */
> diff --git a/lib/bundle.c b/lib/bundle.c
> index af1be63..600514f 100644
> --- a/lib/bundle.c
> +++ b/lib/bundle.c
> @@ -24,6 +24,7 @@
>  #include "multipath.h"
>  #include "nx-match.h"
>  #include "ofpbuf.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "openflow/nicira-ext.h"
>  #include "vlog.h"
> @@ -100,8 +101,8 @@ bundle_execute_load(const struct nx_action_bundle *nab, struct flow *flow,
>  /* Checks that 'nab' specifies a bundle action which is supported by this
>  * bundle module.  Uses the 'max_ports' parameter to validate each port using
>  * ofputil_check_output_port().  Returns 0 if 'nab' is supported, otherwise an
> - * OpenFlow error code (as returned by ofp_mkerr()). */
> -int
> + * OFPERR_* error code. */
> +enum ofperr
>  bundle_check(const struct nx_action_bundle *nab, int max_ports,
>              const struct flow *flow)
>  {
> @@ -109,7 +110,7 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>     uint16_t n_slaves, fields, algorithm, subtype;
>     uint32_t slave_type;
>     size_t slaves_size, i;
> -    int error;
> +    enum ofperr error;
>
>     subtype = ntohs(nab->subtype);
>     n_slaves = ntohs(nab->n_slaves);
> @@ -118,7 +119,7 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>     slave_type = ntohl(nab->slave_type);
>     slaves_size = ntohs(nab->len) - sizeof *nab;
>
> -    error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +    error = OFPERR_OFPBAC_BAD_ARGUMENT;
>     if (!flow_hash_fields_valid(fields)) {
>         VLOG_WARN_RL(&rl, "unsupported fields %"PRIu16, fields);
>     } else if (n_slaves > BUNDLE_MAX_SLAVES) {
> @@ -135,13 +136,13 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>     for (i = 0; i < sizeof(nab->zero); i++) {
>         if (nab->zero[i]) {
>             VLOG_WARN_RL(&rl, "reserved field is nonzero");
> -            error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +            error = OFPERR_OFPBAC_BAD_ARGUMENT;
>         }
>     }
>
>     if (subtype == NXAST_BUNDLE && (nab->ofs_nbits || nab->dst)) {
>         VLOG_WARN_RL(&rl, "bundle action has nonzero reserved fields");
> -        error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        error = OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     if (subtype == NXAST_BUNDLE_LOAD) {
> @@ -151,7 +152,7 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>         if (n_bits < 16) {
>             VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit "
>                          "destination.");
> -            error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +            error = OFPERR_OFPBAC_BAD_ARGUMENT;
>         } else {
>             error = nxm_dst_check(nab->dst, ofs, n_bits, flow) || error;
>         }
> @@ -162,13 +163,14 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>                      "allocated for slaves.  %zu bytes are required for "
>                      "%"PRIu16" slaves.", subtype, slaves_size,
>                      n_slaves * sizeof(ovs_be16), n_slaves);
> -        error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
> +        error = OFPERR_OFPBAC_BAD_LEN;
>     }
>
>     for (i = 0; i < n_slaves; i++) {
>         uint16_t ofp_port = bundle_get_slave(nab, i);
> -        int ofputil_error = ofputil_check_output_port(ofp_port, max_ports);
> +        enum ofperr ofputil_error;
>
> +        ofputil_error = ofputil_check_output_port(ofp_port, max_ports);
>         if (ofputil_error) {
>             VLOG_WARN_RL(&rl, "invalid slave %"PRIu16, ofp_port);
>             error = ofputil_error;
> @@ -179,7 +181,7 @@ bundle_check(const struct nx_action_bundle *nab, int max_ports,
>          * seem to be a real-world use-case for supporting it. */
>         if (ofp_port == OFPP_CONTROLLER) {
>             VLOG_WARN_RL(&rl, "unsupported controller slave");
> -            error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
> +            error = OFPERR_OFPBAC_BAD_OUT_PORT;
>         }
>     }
>
> diff --git a/lib/bundle.h b/lib/bundle.h
> index 12497f7..580ecf8 100644
> --- a/lib/bundle.h
> +++ b/lib/bundle.h
> @@ -21,6 +21,7 @@
>  #include <stddef.h>
>  #include <stdint.h>
>
> +#include "ofp-errors.h"
>  #include "openflow/nicira-ext.h"
>  #include "openvswitch/types.h"
>
> @@ -38,8 +39,8 @@ uint16_t bundle_execute(const struct nx_action_bundle *, const struct flow *,
>  void bundle_execute_load(const struct nx_action_bundle *, struct flow *,
>                          bool (*slave_enabled)(uint16_t ofp_port, void *aux),
>                          void *aux);
> -int bundle_check(const struct nx_action_bundle *, int max_ports,
> -                 const struct flow *);
> +enum ofperr bundle_check(const struct nx_action_bundle *, int max_ports,
> +                         const struct flow *);
>  void bundle_parse(struct ofpbuf *, const char *);
>  void bundle_parse_load(struct ofpbuf *b, const char *);
>  void bundle_format(const struct nx_action_bundle *, struct ds *);
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 9cbf877..700b27a 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -30,6 +30,7 @@
>  #include "netdev.h"
>  #include "netlink.h"
>  #include "odp-util.h"
> +#include "ofp-errors.h"
>  #include "ofp-print.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
> @@ -1201,13 +1202,12 @@ log_operation(const struct dpif *dpif, const char *operation, int error)
>  {
>     if (!error) {
>         VLOG_DBG_RL(&dpmsg_rl, "%s: %s success", dpif_name(dpif), operation);
> -    } else if (is_errno(error)) {
> +    } else if (ofperr_is_valid(error)) {
>         VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
> -                     dpif_name(dpif), operation, strerror(error));
> +                     dpif_name(dpif), operation, ofperr_get_name(error));
>     } else {
> -        VLOG_WARN_RL(&error_rl, "%s: %s failed (%d/%d)",
> -                     dpif_name(dpif), operation,
> -                     get_ofp_err_type(error), get_ofp_err_code(error));
> +        VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
> +                     dpif_name(dpif), operation, strerror(error));
>     }
>  }
>
> diff --git a/lib/learn.c b/lib/learn.c
> index 9d97cb3..241f3d1 100644
> --- a/lib/learn.c
> +++ b/lib/learn.c
> @@ -22,6 +22,7 @@
>  #include "dynamic-string.h"
>  #include "meta-flow.h"
>  #include "nx-match.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
>  #include "openflow/openflow.h"
> @@ -81,7 +82,7 @@ learn_min_len(uint16_t header)
>     return min_len;
>  }
>
> -static int
> +static enum ofperr
>  learn_check_header(uint16_t header, size_t len)
>  {
>     int src_type = header & NX_LEARN_SRC_MASK;
> @@ -94,12 +95,12 @@ learn_check_header(uint16_t header, size_t len)
>          src_type == NX_LEARN_SRC_FIELD)) {
>         /* OK. */
>     } else {
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     /* Check that the arguments don't overrun the end of the action. */
>     if (len < learn_min_len(header)) {
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
> +        return OFPERR_OFPBAC_BAD_LEN;
>     }
>
>     return 0;
> @@ -107,7 +108,7 @@ learn_check_header(uint16_t header, size_t len)
>
>  /* Checks that 'learn' (which must be at least 'sizeof *learn' bytes long) is a
>  * valid action on 'flow'. */
> -int
> +enum ofperr
>  learn_check(const struct nx_action_learn *learn, const struct flow *flow)
>  {
>     struct cls_rule rule;
> @@ -118,7 +119,7 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
>     if (learn->flags & ~htons(OFPFF_SEND_FLOW_REM)
>         || !is_all_zeros(learn->pad, sizeof learn->pad)
>         || learn->table_id == 0xff) {
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     end = (char *) learn + ntohs(learn->len);
> @@ -128,8 +129,8 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
>         int src_type = header & NX_LEARN_SRC_MASK;
>         int dst_type = header & NX_LEARN_DST_MASK;
>
> +        enum ofperr error;
>         uint64_t value;
> -        int error;
>
>         if (!header) {
>             break;
> @@ -158,7 +159,6 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
>         if (dst_type == NX_LEARN_DST_MATCH || dst_type == NX_LEARN_DST_LOAD) {
>             ovs_be32 dst_field = get_be32(&p);
>             int dst_ofs = ntohs(get_be16(&p));
> -            int error;
>
>             error = (dst_type == NX_LEARN_DST_LOAD
>                      ? nxm_dst_check(dst_field, dst_ofs, n_bits, &rule.flow)
> @@ -175,7 +175,7 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
>         }
>     }
>     if (!is_all_zeros(p, (char *) end - (char *) p)) {
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     return 0;
> @@ -412,9 +412,9 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
>  {
>     char *orig = xstrdup(arg);
>     char *name, *value;
> +    enum ofperr error;
>     size_t learn_ofs;
>     size_t len;
> -    int error;
>
>     struct nx_action_learn *learn;
>     struct cls_rule rule;
> @@ -512,8 +512,7 @@ learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
>     /* In theory the above should have caught any errors, but... */
>     error = learn_check(learn, flow);
>     if (error) {
> -        char *msg = ofputil_error_to_string(error);
> -        ovs_fatal(0, "%s: %s", orig, msg);
> +        ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error));
>     }
>     free(orig);
>  }
> @@ -566,7 +565,7 @@ learn_format(const struct nx_action_learn *learn, struct ds *s)
>         int dst_ofs;
>         const struct mf_field *dst_field;
>
> -        int error;
> +        enum ofperr error;
>         int i;
>
>         if (!header) {
> @@ -574,11 +573,11 @@ learn_format(const struct nx_action_learn *learn, struct ds *s)
>         }
>
>         error = learn_check_header(header, (char *) end - (char *) p);
> -        if (error == ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT)) {
> +        if (error == OFPERR_OFPBAC_BAD_ARGUMENT) {
>             ds_put_format(s, ",***bad flow_mod_spec header %"PRIx16"***)",
>                           header);
>             return;
> -        } else if (error == ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN)) {
> +        } else if (error == OFPERR_OFPBAC_BAD_LEN) {
>             ds_put_format(s, ",***flow_mod_spec at offset %td is %u bytes "
>                           "long but only %td bytes are left***)",
>                           (char *) p - (char *) (learn + 1) - 2,
> diff --git a/lib/learn.h b/lib/learn.h
> index 19a9089..b83bee2 100644
> --- a/lib/learn.h
> +++ b/lib/learn.h
> @@ -17,6 +17,8 @@
>  #ifndef LEARN_H
>  #define LEARN_H 1
>
> +#include "ofp-errors.h"
> +
>  struct ds;
>  struct flow;
>  struct ofpbuf;
> @@ -28,7 +30,7 @@ struct nx_action_learn;
>  * See include/openflow/nicira-ext.h for NXAST_LEARN specification.
>  */
>
> -int learn_check(const struct nx_action_learn *, const struct flow *);
> +enum ofperr learn_check(const struct nx_action_learn *, const struct flow *);
>  void learn_execute(const struct nx_action_learn *, const struct flow *,
>                    struct ofputil_flow_mod *);
>
> diff --git a/lib/learning-switch.c b/lib/learning-switch.c
> index ecc5509..c47fcb6 100644
> --- a/lib/learning-switch.c
> +++ b/lib/learning-switch.c
> @@ -29,6 +29,7 @@
>  #include "hmap.h"
>  #include "mac-learning.h"
>  #include "ofpbuf.h"
> +#include "ofp-errors.h"
>  #include "ofp-parse.h"
>  #include "ofp-print.h"
>  #include "ofp-util.h"
> diff --git a/lib/multipath.c b/lib/multipath.c
> index f68dafd..80d801d 100644
> --- a/lib/multipath.c
> +++ b/lib/multipath.c
> @@ -23,6 +23,7 @@
>  #include <netinet/in.h>
>  #include "dynamic-string.h"
>  #include "nx-match.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "openflow/nicira-ext.h"
>  #include "packets.h"
> @@ -33,14 +34,14 @@ VLOG_DEFINE_THIS_MODULE(multipath);
>  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
>  /* multipath_check(). */
> -int
> +enum ofperr
>  multipath_check(const struct nx_action_multipath *mp, const struct flow *flow)
>  {
>     uint32_t n_links = ntohs(mp->max_link) + 1;
>     size_t min_n_bits = log_2_floor(n_links) + 1;
>     int ofs = nxm_decode_ofs(mp->ofs_nbits);
>     int n_bits = nxm_decode_n_bits(mp->ofs_nbits);
> -    int error;
> +    enum ofperr error;
>
>     error = nxm_dst_check(mp->dst, ofs, n_bits, flow);
>     if (error) {
> @@ -62,7 +63,7 @@ multipath_check(const struct nx_action_multipath *mp, const struct flow *flow)
>         return 0;
>     }
>
> -    return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +    return OFPERR_OFPBAC_BAD_ARGUMENT;
>  }
>
>  /* multipath_execute(). */
> diff --git a/lib/multipath.h b/lib/multipath.h
> index 8ac4bfd..3c4ff45 100644
> --- a/lib/multipath.h
> +++ b/lib/multipath.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2010 Nicira Networks.
> + * Copyright (c) 2010, 2011 Nicira Networks.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -18,6 +18,7 @@
>  #define MULTIPATH_H 1
>
>  #include <stdint.h>
> +#include "ofp-errors.h"
>
>  struct ds;
>  struct flow;
> @@ -29,7 +30,8 @@ struct nx_action_reg_move;
>  * See include/openflow/nicira-ext.h for NXAST_MULTIPATH specification.
>  */
>
> -int multipath_check(const struct nx_action_multipath *, const struct flow *);
> +enum ofperr multipath_check(const struct nx_action_multipath *,
> +                            const struct flow *);
>  void multipath_execute(const struct nx_action_multipath *, struct flow *);
>
>  void multipath_parse(struct nx_action_multipath *, const char *);
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 9b3c1e0..e8aee53 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -23,6 +23,7 @@
>  #include "classifier.h"
>  #include "dynamic-string.h"
>  #include "meta-flow.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
>  #include "openflow/nicira-ext.h"
> @@ -36,16 +37,6 @@ VLOG_DEFINE_THIS_MODULE(nx_match);
>  * peer and so there's not much point in showing a lot of them. */
>  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
> -enum {
> -    NXM_INVALID = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID),
> -    NXM_BAD_TYPE = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_TYPE),
> -    NXM_BAD_VALUE = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_VALUE),
> -    NXM_BAD_MASK = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_MASK),
> -    NXM_BAD_PREREQ = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_PREREQ),
> -    NXM_DUP_TYPE = OFP_MKERR_NICIRA(OFPET_BAD_REQUEST, NXBRC_NXM_DUP_TYPE),
> -    BAD_ARGUMENT = OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT)
> -};
> -
>  /* Returns the width of the data for a field with the given 'header', in
>  * bytes. */
>  int
> @@ -96,7 +87,7 @@ nx_entry_ok(const void *p, unsigned int match_len)
>     return header;
>  }
>
> -int
> +enum ofperr
>  nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
>               struct cls_rule *rule)
>  {
> @@ -108,29 +99,29 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
>         VLOG_DBG_RL(&rl, "nx_match length %u, rounded up to a "
>                     "multiple of 8, is longer than space in message (max "
>                     "length %zu)", match_len, b->size);
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     cls_rule_init_catchall(rule, priority);
>     while ((header = nx_entry_ok(p, match_len)) != 0) {
>         unsigned length = NXM_LENGTH(header);
>         const struct mf_field *mf;
> -        int error;
> +        enum ofperr error;
>
>         mf = mf_from_nxm_header(header);
>         if (!mf) {
> -            error = NXM_BAD_TYPE;
> +            error = OFPERR_NXBRC_NXM_BAD_TYPE;
>         } else if (!mf_are_prereqs_ok(mf, &rule->flow)) {
> -            error = NXM_BAD_PREREQ;
> +            error = OFPERR_NXBRC_NXM_BAD_PREREQ;
>         } else if (!mf_is_all_wild(mf, &rule->wc)) {
> -            error = NXM_DUP_TYPE;
> +            error = OFPERR_NXBRC_NXM_DUP_TYPE;
>         } else {
>             unsigned int width = mf->n_bytes;
>             union mf_value value;
>
>             memcpy(&value, p + 4, width);
>             if (!mf_is_value_valid(mf, &value)) {
> -                error = NXM_BAD_VALUE;
> +                error = OFPERR_NXBRC_NXM_BAD_VALUE;
>             } else if (!NXM_HASMASK(header)) {
>                 error = 0;
>                 mf_set_value(mf, &value, rule);
> @@ -139,7 +130,7 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
>
>                 memcpy(&mask, p + 4 + width, width);
>                 if (!mf_is_mask_valid(mf, &mask)) {
> -                    error = NXM_BAD_MASK;
> +                    error = OFPERR_NXBRC_NXM_BAD_MASK;
>                 } else {
>                     error = 0;
>                     mf_set(mf, &value, &mask, rule);
> @@ -148,15 +139,12 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
>         }
>
>         if (error) {
> -            char *msg = ofputil_error_to_string(error);
>             VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", "
>                         "field=%"PRIu32", hasmask=%"PRIu32", len=%"PRIu32"), "
>                         "(%s)", header,
>                         NXM_VENDOR(header), NXM_FIELD(header),
>                         NXM_HASMASK(header), NXM_LENGTH(header),
> -                        msg);
> -            free(msg);
> -
> +                        ofperr_to_string(error));
>             return error;
>         }
>
> @@ -164,7 +152,7 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
>         match_len -= 4 + length;
>     }
>
> -    return match_len ? NXM_INVALID : 0;
> +    return match_len ? OFPERR_NXBRC_NXM_INVALID : 0;
>  }
>
>  /* nx_put_match() and helpers.
> @@ -918,7 +906,7 @@ nxm_check_reg_move(const struct nx_action_reg_move *action,
>
>  /* Given a flow, checks that the source field represented by 'src_header'
>  * in the range ['ofs', 'ofs' + 'n_bits') is valid. */
> -int
> +enum ofperr
>  nxm_src_check(ovs_be32 src_header_, unsigned int ofs, unsigned int n_bits,
>               const struct flow *flow)
>  {
> @@ -933,12 +921,12 @@ nxm_src_check(ovs_be32 src_header_, unsigned int ofs, unsigned int n_bits,
>         return 0;
>     }
>
> -    return BAD_ARGUMENT;
> +    return OFPERR_OFPBAC_BAD_ARGUMENT;
>  }
>
>  /* Given a flow, checks that the destination field represented by 'dst_header'
>  * in the range ['ofs', 'ofs' + 'n_bits') is valid. */
> -int
> +enum ofperr
>  nxm_dst_check(ovs_be32 dst_header_, unsigned int ofs, unsigned int n_bits,
>               const struct flow *flow)
>  {
> @@ -955,16 +943,16 @@ nxm_dst_check(ovs_be32 dst_header_, unsigned int ofs, unsigned int n_bits,
>         return 0;
>     }
>
> -    return BAD_ARGUMENT;
> +    return OFPERR_OFPBAC_BAD_ARGUMENT;
>  }
>
> -int
> +enum ofperr
>  nxm_check_reg_load(const struct nx_action_reg_load *action,
>                    const struct flow *flow)
>  {
>     unsigned int ofs = nxm_decode_ofs(action->ofs_nbits);
>     unsigned int n_bits = nxm_decode_n_bits(action->ofs_nbits);
> -    int error;
> +    enum ofperr error;
>
>     error = nxm_dst_check(action->dst, ofs, n_bits, flow);
>     if (error) {
> @@ -974,7 +962,7 @@ nxm_check_reg_load(const struct nx_action_reg_load *action,
>     /* Reject 'action' if a bit numbered 'n_bits' or higher is set to 1 in
>      * action->value. */
>     if (n_bits < 64 && ntohll(action->value) >> n_bits) {
> -        return BAD_ARGUMENT;
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>
>     return 0;
> diff --git a/lib/nx-match.h b/lib/nx-match.h
> index faeacd6..5ad1618 100644
> --- a/lib/nx-match.h
> +++ b/lib/nx-match.h
> @@ -21,6 +21,7 @@
>  #include <sys/types.h>
>  #include <netinet/in.h>
>  #include "openvswitch/types.h"
> +#include "ofp-errors.h"
>
>  struct cls_rule;
>  struct ds;
> @@ -34,8 +35,8 @@ struct nx_action_reg_move;
>  * See include/openflow/nicira-ext.h for NXM specification.
>  */
>
> -int nx_pull_match(struct ofpbuf *, unsigned int match_len, uint16_t priority,
> -                  struct cls_rule *);
> +enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len,
> +                          uint16_t priority, struct cls_rule *);
>  int nx_put_match(struct ofpbuf *, const struct cls_rule *);
>
>  char *nx_match_to_string(const uint8_t *, unsigned int match_len);
> @@ -51,11 +52,12 @@ void nxm_format_reg_move(const struct nx_action_reg_move *, struct ds *);
>  void nxm_format_reg_load(const struct nx_action_reg_load *, struct ds *);
>
>  int nxm_check_reg_move(const struct nx_action_reg_move *, const struct flow *);
> -int nxm_check_reg_load(const struct nx_action_reg_load *, const struct flow *);
> -int nxm_src_check(ovs_be32 src, unsigned int ofs, unsigned int n_bits,
> -                  const struct flow *);
> -int nxm_dst_check(ovs_be32 dst, unsigned int ofs, unsigned int n_bits,
> -                  const struct flow *);
> +enum ofperr nxm_check_reg_load(const struct nx_action_reg_load *,
> +                               const struct flow *);
> +enum ofperr nxm_src_check(ovs_be32 src, unsigned int ofs, unsigned int n_bits,
> +                          const struct flow *);
> +enum ofperr nxm_dst_check(ovs_be32 dst, unsigned int ofs, unsigned int n_bits,
> +                          const struct flow *);
>
>  void nxm_execute_reg_move(const struct nx_action_reg_move *, struct flow *);
>  void nxm_execute_reg_load(const struct nx_action_reg_load *, struct flow *);
> diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c
> new file mode 100644
> index 0000000..785464e
> --- /dev/null
> +++ b/lib/ofp-errors.c
> @@ -0,0 +1,286 @@
> +#include <config.h>
> +#include "ofp-errors.h"
> +#include <errno.h>
> +#include "byte-order.h"
> +#include "dynamic-string.h"
> +#include "ofp-util.h"
> +#include "ofpbuf.h"
> +#include "openflow/openflow.h"
> +#include "vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(ofp_errors);
> +
> +struct pair {
> +    int type, code;
> +};
> +
> +#include "ofp-errors.inc"
> +
> +/* Returns an ofperr_domain that corresponds to the OpenFlow version number
> + * 'version' (one of the possible values of struct ofp_header's 'version'
> + * member).  Returns NULL if the version isn't defined or isn't understood by
> + * OVS. */
> +const struct ofperr_domain *
> +ofperr_domain_from_version(uint8_t version)
> +{
> +    return (version == ofperr_of10.version ? &ofperr_of10
> +            : version == ofperr_of11.version ? &ofperr_of11
> +            : NULL);
> +}
> +
> +/* Returns true if 'error' is a valid OFPERR_* value, false otherwise. */
> +bool
> +ofperr_is_valid(enum ofperr error)
> +{
> +    return error >= OFPERR_OFS && error < OFPERR_OFS + OFPERR_N_ERRORS;
> +}
> +
> +/* Returns true if 'error' is a valid OFPERR_* value that designates a whole
> + * category of errors instead of a particular error, e.g. if it is an
> + * OFPERR_OFPET_* value, and false otherwise.  */
> +bool
> +ofperr_is_category(enum ofperr error)
> +{
> +    return (ofperr_is_valid(error)
> +            && ofperr_of10.errors[error - OFPERR_OFS].code == -1
> +            && ofperr_of11.errors[error - OFPERR_OFS].code == -1);
> +}
> +
> +/* Returns true if 'error' is a valid OFPERR_* value that is a Nicira
> + * extension, e.g. if it is an OFPERR_NX* value, and false otherwise. */
> +bool
> +ofperr_is_nx_extension(enum ofperr error)
> +{
> +    return (ofperr_is_valid(error)
> +            && (ofperr_of10.errors[error - OFPERR_OFS].code >= 0x100 ||
> +                ofperr_of11.errors[error - OFPERR_OFS].code >= 0x100));
> +}
> +
> +/* Returns true if 'error' can be encoded as an OpenFlow error message in
> + * 'domain', false otherwise.
> + *
> + * A given error may not be encodable in some domains because each OpenFlow
> + * version tends to introduce new errors and retire some old ones. */
> +bool
> +ofperr_is_encodable(enum ofperr error, const struct ofperr_domain *domain)
> +{
> +    return (ofperr_is_valid(error)
> +            && domain->errors[error - OFPERR_OFS].code >= 0);
> +}
> +
> +/* Returns the OFPERR_* value that corresponds to 'type' and 'code' within
> + * 'domain', or 0 if no such OFPERR_* value exists. */
> +enum ofperr
> +ofperr_decode(const struct ofperr_domain *domain, uint16_t type, uint16_t code)
> +{
> +    return domain->decode(type, code);
> +}
> +
> +/* Returns the OFPERR_* value that corresponds to the category 'type' within
> + * 'domain', or 0 if no such OFPERR_* value exists. */
> +enum ofperr
> +ofperr_decode_type(const struct ofperr_domain *domain, uint16_t type)
> +{
> +    return domain->decode_type(type);
> +}
> +
> +/* Returns the name of 'error', e.g. "OFPBRC_BAD_TYPE" if 'error' is
> + * OFPBRC_BAD_TYPE, or "<invalid>" if 'error' is not a valid OFPERR_* value.
> + *
> + * Consider ofperr_to_string() instead, if the error code might be an errno
> + * value. */
> +const char *
> +ofperr_get_name(enum ofperr error)
> +{
> +    return (ofperr_is_valid(error)
> +            ? error_names[error - OFPERR_OFS]
> +            : "<invalid>");
> +}
> +
> +/* Returns an extended description name of 'error', e.g. "ofp_header.type not
> + * supported." if 'error' is OFPBRC_BAD_TYPE, or "<invalid>" if 'error' is not
> + * a valid OFPERR_* value. */
> +const char *
> +ofperr_get_description(enum ofperr error)
> +{
> +    return (ofperr_is_valid(error)
> +            ? error_comments[error - OFPERR_OFS]
> +            : "<invalid>");
> +}
> +
> +static struct ofpbuf *
> +ofperr_encode_msg__(enum ofperr error, const struct ofperr_domain *domain,
> +                    ovs_be32 xid, const void *data, size_t data_len)
> +{
> +    struct ofp_error_msg *oem;
> +    const struct pair *pair;
> +    struct ofpbuf *buf;
> +
> +    if (!domain) {
> +        return NULL;
> +    }
> +
> +    if (!ofperr_is_encodable(error, domain)) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> +
> +        if (!ofperr_is_valid(error)) {
> +            /* 'error' seems likely to be a system errno value. */
> +            VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)",
> +                         error, strerror(error));
> +        } else {
> +            const char *s = ofperr_get_name(error);
> +            if (ofperr_is_category(error)) {
> +                VLOG_WARN_RL(&rl, "cannot encode error category (%s)", s);
> +            } else {
> +                VLOG_WARN_RL(&rl, "cannot encode %s for %s", s, domain->name);
> +            }
> +        }
> +
> +        return NULL;
> +    }
> +
> +    pair = &domain->errors[MIN(error - OFPERR_OFS, OFPERR_N_ERRORS)];
> +    if (!ofperr_is_nx_extension(error)) {
> +        oem = make_openflow_xid(data_len + sizeof *oem, OFPT_ERROR, xid, &buf);
> +        oem->type = htons(pair->type);
> +        oem->code = htons(pair->code);
> +    } else {
> +        struct nx_vendor_error *nve;
> +
> +        oem = make_openflow_xid(data_len + sizeof *oem + sizeof *nve,
> +                                OFPT_ERROR, xid, &buf);
> +        oem->type = htons(NXET_VENDOR);
> +        oem->code = htons(NXVC_VENDOR_ERROR);
> +
> +        nve = (struct nx_vendor_error *)oem->data;
> +        nve->vendor = htonl(NX_VENDOR_ID);
> +        nve->type = htons(pair->type);
> +        nve->code = htons(pair->code);
> +    }
> +    oem->header.version = domain->version;
> +
> +    buf->size -= data_len;
> +    ofpbuf_put(buf, data, data_len);
> +
> +    return buf;
> +}
> +
> +/* Creates and returns an OpenFlow message of type OFPT_ERROR that conveys the
> + * given 'error'.
> + *
> + * 'oh->version' determines the OpenFlow version of the error reply.
> + * 'oh->xid' determines the xid of the error reply.
> + * The error reply will contain an initial subsequence of 'oh', up to
> + * 'oh->length' or 64 bytes, whichever is shorter.
> + *
> + * Returns NULL if 'error' is not an OpenFlow error code or if 'error' cannot
> + * be encoded as OpenFlow version 'oh->version'.
> + *
> + * This function isn't appropriate for encoding OFPET_HELLO_FAILED error
> + * messages.  Use ofperr_encode_hello() instead. */
> +struct ofpbuf *
> +ofperr_encode_reply(enum ofperr error, const struct ofp_header *oh)
> +{
> +    const struct ofperr_domain *domain;
> +    uint16_t len = ntohs(oh->length);
> +
> +    domain = ofperr_domain_from_version(oh->version);
> +    return ofperr_encode_msg__(error, domain, oh->xid, oh, MIN(len, 64));
> +}
> +
> +/* Creates and returns an OpenFlow message of type OFPT_ERROR that conveys the
> + * given 'error', in the error domain 'domain'.  The error message will include
> + * the additional null-terminated text string 's'.
> + *
> + * If 'domain' is NULL, uses the OpenFlow 1.0 error domain.  OFPET_HELLO_FAILED
> + * error messages are supposed to be backward-compatible, so in theory this
> + * should work.
> + *
> + * Returns NULL if 'error' is not an OpenFlow error code or if 'error' cannot
> + * be encoded in 'domain'. */
> +struct ofpbuf *
> +ofperr_encode_hello(enum ofperr error, const struct ofperr_domain *domain,
> +                    const char *s)
> +{
> +    if (!domain) {
> +        domain = &ofperr_of10;
> +    }
> +    return ofperr_encode_msg__(error, domain, htonl(0), s, strlen(s));
> +}
> +
> +/* Tries to decodes 'oh', which should be an OpenFlow OFPT_ERROR message.
> + * Returns an OFPERR_* constant on success, 0 on failure.
> + *
> + * If 'payload_ofs' is nonnull, on success '*payload_ofs' is set to the offset
> + * to the payload starting from 'oh' and on failure it is set to 0. */
> +enum ofperr
> +ofperr_decode_msg(const struct ofp_header *oh, size_t *payload_ofs)
> +{
> +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> +
> +    const struct ofperr_domain *domain;
> +    const struct ofp_error_msg *oem;
> +    uint16_t type, code;
> +    enum ofperr error;
> +    struct ofpbuf b;
> +
> +    if (payload_ofs) {
> +        *payload_ofs = 0;
> +    }
> +
> +    /* Pull off the error message. */
> +    ofpbuf_use_const(&b, oh, ntohs(oh->length));
> +    oem = ofpbuf_try_pull(&b, sizeof *oem);
> +    if (!oem) {
> +        return 0;
> +    }
> +
> +    /* Check message type and version. */
> +    if (oh->type != OFPT_ERROR) {
> +        return 0;
> +    }
> +    domain = ofperr_domain_from_version(oh->version);
> +    if (!domain) {
> +        return 0;
> +    }
> +
> +    /* Get the error type and code. */
> +    type = ntohs(oem->type);
> +    code = ntohs(oem->code);
> +    if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
> +        const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve);
> +        if (!nve) {
> +            return 0;
> +        }
> +
> +        if (nve->vendor != htonl(NX_VENDOR_ID)) {
> +            VLOG_WARN_RL(&rl, "error contains unknown vendor ID %#"PRIx32,
> +                         ntohl(nve->vendor));
> +            return 0;
> +        }
> +        type = ntohs(nve->type);
> +        code = ntohs(nve->code);
> +    }
> +
> +    /* Translate the error type and code into an ofperr.
> +     * If we don't know the error type and code, at least try for the type. */
> +    error = ofperr_decode(domain, type, code);
> +    if (!error) {
> +        error = ofperr_decode_type(domain, type);
> +    }
> +    if (error && payload_ofs) {
> +        *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh;
> +    }
> +    return error;
> +}
> +
> +/* If 'error' is a valid OFPERR_* value, returns its name
> + * (e.g. "OFPBRC_BAD_TYPE" for OFPBRC_BAD_TYPE).  Otherwise, assumes that
> + * 'error' is a positive errno value and returns what strerror() produces for
> + * 'error'.  */
> +const char *
> +ofperr_to_string(enum ofperr error)
> +{
> +    return ofperr_is_valid(error) ? ofperr_get_name(error) : strerror(error);
> +}
> +
> diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
> index d677b5d..fbd28e3 100644
> --- a/lib/ofp-errors.h
> +++ b/lib/ofp-errors.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010 Nicira Networks.
> + * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -17,12 +17,389 @@
>  #ifndef OFP_ERRORS_H
>  #define OFP_ERRORS_H 1
>
> +#include <stdbool.h>
> +#include <stddef.h>
>  #include <stdint.h>
>
> -/* These functions are building blocks for the ofputil_format_error() and
> - * ofputil_error_to_string() functions declared in ofp-util.h.  Those functions
> - * have friendlier interfaces and should usually be preferred. */
> -const char *ofp_error_type_to_string(uint16_t value);
> -const char *ofp_error_code_to_string(uint16_t type, uint16_t code);
> +struct ds;
> +struct ofp_header;
> +
> +/* Error codes.
> + *
> + * We embed system errno values and OpenFlow standard and vendor extension
> + * error codes into the positive range of "int":
> + *
> + *   - Errno values are assumed to use the range 1 through 2**30 - 1.
> + *
> + *     (C and POSIX say that errno values are positive.  We assume that they
> + *     are less than 2**29.  They are actually less than 65536 on at least
> + *     Linux, FreeBSD, OpenBSD, and Windows.)
> + *
> + *   - OpenFlow standard and vendor extension error codes use the range
> + *     starting at 2**30 (OFPERR_OFS).
> + *
> + * Zero and negative values are not used.
> + */
> +
> +#define OFPERR_OFS (1 << 30)
> +
> +enum ofperr {
> +/* ## ------------------ ## */
> +/* ## OFPET_HELLO_FAILED ## */
> +/* ## ------------------ ## */
> +
> +    /* OF(0).  Hello protocol failed. */
> +    OFPERR_OFPET_HELLO_FAILED = OFPERR_OFS,
> +
> +    /* OF(0,0).  No compatible version. */
> +    OFPERR_OFPHFC_INCOMPATIBLE,
> +
> +    /* OF(0,1).  Permissions error. */
> +    OFPERR_OFPHFC_EPERM,
> +
> +/* ## ----------------- ## */
> +/* ## OFPET_BAD_REQUEST ## */
> +/* ## ----------------- ## */
> +
> +    /* OF(1).  Request was not understood. */
> +    OFPERR_OFPET_BAD_REQUEST,
> +
> +    /* OF(1,0).  ofp_header.version not supported. */
> +    OFPERR_OFPBRC_BAD_VERSION,
> +
> +    /* OF(1,1).  ofp_header.type not supported. */
> +    OFPERR_OFPBRC_BAD_TYPE,
> +
> +    /* OF(1,2).  ofp_stats_msg.type not supported. */
> +    OFPERR_OFPBRC_BAD_STAT,
> +
> +    /* OF(1,3).  Vendor not supported (in ofp_vendor_header or
> +     * ofp_stats_msg). */
> +    OFPERR_OFPBRC_BAD_VENDOR,
> +
> +    /* OF(1,4).  Vendor subtype not supported. */
> +    OFPERR_OFPBRC_BAD_SUBTYPE,
> +
> +    /* OF(1,5).  Permissions error. */
> +    OFPERR_OFPBRC_EPERM,
> +
> +    /* OF(1,6).  Wrong request length for type. */
> +    OFPERR_OFPBRC_BAD_LEN,
> +
> +    /* OF(1,7).  Specified buffer has already been used. */
> +    OFPERR_OFPBRC_BUFFER_EMPTY,
> +
> +    /* OF(1,8).  Specified buffer does not exist. */
> +    OFPERR_OFPBRC_BUFFER_UNKNOWN,
> +
> +    /* OF1.1(1,9).  Specified table-id invalid or does not exist. */
> +    OFPERR_OFPBRC_BAD_TABLE_ID,
> +
> +    /* NX(1,256).  Invalid NXM flow match. */
> +    OFPERR_NXBRC_NXM_INVALID,
> +
> +    /* NX(1,257).  The nxm_type, or nxm_type taken in combination with
> +     * nxm_hasmask or nxm_length or both, is invalid or not implemented. */
> +    OFPERR_NXBRC_NXM_BAD_TYPE,
> +
> +    /* NX(1,258).  Invalid nxm_value. */
> +    OFPERR_NXBRC_NXM_BAD_VALUE,
> +
> +    /* NX(1,259).  Invalid nxm_mask. */
> +    OFPERR_NXBRC_NXM_BAD_MASK,
> +
> +    /* NX(1,260).  A prerequisite was not met. */
> +    OFPERR_NXBRC_NXM_BAD_PREREQ,
> +
> +    /* NX(1,261).  A given nxm_type was specified more than once. */
> +    OFPERR_NXBRC_NXM_DUP_TYPE,
> +
> +    /* NX(1,512).  A request specified a nonexistent table ID. */
> +    OFPERR_NXBRC_BAD_TABLE_ID,
> +
> +    /* NX(1,513).  NXT_ROLE_REQUEST specified an invalid role. */
> +    OFPERR_NXBRC_BAD_ROLE,
> +
> +    /* NX(1,514).  The in_port in an ofp_packet_out request is invalid. */
> +    OFPERR_NXBRC_BAD_IN_PORT,
> +
> +/* ## ---------------- ## */
> +/* ## OFPET_BAD_ACTION ## */
> +/* ## ---------------- ## */
> +
> +    /* OF(2).  Error in action description. */
> +    OFPERR_OFPET_BAD_ACTION,
> +
> +    /* OF(2,0).  Unknown action type. */
> +    OFPERR_OFPBAC_BAD_TYPE,
> +
> +    /* OF(2,1).  Length problem in actions. */
> +    OFPERR_OFPBAC_BAD_LEN,
> +
> +    /* OF(2,2).  Unknown experimenter id specified. */
> +    OFPERR_OFPBAC_BAD_VENDOR,
> +
> +    /* OF(2,3).  Unknown action type for experimenter id. */
> +    OFPERR_OFPBAC_BAD_VENDOR_TYPE,
> +
> +    /* OF(2,4).  Problem validating output port. */
> +    OFPERR_OFPBAC_BAD_OUT_PORT,
> +
> +    /* OF(2,5).  Bad action argument. */
> +    OFPERR_OFPBAC_BAD_ARGUMENT,
> +
> +    /* OF(2,6).  Permissions error. */
> +    OFPERR_OFPBAC_EPERM,
> +
> +    /* OF(2,7).  Can't handle this many actions. */
> +    OFPERR_OFPBAC_TOO_MANY,
> +
> +    /* OF(2,8).  Problem validating output queue. */
> +    OFPERR_OFPBAC_BAD_QUEUE,
> +
> +    /* OF1.1(2,9).  Invalid group id in forward action. */
> +    OFPERR_OFPBAC_BAD_OUT_GROUP,
> +
> +    /* OF1.1(2,10).  Action can't apply for this match. */
> +    OFPERR_OFPBAC_MATCH_INCONSISTENT,
> +
> +    /* OF1.1(2,11).  Action order is unsupported for the action list in an
> +     * Apply-Actions instruction */
> +    OFPERR_OFPBAC_UNSUPPORTED_ORDER,
> +
> +    /* OF1.1(2,12).  Actions uses an unsupported tag/encap. */
> +    OFPERR_OFPBAC_BAD_TAG,
> +
> +/* ## --------------------- ## */
> +/* ## OFPET_BAD_INSTRUCTION ## */
> +/* ## --------------------- ## */
> +
> +    /* OF1.1(3).  Error in instruction list. */
> +    OFPERR_OFPET_BAD_INSTRUCTION,
> +
> +    /* OF1.1(3,0).  Unknown instruction. */
> +    OFPERR_OFPBIC_UNKNOWN_INST,
> +
> +    /* OF1.1(3,1).  Switch or table does not support the instruction. */
> +    OFPERR_OFPBIC_UNSUP_INST,
> +
> +    /* OF1.1(3,2).  Invalid Table-ID specified. */
> +    OFPERR_OFPBIC_BAD_TABLE_ID,
> +
> +    /* OF1.1(3,3).  Metadata value unsupported by datapath. */
> +    OFPERR_OFPBIC_UNSUP_METADATA,
> +
> +    /* OF1.1(3,4).  Metadata mask value unsupported by datapath. */
> +    OFPERR_OFPBIC_UNSUP_METADATA_MASK,
> +
> +    /* OF1.1(3,5).  Specific experimenter instruction unsupported. */
> +    OFPERR_OFPBIC_UNSUP_EXP_INST,
> +
> +/* ## --------------- ## */
> +/* ## OFPET_BAD_MATCH ## */
> +/* ## --------------- ## */
> +
> +    /* OF1.1(4).  Error in match. */
> +    OFPERR_OFPET_BAD_MATCH,
> +
> +    /* OF1.1(4,0).  Unsupported match type specified by the match */
> +    OFPERR_OFPBMC_BAD_TYPE,
> +
> +    /* OF1.1(4,1).  Length problem in match. */
> +    OFPERR_OFPBMC_BAD_LEN,
> +
> +    /* OF1.1(4,2).  Match uses an unsupported tag/encap. */
> +    OFPERR_OFPBMC_BAD_TAG,
> +
> +    /* OF1.1(4,3).  Unsupported datalink addr mask - switch does not support
> +     * arbitrary datalink address mask. */
> +    OFPERR_OFPBMC_BAD_DL_ADDR_MASK,
> +
> +    /* OF1.1(4,4).  Unsupported network addr mask - switch does not support
> +     * arbitrary network address mask. */
> +    OFPERR_OFPBMC_BAD_NW_ADDR_MASK,
> +
> +    /* OF1.1(4,5).  Unsupported wildcard specified in the match. */
> +    OFPERR_OFPBMC_BAD_WILDCARDS,
> +
> +    /* OF1.1(4,6).  Unsupported field in the match. */
> +    OFPERR_OFPBMC_BAD_FIELD,
> +
> +    /* OF1.1(4,7).  Unsupported value in a match field. */
> +    OFPERR_OFPBMC_BAD_VALUE,
> +
> +/* ## --------------------- ## */
> +/* ## OFPET_FLOW_MOD_FAILED ## */
> +/* ## --------------------- ## */
> +
> +    /* OF1.0(3), OF1.1(5).  Problem modifying flow entry. */
> +    OFPERR_OFPET_FLOW_MOD_FAILED,
> +
> +    /* OF1.1(5,0).  Unspecified error. */
> +    OFPERR_OFPFMFC_UNKNOWN,
> +
> +    /* OF1.0(3,0).  Flow not added because of full tables. */
> +    OFPERR_OFPFMFC_ALL_TABLES_FULL,
> +
> +    /* OF1.1(5,1).  Flow not added because table was full. */
> +    OFPERR_OFPFMFC_TABLE_FULL,
> +
> +    /* OF1.1(5,2).  Table does not exist */
> +    OFPERR_OFPFMFC_BAD_TABLE_ID,
> +
> +    /* OF1.0(3,1), OF1.1(5,3).  Attempted to add overlapping flow with
> +     * CHECK_OVERLAP flag set. */
> +    OFPERR_OFPFMFC_OVERLAP,
> +
> +    /* OF1.0(3,2), OF1.1(5,4).  Permissions error. */
> +    OFPERR_OFPFMFC_EPERM,
> +
> +    /* OF1.1(5,5).  Flow not added because of unsupported idle/hard timeout. */
> +    OFPERR_OFPFMFC_BAD_TIMEOUT,
> +
> +    /* OF1.0(3,3).  Flow not added because of non-zero idle/hard timeout. */
> +    OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT,
> +
> +    /* OF1.0(3,4), OF1.1(5,6).  Unsupported or unknown command. */
> +    OFPERR_OFPFMFC_BAD_COMMAND,
> +
> +    /* OF1.0(3,5).  Unsupported action list - cannot process in the order
> +     * specified. */
> +    OFPERR_OFPFMFC_UNSUPPORTED,
> +
> +    /* NX1.0(3,256), NX1.1(5,256).  Generic hardware error. */
> +    OFPERR_NXFMFC_HARDWARE,
> +
> +    /* NX1.0(3,257), NX1.1(5,257).  A nonexistent table ID was specified in the
> +     * "command" field of struct ofp_flow_mod, when the nxt_flow_mod_table_id
> +     * extension is enabled. */
> +    OFPERR_NXFMFC_BAD_TABLE_ID,
> +
> +/* ## ---------------------- ## */
> +/* ## OFPET_GROUP_MOD_FAILED ## */
> +/* ## ---------------------- ## */
> +
> +    /* OF1.1(6).  Problem modifying group entry. */
> +    OFPERR_OFPET_GROUP_MOD_FAILED,
> +
> +    /* OF1.1(6,0).  Group not added because a group ADD attempted to replace an
> +     * already-present group. */
> +    OFPERR_OFPGMFC_GROUP_EXISTS,
> +
> +    /* OF1.1(6,1).  Group not added because Group specified is invalid. */
> +    OFPERR_OFPGMFC_INVALID_GROUP,
> +
> +    /* OF1.1(6,2).  Switch does not support unequal load sharing with select
> +     * groups. */
> +    OFPERR_OFPGMFC_WEIGHT_UNSUPPORTED,
> +
> +    /* OF1.1(6,3).  The group table is full. */
> +    OFPERR_OFPGMFC_OUT_OF_GROUPS,
> +
> +    /* OF1.1(6,4).  The maximum number of action buckets for a group has been
> +     * exceeded. */
> +    OFPERR_OFPGMFC_OUT_OF_BUCKETS,
> +
> +    /* OF1.1(6,5).  Switch does not support groups that forward to groups. */
> +    OFPERR_OFPGMFC_CHAINING_UNSUPPORTED,
> +
> +    /* OF1.1(6,6).  This group cannot watch the watch_port or watch_group
> +     * specified. */
> +    OFPERR_OFPGMFC_WATCH_UNSUPPORTED,
> +
> +    /* OF1.1(6,7).  Group entry would cause a loop. */
> +    OFPERR_OFPGMFC_LOOP,
> +
> +    /* OF1.1(6,8).  Group not modified because a group MODIFY attempted to
> +     * modify a non-existent group. */
> +    OFPERR_OFPGMFC_UNKNOWN_GROUP,
> +
> +/* ## --------------------- ## */
> +/* ## OFPET_PORT_MOD_FAILED ## */
> +/* ## --------------------- ## */
> +
> +    /* OF1.0(4), OF1.1(7).  OFPT_PORT_MOD failed. */
> +    OFPERR_OFPET_PORT_MOD_FAILED,
> +
> +    /* OF1.0(4,0), OF1.1(7,0).  Specified port does not exist. */
> +    OFPERR_OFPPMFC_BAD_PORT,
> +
> +    /* OF1.0(4,1), OF1.1(7,1).  Specified hardware address does not match the
> +     * port number. */
> +    OFPERR_OFPPMFC_BAD_HW_ADDR,
> +
> +    /* OF1.1(7,2).  Specified config is invalid. */
> +    OFPERR_OFPPMFC_BAD_CONFIG,
> +
> +    /* OF1.1(7,3).  Specified advertise is invalid. */
> +    OFPERR_OFPPMFC_BAD_ADVERTISE,
> +
> +/* ## ---------------------- ## */
> +/* ## OFPET_TABLE_MOD_FAILED ## */
> +/* ## ---------------------- ## */
> +
> +    /* OF1.1(8).  Table mod request failed. */
> +    OFPERR_OFPET_TABLE_MOD_FAILED,
> +
> +    /* OF1.1(8,0).  Specified table does not exist. */
> +    OFPERR_OFPTMFC_BAD_TABLE,
> +
> +    /* OF1.1(8,1).  Specified config is invalid. */
> +    OFPERR_OFPTMFC_BAD_CONFIG,
> +
> +/* ## --------------------- ## */
> +/* ## OFPET_QUEUE_OP_FAILED ## */
> +/* ## --------------------- ## */
> +
> +    /* OF1.0(5), OF1.1(9).  Queue operation failed. */
> +    OFPERR_OFPET_QUEUE_OP_FAILED,
> +
> +    /* OF1.0(5,0), OF1.1(9,0).  Invalid port (or port does not exist). */
> +    OFPERR_OFPQOFC_BAD_PORT,
> +
> +    /* OF1.0(5,1), OF1.1(9,1).  Queue does not exist. */
> +    OFPERR_OFPQOFC_BAD_QUEUE,
> +
> +    /* OF1.0(5,2), OF1.1(9,2).  Permissions error. */
> +    OFPERR_OFPQOFC_EPERM,
> +
> +/* ## -------------------------- ## */
> +/* ## OFPET_SWITCH_CONFIG_FAILED ## */
> +/* ## -------------------------- ## */
> +
> +    /* OF1.1(10).  Switch config request failed. */
> +    OFPERR_OFPET_SWITCH_CONFIG_FAILED,
> +
> +    /* OF1.1(10,0).  Specified flags is invalid. */
> +    OFPERR_OFPSCFC_BAD_FLAGS,
> +
> +    /* OF1.1(10,1).  Specified len is invalid. */
> +    OFPERR_OFPSCFC_BAD_LEN,
> +};
> +
> +extern const struct ofperr_domain ofperr_of10;
> +extern const struct ofperr_domain ofperr_of11;
> +
> +const struct ofperr_domain *ofperr_domain_from_version(uint8_t version);
> +
> +bool ofperr_is_valid(enum ofperr);
> +bool ofperr_is_category(enum ofperr);
> +bool ofperr_is_nx_extension(enum ofperr);
> +bool ofperr_is_encodable(enum ofperr, const struct ofperr_domain *);
> +
> +enum ofperr ofperr_decode(const struct ofperr_domain *,
> +                          uint16_t type, uint16_t code);
> +enum ofperr ofperr_decode_type(const struct ofperr_domain *, uint16_t type);
> +
> +enum ofperr ofperr_decode_msg(const struct ofp_header *, size_t *payload_ofs);
> +struct ofpbuf *ofperr_encode_reply(enum ofperr, const struct ofp_header *);
> +struct ofpbuf *ofperr_encode_hello(enum ofperr, const struct ofperr_domain *,
> +                                   const char *);
> +
> +const char *ofperr_get_name(enum ofperr);
> +const char *ofperr_get_description(enum ofperr);
> +
> +void ofperr_format(struct ds *, enum ofperr);
> +const char *ofperr_to_string(enum ofperr);
>
>  #endif /* ofp-errors.h */
> diff --git a/lib/ofp-print.c b/lib/ofp-print.c
> index 67f5883..632766c 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -34,6 +34,7 @@
>  #include "learn.h"
>  #include "multipath.h"
>  #include "nx-match.h"
> +#include "ofp-errors.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
>  #include "openflow/openflow.h"
> @@ -45,7 +46,7 @@
>  #include "util.h"
>
>  static void ofp_print_queue_name(struct ds *string, uint32_t port);
> -static void ofp_print_error(struct ds *, int error);
> +static void ofp_print_error(struct ds *, enum ofperr);
>
>
>  /* Returns a string that represents the contents of the Ethernet frame in the
> @@ -752,7 +753,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
>  {
>     struct ofputil_flow_mod fm;
>     bool need_priority;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_flow_mod(&fm, oh, true);
>     if (error) {
> @@ -851,7 +852,7 @@ static void
>  ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
>  {
>     struct ofputil_flow_removed fr;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_flow_removed(&fr, oh);
>     if (error) {
> @@ -902,14 +903,12 @@ ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
>  }
>
>  static void
> -ofp_print_error(struct ds *string, int error)
> +ofp_print_error(struct ds *string, enum ofperr error)
>  {
>     if (string->length) {
>         ds_put_char(string, ' ');
>     }
> -    ds_put_cstr(string, "***decode error: ");
> -    ofputil_format_error(string, error);
> -    ds_put_cstr(string, "***\n");
> +    ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
>  }
>
>  static void
> @@ -918,32 +917,26 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
>     size_t len = ntohs(oem->header.length);
>     size_t payload_ofs, payload_len;
>     const void *payload;
> -    int error;
> +    enum ofperr error;
>     char *s;
>
> -    error = ofputil_decode_error_msg(&oem->header, &payload_ofs);
> -    if (!is_ofp_error(error)) {
> -        ofp_print_error(string, error);
> +    error = ofperr_decode_msg(&oem->header, &payload_ofs);
> +    if (!error) {
> +        ds_put_cstr(string, "***decode error***");
>         ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
>         return;
>     }
>
> -    ds_put_char(string, ' ');
> -    ofputil_format_error(string, error);
> -    ds_put_char(string, '\n');
> +    ds_put_format(string, " %s\n", ofperr_get_name(error));
>
>     payload = (const uint8_t *) oem + payload_ofs;
>     payload_len = len - payload_ofs;
> -    switch (get_ofp_err_type(error)) {
> -    case OFPET_HELLO_FAILED:
> +    if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
>         ds_put_printable(string, payload, payload_len);
> -        break;
> -
> -    default:
> +    } else {
>         s = ofp_to_string(payload, payload_len, 1);
>         ds_put_cstr(string, s);
>         free(s);
> -        break;
>     }
>  }
>
> @@ -982,7 +975,7 @@ ofp_print_flow_stats_request(struct ds *string,
>                              const struct ofp_stats_msg *osm)
>  {
>     struct ofputil_flow_stats_request fsr;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
>     if (error) {
> @@ -1454,9 +1447,6 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
>     } else if (len < sizeof(struct ofp_header)) {
>         ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
>                       len);
> -    } else if (oh->version != OFP_VERSION) {
> -        ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n",
> -                      oh->version);
>     } else if (ntohs(oh->length) > len) {
>         ds_put_format(&string,
>                       "(***truncated to %zu bytes from %"PRIu16"***)\n",
> @@ -1467,7 +1457,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
>                       ntohs(oh->length), len);
>     } else {
>         const struct ofputil_msg_type *type;
> -        int error;
> +        enum ofperr error;
>
>         error = ofputil_decode_msg_type(oh, &type);
>         if (!error) {
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index ec0e864..cba4f32 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -289,10 +289,10 @@ struct ofputil_msg_category {
>     const char *name;           /* e.g. "OpenFlow message" */
>     const struct ofputil_msg_type *types;
>     size_t n_types;
> -    int missing_error;          /* ofp_mkerr() value for missing type. */
> +    enum ofperr missing_error;  /* Error value for missing type. */
>  };
>
> -static int
> +static enum ofperr
>  ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
>  {
>     switch (type->extra_multiple) {
> @@ -301,7 +301,7 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
>             VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
>                          "length %u (expected length %u)",
>                          type->name, size, type->min_size);
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +            return OFPERR_OFPBRC_BAD_LEN;
>         }
>         return 0;
>
> @@ -310,7 +310,7 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
>             VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
>                          "length %u (expected length at least %u bytes)",
>                          type->name, size, type->min_size);
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +            return OFPERR_OFPBRC_BAD_LEN;
>         }
>         return 0;
>
> @@ -322,13 +322,13 @@ ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
>                          "by an integer multiple of %u bytes)",
>                          type->name, size,
>                          type->min_size, type->extra_multiple);
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +            return OFPERR_OFPBRC_BAD_LEN;
>         }
>         return 0;
>     }
>  }
>
> -static int
> +static enum ofperr
>  ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
>                                 uint8_t version, uint32_t value,
>                                 const struct ofputil_msg_type **typep)
> @@ -348,7 +348,7 @@ ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
>     return cat->missing_error;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
>                       const struct ofputil_msg_type **typep)
>  {
> @@ -381,7 +381,7 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category nxt_category = {
>         "Nicira extension message",
>         nxt_messages, ARRAY_SIZE(nxt_messages),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
> +        OFPERR_OFPBRC_BAD_SUBTYPE
>     };
>
>     const struct ofp_vendor_header *ovh;
> @@ -391,14 +391,14 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
>         if (length == ntohs(oh->length)) {
>             VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor message");
>         }
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     ovh = (const struct ofp_vendor_header *) oh;
>     if (ovh->vendor != htonl(NX_VENDOR_ID)) {
>         VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor message for unknown "
>                      "vendor %"PRIx32, ntohl(ovh->vendor));
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
> +        return OFPERR_OFPBRC_BAD_VENDOR;
>     }
>
>     if (length < sizeof(struct nicira_header)) {
> @@ -408,7 +408,7 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
>                          ntohs(ovh->header.length),
>                          sizeof(struct nicira_header));
>         }
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     nh = (const struct nicira_header *) oh;
> @@ -416,7 +416,7 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
>                                            ntohl(nh->subtype), typep);
>  }
>
> -static int
> +static enum ofperr
>  check_nxstats_msg(const struct ofp_header *oh, size_t length)
>  {
>     const struct ofp_stats_msg *osm = (const struct ofp_stats_msg *) oh;
> @@ -426,27 +426,27 @@ check_nxstats_msg(const struct ofp_header *oh, size_t length)
>         if (length == ntohs(oh->length)) {
>             VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor stats message");
>         }
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     memcpy(&vendor, osm + 1, sizeof vendor);
>     if (vendor != htonl(NX_VENDOR_ID)) {
>         VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor stats message for "
>                      "unknown vendor %"PRIx32, ntohl(vendor));
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
> +        return OFPERR_OFPBRC_BAD_VENDOR;
>     }
>
>     if (length < sizeof(struct nicira_stats_msg)) {
>         if (length == ntohs(osm->header.length)) {
>             VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message");
>         }
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length,
>                             const struct ofputil_msg_type **typep)
>  {
> @@ -463,11 +463,11 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category nxst_request_category = {
>         "Nicira extension statistics request",
>         nxst_requests, ARRAY_SIZE(nxst_requests),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
> +        OFPERR_OFPBRC_BAD_SUBTYPE
>     };
>
>     const struct nicira_stats_msg *nsm;
> -    int error;
> +    enum ofperr error;
>
>     error = check_nxstats_msg(oh, length);
>     if (error) {
> @@ -479,7 +479,7 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length,
>                                            ntohl(nsm->subtype), typep);
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length,
>                           const struct ofputil_msg_type **typep)
>  {
> @@ -496,11 +496,11 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category nxst_reply_category = {
>         "Nicira extension statistics reply",
>         nxst_replies, ARRAY_SIZE(nxst_replies),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
> +        OFPERR_OFPBRC_BAD_SUBTYPE
>     };
>
>     const struct nicira_stats_msg *nsm;
> -    int error;
> +    enum ofperr error;
>
>     error = check_nxstats_msg(oh, length);
>     if (error) {
> @@ -512,20 +512,20 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length,
>                                            ntohl(nsm->subtype), typep);
>  }
>
> -static int
> +static enum ofperr
>  check_stats_msg(const struct ofp_header *oh, size_t length)
>  {
>     if (length < sizeof(struct ofp_stats_msg)) {
>         if (length == ntohs(oh->length)) {
>             VLOG_WARN_RL(&bad_ofmsg_rl, "truncated stats message");
>         }
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length,
>                              const struct ofputil_msg_type **typep)
>  {
> @@ -562,11 +562,11 @@ ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category ofpst_request_category = {
>         "OpenFlow statistics",
>         ofpst_requests, ARRAY_SIZE(ofpst_requests),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT)
> +        OFPERR_OFPBRC_BAD_STAT
>     };
>
>     const struct ofp_stats_msg *request = (const struct ofp_stats_msg *) oh;
> -    int error;
> +    enum ofperr error;
>
>     error = check_stats_msg(oh, length);
>     if (error) {
> @@ -582,7 +582,7 @@ ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length,
>     return error;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length,
>                            const struct ofputil_msg_type **typep)
>  {
> @@ -619,11 +619,11 @@ ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category ofpst_reply_category = {
>         "OpenFlow statistics",
>         ofpst_replies, ARRAY_SIZE(ofpst_replies),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT)
> +        OFPERR_OFPBRC_BAD_STAT
>     };
>
>     const struct ofp_stats_msg *reply = (const struct ofp_stats_msg *) oh;
> -    int error;
> +    enum ofperr error;
>
>     error = check_stats_msg(oh, length);
>     if (error) {
> @@ -638,7 +638,7 @@ ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length,
>     return error;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
>                           const struct ofputil_msg_type **typep)
>  {
> @@ -647,7 +647,7 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
>           OFPT_HELLO, "OFPT_HELLO",
>           sizeof(struct ofp_hello), 1 },
>
> -        { OFPUTIL_OFPT_ERROR, OFP10_VERSION,
> +        { OFPUTIL_OFPT_ERROR, 0,
>           OFPT_ERROR, "OFPT_ERROR",
>           sizeof(struct ofp_error_msg), 1 },
>
> @@ -727,10 +727,10 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
>     static const struct ofputil_msg_category ofpt_category = {
>         "OpenFlow message",
>         ofpt_messages, ARRAY_SIZE(ofpt_messages),
> -        OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE)
> +        OFPERR_OFPBRC_BAD_TYPE
>     };
>
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_lookup_openflow_message(&ofpt_category, oh->version,
>                                             oh->type, typep);
> @@ -754,22 +754,21 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
>     return error;
>  }
>
> -/* Decodes the message type represented by 'oh'.  Returns 0 if successful or
> - * an OpenFlow error code constructed with ofp_mkerr() on failure.  Either
> - * way, stores in '*typep' a type structure that can be inspected with the
> - * ofputil_msg_type_*() functions.
> +/* Decodes the message type represented by 'oh'.  Returns 0 if successful or an
> + * OpenFlow error code on failure.  Either way, stores in '*typep' a type
> + * structure that can be inspected with the ofputil_msg_type_*() functions.
>  *
>  * oh->length must indicate the correct length of the message (and must be at
>  * least sizeof(struct ofp_header)).
>  *
>  * Success indicates that 'oh' is at least as long as the minimum-length
>  * message of its type. */
> -int
> +enum ofperr
>  ofputil_decode_msg_type(const struct ofp_header *oh,
>                         const struct ofputil_msg_type **typep)
>  {
>     size_t length = ntohs(oh->length);
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_msg_type__(oh, length, typep);
>     if (!error) {
> @@ -783,18 +782,17 @@ ofputil_decode_msg_type(const struct ofp_header *oh,
>
>  /* Decodes the message type represented by 'oh', of which only the first
>  * 'length' bytes are available.  Returns 0 if successful or an OpenFlow error
> - * code constructed with ofp_mkerr() on failure.  Either way, stores in
> - * '*typep' a type structure that can be inspected with the
> - * ofputil_msg_type_*() functions.  */
> -int
> + * code on failure.  Either way, stores in '*typep' a type structure that can
> + * be inspected with the ofputil_msg_type_*() functions.  */
> +enum ofperr
>  ofputil_decode_msg_type_partial(const struct ofp_header *oh, size_t length,
>                                 const struct ofputil_msg_type **typep)
>  {
> -    int error;
> +    enum ofperr error;
>
>     error = (length >= sizeof *oh
>              ? ofputil_decode_msg_type__(oh, length, typep)
> -             : ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN));
> +             : OFPERR_OFPBRC_BAD_LEN);
>     if (error) {
>         *typep = &ofputil_invalid_type;
>     }
> @@ -952,7 +950,7 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
>  * enabled, false otherwise.
>  *
>  * Does not validate the flow_mod actions. */
> -int
> +enum ofperr
>  ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
>                         const struct ofp_header *oh, bool flow_mod_table_id)
>  {
> @@ -967,7 +965,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
>         /* Standard OpenFlow flow_mod. */
>         const struct ofp_flow_mod *ofm;
>         uint16_t priority;
> -        int error;
> +        enum ofperr error;
>
>         /* Dissect the message. */
>         ofm = ofpbuf_pull(&b, sizeof *ofm);
> @@ -1000,7 +998,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
>     } else if (ofputil_msg_type_code(type) == OFPUTIL_NXT_FLOW_MOD) {
>         /* Nicira extended flow_mod. */
>         const struct nx_flow_mod *nfm;
> -        int error;
> +        enum ofperr error;
>
>         /* Dissect the message. */
>         nfm = ofpbuf_pull(&b, sizeof *nfm);
> @@ -1096,7 +1094,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
>     return msg;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
>                                   const struct ofp_header *oh,
>                                   bool aggregate)
> @@ -1112,14 +1110,14 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
>                                  const struct ofp_header *oh,
>                                  bool aggregate)
>  {
>     const struct nx_flow_stats_request *nfsr;
>     struct ofpbuf b;
> -    int error;
> +    enum ofperr error;
>
>     ofpbuf_use_const(&b, oh, ntohs(oh->length));
>
> @@ -1129,7 +1127,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
>         return error;
>     }
>     if (b.size) {
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +        return OFPERR_OFPBRC_BAD_LEN;
>     }
>
>     fsr->aggregate = aggregate;
> @@ -1142,7 +1140,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
>  /* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE
>  * request 'oh', into an abstract flow_stats_request in 'fsr'.  Returns 0 if
>  * successful, otherwise an OpenFlow error code. */
> -int
> +enum ofperr
>  ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
>                                   const struct ofp_header *oh)
>  {
> @@ -1426,7 +1424,7 @@ ofputil_encode_aggregate_stats_reply(
>  /* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh' into an
>  * abstract ofputil_flow_removed in 'fr'.  Returns 0 if successful, otherwise
>  * an OpenFlow error code. */
> -int
> +enum ofperr
>  ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
>                             const struct ofp_header *oh)
>  {
> @@ -1462,7 +1460,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
>             return error;
>         }
>         if (b.size) {
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +            return OFPERR_OFPBRC_BAD_LEN;
>         }
>
>         fr->cookie = nfr->cookie;
> @@ -2059,8 +2057,8 @@ ofputil_frag_handling_from_string(const char *s, enum ofp_config_flags *flags)
>
>  /* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given
>  * that the switch will never have more than 'max_ports' ports.  Returns 0 if
> - * 'port' is valid, otherwise an ofp_mkerr() return code. */
> -int
> + * 'port' is valid, otherwise an OpenFlow return code. */
> +enum ofperr
>  ofputil_check_output_port(uint16_t port, int max_ports)
>  {
>     switch (port) {
> @@ -2077,7 +2075,7 @@ ofputil_check_output_port(uint16_t port, int max_ports)
>         if (port < max_ports) {
>             return 0;
>         }
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
> +        return OFPERR_OFPBAC_BAD_OUT_PORT;
>     }
>  }
>
> @@ -2143,16 +2141,16 @@ ofputil_format_port(uint16_t port, struct ds *s)
>     ds_put_cstr(s, name);
>  }
>
> -static int
> +static enum ofperr
>  check_resubmit_table(const struct nx_action_resubmit *nar)
>  {
>     if (nar->pad[0] || nar->pad[1] || nar->pad[2]) {
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +        return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  check_output_reg(const struct nx_action_output_reg *naor,
>                  const struct flow *flow)
>  {
> @@ -2160,7 +2158,7 @@ check_output_reg(const struct nx_action_output_reg *naor,
>
>     for (i = 0; i < sizeof naor->zero; i++) {
>         if (naor->zero[i]) {
> -            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +            return OFPERR_OFPBAC_BAD_ARGUMENT;
>         }
>     }
>
> @@ -2168,7 +2166,7 @@ check_output_reg(const struct nx_action_output_reg *naor,
>                          nxm_decode_n_bits(naor->ofs_nbits), flow);
>  }
>
> -int
> +enum ofperr
>  validate_actions(const union ofp_action *actions, size_t n_actions,
>                  const struct flow *flow, int max_ports)
>  {
> @@ -2176,20 +2174,16 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
>     size_t left;
>
>     OFPUTIL_ACTION_FOR_EACH (a, left, actions, n_actions) {
> +        enum ofperr error;
>         uint16_t port;
> -        int error;
>         int code;
>
>         code = ofputil_decode_action(a);
>         if (code < 0) {
> -            char *msg;
> -
>             error = -code;
> -            msg = ofputil_error_to_string(error);
>             VLOG_WARN_RL(&bad_ofmsg_rl,
>                          "action decoding error at offset %td (%s)",
> -                         (a - actions) * sizeof *a, msg);
> -            free(msg);
> +                         (a - actions) * sizeof *a, ofperr_get_name(error));
>
>             return error;
>         }
> @@ -2203,13 +2197,13 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
>
>         case OFPUTIL_OFPAT_SET_VLAN_VID:
>             if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
> -                error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +                error = OFPERR_OFPBAC_BAD_ARGUMENT;
>             }
>             break;
>
>         case OFPUTIL_OFPAT_SET_VLAN_PCP:
>             if (a->vlan_pcp.vlan_pcp & ~7) {
> -                error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
> +                error = OFPERR_OFPBAC_BAD_ARGUMENT;
>             }
>             break;
>
> @@ -2217,7 +2211,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
>             port = ntohs(((const struct ofp_action_enqueue *) a)->port);
>             if (port >= max_ports && port != OFPP_IN_PORT
>                 && port != OFPP_LOCAL) {
> -                error = ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);
> +                error = OFPERR_OFPBAC_BAD_OUT_PORT;
>             }
>             break;
>
> @@ -2280,17 +2274,15 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
>         }
>
>         if (error) {
> -            char *msg = ofputil_error_to_string(error);
>             VLOG_WARN_RL(&bad_ofmsg_rl, "bad action at offset %td (%s)",
> -                         (a - actions) * sizeof *a, msg);
> -            free(msg);
> +                         (a - actions) * sizeof *a, ofperr_get_name(error));
>             return error;
>         }
>     }
>     if (left) {
>         VLOG_WARN_RL(&bad_ofmsg_rl, "bad action format at offset %zu",
>                      (n_actions - left) * sizeof *a);
> -        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
> +        return OFPERR_OFPBAC_BAD_LEN;
>     }
>     return 0;
>  }
> @@ -2302,11 +2294,11 @@ struct ofputil_action {
>  };
>
>  static const struct ofputil_action action_bad_type
> -    = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),   0, UINT_MAX };
> +    = { -OFPERR_OFPBAC_BAD_TYPE,   0, UINT_MAX };
>  static const struct ofputil_action action_bad_len
> -    = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_LEN),    0, UINT_MAX };
> +    = { -OFPERR_OFPBAC_BAD_LEN,    0, UINT_MAX };
>  static const struct ofputil_action action_bad_vendor
> -    = { -OFP_MKERR(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR), 0, UINT_MAX };
> +    = { -OFPERR_OFPBAC_BAD_VENDOR, 0, UINT_MAX };
>
>  static const struct ofputil_action *
>  ofputil_decode_ofpat_action(const union ofp_action *a)
> @@ -2357,8 +2349,8 @@ ofputil_decode_nxast_action(const union ofp_action *a)
>  }
>
>  /* Parses 'a' to determine its type.  Returns a nonnegative OFPUTIL_OFPAT_* or
> - * OFPUTIL_NXAST_* constant if successful, otherwise a negative OpenFlow error
> - * code (as returned by ofp_mkerr()).
> + * OFPUTIL_NXAST_* constant if successful, otherwise a negative OFPERR_* error
> + * code.
>  *
>  * The caller must have already verified that 'a''s length is correct (that is,
>  * a->header.len is nonzero and a multiple of sizeof(union ofp_action) and no
> @@ -2378,7 +2370,7 @@ ofputil_decode_action(const union ofp_action *a)
>         switch (ntohl(a->vendor.vendor)) {
>         case NX_VENDOR_ID:
>             if (len < sizeof(struct nx_action_header)) {
> -                return -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
> +                return -OFPERR_OFPBAC_BAD_LEN;
>             }
>             action = ofputil_decode_nxast_action(a);
>             break;
> @@ -2390,7 +2382,7 @@ ofputil_decode_action(const union ofp_action *a)
>
>     return (len >= action->min_len && len <= action->max_len
>             ? action->code
> -            : -ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN));
> +            : -OFPERR_OFPBAC_BAD_LEN);
>  }
>
>  /* Parses 'a' and returns its type as an OFPUTIL_OFPAT_* or OFPUTIL_NXAST_*
> @@ -2617,207 +2609,6 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
>     }
>  }
>
> -static uint32_t
> -vendor_code_to_id(uint8_t code)
> -{
> -    switch (code) {
> -#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case NAME: return VENDOR_ID;
> -        OFPUTIL_VENDORS
> -#undef OFPUTIL_VENDOR
> -    default:
> -        return UINT32_MAX;
> -    }
> -}
> -
> -static int
> -vendor_id_to_code(uint32_t id)
> -{
> -    switch (id) {
> -#define OFPUTIL_VENDOR(NAME, VENDOR_ID) case VENDOR_ID: return NAME;
> -        OFPUTIL_VENDORS
> -#undef OFPUTIL_VENDOR
> -    default:
> -        return -1;
> -    }
> -}
> -
> -/* Creates and returns an OpenFlow message of type OFPT_ERROR with the error
> - * information taken from 'error', whose encoding must be as described in the
> - * large comment in ofp-util.h.  If 'oh' is nonnull, then the error will use
> - * oh->xid as its transaction ID, and it will include up to the first 64 bytes
> - * of 'oh'.
> - *
> - * Returns NULL if 'error' is not an OpenFlow error code. */
> -struct ofpbuf *
> -ofputil_encode_error_msg(int error, const struct ofp_header *oh)
> -{
> -    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> -
> -    struct ofpbuf *buf;
> -    const void *data;
> -    size_t len;
> -    uint8_t vendor;
> -    uint16_t type;
> -    uint16_t code;
> -    ovs_be32 xid;
> -
> -    if (!is_ofp_error(error)) {
> -        /* We format 'error' with strerror() here since it seems likely to be
> -         * a system errno value. */
> -        VLOG_WARN_RL(&rl, "invalid OpenFlow error code %d (%s)",
> -                     error, strerror(error));
> -        return NULL;
> -    }
> -
> -    if (oh) {
> -        xid = oh->xid;
> -        data = oh;
> -        len = ntohs(oh->length);
> -        if (len > 64) {
> -            len = 64;
> -        }
> -    } else {
> -        xid = 0;
> -        data = NULL;
> -        len = 0;
> -    }
> -
> -    vendor = get_ofp_err_vendor(error);
> -    type = get_ofp_err_type(error);
> -    code = get_ofp_err_code(error);
> -    if (vendor == OFPUTIL_VENDOR_OPENFLOW) {
> -        struct ofp_error_msg *oem;
> -
> -        oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR, xid, &buf);
> -        oem->type = htons(type);
> -        oem->code = htons(code);
> -    } else {
> -        struct ofp_error_msg *oem;
> -        struct nx_vendor_error *nve;
> -        uint32_t vendor_id;
> -
> -        vendor_id = vendor_code_to_id(vendor);
> -        if (vendor_id == UINT32_MAX) {
> -            VLOG_WARN_RL(&rl, "error %x contains invalid vendor code %d",
> -                         error, vendor);
> -            return NULL;
> -        }
> -
> -        oem = make_openflow_xid(len + sizeof *oem + sizeof *nve,
> -                                OFPT_ERROR, xid, &buf);
> -        oem->type = htons(NXET_VENDOR);
> -        oem->code = htons(NXVC_VENDOR_ERROR);
> -
> -        nve = (struct nx_vendor_error *)oem->data;
> -        nve->vendor = htonl(vendor_id);
> -        nve->type = htons(type);
> -        nve->code = htons(code);
> -    }
> -
> -    if (len) {
> -        buf->size -= len;
> -        ofpbuf_put(buf, data, len);
> -    }
> -
> -    return buf;
> -}
> -
> -/* Decodes 'oh', which should be an OpenFlow OFPT_ERROR message, and returns an
> - * Open vSwitch internal error code in the format described in the large
> - * comment in ofp-util.h.
> - *
> - * If 'payload_ofs' is nonnull, on success '*payload_ofs' is set to the offset
> - * to the payload starting from 'oh' and on failure it is set to 0. */
> -int
> -ofputil_decode_error_msg(const struct ofp_header *oh, size_t *payload_ofs)
> -{
> -    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> -
> -    const struct ofp_error_msg *oem;
> -    uint16_t type, code;
> -    struct ofpbuf b;
> -    int vendor;
> -
> -    if (payload_ofs) {
> -        *payload_ofs = 0;
> -    }
> -    if (oh->type != OFPT_ERROR) {
> -        return EPROTO;
> -    }
> -
> -    ofpbuf_use_const(&b, oh, ntohs(oh->length));
> -    oem = ofpbuf_try_pull(&b, sizeof *oem);
> -    if (!oem) {
> -        return EPROTO;
> -    }
> -
> -    type = ntohs(oem->type);
> -    code = ntohs(oem->code);
> -    if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
> -        const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve);
> -        if (!nve) {
> -            return EPROTO;
> -        }
> -
> -        vendor = vendor_id_to_code(ntohl(nve->vendor));
> -        if (vendor < 0) {
> -            VLOG_WARN_RL(&rl, "error contains unknown vendor ID %#"PRIx32,
> -                         ntohl(nve->vendor));
> -            return EPROTO;
> -        }
> -        type = ntohs(nve->type);
> -        code = ntohs(nve->code);
> -    } else {
> -        vendor = OFPUTIL_VENDOR_OPENFLOW;
> -    }
> -
> -    if (type >= 1024) {
> -        VLOG_WARN_RL(&rl, "error contains type %"PRIu16" greater than "
> -                     "supported maximum value 1023", type);
> -        return EPROTO;
> -    }
> -
> -    if (payload_ofs) {
> -        *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh;
> -    }
> -    return ofp_mkerr_vendor(vendor, type, code);
> -}
> -
> -void
> -ofputil_format_error(struct ds *s, int error)
> -{
> -    if (is_errno(error)) {
> -        ds_put_cstr(s, strerror(error));
> -    } else {
> -        uint16_t type = get_ofp_err_type(error);
> -        uint16_t code = get_ofp_err_code(error);
> -        const char *type_s = ofp_error_type_to_string(type);
> -        const char *code_s = ofp_error_code_to_string(type, code);
> -
> -        ds_put_format(s, "type ");
> -        if (type_s) {
> -            ds_put_cstr(s, type_s);
> -        } else {
> -            ds_put_format(s, "%"PRIu16, type);
> -        }
> -
> -        ds_put_cstr(s, ", code ");
> -        if (code_s) {
> -            ds_put_cstr(s, code_s);
> -        } else {
> -            ds_put_format(s, "%"PRIu16, code);
> -        }
> -    }
> -}
> -
> -char *
> -ofputil_error_to_string(int error)
> -{
> -    struct ds s = DS_EMPTY_INITIALIZER;
> -    ofputil_format_error(&s, error);
> -    return ds_steal_cstr(&s);
> -}
> -
>  /* Attempts to pull 'actions_len' bytes from the front of 'b'.  Returns 0 if
>  * successful, otherwise an OpenFlow error.
>  *
> @@ -2829,7 +2620,7 @@ ofputil_error_to_string(int error)
>  * do so, with validate_actions()).  The caller is also responsible for making
>  * sure that 'b->data' is initially aligned appropriately for "union
>  * ofp_action". */
> -int
> +enum ofperr
>  ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len,
>                      union ofp_action **actionsp, size_t *n_actionsp)
>  {
> @@ -2853,7 +2644,7 @@ ofputil_pull_actions(struct ofpbuf *b, unsigned int actions_len,
>  error:
>     *actionsp = NULL;
>     *n_actionsp = 0;
> -    return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
> +    return OFPERR_OFPBRC_BAD_LEN;
>  }
>
>  bool
> diff --git a/lib/ofp-util.h b/lib/ofp-util.h
> index 909467f..88e998e 100644
> --- a/lib/ofp-util.h
> +++ b/lib/ofp-util.h
> @@ -88,15 +88,16 @@ enum ofputil_msg_code {
>  };
>
>  struct ofputil_msg_type;
> -int ofputil_decode_msg_type(const struct ofp_header *,
> -                            const struct ofputil_msg_type **);
> -int ofputil_decode_msg_type_partial(const struct ofp_header *, size_t length,
> +enum ofperr ofputil_decode_msg_type(const struct ofp_header *,
>                                     const struct ofputil_msg_type **);
> +enum ofperr ofputil_decode_msg_type_partial(const struct ofp_header *,
> +                                            size_t length,
> +                                            const struct ofputil_msg_type **);
>  enum ofputil_msg_code ofputil_msg_type_code(const struct ofputil_msg_type *);
>  const char *ofputil_msg_type_name(const struct ofputil_msg_type *);
>
>  /* Port numbers. */
> -int ofputil_check_output_port(uint16_t ofp_port, int max_ports);
> +enum ofperr ofputil_check_output_port(uint16_t ofp_port, int max_ports);
>  bool ofputil_port_from_string(const char *, uint16_t *port);
>  void ofputil_format_port(uint16_t port, struct ds *);
>
> @@ -142,8 +143,9 @@ struct ofputil_flow_mod {
>     size_t n_actions;
>  };
>
> -int ofputil_decode_flow_mod(struct ofputil_flow_mod *,
> -                            const struct ofp_header *, bool flow_mod_table_id);
> +enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *,
> +                                    const struct ofp_header *,
> +                                    bool flow_mod_table_id);
>  struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *,
>                                        enum nx_flow_format,
>                                        bool flow_mod_table_id);
> @@ -156,8 +158,8 @@ struct ofputil_flow_stats_request {
>     uint8_t table_id;
>  };
>
> -int ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *,
> -                                      const struct ofp_header *);
> +enum ofperr ofputil_decode_flow_stats_request(
> +    struct ofputil_flow_stats_request *, const struct ofp_header *);
>  struct ofpbuf *ofputil_encode_flow_stats_request(
>     const struct ofputil_flow_stats_request *, enum nx_flow_format);
>
> @@ -204,8 +206,8 @@ struct ofputil_flow_removed {
>     uint64_t byte_count;        /* Byte count, UINT64_MAX if unknown. */
>  };
>
> -int ofputil_decode_flow_removed(struct ofputil_flow_removed *,
> -                                const struct ofp_header *);
> +enum ofperr ofputil_decode_flow_removed(struct ofputil_flow_removed *,
> +                                        const struct ofp_header *);
>  struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
>                                            enum nx_flow_format);
>
> @@ -397,160 +399,16 @@ ofputil_action_is_valid(const union ofp_action *a, size_t n_actions)
>          ((LEFT) -= ntohs((ITER)->header.len) / sizeof(union ofp_action), \
>           (ITER) = ofputil_action_next(ITER)))
>
> -int validate_actions(const union ofp_action *, size_t n_actions,
> -                     const struct flow *, int max_ports);
> +enum ofperr validate_actions(const union ofp_action *, size_t n_actions,
> +                             const struct flow *, int max_ports);
>  bool action_outputs_to_port(const union ofp_action *, ovs_be16 port);
>
> -int ofputil_pull_actions(struct ofpbuf *, unsigned int actions_len,
> -                         union ofp_action **, size_t *);
> +enum ofperr ofputil_pull_actions(struct ofpbuf *, unsigned int actions_len,
> +                                 union ofp_action **, size_t *);
>
>  bool ofputil_actions_equal(const union ofp_action *a, size_t n_a,
>                            const union ofp_action *b, size_t n_b);
>  union ofp_action *ofputil_actions_clone(const union ofp_action *, size_t n);
> -
> -/* OpenFlow vendors.
> - *
> - * These functions map OpenFlow 32-bit vendor IDs (as used in struct
> - * ofp_vendor_header) into 4-bit values to embed in an "int".  The 4-bit values
> - * are only used internally in Open vSwitch and never appear on the wire, so
> - * particular codes used are not important.
> - */
> -
> -/* Vendor error numbers currently used in Open vSwitch. */
> -#define OFPUTIL_VENDORS                                     \
> -    /*             vendor name              vendor value */ \
> -    OFPUTIL_VENDOR(OFPUTIL_VENDOR_OPENFLOW, 0x00000000)     \
> -    OFPUTIL_VENDOR(OFPUTIL_VENDOR_NICIRA,   NX_VENDOR_ID)
> -
> -/* OFPUTIL_VENDOR_* definitions. */
> -enum ofputil_vendor_codes {
> -#define OFPUTIL_VENDOR(NAME, VENDOR_ID) NAME,
> -    OFPUTIL_VENDORS
> -    OFPUTIL_N_VENDORS
> -#undef OFPUTIL_VENDOR
> -};
> -
> -/* Error codes.
> - *
> - * We embed system errno values and OpenFlow standard and vendor extension
> - * error codes into a single 31-bit space using the following encoding.
> - * (Bit 31 is unused and assumed 0 to avoid negative "int" values.)
> - *
> - *   30                                                   0
> - *  +------------------------------------------------------+
> - *  |                           0                          |  success
> - *  +------------------------------------------------------+
> - *
> - *   30 29                                                0
> - *  +--+---------------------------------------------------+
> - *  | 0|                    errno value                    |  errno value
> - *  +--+---------------------------------------------------+
> - *
> - *   30 29   26 25            16 15                       0
> - *  +--+-------+----------------+--------------------------+
> - *  | 1|   0   |      type      |           code           |  standard OpenFlow
> - *  +--+-------+----------------+--------------------------+  error
> - *
> - *   30 29   26 25            16 15                       0
> - *  +--+-------+----------------+--------------------------+  Nicira
> - *  | 1| vendor|      type      |           code           |  NXET_VENDOR
> - *  +--+-------+----------------+--------------------------+  error extension
> - *
> - * C and POSIX say that errno values are positive.  We assume that they are
> - * less than 2**29.  They are actually less than 65536 on at least Linux,
> - * FreeBSD, OpenBSD, and Windows.
> - *
> - * The 'vendor' field holds one of the OFPUTIL_VENDOR_* codes defined above.
> - * It must be nonzero.
> - *
> - * Negative values are not defined.
> - */
> -
> -/* Currently 4 bits are allocated to the "vendor" field.  Make sure that all
> - * the vendor codes can fit. */
> -BUILD_ASSERT_DECL(OFPUTIL_N_VENDORS <= 16);
> -
> -/* These are macro versions of the functions defined below.  The macro versions
> - * are intended for use in contexts where function calls are not allowed,
> - * e.g. static initializers and case labels. */
> -#define OFP_MKERR(TYPE, CODE) ((1 << 30) | ((TYPE) << 16) | (CODE))
> -#define OFP_MKERR_VENDOR(VENDOR, TYPE, CODE) \
> -        ((1 << 30) | ((VENDOR) << 26) | ((TYPE) << 16) | (CODE))
> -#define OFP_MKERR_NICIRA(TYPE, CODE) \
> -        OFP_MKERR_VENDOR(OFPUTIL_VENDOR_NICIRA, TYPE, CODE)
> -
> -/* Returns the standard OpenFlow error with the specified 'type' and 'code' as
> - * an integer. */
> -static inline int
> -ofp_mkerr(uint16_t type, uint16_t code)
> -{
> -    return OFP_MKERR(type, code);
> -}
> -
> -/* Returns the OpenFlow vendor error with the specified 'vendor', 'type', and
> - * 'code' as an integer.  'vendor' must be an OFPUTIL_VENDOR_* constant. */
> -static inline int
> -ofp_mkerr_vendor(uint8_t vendor, uint16_t type, uint16_t code)
> -{
> -    assert(vendor < OFPUTIL_N_VENDORS);
> -    return OFP_MKERR_VENDOR(vendor, type, code);
> -}
> -
> -/* Returns the OpenFlow vendor error with Nicira as vendor, with the specific
> - * 'type' and 'code', as an integer. */
> -static inline int
> -ofp_mkerr_nicira(uint16_t type, uint16_t code)
> -{
> -    return OFP_MKERR_NICIRA(type, code);
> -}
> -
> -/* Returns true if 'error' encodes an OpenFlow standard or vendor extension
> - * error codes as documented above. */
> -static inline bool
> -is_ofp_error(int error)
> -{
> -    return (error & (1 << 30)) != 0;
> -}
> -
> -/* Returns true if 'error' appears to be a system errno value. */
> -static inline bool
> -is_errno(int error)
> -{
> -    return !is_ofp_error(error);
> -}
> -
> -/* Returns the "vendor" part of the OpenFlow error code 'error' (which must be
> - * in the format explained above).  This is normally one of the
> - * OFPUTIL_VENDOR_* constants.  Returns OFPUTIL_VENDOR_OPENFLOW (0) for a
> - * standard OpenFlow error. */
> -static inline uint8_t
> -get_ofp_err_vendor(int error)
> -{
> -    return (error >> 26) & 0xf;
> -}
> -
> -/* Returns the "type" part of the OpenFlow error code 'error' (which must be in
> - * the format explained above). */
> -static inline uint16_t
> -get_ofp_err_type(int error)
> -{
> -    return (error >> 16) & 0x3ff;
> -}
> -
> -/* Returns the "code" part of the OpenFlow error code 'error' (which must be in
> - * the format explained above). */
> -static inline uint16_t
> -get_ofp_err_code(int error)
> -{
> -    return error & 0xffff;
> -}
> -
> -struct ofpbuf *ofputil_encode_error_msg(int error, const struct ofp_header *);
> -int ofputil_decode_error_msg(const struct ofp_header *, size_t *payload_ofs);
> -
> -/* String versions of errors. */
> -void ofputil_format_error(struct ds *, int error);
> -char *ofputil_error_to_string(int error);
>
>  /* Handy utility for parsing flows and actions. */
>  bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep);
> diff --git a/lib/vconn.c b/lib/vconn.c
> index 6ea9366..8e6374e 100644
> --- a/lib/vconn.c
> +++ b/lib/vconn.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010 Nicira Networks.
> + * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -27,6 +27,7 @@
>  #include "dynamic-string.h"
>  #include "fatal-signal.h"
>  #include "flow.h"
> +#include "ofp-errors.h"
>  #include "ofp-print.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
> @@ -442,7 +443,6 @@ vcs_recv_hello(struct vconn *vconn)
>  static void
>  vcs_send_error(struct vconn *vconn)
>  {
> -    struct ofp_error_msg *error;
>     struct ofpbuf *b;
>     char s[128];
>     int retval;
> @@ -450,11 +450,8 @@ vcs_send_error(struct vconn *vconn)
>     snprintf(s, sizeof s, "We support versions 0x%02x to 0x%02x inclusive but "
>              "you support no later than version 0x%02"PRIx8".",
>              vconn->min_version, OFP_VERSION, vconn->version);
> -    error = make_openflow(sizeof *error, OFPT_ERROR, &b);
> -    error->type = htons(OFPET_HELLO_FAILED);
> -    error->code = htons(OFPHFC_INCOMPATIBLE);
> -    ofpbuf_put(b, s, strlen(s));
> -    update_openflow_length(b);
> +    b = ofperr_encode_hello(OFPERR_OFPHFC_INCOMPATIBLE,
> +                            ofperr_domain_from_version(vconn->version), s);
>     retval = do_send(vconn, b);
>     if (retval) {
>         ofpbuf_delete(b);
> diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
> index 6432ba6..63cb133 100644
> --- a/ofproto/connmgr.c
> +++ b/ofproto/connmgr.c
> @@ -821,24 +821,22 @@ ofconn_send_replies(const struct ofconn *ofconn, struct list *replies)
>     }
>  }
>
> -/* Sends 'error', which should be an OpenFlow error created with
> - * e.g. ofp_mkerr(), on 'ofconn', as a reply to 'request'.  Only at most the
> +/* Sends 'error' on 'ofconn', as a reply to 'request'.  Only at most the
>  * first 64 bytes of 'request' are used. */
>  void
>  ofconn_send_error(const struct ofconn *ofconn,
> -                  const struct ofp_header *request, int error)
> +                  const struct ofp_header *request, enum ofperr error)
>  {
> -    struct ofpbuf *msg;
> +    struct ofpbuf *reply;
>
> -    msg = ofputil_encode_error_msg(error, request);
> -    if (msg) {
> +    reply = ofperr_encode_reply(error, request);
> +    if (reply) {
>         static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(10, 10);
>
>         if (!VLOG_DROP_INFO(&err_rl)) {
>             const struct ofputil_msg_type *type;
>             const char *type_name;
>             size_t request_len;
> -            char *error_s;
>
>             request_len = ntohs(request->length);
>             type_name = (!ofputil_decode_msg_type_partial(request,
> @@ -847,17 +845,16 @@ ofconn_send_error(const struct ofconn *ofconn,
>                          ? ofputil_msg_type_name(type)
>                          : "invalid");
>
> -            error_s = ofputil_error_to_string(error);
>             VLOG_INFO("%s: sending %s error reply to %s message",
> -                      rconn_get_name(ofconn->rconn), error_s, type_name);
> -            free(error_s);
> +                      rconn_get_name(ofconn->rconn), ofperr_to_string(error),
> +                      type_name);
>         }
> -        ofconn_send_reply(ofconn, msg);
> +        ofconn_send_reply(ofconn, reply);
>     }
>  }
>
>  /* Same as pktbuf_retrieve(), using the pktbuf owned by 'ofconn'. */
> -int
> +enum ofperr
>  ofconn_pktbuf_retrieve(struct ofconn *ofconn, uint32_t id,
>                        struct ofpbuf **bufferp, uint16_t *in_port)
>  {
> diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
> index 0224352..0040c98 100644
> --- a/ofproto/connmgr.h
> +++ b/ofproto/connmgr.h
> @@ -19,6 +19,7 @@
>
>  #include "hmap.h"
>  #include "list.h"
> +#include "ofp-errors.h"
>  #include "ofproto.h"
>  #include "openflow/nicira-ext.h"
>  #include "openvswitch/types.h"
> @@ -94,10 +95,10 @@ void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len);
>  void ofconn_send_reply(const struct ofconn *, struct ofpbuf *);
>  void ofconn_send_replies(const struct ofconn *, struct list *);
>  void ofconn_send_error(const struct ofconn *, const struct ofp_header *request,
> -                       int error);
> +                       enum ofperr);
>
> -int ofconn_pktbuf_retrieve(struct ofconn *, uint32_t id,
> -                           struct ofpbuf **bufferp, uint16_t *in_port);
> +enum ofperr ofconn_pktbuf_retrieve(struct ofconn *, uint32_t id,
> +                                   struct ofpbuf **bufferp, uint16_t *in_port);
>
>  bool ofconn_has_pending_opgroups(const struct ofconn *);
>  void ofconn_add_opgroup(struct ofconn *, struct list *);
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index e68bec3..2d3599c 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -3822,14 +3822,14 @@ rule_dealloc(struct rule *rule_)
>     free(rule);
>  }
>
> -static int
> +static enum ofperr
>  rule_construct(struct rule *rule_)
>  {
>     struct rule_dpif *rule = rule_dpif_cast(rule_);
>     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
>     struct rule_dpif *victim;
>     uint8_t table_id;
> -    int error;
> +    enum ofperr error;
>
>     error = validate_actions(rule->up.actions, rule->up.n_actions,
>                              &rule->up.cr.flow, ofproto->max_ports);
> @@ -3906,7 +3906,7 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes)
>     }
>  }
>
> -static int
> +static enum ofperr
>  rule_execute(struct rule *rule_, const struct flow *flow,
>              struct ofpbuf *packet)
>  {
> @@ -3936,7 +3936,7 @@ rule_modify_actions(struct rule *rule_)
>  {
>     struct rule_dpif *rule = rule_dpif_cast(rule_);
>     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
> -    int error;
> +    enum ofperr error;
>
>     error = validate_actions(rule->up.actions, rule->up.n_actions,
>                              &rule->up.cr.flow, ofproto->max_ports);
> @@ -4434,9 +4434,8 @@ xlate_learn_action(struct action_xlate_ctx *ctx,
>
>     error = ofproto_flow_mod(&ctx->ofproto->up, &fm);
>     if (error && !VLOG_DROP_WARN(&rl)) {
> -        char *msg = ofputil_error_to_string(error);
> -        VLOG_WARN("learning action failed to modify flow table (%s)", msg);
> -        free(msg);
> +        VLOG_WARN("learning action failed to modify flow table (%s)",
> +                  ofperr_get_name(error));
>     }
>
>     free(fm.actions);
> @@ -5411,16 +5410,16 @@ set_frag_handling(struct ofproto *ofproto_,
>     }
>  }
>
> -static int
> +static enum ofperr
>  packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
>            const struct flow *flow,
>            const union ofp_action *ofp_actions, size_t n_ofp_actions)
>  {
>     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
> -    int error;
> +    enum ofperr error;
>
>     if (flow->in_port >= ofproto->max_ports && flow->in_port < OFPP_MAX) {
> -        return ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_IN_PORT);
> +        return OFPERR_NXBRC_BAD_IN_PORT;
>     }
>
>     error = validate_actions(ofp_actions, n_ofp_actions, flow,
> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
> index 6c8583e..b995831 100644
> --- a/ofproto/ofproto-provider.h
> +++ b/ofproto/ofproto-provider.h
> @@ -23,6 +23,7 @@
>  #include "cfm.h"
>  #include "classifier.h"
>  #include "list.h"
> +#include "ofp-errors.h"
>  #include "shash.h"
>  #include "timeval.h"
>
> @@ -140,7 +141,7 @@ rule_from_cls_rule(const struct cls_rule *cls_rule)
>  void ofproto_rule_expire(struct rule *, uint8_t reason);
>  void ofproto_rule_destroy(struct rule *);
>
> -void ofoperation_complete(struct ofoperation *, int status);
> +void ofoperation_complete(struct ofoperation *, enum ofperr);
>  struct rule *ofoperation_get_victim(struct ofoperation *);
>
>  /* ofproto class structure, to be defined by each ofproto implementation.
> @@ -235,7 +236,7 @@ struct rule *ofoperation_get_victim(struct ofoperation *);
>  *
>  * Most of these functions return 0 if they are successful or a positive error
>  * code on failure.  Depending on the function, valid error codes are either
> - * errno values or OpenFlow error codes constructed with ofp_mkerr().
> + * errno values or OFPERR_* OpenFlow error codes.
>  *
>  * Most of these functions are expected to execute synchronously, that is, to
>  * block as necessary to obtain a result.  Thus, these functions may return
> @@ -624,7 +625,7 @@ struct ofproto_class {
>
>     /* Chooses an appropriate table for 'cls_rule' within 'ofproto'.  On
>      * success, stores the table ID into '*table_idp' and returns 0.  On
> -     * failure, returns an OpenFlow error code (as returned by ofp_mkerr()).
> +     * failure, returns an OpenFlow error code.
>      *
>      * The choice of table should be a function of 'cls_rule' and 'ofproto''s
>      * datapath capabilities.  It should not depend on the flows already in
> @@ -636,9 +637,9 @@ struct ofproto_class {
>      * should choose one arbitrarily (but deterministically).
>      *
>      * If this function is NULL then table 0 is always chosen. */
> -    int (*rule_choose_table)(const struct ofproto *ofproto,
> -                             const struct cls_rule *cls_rule,
> -                             uint8_t *table_idp);
> +    enum ofperr (*rule_choose_table)(const struct ofproto *ofproto,
> +                                     const struct cls_rule *cls_rule,
> +                                     uint8_t *table_idp);
>
>     /* Life-cycle functions for a "struct rule" (see "Life Cycle" above).
>      *
> @@ -749,8 +750,8 @@ struct ofproto_class {
>      *
>      *       * Call ofoperation_complete() and return 0.
>      *
> -     *       * Return an OpenFlow error code (as returned by ofp_mkerr()).  (Do
> -     *         not call ofoperation_complete() in this case.)
> +     *       * Return an OpenFlow error code.  (Do not call
> +     *         ofoperation_complete() in this case.)
>      *
>      *     Either way, ->rule_destruct() will not be called for 'rule', but
>      *     ->rule_dealloc() will be.
> @@ -775,7 +776,7 @@ struct ofproto_class {
>      *
>      * Rule destruction must not fail. */
>     struct rule *(*rule_alloc)(void);
> -    int (*rule_construct)(struct rule *rule);
> +    enum ofperr (*rule_construct)(struct rule *rule);
>     void (*rule_destruct)(struct rule *rule);
>     void (*rule_dealloc)(struct rule *rule);
>
> @@ -799,10 +800,9 @@ struct ofproto_class {
>      *
>      * The statistics for 'packet' should be included in 'rule'.
>      *
> -     * Returns 0 if successful, otherwise an OpenFlow error code (as returned
> -     * by ofp_mkerr()). */
> -    int (*rule_execute)(struct rule *rule, const struct flow *flow,
> -                        struct ofpbuf *packet);
> +     * Returns 0 if successful, otherwise an OpenFlow error code. */
> +    enum ofperr (*rule_execute)(struct rule *rule, const struct flow *flow,
> +                                struct ofpbuf *packet);
>
>     /* When ->rule_modify_actions() is called, the caller has already replaced
>      * the OpenFlow actions in 'rule' by a new set.  (The original actions are
> @@ -866,8 +866,7 @@ struct ofproto_class {
>      *
>      * This function must validate that the 'n_actions' elements in 'actions'
>      * are well-formed OpenFlow actions that can be correctly implemented by
> -     * the datapath.  If not, then it should return an OpenFlow error code (as
> -     * returned by ofp_mkerr()).
> +     * the datapath.  If not, then it should return an OpenFlow error code.
>      *
>      * 'flow' reflects the flow information for 'packet'.  All of the
>      * information in 'flow' is extracted from 'packet', except for
> @@ -877,12 +876,11 @@ struct ofproto_class {
>      * 'packet' is not matched against the OpenFlow flow table, so its
>      * statistics should not be included in OpenFlow flow statistics.
>      *
> -     * Returns 0 if successful, otherwise an OpenFlow error code (as returned
> -     * by ofp_mkerr()). */
> -    int (*packet_out)(struct ofproto *ofproto, struct ofpbuf *packet,
> -                      const struct flow *flow,
> -                      const union ofp_action *actions,
> -                      size_t n_actions);
> +     * Returns 0 if successful, otherwise an OpenFlow error code. */
> +    enum ofperr (*packet_out)(struct ofproto *ofproto, struct ofpbuf *packet,
> +                              const struct flow *flow,
> +                              const union ofp_action *actions,
> +                              size_t n_actions);
>
>  /* ## ------------------------- ## */
>  /* ## OFPP_NORMAL configuration ## */
> @@ -1095,10 +1093,11 @@ int ofproto_class_unregister(const struct ofproto_class *);
>  *
>  * ofproto.c also uses this value internally for additional (similar) purposes.
>  *
> - * This particular value is a good choice because it is negative (so it won't
> - * collide with any errno value or any value returned by ofp_mkerr()) and large
> - * (so it won't accidentally collide with EOF or a negative errno value). */
> -enum { OFPROTO_POSTPONE = -100000 };
> + * This particular value is a good choice because it is large, so that it does
> + * not collide with any errno value, but not large enough to collide with an
> + * OFPERR_* value. */
> +enum { OFPROTO_POSTPONE = 1 << 16 };
> +BUILD_ASSERT_DECL(OFPROTO_POSTPONE < OFPERR_OFS);
>
>  int ofproto_flow_mod(struct ofproto *, const struct ofputil_flow_mod *);
>  void ofproto_add_flow(struct ofproto *, const struct cls_rule *,
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index b7433fc..ccb5f91 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -31,6 +31,7 @@
>  #include "hmap.h"
>  #include "netdev.h"
>  #include "nx-match.h"
> +#include "ofp-errors.h"
>  #include "ofp-print.h"
>  #include "ofp-util.h"
>  #include "ofpbuf.h"
> @@ -136,13 +137,13 @@ static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
>
>  static void ofopgroup_destroy(struct ofopgroup *);
>
> -static int add_flow(struct ofproto *, struct ofconn *,
> -                    const struct ofputil_flow_mod *,
> -                    const struct ofp_header *);
> +static enum ofperr add_flow(struct ofproto *, struct ofconn *,
> +                            const struct ofputil_flow_mod *,
> +                            const struct ofp_header *);
>
>  static bool handle_openflow(struct ofconn *, struct ofpbuf *);
> -static int handle_flow_mod__(struct ofproto *, struct ofconn *,
> -                             const struct ofputil_flow_mod *,
> +static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *,
> +                                     const struct ofputil_flow_mod *,
>                              const struct ofp_header *);
>
>  static void update_port(struct ofproto *, const char *devname);
> @@ -1191,9 +1192,8 @@ ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule,
>  }
>
>  /* Executes the flow modification specified in 'fm'.  Returns 0 on success, an
> - * OpenFlow error code as encoded by ofp_mkerr() on failure, or
> - * OFPROTO_POSTPONE if the operation cannot be initiated now but may be retried
> - * later.
> + * OFPERR_* OpenFlow error code on failure, or OFPROTO_POSTPONE if the
> + * operation cannot be initiated now but may be retried later.
>  *
>  * This is a helper function for in-band control and fail-open. */
>  int
> @@ -1702,14 +1702,14 @@ rule_is_hidden(const struct rule *rule)
>     return rule->cr.priority > UINT16_MAX;
>  }
>
> -static int
> +static enum ofperr
>  handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     ofconn_send_reply(ofconn, make_echo_reply(oh));
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
> @@ -1741,7 +1741,7 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
> @@ -1757,7 +1757,7 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
>  {
>     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
> @@ -1786,20 +1786,22 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
>  }
>
>  /* Checks whether 'ofconn' is a slave controller.  If so, returns an OpenFlow
> - * error message code (composed with ofp_mkerr()) for the caller to propagate
> - * upward.  Otherwise, returns 0. */
> -static int
> -reject_slave_controller(const struct ofconn *ofconn)
> + * error message code for the caller to propagate upward.  Otherwise, returns
> + * 0.
> + *
> + * The log message mentions 'msg_type'. */
> +static enum ofperr
> +reject_slave_controller(struct ofconn *ofconn)
>  {
>     if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
>         && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) {
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
> +        return OFPERR_OFPBRC_EPERM;
>     } else {
>         return 0;
>     }
>  }
>
> -static int
> +static enum ofperr
>  handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofproto *p = ofconn_get_ofproto(ofconn);
> @@ -1809,8 +1811,8 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
>     struct ofpbuf request;
>     struct flow flow;
>     size_t n_ofp_actions;
> +    enum ofperr error;
>     uint16_t in_port;
> -    int error;
>
>     COVERAGE_INC(ofproto_packet_out);
>
> @@ -1850,7 +1852,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
>      * above) are valid. */
>     in_port = ntohs(opo->in_port);
>     if (in_port >= OFPP_MAX && in_port != OFPP_LOCAL && in_port != OFPP_NONE) {
> -        return ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_IN_PORT);
> +        return OFPERR_NXBRC_BAD_IN_PORT;
>     }
>
>     /* Send out packet. */
> @@ -1884,7 +1886,7 @@ update_port_config(struct ofport *port, ovs_be32 config, ovs_be32 mask)
>     }
>  }
>
> -static int
> +static enum ofperr
>  handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofproto *p = ofconn_get_ofproto(ofconn);
> @@ -1899,9 +1901,9 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>
>     port = ofproto_get_port(p, ntohs(opm->port_no));
>     if (!port) {
> -        return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT);
> +        return OFPERR_OFPPMFC_BAD_PORT;
>     } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
> -        return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR);
> +        return OFPERR_OFPPMFC_BAD_HW_ADDR;
>     } else {
>         update_port_config(port, opm->config, opm->mask);
>         if (opm->advertise) {
> @@ -1911,7 +1913,7 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_desc_stats_request(struct ofconn *ofconn,
>                           const struct ofp_stats_msg *request)
>  {
> @@ -1930,7 +1932,7 @@ handle_desc_stats_request(struct ofconn *ofconn,
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_table_stats_request(struct ofconn *ofconn,
>                            const struct ofp_stats_msg *request)
>  {
> @@ -1984,7 +1986,7 @@ append_port_stat(struct ofport *port, struct list *replies)
>     put_32aligned_be64(&ops->collisions, htonll(stats.collisions));
>  }
>
> -static int
> +static enum ofperr
>  handle_port_stats_request(struct ofconn *ofconn,
>                           const struct ofp_port_stats_request *psr)
>  {
> @@ -2018,12 +2020,12 @@ calc_flow_duration__(long long int start, uint32_t *sec, uint32_t *nsec)
>
>  /* Checks whether 'table_id' is 0xff or a valid table ID in 'ofproto'.  Returns
>  * 0 if 'table_id' is OK, otherwise an OpenFlow error code.  */
> -static int
> +static enum ofperr
>  check_table_id(const struct ofproto *ofproto, uint8_t table_id)
>  {
>     return (table_id == 0xff || table_id < ofproto->n_tables
>             ? 0
> -            : ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_TABLE_ID));
> +            : OFPERR_NXBRC_BAD_TABLE_ID);
>
>  }
>
> @@ -2079,13 +2081,13 @@ next_matching_table(struct ofproto *ofproto,
>  * Hidden rules are always omitted.
>  *
>  * Returns 0 on success, otherwise an OpenFlow error code. */
> -static int
> +static enum ofperr
>  collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
>                     const struct cls_rule *match, uint16_t out_port,
>                     struct list *rules)
>  {
>     struct classifier *cls;
> -    int error;
> +    enum ofperr error;
>
>     error = check_table_id(ofproto, table_id);
>     if (error) {
> @@ -2121,7 +2123,7 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
>  * Hidden rules are always omitted.
>  *
>  * Returns 0 on success, otherwise an OpenFlow error code. */
> -static int
> +static enum ofperr
>  collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
>                      const struct cls_rule *match, uint16_t out_port,
>                      struct list *rules)
> @@ -2151,7 +2153,7 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_flow_stats_request(struct ofconn *ofconn,
>                           const struct ofp_stats_msg *osm)
>  {
> @@ -2160,7 +2162,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
>     struct list replies;
>     struct list rules;
>     struct rule *rule;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
>     if (error) {
> @@ -2279,7 +2281,7 @@ ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto,
>             : -1);
>  }
>
> -static int
> +static enum ofperr
>  handle_aggregate_stats_request(struct ofconn *ofconn,
>                                const struct ofp_stats_msg *osm)
>  {
> @@ -2290,7 +2292,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
>     struct ofpbuf *reply;
>     struct list rules;
>     struct rule *rule;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_flow_stats_request(&request, &osm->header);
>     if (error) {
> @@ -2386,7 +2388,7 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
>     }
>  }
>
> -static int
> +static enum ofperr
>  handle_queue_stats_request(struct ofconn *ofconn,
>                            const struct ofp_queue_stats_request *qsr)
>  {
> @@ -2413,7 +2415,7 @@ handle_queue_stats_request(struct ofconn *ofconn,
>         }
>     } else {
>         ofpbuf_list_delete(&cbdata.replies);
> -        return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT);
> +        return OFPERR_OFPQOFC_BAD_PORT;
>     }
>     ofconn_send_replies(ofconn, &cbdata.replies);
>
> @@ -2445,12 +2447,12 @@ is_flow_deletion_pending(const struct ofproto *ofproto,
>  *
>  * Adds the flow specified by 'ofm', which is followed by 'n_actions'
>  * ofp_actions, to the ofproto's flow table.  Returns 0 on success, an OpenFlow
> - * error code as encoded by ofp_mkerr() on failure, or OFPROTO_POSTPONE if the
> - * operation cannot be initiated now but may be retried later.
> + * error code on failure, or OFPROTO_POSTPONE if the operation cannot be
> + * initiated now but may be retried later.
>  *
>  * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
>  * if any. */
> -static int
> +static enum ofperr
>  add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
>          const struct ofputil_flow_mod *fm, const struct ofp_header *request)
>  {
> @@ -2482,13 +2484,13 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
>     } else if (fm->table_id < ofproto->n_tables) {
>         table = &ofproto->tables[fm->table_id];
>     } else {
> -        return ofp_mkerr_nicira(OFPET_FLOW_MOD_FAILED, NXFMFC_BAD_TABLE_ID);
> +        return OFPERR_NXFMFC_BAD_TABLE_ID;
>     }
>
>     /* Check for overlap, if requested. */
>     if (fm->flags & OFPFF_CHECK_OVERLAP
>         && classifier_rule_overlaps(table, &fm->cr)) {
> -        return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
> +        return OFPERR_OFPFMFC_OVERLAP;
>     }
>
>     /* Serialize against pending deletion. */
> @@ -2552,7 +2554,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
>  * if any.
>  *
>  * Returns 0 on success, otherwise an OpenFlow error code. */
> -static int
> +static enum ofperr
>  modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
>                const struct ofputil_flow_mod *fm,
>                const struct ofp_header *request, struct list *rules)
> @@ -2580,12 +2582,12 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
>     return 0;
>  }
>
> -/* Implements OFPFC_MODIFY.  Returns 0 on success or an OpenFlow error code as
> - * encoded by ofp_mkerr() on failure.
> +/* Implements OFPFC_MODIFY.  Returns 0 on success or an OpenFlow error code on
> + * failure.
>  *
>  * 'ofconn' is used to retrieve the packet buffer specified in fm->buffer_id,
>  * if any. */
> -static int
> +static enum ofperr
>  modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
>                    const struct ofputil_flow_mod *fm,
>                    const struct ofp_header *request)
> @@ -2601,11 +2603,11 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
>  }
>
>  /* Implements OFPFC_MODIFY_STRICT.  Returns 0 on success or an OpenFlow error
> - * code as encoded by ofp_mkerr() on failure.
> + * code on failure.
>  *
>  * 'ofconn' is used to retrieve the packet buffer specified in fm->buffer_id,
>  * if any. */
> -static int
> +static enum ofperr
>  modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
>                    const struct ofputil_flow_mod *fm,
>                    const struct ofp_header *request)
> @@ -2627,7 +2629,7 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
>  /* Deletes the rules listed in 'rules'.
>  *
>  * Returns 0 on success, otherwise an OpenFlow error code. */
> -static int
> +static enum ofperr
>  delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
>                const struct ofp_header *request, struct list *rules)
>  {
> @@ -2648,13 +2650,13 @@ delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
>  }
>
>  /* Implements OFPFC_DELETE. */
> -static int
> +static enum ofperr
>  delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
>                    const struct ofputil_flow_mod *fm,
>                    const struct ofp_header *request)
>  {
>     struct list rules;
> -    int error;
> +    enum ofperr error;
>
>     error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, fm->out_port,
>                                 &rules);
> @@ -2665,13 +2667,13 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
>  }
>
>  /* Implements OFPFC_DELETE_STRICT. */
> -static int
> +static enum ofperr
>  delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
>                    const struct ofputil_flow_mod *fm,
>                    const struct ofp_header *request)
>  {
>     struct list rules;
> -    int error;
> +    enum ofperr error;
>
>     error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, fm->out_port,
>                                  &rules);
> @@ -2724,11 +2726,11 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason)
>     ofopgroup_submit(group);
>  }
>
> -static int
> +static enum ofperr
>  handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofputil_flow_mod fm;
> -    int error;
> +    enum ofperr error;
>
>     error = reject_slave_controller(ofconn);
>     if (error) {
> @@ -2746,13 +2748,13 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>     if (fm.flags & OFPFF_EMERG) {
>         /* There isn't a good fit for an error code, so just state that the
>          * flow table is full. */
> -        return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
> +        return OFPERR_OFPFMFC_ALL_TABLES_FULL;
>     }
>
>     return handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
>  }
>
> -static int
> +static enum ofperr
>  handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
>                   const struct ofputil_flow_mod *fm,
>                   const struct ofp_header *oh)
> @@ -2783,11 +2785,11 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
>             VLOG_WARN_RL(&rl, "flow_mod has explicit table_id but "
>                          "flow_mod_table_id extension is not enabled");
>         }
> -        return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND);
> +        return OFPERR_OFPFMFC_BAD_COMMAND;
>     }
>  }
>
> -static int
> +static enum ofperr
>  handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct nx_role_request *nrr = (struct nx_role_request *) oh;
> @@ -2796,13 +2798,13 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
>     uint32_t role;
>
>     if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) {
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
> +        return OFPERR_OFPBRC_EPERM;
>     }
>
>     role = ntohl(nrr->role);
>     if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
>         && role != NX_ROLE_SLAVE) {
> -        return ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_ROLE);
> +        return OFPERR_NXBRC_BAD_ROLE;
>     }
>
>     if (ofconn_get_role(ofconn) != role
> @@ -2819,7 +2821,7 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
>                              const struct ofp_header *oh)
>  {
> @@ -2830,7 +2832,7 @@ handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     const struct nx_set_flow_format *msg
> @@ -2839,7 +2841,7 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
>
>     format = ntohl(msg->format);
>     if (format != NXFF_OPENFLOW10 && format != NXFF_NXM) {
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
> +        return OFPERR_OFPBRC_EPERM;
>     }
>
>     if (format != ofconn_get_flow_format(ofconn)
> @@ -2852,7 +2854,7 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
>  {
>     struct ofp_header *ob;
> @@ -2867,12 +2869,12 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
>     return 0;
>  }
>
> -static int
> +static enum ofperr
>  handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
>  {
>     const struct ofp_header *oh = msg->data;
>     const struct ofputil_msg_type *type;
> -    int error;
> +    enum ofperr error;
>
>     error = ofputil_decode_msg_type(oh, &type);
>     if (error) {
> @@ -2966,9 +2968,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
>     case OFPUTIL_NXST_AGGREGATE_REPLY:
>     default:
>         if (oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY) {
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT);
> +            return OFPERR_OFPBRC_BAD_STAT;
>         } else {
> -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);
> +            return OFPERR_OFPBRC_BAD_TYPE;
>         }
>     }
>  }
> @@ -3114,8 +3116,7 @@ ofoperation_destroy(struct ofoperation *op)
>  }
>
>  /* Indicates that 'op' completed with status 'error', which is either 0 to
> - * indicate success or an OpenFlow error code (constructed with
> - * e.g. ofp_mkerr()).
> + * indicate success or an OpenFlow error code on failure.
>  *
>  * If 'error' is 0, indicating success, the operation will be committed
>  * permanently to the flow table.  There is one interesting subcase:
> @@ -3144,7 +3145,7 @@ ofoperation_destroy(struct ofoperation *op)
>  * Please see the large comment in ofproto/ofproto-provider.h titled
>  * "Asynchronous Operation Support" for more information. */
>  void
> -ofoperation_complete(struct ofoperation *op, int error)
> +ofoperation_complete(struct ofoperation *op, enum ofperr error)
>  {
>     struct ofopgroup *group = op->group;
>     struct rule *rule = op->rule;
> diff --git a/ofproto/pktbuf.c b/ofproto/pktbuf.c
> index fc4c66c..9382047 100644
> --- a/ofproto/pktbuf.c
> +++ b/ofproto/pktbuf.c
> @@ -152,8 +152,7 @@ pktbuf_get_null(void)
>  }
>
>  /* Attempts to retrieve a saved packet with the given 'id' from 'pb'.  Returns
> - * 0 if successful, otherwise an OpenFlow error code constructed with
> - * ofp_mkerr().
> + * 0 if successful, otherwise an OpenFlow error code.
>  *
>  * On success, ordinarily stores the buffered packet in '*bufferp' and the
>  * datapath port number on which the packet was received in '*in_port'.  The
> @@ -167,13 +166,13 @@ pktbuf_get_null(void)
>  * headroom.
>  *
>  * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
> -int
> +enum ofperr
>  pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
>                 uint16_t *in_port)
>  {
>     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 20);
>     struct packet *p;
> -    int error;
> +    enum ofperr error;
>
>     if (id == UINT32_MAX) {
>         error = 0;
> @@ -183,7 +182,7 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
>     if (!pb) {
>         VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
>                      "without buffers");
> -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
> +        return OFPERR_OFPBRC_BUFFER_UNKNOWN;
>     }
>
>     p = &pb->packets[id & PKTBUF_MASK];
> @@ -200,13 +199,13 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
>         } else {
>             COVERAGE_INC(pktbuf_reuse_error);
>             VLOG_WARN_RL(&rl, "attempt to reuse buffer %08"PRIx32, id);
> -            error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY);
> +            error = OFPERR_OFPBRC_BUFFER_EMPTY;
>         }
>     } else if (id >> PKTBUF_BITS != COOKIE_MAX) {
>         COVERAGE_INC(pktbuf_buffer_unknown);
>         VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
>                      id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
> -        error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
> +        error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
>     } else {
>         COVERAGE_INC(pktbuf_null_cookie);
>         VLOG_INFO_RL(&rl, "Received null cookie %08"PRIx32" (this is normal "
> diff --git a/ofproto/pktbuf.h b/ofproto/pktbuf.h
> index 67f4973..80bf540 100644
> --- a/ofproto/pktbuf.h
> +++ b/ofproto/pktbuf.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009 Nicira Networks.
> + * Copyright (c) 2008, 2009, 2011 Nicira Networks.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -19,6 +19,8 @@
>
>  #include <stdint.h>
>
> +#include "ofp-errors.h"
> +
>  struct pktbuf;
>  struct ofpbuf;
>
> @@ -28,8 +30,8 @@ struct pktbuf *pktbuf_create(void);
>  void pktbuf_destroy(struct pktbuf *);
>  uint32_t pktbuf_save(struct pktbuf *, struct ofpbuf *buffer, uint16_t in_port);
>  uint32_t pktbuf_get_null(void);
> -int pktbuf_retrieve(struct pktbuf *, uint32_t id, struct ofpbuf **bufferp,
> -                    uint16_t *in_port);
> +enum ofperr pktbuf_retrieve(struct pktbuf *, uint32_t id,
> +                            struct ofpbuf **bufferp, uint16_t *in_port);
>  void pktbuf_discard(struct pktbuf *, uint32_t id);
>
>  #endif /* pktbuf.h */
> diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> index df5dc9b..7c32697 100644
> --- a/tests/ofp-print.at
> +++ b/tests/ofp-print.at
> @@ -16,9 +16,11 @@ AT_CLEANUP
>
>  AT_SETUP([wrong OpenFlow version])
>  AT_KEYWORDS([ofp-print])
> -AT_CHECK([ovs-ofctl ofp-print aabbccddeeff0011], [0], [dnl
> -Bad OpenFlow version 170:
> -00000000  aa bb cc dd ee ff 00 11-                        |........        |
> +AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print 00bb0008eeff0011],
> +  [0], [dnl
> +***decode error: OFPBRC_BAD_TYPE***
> +00000000  00 bb 00 08 ee ff 00 11-                        |........        |
> +], [ofp_util|WARN|received OpenFlow message of unknown type 187
>  ])
>  AT_CLEANUP
>
> @@ -55,31 +57,66 @@ OFPT_HELLO (xid=0x0):
>  ])
>  AT_CLEANUP
>
> -AT_SETUP([OFPT_ERROR with type OFPET_HELLO_FAILED])
> +AT_SETUP([OFPT_ERROR with type OFPET_HELLO_FAILED - OF1.0])
>  AT_KEYWORDS([ofp-print])
>  AT_CHECK([ovs-ofctl ofp-print 010100170000000000000001657874726120646174610a], [0], [dnl
> -OFPT_ERROR (xid=0x0): type OFPET_HELLO_FAILED, code OFPHFC_EPERM
> +OFPT_ERROR (xid=0x0): OFPHFC_EPERM
>  extra data\012
>  ])
>  AT_CLEANUP
>
> -AT_SETUP([OFPT_ERROR with type OFPET_BAD_REQUEST])
> +AT_SETUP([OFPT_ERROR with type OFPET_HELLO_FAILED - OF1.1])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print 020100170000000000000001657874726120646174610a], [0], [dnl
> +OFPT_ERROR (xid=0x0): OFPHFC_EPERM
> +extra data\012
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_ERROR with type OFPET_BAD_REQUEST - OF1.0])
>  AT_KEYWORDS([ofp-print])
>  AT_CHECK([ovs-ofctl ofp-print 01010014000000000001000601bbccddeeff0011], [0], [dnl
> -OFPT_ERROR (xid=0x0): type OFPET_BAD_REQUEST, code OFPBRC_BAD_LEN
> +OFPT_ERROR (xid=0x0): OFPBRC_BAD_LEN
>  (***truncated to 8 bytes from 52445***)
>  00000000  01 bb cc dd ee ff 00 11-                        |........        |
>  ])
>  AT_CLEANUP
>
> -AT_SETUP([OFPT_ERROR with code NXBRC_NXM_BAD_PREREQ])
> +AT_SETUP([OFPT_ERROR with code NXBRC_NXM_BAD_PREREQ - OF1.0])
>  AT_KEYWORDS([ofp-print])
>  AT_CHECK([ovs-ofctl ofp-print '0101001c55555555 b0c20000 0000232000010104 0102000811111111'], [0], [dnl
> -OFPT_ERROR (xid=0x55555555): type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ
> +OFPT_ERROR (xid=0x55555555): NXBRC_NXM_BAD_PREREQ
> +OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_ERROR with code NXBRC_NXM_BAD_PREREQ - OF1.1])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print '0201001c55555555 b0c20000 0000232000010104 0102000811111111'], [0], [dnl
> +OFPT_ERROR (xid=0x55555555): NXBRC_NXM_BAD_PREREQ
>  OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
>  ])
>  AT_CLEANUP
>
> +dnl Error type 3, code 1 is OFPFMFC_OVERLAP in OF1.0
> +dnl and OFPBIC_UNSUP_INST in OF1.1, so check that value in both versions.
> +AT_SETUP([OFPT_ERROR with type OFPFMFC_OVERLAP - OF1.0])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print 01010014000000000003000101bbccddeeff0011], [0], [dnl
> +OFPT_ERROR (xid=0x0): OFPFMFC_OVERLAP
> +(***truncated to 8 bytes from 52445***)
> +00000000  01 bb cc dd ee ff 00 11-                        |........        |
> +])
> +AT_CLEANUP
> +AT_SETUP([OFPT_ERROR with type OFPBIC_UNSUP_INST - OF1.1])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print 02010014000000000003000102bbccddeeff0011], [0], [dnl
> +OFPT_ERROR (xid=0x0): OFPBIC_UNSUP_INST
> +(***truncated to 8 bytes from 52445***)
> +00000000  02 bb cc dd ee ff 00 11-                        |........        |
> +])
> +AT_CLEANUP
> +
>  AT_SETUP([OFPT_ECHO_REQUEST, empty payload])
>  AT_KEYWORDS([ofp-print])
>  AT_CHECK([ovs-ofctl ofp-print '01 02 00 08 00 00 00 01'], [0], [dnl
> @@ -180,7 +217,7 @@ ff fe 50 54 00 00 00 01 62 72 30 00 00 00 00 00 \
>  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
>  00 00 02 08 00 00 02 8f 00 00 02 8f \
>  "], [0], [dnl
> -***decode error: type OFPET_BAD_REQUEST, code OFPBRC_BAD_LEN***
> +***decode error: OFPBRC_BAD_LEN***
>  00000000  01 06 00 dc 00 00 00 01-00 00 50 54 00 00 00 01 |..........PT....|
>  00000010  00 00 01 00 02 00 00 00-00 00 00 87 00 00 0f ff |................|
>  00000020  ff fe 50 54 00 00 00 01-62 72 30 00 00 00 00 00 |..PT....br0.....|
> diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> index 2a458c8..acf5809 100644
> --- a/tests/ovs-ofctl.at
> +++ b/tests/ovs-ofctl.at
> @@ -390,7 +390,7 @@ NXM_OF_IN_PORT(0012), NXM_OF_ETH_TYPE(0800)
>
>  # vlan tci
>  NXM_OF_VLAN_TCI(f009)
> -nx_pull_match() returned error 44010105 (type OFPET_BAD_REQUEST, code NXBRC_NXM_DUP_TYPE)
> +nx_pull_match() returned error NXBRC_NXM_DUP_TYPE
>  NXM_OF_VLAN_TCI(0000)
>  NXM_OF_VLAN_TCI(3123)
>  NXM_OF_VLAN_TCI(0123)
> @@ -400,114 +400,114 @@ NXM_OF_VLAN_TCI_W(0000/e000)
>
>  # IP TOS
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0)
> -nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IP ECN
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_ECN(03)
> -nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IP protocol
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(05)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IP TTL
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_TTL(80)
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_TTL(ff)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IP source
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC(ac100014)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_SRC_W(c0a80000/ffff0000)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IP destination
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_DST(ac100014)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_DST_W(c0a80000/ffff0000)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # TCP source port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(4231)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # TCP destination port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST(4231)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # UDP source port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_SRC(8732)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # UDP destination port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST(1782)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ICMP type
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01), NXM_OF_ICMP_TYPE(12)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ICMP code
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01), NXM_OF_ICMP_CODE(12)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ARP opcode
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_OP(0001)
> -nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010105 (type OFPET_BAD_REQUEST, code NXBRC_NXM_DUP_TYPE)
> +nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_DUP_TYPE
>
>  # ARP source protocol address
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA(ac100014)
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_SPA_W(c0a81200/ffffff00)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ARP destination protocol address
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_TPA(ac100014)
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_TPA_W(c0a81200/ffffff00)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ARP source hardware address
>  NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_SHA(0002e30f80a4)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ARP destination hardware address
>  NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_THA(0002e30f80a4)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IPv6 source
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_SRC(20010db83c4d00010002000300040005)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IPv6 destination
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_DST(20010db83c4d00010002000300040005)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_DST_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ND source hardware address
>  NXM_OF_ETH_TYPE(86dd), NXM_OF_IP_PROTO(3a), NXM_NX_ICMPV6_TYPE(87), NXM_NX_ND_TARGET(20010db83c4d00010002000300040005), NXM_NX_ND_SLL(0002e30f80a4)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # ND destination hardware address
>  NXM_OF_ETH_TYPE(86dd), NXM_OF_IP_PROTO(3a), NXM_NX_ICMPV6_TYPE(88), NXM_NX_ND_TARGET(20010db83c4d00010002000300040005), NXM_NX_ND_TLL(0002e30f80a4)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> -nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
>
>  # IPv4 fragments.
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG(00)
> @@ -520,7 +520,7 @@ NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG_W(00/02)
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG_W(01/01)
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG_W(02/02)
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG(03)
> -nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
> +nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
>
>  # IPv6 fragments.
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG(00)
> @@ -533,7 +533,7 @@ NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG_W(00/02)
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG_W(01/01)
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG_W(02/02)
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG(03)
> -nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
> +nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
>
>  # Tunnel ID.
>  NXM_NX_TUN_ID(00000000abcdef01)
> @@ -544,7 +544,7 @@ NXM_NX_REG0(acebdf56)
>  NXM_NX_REG0_W(a0e0d050/f0f0f0f0)
>
>  # Invalid field number.
> -nx_pull_match() returned error 44010101 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_TYPE)
> +nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
>
>  # Unimplemented registers.
>  #
> @@ -552,8 +552,8 @@ nx_pull_match() returned error 44010101 (type OFPET_BAD_REQUEST, code NXBRC_NXM_
>  # registers are implemented.
>  NXM_NX_REG0(12345678)
>  NXM_NX_REG0_W(12345678/12345678)
> -nx_pull_match() returned error 44010101 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_TYPE)
> -nx_pull_match() returned error 44010101 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_TYPE)
> +nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
> +nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
>  ])
>  AT_CLEANUP
>
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index cf77300..bd184b8 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -36,6 +36,7 @@
>  #include "netlink.h"
>  #include "nx-match.h"
>  #include "odp-util.h"
> +#include "ofp-errors.h"
>  #include "ofp-parse.h"
>  #include "ofp-print.h"
>  #include "ofp-util.h"
> @@ -1455,8 +1456,8 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
>     while (!ds_get_line(&in, stdin)) {
>         struct ofpbuf nx_match;
>         struct cls_rule rule;
> +        enum ofperr error;
>         int match_len;
> -        int error;
>         char *s;
>
>         /* Delete comments, skip blank lines. */
> @@ -1492,8 +1493,8 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
>             puts(out);
>             free(out);
>         } else {
> -            printf("nx_pull_match() returned error %x (%s)\n", error,
> -                   ofputil_error_to_string(error));
> +            printf("nx_pull_match() returned error %s\n",
> +                   ofperr_get_name(error));
>         }
>
>         ofpbuf_uninit(&nx_match);
> --
> 1.7.2.5
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list