--- /dev/null
+#! /usr/bin/python
+
+import sys
+import os.path
+import re
+
+macros = {}
+
+token = None
+line = ""
+idRe = "[a-zA-Z_][a-zA-Z_0-9]*"
+tokenRe = "#?" + idRe + "|[0-9]+|."
+inComment = False
+inDirective = False
+def getToken():
+ global token
+ global line
+ global inComment
+ global inDirective
+ while True:
+ line = line.lstrip()
+ if line != "":
+ if line.startswith("/*"):
+ inComment = True
+ line = line[2:]
+ elif inComment:
+ commentEnd = line.find("*/")
+ if commentEnd < 0:
+ line = ""
+ else:
+ inComment = False
+ line = line[commentEnd + 2:]
+ else:
+ match = re.match(tokenRe, line)
+ token = match.group(0)
+ line = line[len(token):]
+ if token.startswith('#'):
+ inDirective = True
+ elif token in macros and not inDirective:
+ line = macros[token] + line
+ continue
+ return True
+ elif inDirective:
+ token = "$"
+ inDirective = False
+ return True
+ else:
+ global lineNumber
+ line = inputFile.readline()
+ lineNumber += 1
+ while line.endswith("\\\n"):
+ line = line[:-2] + inputFile.readline()
+ lineNumber += 1
+ if line == "":
+ if token == None:
+ fatal("unexpected end of input")
+ token = None
+ return False
+
+def fatal(msg):
+ sys.stderr.write("%s:%d: error at \"%s\": %s\n" % (fileName, lineNumber, token, msg))
+ sys.exit(1)
+
+def skipDirective():
+ getToken()
+ while token != '$':
+ getToken()
+
+def isId(s):
+ return re.match(idRe + "$", s) != None
+
+def forceId():
+ if not isId(token):
+ fatal("identifier expected")
+
+def forceInteger():
+ if not re.match('[0-9]+$', token):
+ fatal("integer expected")
+
+def match(t):
+ if token == t:
+ getToken()
+ return True
+ else:
+ return False
+
+def forceMatch(t):
+ if not match(t):
+ fatal("%s expected" % t)
+
+def parseTaggedName():
+ assert token in ('struct', 'union')
+ name = token
+ getToken()
+ forceId()
+ name = "%s %s" % (name, token)
+ getToken()
+ return name
+
+def print_enum(tag, constants, storage_class):
+ print """
+%(storage_class)sconst char *
+%(tag)s_to_string(uint16_t value)
+{
+ switch (value) {\
+""" % {"tag": tag,
+ "bufferlen": len(tag) + 32,
+ "storage_class": storage_class}
+ for constant in constants:
+ print " case %s: return \"%s\";" % (constant, constant)
+ print """\
+ }
+ return NULL;
+}\
+""" % {"tag": tag}
+
+def usage():
+ argv0 = os.path.basename(sys.argv[0])
+ print '''\
+%(argv0)s, for extracting OpenFlow error codes from header files
+usage: %(argv0)s FILE [FILE...]
+
+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}
+ sys.exit(0)
+
+def extract_ofp_errors(filenames):
+ error_types = {}
+
+ 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")
+ inputFile.close()
+
+ print "/* -*- buffer-read-only: t -*- */"
+ print "#include <config.h>"
+ print '#include "ofp-errors.h"'
+ print "#include <inttypes.h>"
+ print "#include <stdio.h>"
+ for fileName in sys.argv[1:]:
+ print '#include "%s"' % fileName
+ print '#include "type-props.h"'
+
+ for error_type, constants in sorted(error_types.items()):
+ tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
+ print_enum(tag, constants, "static ")
+ print_enum("ofp_error_type", error_types.keys(), "")
+ print """
+const char *
+ofp_error_code_to_string(uint16_t type, uint16_t code)
+{
+ switch (type) {\
+"""
+ for error_type in error_types:
+ tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
+ print " case %s:" % error_type
+ print " return %s_to_string(code);" % tag
+ print """\
+ }
+ return NULL;
+}\
+"""
+
+if __name__ == '__main__':
+ if '--help' in sys.argv:
+ usage()
+ elif len(sys.argv) < 2:
+ sys.stderr.write("at least one non-option argument required; "
+ "use --help for help\n")
+ sys.exit(1)
+ else:
+ extract_ofp_errors(sys.argv[1:])
* that duplicate the current ones' meanings. */
/* Additional "code" values for OFPET_BAD_REQUEST. */
-enum {
+enum nx_bad_request_code {
/* Nicira Extended Match (NXM) errors. */
/* Generic error code used when there is an error in an NXM sent to the
};
/* Additional "code" values for OFPET_FLOW_MOD_FAILED. */
-enum {
+enum nx_flow_mod_failed_code {
/* Generic hardware error. */
NXFMFC_HARDWARE = 0x100,
/dhparams.c
/dirs.c
/coverage-counters.c
+/ofp-errors.c
lib/nx-match.h \
lib/odp-util.c \
lib/odp-util.h \
+ lib/ofp-errors.c \
+ lib/ofp-errors.h \
lib/ofp-parse.c \
lib/ofp-parse.h \
lib/ofp-print.c \
> 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
+
install-data-local: lib-install-data-local
lib-install-data-local:
$(MKDIR_P) $(DESTDIR)$(RUNDIR)
--- /dev/null
+/*
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFP_ERRORS_H
+#define OFP_ERRORS_H 1
+
+#include <stdint.h>
+
+/* These functions are building blocks for the ofputil_format_error() and
+ * ofputil_error_to_string() functions declared in ofp-util.h. Those functions
+ * have friendlier interfaces and should usually be preferred. */
+const char *ofp_error_type_to_string(uint16_t value);
+const char *ofp_error_code_to_string(uint16_t type, uint16_t code);
+
+#endif /* ofp-errors.h */
}
}
-struct error_type {
- int type;
- int code;
- const char *name;
-};
-
-static const struct error_type error_types[] = {
-#define ERROR_TYPE(TYPE) {TYPE, -1, #TYPE}
-#define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
- ERROR_TYPE(OFPET_HELLO_FAILED),
- ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
- ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_EPERM),
-
- ERROR_TYPE(OFPET_BAD_REQUEST),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_EPERM),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY),
- ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN),
- /* Nicira error extensions. */
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID),
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_TYPE),
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_VALUE),
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_MASK),
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_PREREQ),
- ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_DUP_TYPE),
-
- ERROR_TYPE(OFPET_BAD_ACTION),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_LEN),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_EPERM),
- ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_TOO_MANY),
-
- ERROR_TYPE(OFPET_FLOW_MOD_FAILED),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EPERM),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_EMERG_TIMEOUT),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND),
- /* Nicira error extenstions. */
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, NXFMFC_HARDWARE),
- ERROR_CODE(OFPET_FLOW_MOD_FAILED, NXFMFC_BAD_TABLE_ID),
-
- ERROR_TYPE(OFPET_PORT_MOD_FAILED),
- ERROR_CODE(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT),
- ERROR_CODE(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR)
-};
-#define N_ERROR_TYPES ARRAY_SIZE(error_types)
-
-static const char *
-lookup_error_type(int type)
-{
- const struct error_type *t;
-
- for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
- if (t->type == type && t->code == -1) {
- return t->name;
- }
- }
- return "?";
-}
-
-static const char *
-lookup_error_code(int type, int code)
-{
- const struct error_type *t;
-
- for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
- if (t->type == type && t->code == code) {
- return t->name;
- }
- }
- return "?";
-}
-
static void
ofp_print_error(struct ds *string, int error)
{
- int type = get_ofp_err_type(error);
- int code = get_ofp_err_code(error);
if (string->length) {
ds_put_char(string, ' ');
}
- ds_put_format(string, " ***decode error type:%d(%s) code:%d(%s)***\n",
- type, lookup_error_type(type),
- code, lookup_error_code(type, code));
-}
-
-static void
-ofp_print_nx_error_msg(struct ds *string, const struct ofp_error_msg *oem)
-{
- size_t len = ntohs(oem->header.length);
- const struct nx_vendor_error *nve = (struct nx_vendor_error *)oem->data;
- int vendor = ntohl(nve->vendor);
- int type = ntohs(nve->type);
- int code = ntohs(nve->code);
-
- ds_put_format(string, " vendor:%x type:%d(%s) code:%d(%s) payload:\n",
- vendor,
- type, lookup_error_type(type),
- code, lookup_error_code(type, code));
-
- ds_put_hex_dump(string, nve + 1, len - sizeof *oem - sizeof *nve,
- 0, true);
+ ds_put_cstr(string, "***decode error: ");
+ ofputil_format_error(string, error);
+ ds_put_cstr(string, "***\n");
}
static void
ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
{
size_t len = ntohs(oem->header.length);
- int type = ntohs(oem->type);
- int code = ntohs(oem->code);
+ size_t payload_ofs, payload_len;
+ const void *payload;
+ int error;
char *s;
-
- if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
- if (len < sizeof *oem + sizeof(struct nx_vendor_error)) {
- ds_put_format(string,
- "(***truncated extended error message is %zu bytes "
- "when it should be at least %zu***)\n",
- len, sizeof(struct nx_vendor_error));
- return;
- }
-
- return ofp_print_nx_error_msg(string, oem);
+ error = ofputil_decode_error_msg(&oem->header, &payload_ofs);
+ if (!is_ofp_error(error)) {
+ ofp_print_error(string, error);
+ ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
+ return;
}
- ds_put_format(string, " type:%d(%s) code:%d(%s) payload:\n",
- type, lookup_error_type(type),
- code, lookup_error_code(type, code));
+ ds_put_char(string, ' ');
+ ofputil_format_error(string, error);
+ ds_put_char(string, '\n');
- switch (type) {
+ payload = (const uint8_t *) oem + payload_ofs;
+ payload_len = len - payload_ofs;
+ switch (get_ofp_err_type(error)) {
case OFPET_HELLO_FAILED:
- ds_put_printable(string, (char *) oem->data, len - sizeof *oem);
+ ds_put_printable(string, payload, payload_len);
break;
case OFPET_BAD_REQUEST:
- s = ofp_to_string(oem->data, len - sizeof *oem, 1);
+ s = ofp_to_string(payload, payload_len, 1);
ds_put_cstr(string, s);
free(s);
break;
default:
- ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
+ ds_put_hex_dump(string, payload, payload_len, 0, true);
break;
}
}
break;
case OFPUTIL_OFPT_HELLO:
+ ds_put_char(string, '\n');
+ ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
+ 0, true);
break;
case OFPUTIL_OFPT_ERROR:
/*
- * 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.
#include <config.h>
#include "ofp-print.h"
+#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include "byte-order.h"
#include "classifier.h"
+#include "dynamic-string.h"
#include "multipath.h"
#include "nx-match.h"
+#include "ofp-errors.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "packets.h"
}
}
+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
*
* Returns NULL if 'error' is not an OpenFlow error code. */
struct ofpbuf *
-make_ofp_error_msg(int error, const struct ofp_header *oh)
+ofputil_encode_error_msg(int error, const struct ofp_header *oh)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
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.
*
return error & 0xffff;
}
-struct ofpbuf *make_ofp_error_msg(int error, const struct ofp_header *);
+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);
#endif /* ofp-util.h */
send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
int error)
{
- struct ofpbuf *buf = make_ofp_error_msg(error, oh);
+ struct ofpbuf *buf = ofputil_encode_error_msg(error, oh);
if (buf) {
COVERAGE_INC(ofproto_error);
queue_tx(buf, ofconn, ofconn->reply_counter);