From 90bf1e0732ac9b11dd51ca856b635cac1f0269c1 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 12 Jan 2012 15:48:19 -0800 Subject: [PATCH] Better abstract OpenFlow error codes. 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. Signed-off-by: Ben Pfaff --- 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 | 24 ++- 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 | 56 ++--- lib/nx-match.h | 25 ++- lib/ofp-errors.c | 287 ++++++++++++++++++++++++++ lib/ofp-errors.h | 389 ++++++++++++++++++++++++++++++++++- lib/ofp-print.c | 40 ++-- lib/ofp-util.c | 367 +++++++-------------------------- 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 | 150 +++++++------- ofproto/pktbuf.c | 13 +- ofproto/pktbuf.h | 8 +- tests/ofp-print.at | 57 ++++- tests/ovs-ofctl.at | 94 ++++----- utilities/ovs-ofctl.c | 7 +- 32 files changed, 1277 insertions(+), 925 deletions(-) create mode 100644 lib/ofp-errors.c diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors index c34888fc..5c3cd26f 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 " - print '#include "ofp-errors.h"' - print "#include " - print "#include " - 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 f2609840..f68a140b 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 c5b6cac9..6cbaf304 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 7153e930..4e2fcf3b 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -278,13 +278,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 9a39c6a1..321b106d 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 98b02b41..19e2d073 100644 --- a/lib/autopath.h +++ b/lib/autopath.h @@ -18,6 +18,7 @@ #define AUTOPATH_H 1 #include +#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 5db97d39..8e98fb57 100644 --- a/lib/bundle.c +++ b/lib/bundle.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 Nicira Networks. +/* Copyright (c) 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -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 if (!error) { error = nxm_dst_check(nab->dst, ofs, n_bits, flow); } @@ -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 12497f78..580ecf81 100644 --- a/lib/bundle.h +++ b/lib/bundle.h @@ -21,6 +21,7 @@ #include #include +#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 a01b998c..ecafac1a 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" @@ -1200,13 +1201,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 9d97cb35..241f3d1f 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 19a9089c..b83bee20 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 2fc6392f..3bcb9610 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 f68dafdc..80d801d6 100644 --- a/lib/multipath.c +++ b/lib/multipath.c @@ -23,6 +23,7 @@ #include #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 8ac4bfd3..3c4ff450 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 +#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 eaccce12..63e5e5be 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011 Nicira Networks. + * Copyright (c) 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -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; } -static int +static enum ofperr nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) @@ -111,7 +102,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 ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } cls_rule_init_catchall(rule, priority); @@ -122,26 +113,26 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, (header = nx_entry_ok(p, match_len)) != 0; p += 4 + NXM_LENGTH(header), match_len -= 4 + NXM_LENGTH(header)) { const struct mf_field *mf; - int error; + enum ofperr error; mf = mf_from_nxm_header(header); if (!mf) { if (strict) { - error = NXM_BAD_TYPE; + error = OFPERR_NXBRC_NXM_BAD_TYPE; } else { continue; } } 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); @@ -150,7 +141,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 = NXM_BAD_MASK; + error = OFPERR_NXBRC_NXM_BAD_MASK; } else { error = 0; mf_set(mf, &value, &mask, rule); @@ -161,7 +152,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 = NXM_DUP_TYPE; + error = OFPERR_NXBRC_NXM_DUP_TYPE; } else { unsigned int width = sizeof *cookie; @@ -176,20 +167,17 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, } 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; } } - return match_len ? NXM_INVALID : 0; + return match_len ? OFPERR_NXBRC_NXM_INVALID : 0; } /* Parses the nx_match formatted match description in 'b' with length @@ -201,7 +189,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, * Fails with an error when encountering unknown NXM headers. * * Returns 0 if successful, otherwise an OpenFlow error code. */ -int +enum ofperr nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) @@ -212,7 +200,7 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, /* Behaves the same as nx_pull_match() with one exception. Skips over unknown * NXM headers instead of failing with an error when they are encountered. */ -int +enum ofperr nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len, uint16_t priority, struct cls_rule *rule, ovs_be64 *cookie, ovs_be64 *cookie_mask) @@ -992,7 +980,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) { @@ -1007,12 +995,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) { @@ -1029,16 +1017,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) { @@ -1048,7 +1036,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 8931d58a..c1892873 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011 Nicira Networks. + * Copyright (c) 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include #include #include "openvswitch/types.h" +#include "ofp-errors.h" struct cls_rule; struct ds; @@ -34,11 +35,12 @@ 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 *, ovs_be64 *cookie, ovs_be64 *cookie_mask); -int nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, - uint16_t priority, struct cls_rule *, - ovs_be64 *cookie, ovs_be64 *cookie_mask); +enum ofperr nx_pull_match(struct ofpbuf *, unsigned int match_len, + uint16_t priority, struct cls_rule *, + ovs_be64 *cookie, ovs_be64 *cookie_mask); +enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, + uint16_t priority, struct cls_rule *, + ovs_be64 *cookie, ovs_be64 *cookie_mask); int nx_put_match(struct ofpbuf *, const struct cls_rule *, ovs_be64 cookie, ovs_be64 cookie_mask); @@ -55,11 +57,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 00000000..028475e1 --- /dev/null +++ b/lib/ofp-errors.c @@ -0,0 +1,287 @@ +#include +#include "ofp-errors.h" +#include +#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 "" 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] + : ""); +} + +/* Returns an extended description name of 'error', e.g. "ofp_header.type not + * supported." if 'error' is OFPBRC_BAD_TYPE, or "" 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] + : ""); +} + +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; + size_t ofs; + + 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; + } + + ofs = error - OFPERR_OFS; + pair = &domain->errors[ofs]; + 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 d677b5d4..fbd28e3b 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 +#include #include -/* 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 89267d87..aff12b6e 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 @@ -746,7 +747,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) { @@ -845,7 +846,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) { @@ -896,14 +897,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 @@ -912,32 +911,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; } } @@ -976,7 +969,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) { @@ -1467,9 +1460,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", @@ -1480,7 +1470,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 a00939dc..b20d3fb6 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) { @@ -389,7 +389,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; @@ -399,14 +399,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)) { @@ -416,7 +416,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; @@ -424,7 +424,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; @@ -434,27 +434,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) { @@ -471,11 +471,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) { @@ -487,7 +487,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) { @@ -504,11 +504,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) { @@ -520,20 +520,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) { @@ -570,11 +570,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) { @@ -590,7 +590,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) { @@ -627,11 +627,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) { @@ -646,7 +646,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) { @@ -655,7 +655,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 }, @@ -735,10 +735,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); @@ -762,22 +762,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) { @@ -791,18 +790,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; } @@ -1005,7 +1003,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) { @@ -1020,7 +1018,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); @@ -1054,7 +1052,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); @@ -1075,7 +1073,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, /* The "NXM_NX_COOKIE*" matches are not valid for flow * additions. Additions must use the "cookie" field of * the "nx_flow_mod" structure. */ - return ofp_mkerr(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID); + return OFPERR_NXBRC_NXM_INVALID; } else { fm->cookie = nfm->cookie; fm->cookie_mask = htonll(UINT64_MAX); @@ -1165,7 +1163,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) @@ -1182,14 +1180,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)); @@ -1200,7 +1198,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; @@ -1213,7 +1211,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) { @@ -1499,7 +1497,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) { @@ -1535,7 +1533,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; @@ -1637,7 +1635,7 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, } if (!ofpbuf_try_pull(&b, 2)) { - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + return OFPERR_OFPBRC_BAD_LEN; } pin->packet = b.data; @@ -2225,8 +2223,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) { @@ -2243,7 +2241,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; } } @@ -2309,16 +2307,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) { @@ -2326,7 +2324,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; } } @@ -2334,7 +2332,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) { @@ -2342,20 +2340,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; } @@ -2369,13 +2363,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; @@ -2383,7 +2377,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; @@ -2446,17 +2440,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; } @@ -2468,11 +2460,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) @@ -2523,8 +2515,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 @@ -2544,7 +2536,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; @@ -2556,7 +2548,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_* @@ -2783,207 +2775,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. * @@ -2995,7 +2786,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) { @@ -3019,7 +2810,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 13195c76..d01e17a5 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -90,15 +90,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 *); @@ -151,8 +152,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); @@ -167,8 +169,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); @@ -215,8 +217,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); @@ -418,160 +420,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 6ea93667..8e6374e7 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 46d6d796..28d9488d 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -844,24 +844,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, @@ -870,17 +868,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 0df840b5..bbee7f4f 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" @@ -97,10 +98,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 60f81755..15532e02 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3872,14 +3872,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); @@ -3956,7 +3956,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) { @@ -3987,7 +3987,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); @@ -4535,9 +4535,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); @@ -5521,16 +5520,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 6c8583ea..b9958318 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 07d4934b..29259e40 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,14 +2081,14 @@ 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, ovs_be64 cookie, ovs_be64 cookie_mask, uint16_t out_port, struct list *rules) { struct classifier *cls; - int error; + enum ofperr error; error = check_table_id(ofproto, table_id); if (error) { @@ -2123,7 +2125,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, ovs_be64 cookie, ovs_be64 cookie_mask, @@ -2155,7 +2157,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) { @@ -2164,7 +2166,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) { @@ -2284,7 +2286,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) { @@ -2295,7 +2297,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) { @@ -2392,7 +2394,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) { @@ -2419,7 +2421,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); @@ -2451,12 +2453,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) { @@ -2488,13 +2490,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. */ @@ -2558,7 +2560,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) @@ -2586,12 +2588,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) @@ -2608,11 +2610,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) @@ -2635,7 +2637,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) { @@ -2656,13 +2658,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->cookie, fm->cookie_mask, @@ -2674,13 +2676,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->cookie, fm->cookie_mask, @@ -2734,11 +2736,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) { @@ -2756,13 +2758,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) @@ -2793,11 +2795,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; @@ -2806,13 +2808,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 @@ -2829,7 +2831,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) { @@ -2840,7 +2842,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 @@ -2849,7 +2851,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) @@ -2862,7 +2864,7 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } -static int +static enum ofperr handle_nxt_set_packet_in_format(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -2872,7 +2874,7 @@ handle_nxt_set_packet_in_format(struct ofconn *ofconn, msg = (const struct nx_set_packet_in_format *) oh; format = ntohl(msg->format); if (format != NXFF_OPENFLOW10 && format != NXPIF_NXM) { - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); + return OFPERR_OFPBRC_EPERM; } if (format != ofconn_get_packet_in_format(ofconn) @@ -2885,7 +2887,7 @@ handle_nxt_set_packet_in_format(struct ofconn *ofconn, return 0; } -static int +static enum ofperr handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) { struct ofp_header *ob; @@ -2900,12 +2902,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) { @@ -3003,9 +3005,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; } } } @@ -3151,8 +3153,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: @@ -3181,7 +3182,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; @@ -3190,7 +3191,6 @@ ofoperation_complete(struct ofoperation *op, int error) assert(rule->pending == op); assert(op->status < 0); - assert(error >= 0); if (!error && !group->error diff --git a/ofproto/pktbuf.c b/ofproto/pktbuf.c index 7cc96a5c..23c01e03 100644 --- a/ofproto/pktbuf.c +++ b/ofproto/pktbuf.c @@ -155,8 +155,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 @@ -170,13 +169,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; @@ -186,7 +185,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]; @@ -203,13 +202,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 82d7a85b..e29117ab 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. @@ -20,6 +20,8 @@ #include #include +#include "ofp-errors.h" + struct pktbuf; struct ofpbuf; @@ -30,8 +32,8 @@ void pktbuf_destroy(struct pktbuf *); uint32_t pktbuf_save(struct pktbuf *, const void *buffer, size_t buffer_size, 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 2ca07c46..0619e986 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 57712c06..0b58b3da 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -394,7 +394,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) @@ -404,114 +404,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) @@ -524,7 +524,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) @@ -537,7 +537,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 # Flow cookie. NXM_NX_COOKIE(00000000abcdef01) @@ -552,7 +552,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. # @@ -560,8 +560,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 @@ -572,7 +572,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 44010101 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_TYPE) +nx_pull_match() returned error NXBRC_NXM_BAD_TYPE ]) AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [dnl diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 995a6c6c..6219f94a 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -37,6 +37,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" @@ -1562,8 +1563,8 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) struct ofpbuf nx_match; struct cls_rule rule; ovs_be64 cookie, cookie_mask; + enum ofperr error; int match_len; - int error; char *s; /* Delete comments, skip blank lines. */ @@ -1606,8 +1607,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); -- 2.30.2