On Mon, Mar 26, 2012 at 01:59:20PM -0700, Ben Pfaff wrote:
> From: Simon Horman <ho...@verge.net.au>
> 
> * Where Open Flow 1.2 breaks apart error codes defined
>   in previous versions, provide all new definitions to
>   previous versions and map the numeric error code to
>   the first first definition supplied in ofp-errors.h.
>   The case handled so far is:
>   OFPERR_OFPBIC_BAD_EXP_TYPE -> { OFPERR_OFPBIC_BAD_EXPERIMENTER,
>                                   OFPERR_OFPBIC_BAD_EXP_TYPE }
> 
> * Where Open Flow 1.2 adds error codes that were previously
>   defined as Nicira extension errors define the later in terms
>   of the new codes.
> 
> Signed-off-by: Simon Horman <ho...@verge.net.au>
> [b...@nicira.com added better error checking in extract-ofp-errors, added
>  unit tests, miscellaneous cleanup]
> Signed-off-by: Ben Pfaff <b...@nicira.com>

Hi Ben,

this looks much more robust than my attempt. Ack.

> ---
>  build-aux/extract-ofp-errors |   92 ++++++++++++++++++++++++------
>  lib/nx-match.c               |   16 +++---
>  lib/ofp-errors.c             |   61 +++++++++++++++++++-
>  lib/ofp-errors.h             |  128 
> ++++++++++++++++++++++++++++++++++++------
>  ofproto/ofproto.c            |    2 +-
>  tests/automake.mk            |    1 +
>  tests/ofp-errors.at          |   97 +++++++++++++++++++++++++++++++
>  tests/ofp-print.at           |   60 +-------------------
>  tests/ovs-ofctl.at           |   94 +++++++++++++++---------------
>  tests/testsuite.at           |    1 +
>  utilities/ovs-ofctl.c        |   29 ++++++++++
>  11 files changed, 427 insertions(+), 154 deletions(-)
>  create mode 100644 tests/ofp-errors.at
> 
> diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
> index 4b3d46b..7054408 100755
> --- a/build-aux/extract-ofp-errors
> +++ b/build-aux/extract-ofp-errors
> @@ -66,8 +66,14 @@ def getToken():
>                  token = None
>                  return False
>  
> -def fatal(msg):
> +n_errors = 0
> +def error(msg):
> +    global n_errors
>      sys.stderr.write("%s:%d: %s\n" % (fileName, lineNumber, msg))
> +    n_errors += 1
> +
> +def fatal(msg):
> +    error(msg)
>      sys.exit(1)
>  
>  def skipDirective():
> @@ -145,10 +151,13 @@ def extract_ofp_errors(filenames):
>      names = []
>      domain = {}
>      reverse = {}
> -    for domain_name in ("OF1.0", "OF1.1", "NX1.0", "NX1.1"):
> +    for domain_name in ("OF1.0", "OF1.1", "OF1.2", "NX1.0", "NX1.1"):
>          domain[domain_name] = {}
>          reverse[domain_name] = {}
>  
> +    n_errors = 0
> +    expected_errors = {}
> +
>      global fileName
>      for fileName in filenames:
>          global inputFile
> @@ -168,13 +177,10 @@ def extract_ofp_errors(filenames):
>              elif re.match('}', line):
>                  break
>  
> -            m = re.match('\s+/\* ((?:.(?!\.  ))+.)\.  (.*)$', line)
> -            if not m:
> +            if not line.lstrip().startswith('/*'):
>                  fatal("unexpected syntax between errors")
>  
> -            dsts, comment = m.groups()
> -
> -            comment.rstrip()
> +            comment = line.lstrip()[2:].strip()
>              while not comment.endswith('*/'):
>                  getLine()
>                  if line.startswith('/*') or not line or line.isspace():
> @@ -182,6 +188,17 @@ def extract_ofp_errors(filenames):
>                  comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
>              comment = comment[:-2].rstrip()
>  
> +            m = re.match('Expected: (.*)\.$', comment)
> +            if m:
> +                expected_errors[m.group(1)] = (fileName, lineNumber)
> +                continue
> +
> +            m = re.match('((?:.(?!\.  ))+.)\.  (.*)$', comment)
> +            if not m:
> +                fatal("unexpected syntax between errors")
> +
> +            dsts, comment = m.groups()
> +
>              getLine()
>              m = 
> re.match('\s+(?:OFPERR_((?:OFP|NX)[A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
>                           line)
> @@ -194,35 +211,68 @@ def extract_ofp_errors(filenames):
>              names.append(enum)
>  
>              for dst in dsts.split(', '):
> -                m = re.match(r'([A-Z0-9.+]+)\((\d+)(?:,(\d+))?\)$', dst)
> +                m = 
> re.match(r'([A-Z0-9.+]+)\((\d+|(0x)[0-9a-fA-F]+)(?:,(\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))
> +                    base = 16
> +                else:
> +                    base = 10
> +                type_ = int(m.group(2), base)
> +                if m.group(4):
> +                    code = int(m.group(4))
>                  else:
>                      code = None
>  
> -                target_map = {"OF1.0+": ("OF1.0", "OF1.1"),
> -                              "OF1.1+": ("OF1.1",),
> +                target_map = {"OF1.0+": ("OF1.0", "OF1.1", "OF1.2"),
> +                              "OF1.1+": ("OF1.1", "OF1.2"),
> +                              "OF1.2+": ("OF1.2",),
>                                "OF1.0":  ("OF1.0",),
>                                "OF1.1":  ("OF1.1",),
> -                              "NX1.0+": ("OF1.0", "OF1.1"),
> +                              "OF1.2":  ("OF1.2",),
> +                              "NX1.0+": ("OF1.0", "OF1.1", "OF1.2"),
>                                "NX1.0":  ("OF1.0",),
> -                              "NX1.1":  ("OF1.1",)}
> +                              "NX1.1":  ("OF1.1",),
> +                              "NX1.2":  ("OF1.2",)}
>                  if targets not in target_map:
>                      fatal("%s: unknown error domain" % targets)
>                  for target in target_map[targets]:
> -                    if type_ not in domain[target]:
> -                        domain[target][type_] = {}
> +                    domain[target].setdefault(type_, {})
>                      if code in domain[target][type_]:
> -                        fatal("%s: duplicate assignment in domain" % dst)
> -                    domain[target][type_][code] = enum
> +                        msg = "%d,%d in %s means both %s and %s" % (
> +                            type_, code, target,
> +                            domain[target][type_][code][0], enum)
> +                        if msg in expected_errors:
> +                            del expected_errors[msg]
> +                        else:
> +                            error("%s: %s." % (dst, msg))
> +                            sys.stderr.write("%s:%d: %s: Here is the 
> location "
> +                                             "of the previous definition.\n"
> +                                             % 
> (domain[target][type_][code][1],
> +                                                
> domain[target][type_][code][2],
> +                                                dst))
> +                    else:
> +                        domain[target][type_][code] = (enum, fileName,
> +                                                       lineNumber)
> +
> +                    if enum in reverse[target]:
> +                        error("%s: %s in %s means both %d,%d and %d,%d." %
> +                              (dst, enum, target,
> +                               reverse[target][enum][0],
> +                               reverse[target][enum][1],
> +                               type_, code))
>                      reverse[target][enum] = (type_, code)
>  
>          inputFile.close()
>  
> +    for fn, ln in expected_errors.itervalues():
> +        sys.stderr.write("%s:%d: expected duplicate not used.\n" % (fn, ln))
> +        n_errors += 1
> +
> +    if n_errors:
> +        sys.exit(1)
> +
>      print """\
>  /* Generated automatically; do not modify!     -*- buffer-read-only: t -*- */
>  
> @@ -254,12 +304,17 @@ static enum ofperr
>  %s_decode(uint16_t type, uint16_t code)
>  {
>      switch ((type << 16) | code) {""" % name
> +        found = []
>          for enum in names:
>              if enum not in map:
>                  continue
>              type_, code = map[enum]
>              if code is None:
>                  continue
> +            value = (type_ << 16) | code
> +            if value in found:
> +                continue
> +            found.append(value)
>              print "    case (%d << 16) | %d:" % (type_, code)
>              print "        return OFPERR_%s;" % enum
>          print """\
> @@ -307,6 +362,7 @@ const struct ofperr_domain %s = {
>  
>      output_domain(reverse["OF1.0"], "ofperr_of10", "OpenFlow 1.0", 0x01)
>      output_domain(reverse["OF1.1"], "ofperr_of11", "OpenFlow 1.1", 0x02)
> +    output_domain(reverse["OF1.2"], "ofperr_of12", "OpenFlow 1.2", 0x03)
>  
>  if __name__ == '__main__':
>      if '--help' in sys.argv:
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 3ead9b6..0e61d35 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -103,7 +103,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, 
> bool strict,
>          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 OFPERR_OFPBRC_BAD_LEN;
> +        return OFPERR_OFPBMC_BAD_LEN;
>      }
>  
>      cls_rule_init_catchall(rule, priority);
> @@ -119,21 +119,21 @@ nx_pull_match__(struct ofpbuf *b, unsigned int 
> match_len, bool strict,
>          mf = mf_from_nxm_header(header);
>          if (!mf) {
>              if (strict) {
> -                error = OFPERR_NXBRC_NXM_BAD_TYPE;
> +                error = OFPERR_OFPBMC_BAD_FIELD;
>              } else {
>                  continue;
>              }
>          } else if (!mf_are_prereqs_ok(mf, &rule->flow)) {
> -            error = OFPERR_NXBRC_NXM_BAD_PREREQ;
> +            error = OFPERR_OFPBMC_BAD_PREREQ;
>          } else if (!mf_is_all_wild(mf, &rule->wc)) {
> -            error = OFPERR_NXBRC_NXM_DUP_TYPE;
> +            error = OFPERR_OFPBMC_DUP_FIELD;
>          } else {
>              unsigned int width = mf->n_bytes;
>              union mf_value value;
>  
>              memcpy(&value, p + 4, width);
>              if (!mf_is_value_valid(mf, &value)) {
> -                error = OFPERR_NXBRC_NXM_BAD_VALUE;
> +                error = OFPERR_OFPBMC_BAD_VALUE;
>              } else if (!NXM_HASMASK(header)) {
>                  error = 0;
>                  mf_set_value(mf, &value, rule);
> @@ -142,7 +142,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, 
> bool strict,
>  
>                  memcpy(&mask, p + 4 + width, width);
>                  if (!mf_is_mask_valid(mf, &mask)) {
> -                    error = OFPERR_NXBRC_NXM_BAD_MASK;
> +                    error = OFPERR_OFPBMC_BAD_MASK;
>                  } else {
>                      error = 0;
>                      mf_set(mf, &value, &mask, rule);
> @@ -153,7 +153,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, 
> bool strict,
>          /* Check if the match is for a cookie rather than a classifier rule. 
> */
>          if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W) && 
> cookie) {
>              if (*cookie_mask) {
> -                error = OFPERR_NXBRC_NXM_DUP_TYPE;
> +                error = OFPERR_OFPBMC_DUP_FIELD;
>              } else {
>                  unsigned int width = sizeof *cookie;
>  
> @@ -178,7 +178,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, 
> bool strict,
>          }
>      }
>  
> -    return match_len ? OFPERR_NXBRC_NXM_INVALID : 0;
> +    return match_len ? OFPERR_OFPBMC_BAD_LEN : 0;
>  }
>  
>  /* Parses the nx_match formatted match description in 'b' with length
> diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c
> index 028475e..e1349b0 100644
> --- a/lib/ofp-errors.c
> +++ b/lib/ofp-errors.c
> @@ -25,9 +25,17 @@ ofperr_domain_from_version(uint8_t version)
>  {
>      return (version == ofperr_of10.version ? &ofperr_of10
>              : version == ofperr_of11.version ? &ofperr_of11
> +            : version == ofperr_of12.version ? &ofperr_of12
>              : NULL);
>  }
>  
> +/* Returns the name (e.g. "OpenFlow 1.0") of OpenFlow error domain 'domain'. 
> */
> +const char *
> +ofperr_domain_get_name(const struct ofperr_domain *domain)
> +{
> +    return domain->name;
> +}
> +
>  /* Returns true if 'error' is a valid OFPERR_* value, false otherwise. */
>  bool
>  ofperr_is_valid(enum ofperr error)
> @@ -97,6 +105,24 @@ ofperr_get_name(enum ofperr error)
>              : "<invalid>");
>  }
>  
> +/* Returns the OFPERR_* value that corresponds for 'name', 0 if none exists.
> + * For example, returns OFPERR_OFPHFC_INCOMPATIBLE if 'name' is
> + * "OFPHFC_INCOMPATIBLE".
> + *
> + * This is probably useful only for debugging and testing. */
> +enum ofperr
> +ofperr_from_name(const char *name)
> +{
> +    int i;
> +
> +    for (i = 0; i < OFPERR_N_ERRORS; i++) {
> +        if (!strcmp(name, error_names[i])) {
> +            return i + OFPERR_OFS;
> +        }
> +    }
> +    return 0;
> +}
> +
>  /* 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. */
> @@ -108,6 +134,15 @@ ofperr_get_description(enum ofperr error)
>              : "<invalid>");
>  }
>  
> +static const struct pair *
> +ofperr_get_pair__(enum ofperr error, const struct ofperr_domain *domain)
> +{
> +    size_t ofs = error - OFPERR_OFS;
> +
> +    assert(ofperr_is_valid(error));
> +    return &domain->errors[ofs];
> +}
> +
>  static struct ofpbuf *
>  ofperr_encode_msg__(enum ofperr error, const struct ofperr_domain *domain,
>                      ovs_be32 xid, const void *data, size_t data_len)
> @@ -115,7 +150,6 @@ ofperr_encode_msg__(enum ofperr error, const struct 
> ofperr_domain *domain,
>      struct ofp_error_msg *oem;
>      const struct pair *pair;
>      struct ofpbuf *buf;
> -    size_t ofs;
>  
>      if (!domain) {
>          return NULL;
> @@ -140,8 +174,7 @@ ofperr_encode_msg__(enum ofperr error, const struct 
> ofperr_domain *domain,
>          return NULL;
>      }
>  
> -    ofs = error - OFPERR_OFS;
> -    pair = &domain->errors[ofs];
> +    pair = ofperr_get_pair__(error, domain);
>      if (!ofperr_is_nx_extension(error)) {
>          oem = make_openflow_xid(data_len + sizeof *oem, OFPT_ERROR, xid, 
> &buf);
>          oem->type = htons(pair->type);
> @@ -210,6 +243,28 @@ ofperr_encode_hello(enum ofperr error, const struct 
> ofperr_domain *domain,
>      return ofperr_encode_msg__(error, domain, htonl(0), s, strlen(s));
>  }
>  
> +/* Returns the value that would go into an OFPT_ERROR message's 'type' for
> + * encoding 'error' in 'domain'.  Returns -1 if 'error' is not encodable in
> + * 'domain'.
> + *
> + * 'error' must be a valid OFPERR_* code, as checked by ofperr_is_valid(). */
> +int
> +ofperr_get_type(enum ofperr error, const struct ofperr_domain *domain)
> +{
> +    return ofperr_get_pair__(error, domain)->type;
> +}
> +
> +/* Returns the value that would go into an OFPT_ERROR message's 'code' for
> + * encoding 'error' in 'domain'.  Returns -1 if 'error' is not encodable in
> + * 'domain' or if 'error' represents a category rather than a specific error.
> + *
> + * 'error' must be a valid OFPERR_* code, as checked by ofperr_is_valid(). */
> +int
> +ofperr_get_code(enum ofperr error, const struct ofperr_domain *domain)
> +{
> +    return ofperr_get_pair__(error, domain)->code;
> +}
> +
>  /* Tries to decodes 'oh', which should be an OpenFlow OFPT_ERROR message.
>   * Returns an OFPERR_* constant on success, 0 on failure.
>   *
> diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
> index bd6095b..40e5a61 100644
> --- a/lib/ofp-errors.h
> +++ b/lib/ofp-errors.h
> @@ -44,6 +44,11 @@ struct ofp_header;
>  #define OFPERR_OFS (1 << 30)
>  
>  enum ofperr {
> +/* Expected duplications. */
> +
> +    /* Expected: 3,5 in OF1.1 means both OFPBIC_BAD_EXPERIMENTER and
> +     * OFPBIC_BAD_EXP_TYPE. */
> +
>  /* ## ------------------ ## */
>  /* ## OFPET_HELLO_FAILED ## */
>  /* ## ------------------ ## */
> @@ -95,6 +100,15 @@ enum ofperr {
>      /* OF1.1+(1,9).  Specified table-id invalid or does not exist. */
>      OFPERR_OFPBRC_BAD_TABLE_ID,
>  
> +    /* OF1.2+(1,10).  Denied because controller is slave. */
> +    OFPERR_OFPBRC_IS_SLAVE,
> +
> +    /* OF1.2+(1,11).  Invalid port. */
> +    OFPERR_OFPBRC_BAD_PORT,
> +
> +    /* OF1.2+(1,12).  Invalid packet in packet-out. */
> +    OFPERR_OFPBRC_BAD_PACKET,
> +
>      /* NX1.0+(1,256).  Invalid NXM flow match. */
>      OFPERR_NXBRC_NXM_INVALID,
>  
> @@ -102,24 +116,9 @@ enum ofperr {
>       * nxm_hasmask or nxm_length or both, is invalid or not implemented. */
>      OFPERR_NXBRC_NXM_BAD_TYPE,
>  
> -    /* NX1.0+(1,258).  Invalid nxm_value. */
> -    OFPERR_NXBRC_NXM_BAD_VALUE,
> -
> -    /* NX1.0+(1,259).  Invalid nxm_mask. */
> -    OFPERR_NXBRC_NXM_BAD_MASK,
> -
> -    /* NX1.0+(1,260).  A prerequisite was not met. */
> -    OFPERR_NXBRC_NXM_BAD_PREREQ,
> -
> -    /* NX1.0+(1,261).  A given nxm_type was specified more than once. */
> -    OFPERR_NXBRC_NXM_DUP_TYPE,
> -
>      /* NX1.0+(1,512).  A request specified a nonexistent table ID. */
>      OFPERR_NXBRC_BAD_TABLE_ID,
>  
> -    /* NX1.0+(1,513).  NXT_ROLE_REQUEST specified an invalid role. */
> -    OFPERR_NXBRC_BAD_ROLE,
> -
>      /* NX1.0+(1,514).  The in_port in an ofp_packet_out request is invalid. 
> */
>      OFPERR_NXBRC_BAD_IN_PORT,
>  
> @@ -177,6 +176,15 @@ enum ofperr {
>      /* OF1.1+(2,12).  Actions uses an unsupported tag/encap. */
>      OFPERR_OFPBAC_BAD_TAG,
>  
> +    /* OF1.2+(2,13).  Unsupported type in SET_FIELD action. */
> +    OFPERR_OFPBAC_SET_TYPE,
> +
> +    /* OF1.2+(2,14).  Length problem in SET_FIELD action. */
> +    OFPERR_OFPBAC_SET_LEN,
> +
> +    /* OF1.2+(2,15).  Bad argument in SET_FIELD action. */
> +    OFPERR_OFPBAC_ARGUMENT,
> +
>      /* NX1.0+(2,256).  Must-be-zero action argument had nonzero value. */
>      OFPERR_NXBAC_MUST_BE_ZERO,
>  
> @@ -202,8 +210,17 @@ enum ofperr {
>      /* 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,
> +    /* OF1.1+(3,5).  Unknown experimenter id specified. */
> +    OFPERR_OFPBIC_BAD_EXPERIMENTER,
> +
> +    /* OF1.1(3,5), OF1.2+(3,6).  Unknown instruction for experimenter id. */
> +    OFPERR_OFPBIC_BAD_EXP_TYPE,
> +
> +    /* OF1.2+(3,7).  Length problem in instructions. */
> +    OFPERR_OFPBIC_BAD_LEN,
> +
> +    /* OF1.2+(3,8).  Permissions error. */
> +    OFPERR_OFPBIC_EPERM,
>  
>  /* ## --------------- ## */
>  /* ## OFPET_BAD_MATCH ## */
> @@ -235,9 +252,24 @@ enum ofperr {
>      /* OF1.1+(4,6).  Unsupported field in the match. */
>      OFPERR_OFPBMC_BAD_FIELD,
>  
> -    /* OF1.1+(4,7).  Unsupported value in a match field. */
> +    /* NX1.0(1,258), NX1.1(1,258), OF1.2+(4,7).  Unsupported value in a match
> +     * field. */
>      OFPERR_OFPBMC_BAD_VALUE,
>  
> +    /* NX1.0(1,259), NX1.1(1,259), OF1.2+(4,8).  Unsupported mask specified 
> in
> +     * the match, field is not dl-address or nw-address. */
> +    OFPERR_OFPBMC_BAD_MASK,
> +
> +    /* NX1.0(1,260), NX1.1(1,260), OF1.2+(4,9).  A prerequisite was not met. 
> */
> +    OFPERR_OFPBMC_BAD_PREREQ,
> +
> +    /* NX1.0(1,261), NX1.1(1,261), OF1.2+(4,10).  A field type was
> +     * duplicated. */
> +    OFPERR_OFPBMC_DUP_FIELD,
> +
> +    /* OF1.2+(4,11).  Permissions error. */
> +    OFPERR_OFPBMC_EPERM,
> +
>  /* ## --------------------- ## */
>  /* ## OFPET_FLOW_MOD_FAILED ## */
>  /* ## --------------------- ## */
> @@ -274,6 +306,9 @@ enum ofperr {
>      /* OF1.0(3,4), OF1.1+(5,6).  Unsupported or unknown command. */
>      OFPERR_OFPFMFC_BAD_COMMAND,
>  
> +    /* OF1.2+(5,7).  Unsupported or unknown flags. */
> +    OFPERR_OFPFMFC_BAD_FLAGS,
> +
>      /* OF1.0(3,5).  Unsupported action list - cannot process in the order
>       * specified. */
>      OFPERR_OFPFMFC_UNSUPPORTED,
> @@ -325,6 +360,25 @@ enum ofperr {
>       * modify a non-existent group. */
>      OFPERR_OFPGMFC_UNKNOWN_GROUP,
>  
> +    /* OF1.2+(6,9).  Group not deleted because another
> +                    group is forwarding to it. */
> +    OFPERR_OFPGMFC_CHAINED_GROUP,
> +
> +    /* OF1.2+(6,10).  Unsupported or unknown group type. */
> +    OFPERR_OFPGMFC_BAD_TYPE,
> +
> +    /* OF1.2+(6,11).  Unsupported or unknown command. */
> +    OFPERR_OFPGMFC_BAD_COMMAND,
> +
> +    /* OF1.2+(6,12).  Error in bucket. */
> +    OFPERR_OFPGMFC_OFPGMFC_BAD_BUCKET,
> +
> +    /* OF1.2+(6,13).  Error in watch port/group. */
> +    OFPERR_OFPGMFC_OFPGMFC_BAD_WATCH,
> +
> +    /* OF1.2+(6,14).  Permissions error. */
> +    OFPERR_OFPGMFC_OFPGMFC_EPERM,
> +
>  /* ## --------------------- ## */
>  /* ## OFPET_PORT_MOD_FAILED ## */
>  /* ## --------------------- ## */
> @@ -345,6 +399,9 @@ enum ofperr {
>      /* OF1.1+(7,3).  Specified advertise is invalid. */
>      OFPERR_OFPPMFC_BAD_ADVERTISE,
>  
> +    /* OF1.2+(7,4).  Permissions error. */
> +    OFPERR_OFPPMFC_EPERM,
> +
>  /* ## ---------------------- ## */
>  /* ## OFPET_TABLE_MOD_FAILED ## */
>  /* ## ---------------------- ## */
> @@ -358,6 +415,9 @@ enum ofperr {
>      /* OF1.1+(8,1).  Specified config is invalid. */
>      OFPERR_OFPTMFC_BAD_CONFIG,
>  
> +    /* OF1.2+(8,2).  Permissions error. */
> +    OFPERR_OFPTMFC_EPERM,
> +
>  /* ## --------------------- ## */
>  /* ## OFPET_QUEUE_OP_FAILED ## */
>  /* ## --------------------- ## */
> @@ -386,12 +446,41 @@ enum ofperr {
>  
>      /* OF1.1+(10,1).  Specified len is invalid. */
>      OFPERR_OFPSCFC_BAD_LEN,
> +
> +    /* OF1.2+(10,2).  Permissions error. */
> +    OFPERR_OFPSCFC_EPERM,
> +
> +/* ## ------------------------- ## */
> +/* ## OFPET_ROLE_REQUEST_FAILED ## */
> +/* ## ------------------------- ## */
> +
> +    /* OF1.2+(11).  Controller Role request failed. */
> +    OFPERR_OFPET_ROLE_REQUEST_FAILED,
> +
> +    /* OF1.2+(11,0).  Stale Message: old generation_id. */
> +    OFPERR_OFPRRFC_STALE,
> +
> +    /* OF1.2+(11,1).  Controller role change unsupported. */
> +    OFPERR_OFPRRFC_UNSUP,
> +
> +    /* NX1.0(1,513), NX1.1(1,513), OF1.2+(11,2).  Invalid role. */
> +    OFPERR_OFPRRFC_BAD_ROLE,
> +
> +
> +/* ## ------------------ ## */
> +/* ## OFPET_EXPERIMENTER ## */
> +/* ## ------------------ ## */
> +
> +    /* OF1.2+(0xffff).  Experimenter error messages. */
> +    OFPERR_OFPET_EXPERIMENTER,
>  };
>  
>  extern const struct ofperr_domain ofperr_of10;
>  extern const struct ofperr_domain ofperr_of11;
> +extern const struct ofperr_domain ofperr_of12;
>  
>  const struct ofperr_domain *ofperr_domain_from_version(uint8_t version);
> +const char *ofperr_domain_get_name(const struct ofperr_domain *);
>  
>  bool ofperr_is_valid(enum ofperr);
>  bool ofperr_is_category(enum ofperr);
> @@ -401,11 +490,14 @@ 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_from_name(const char *);
>  
>  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 *);
> +int ofperr_get_type(enum ofperr, const struct ofperr_domain *);
> +int ofperr_get_code(enum ofperr, const struct ofperr_domain *);
>  
>  const char *ofperr_get_name(enum ofperr);
>  const char *ofperr_get_description(enum ofperr);
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index aa97124..e7e0401 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -3064,7 +3064,7 @@ handle_role_request(struct ofconn *ofconn, const struct 
> ofp_header *oh)
>      role = ntohl(nrr->role);
>      if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
>          && role != NX_ROLE_SLAVE) {
> -        return OFPERR_NXBRC_BAD_ROLE;
> +        return OFPERR_OFPRRFC_BAD_ROLE;
>      }
>  
>      if (ofconn_get_role(ofconn) != role
> diff --git a/tests/automake.mk b/tests/automake.mk
> index 7728157..62f0c49 100644
> --- a/tests/automake.mk
> +++ b/tests/automake.mk
> @@ -15,6 +15,7 @@ TESTSUITE_AT = \
>       tests/daemon.at \
>       tests/daemon-py.at \
>       tests/ofp-print.at \
> +     tests/ofp-errors.at \
>       tests/ovs-ofctl.at \
>       tests/odp.at \
>       tests/multipath.at \
> diff --git a/tests/ofp-errors.at b/tests/ofp-errors.at
> new file mode 100644
> index 0000000..5f76294
> --- /dev/null
> +++ b/tests/ofp-errors.at
> @@ -0,0 +1,97 @@
> +AT_BANNER([ofp-errors tests])
> +
> +AT_SETUP([OFPT_ERROR with type OFPET_HELLO_FAILED - OF1.0])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print 
> 010100170000000000000001657874726120646174610a], [0], [dnl
> +OFPT_ERROR (xid=0x0): OFPHFC_EPERM
> +extra data\012
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_ERROR with type OFPET_HELLO_FAILED - OF1.1])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print 
> 020100170000000000000001657874726120646174610a], [0], [dnl
> +OFPT_ERROR (OF1.1) (xid=0x0): OFPHFC_EPERM
> +extra data\012
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_ERROR with type OFPET_BAD_REQUEST - OF1.0])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print 01010014000000000001000601bbccddeeff0011], 
> [0], [dnl
> +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 OFPBMC_BAD_PREREQ - OF1.0])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print '0101001c55555555 b0c20000 0000232000010104 
> 0102000811111111'], [0], [dnl
> +OFPT_ERROR (xid=0x55555555): OFPBMC_BAD_PREREQ
> +OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_ERROR with code OFPBMC_BAD_PREREQ - OF1.1])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print '0201001c55555555 b0c20000 0000232000010104 
> 0102000811111111'], [0], [dnl
> +OFPT_ERROR (OF1.1) (xid=0x55555555): OFPBMC_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 ofp-errors])
> +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 ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print 02010014000000000003000102bbccddeeff0011], 
> [0], [dnl
> +OFPT_ERROR (OF1.1) (xid=0x0): OFPBIC_UNSUP_INST
> +(***truncated to 8 bytes from 52445***)
> +00000000  02 bb cc dd ee ff 00 11-                        |........        |
> +])
> +AT_CLEANUP
> +
> +dnl OF1.1 had OFPBIC_UNSUP_EXP_INST as 3,5.
> +dnl OF1.2 broke it into OFPBIC_BAD_EXPERIMENTER as 3,5
> +dnl                 and OFPBIC_BAD_EXT_TYPE as 3,6.
> +dnl Thus, for OF1.1 we translate both of the latter error codes into 3,5.
> +AT_SETUP([encoding OFPBIC_* experimenter errors])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl print-error OFPBIC_BAD_EXPERIMENTER], [0], [dnl
> +OpenFlow 1.0: -1,-1
> +OpenFlow 1.1: 3,5
> +OpenFlow 1.2: 3,5
> +])
> +AT_CHECK([ovs-ofctl print-error OFPBIC_BAD_EXP_TYPE], [0], [dnl
> +OpenFlow 1.0: -1,-1
> +OpenFlow 1.1: 3,5
> +OpenFlow 1.2: 3,6
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([decoding OFPBIC_* experimenter errors])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print '0201001455555555 00030005 0102000811111111'], 
> [0], [dnl
> +OFPT_ERROR (OF1.1) (xid=0x55555555): OFPBIC_BAD_EXPERIMENTER
> +OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
> +])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print '0301001455555555 00030005 0102000811111111'], 
> [0], [dnl
> +OFPT_ERROR (OF 0x03) (xid=0x55555555): OFPBIC_BAD_EXPERIMENTER
> +OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
> +])
> +AT_KEYWORDS([ofp-print ofp-errors])
> +AT_CHECK([ovs-ofctl ofp-print '0301001455555555 00030006 0102000811111111'], 
> [0], [dnl
> +OFPT_ERROR (OF 0x03) (xid=0x55555555): OFPBIC_BAD_EXP_TYPE
> +OFPT_ECHO_REQUEST (xid=0x11111111): 0 bytes of payload
> +])
> +AT_CLEANUP
> diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> index 9ac1d23..31d3293 100644
> --- a/tests/ofp-print.at
> +++ b/tests/ofp-print.at
> @@ -57,65 +57,7 @@ OFPT_HELLO (xid=0x0):
>  ])
>  AT_CLEANUP
>  
> -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): OFPHFC_EPERM
> -extra data\012
> -])
> -AT_CLEANUP
> -
> -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 (OF1.1) (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): 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 - OF1.0])
> -AT_KEYWORDS([ofp-print])
> -AT_CHECK([ovs-ofctl ofp-print '0101001c55555555 b0c20000 0000232000010104 
> 0102000811111111'], [0], [dnl
> -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 (OF1.1) (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 (OF1.1) (xid=0x0): OFPBIC_UNSUP_INST
> -(***truncated to 8 bytes from 52445***)
> -00000000  02 bb cc dd ee ff 00 11-                        |........        |
> -])
> -AT_CLEANUP
> +dnl OFPT_ERROR tests are in ofp-errors.at.
>  
>  AT_SETUP([OFPT_ECHO_REQUEST, empty payload])
>  AT_KEYWORDS([ofp-print])
> diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> index 0395925..a52382e 100644
> --- a/tests/ovs-ofctl.at
> +++ b/tests/ovs-ofctl.at
> @@ -433,7 +433,7 @@ NXM_OF_IN_PORT(0012), NXM_OF_ETH_TYPE(0800)
>  
>  # vlan tci
>  NXM_OF_VLAN_TCI(f009)
> -nx_pull_match() returned error NXBRC_NXM_DUP_TYPE
> +nx_pull_match() returned error OFPBMC_DUP_FIELD
>  NXM_OF_VLAN_TCI(0000)
>  NXM_OF_VLAN_TCI(3123)
>  NXM_OF_VLAN_TCI(0123)
> @@ -443,118 +443,118 @@ NXM_OF_VLAN_TCI_W(0000/e000)
>  
>  # IP TOS
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0)
> -nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_VALUE
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # IP ECN
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_ECN(03)
> -nx_pull_match() returned error NXBRC_NXM_BAD_VALUE
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_VALUE
> +nx_pull_match() returned error OFPBMC_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 NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # TCP source port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(4231)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC_W(5050/f0f0)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # TCP destination port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST(4231)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST_W(fde0/fff0)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # UDP source port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_SRC(8732)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_SRC_W(0132/01ff)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # UDP destination port
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST(1782)
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST_W(5005/f00f)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # ICMP type
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01), NXM_OF_ICMP_TYPE(12)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # ICMP code
>  NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(01), NXM_OF_ICMP_CODE(12)
> -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
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # ARP opcode
>  NXM_OF_ETH_TYPE(0806), NXM_OF_ARP_OP(0001)
> -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
> +nx_pull_match() returned error OFPBMC_BAD_VALUE
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_DUP_FIELD
>  
>  # 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 NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # ARP source hardware address
>  NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_SHA(0002e30f80a4)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # ARP destination hardware address
>  NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_THA(0002e30f80a4)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # IPv6 source
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_SRC(20010db83c4d00010002000300040005)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  NXM_OF_ETH_TYPE(86dd), 
> NXM_NX_IPV6_SRC_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # IPv6 destination
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_DST(20010db83c4d00010002000300040005)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  NXM_OF_ETH_TYPE(86dd), 
> NXM_NX_IPV6_DST_W(20010db83c4d00010000000000000000/ffffffffffffffff0000000000000000)
> -nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 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 OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_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 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 OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
> +nx_pull_match() returned error OFPBMC_BAD_PREREQ
>  
>  # IPv4 fragments.
>  NXM_OF_ETH_TYPE(0800), NXM_NX_IP_FRAG(00)
> @@ -567,7 +567,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 NXBRC_NXM_BAD_VALUE
> +nx_pull_match() returned error OFPBMC_BAD_VALUE
>  
>  # IPv6 fragments.
>  NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG(00)
> @@ -580,7 +580,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 NXBRC_NXM_BAD_VALUE
> +nx_pull_match() returned error OFPBMC_BAD_VALUE
>  
>  # Flow cookie.
>  NXM_NX_COOKIE(00000000abcdef01)
> @@ -595,7 +595,7 @@ NXM_NX_REG0(acebdf56)
>  NXM_NX_REG0_W(a0e0d050/f0f0f0f0)
>  
>  # Invalid field number.
> -nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
> +nx_pull_match() returned error OFPBMC_BAD_FIELD
>  
>  # Unimplemented registers.
>  #
> @@ -603,8 +603,8 @@ nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
>  # registers are implemented.
>  NXM_NX_REG0(12345678)
>  NXM_NX_REG0_W(12345678/12345678)
> -nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
> -nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
> +nx_pull_match() returned error OFPBMC_BAD_FIELD
> +nx_pull_match() returned error OFPBMC_BAD_FIELD
>  ])
>  AT_CLEANUP
>  
> @@ -615,7 +615,7 @@ NXM_OF_IN_PORT(0001), 01020304(1111/2222), 
> NXM_OF_ETH_TYPE(0800)
>  ])
>  
>  AT_CHECK([ovs-ofctl --strict parse-nx-match < nx-match.txt], [0], [dnl
> -nx_pull_match() returned error NXBRC_NXM_BAD_TYPE
> +nx_pull_match() returned error OFPBMC_BAD_FIELD
>  ])
>  
>  AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [dnl
> diff --git a/tests/testsuite.at b/tests/testsuite.at
> index 755462c..60401d6 100644
> --- a/tests/testsuite.at
> +++ b/tests/testsuite.at
> @@ -57,6 +57,7 @@ m4_include([tests/check-structs.at])
>  m4_include([tests/daemon.at])
>  m4_include([tests/daemon-py.at])
>  m4_include([tests/ofp-print.at])
> +m4_include([tests/ofp-errors.at])
>  m4_include([tests/ovs-ofctl.at])
>  m4_include([tests/odp.at])
>  m4_include([tests/multipath.at])
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index 74a86c1..3e9f462 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -1832,6 +1832,34 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] 
> OVS_UNUSED)
>      ds_destroy(&in);
>  }
>  
> +/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
> + * version. */
> +static void
> +do_print_error(int argc OVS_UNUSED, char *argv[])
> +{
> +    enum ofperr error;
> +    int version;
> +
> +    error = ofperr_from_name(argv[1]);
> +    if (!error) {
> +        ovs_fatal(0, "unknown error \"%s\"", argv[1]);
> +    }
> +
> +    for (version = 0; version <= UINT8_MAX; version++) {
> +        const struct ofperr_domain *domain;
> +
> +        domain = ofperr_domain_from_version(version);
> +        if (!domain) {
> +            continue;
> +        }
> +
> +        printf("%s: %d,%d\n",
> +               ofperr_domain_get_name(domain),
> +               ofperr_get_type(error, domain),
> +               ofperr_get_code(error, domain));
> +    }
> +}
> +
>  /* "ofp-print HEXSTRING [VERBOSITY]": Converts the hex digits in HEXSTRING 
> into
>   * binary data, interpreting them as an OpenFlow message, and prints the
>   * OpenFlow message on stdout, at VERBOSITY (level 2 by default).  */
> @@ -1877,6 +1905,7 @@ static const struct command all_commands[] = {
>      { "parse-flow", 1, 1, do_parse_flow },
>      { "parse-flows", 1, 1, do_parse_flows },
>      { "parse-nx-match", 0, 0, do_parse_nx_match },
> +    { "print-error", 1, 1, do_print_error },
>      { "ofp-print", 1, 2, do_ofp_print },
>  
>      { NULL, 0, 0, NULL },
> -- 
> 1.7.2.5
> 
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to