token = None
return False
-def fatal(msg):
+n_errors = 0
+def error(msg):
+ global n_errors
sys.stderr.write("%s:%d: %s\n" % (fileName, lineNumber, msg))
+ n_errors += 1
+
+def fatal(msg):
+ error(msg)
sys.exit(1)
def skipDirective():
return name
def print_enum(tag, constants, storage_class):
- print """
+ print ("""
%(storage_class)sconst char *
%(tag)s_to_string(uint16_t value)
{
switch (value) {\
""" % {"tag": tag,
"bufferlen": len(tag) + 32,
- "storage_class": storage_class}
+ "storage_class": storage_class})
for constant in constants:
- print " case %s: return \"%s\";" % (constant, constant)
- print """\
+ print (" case %s: return \"%s\";" % (constant, constant))
+ print ("""\
}
return NULL;
}\
-""" % {"tag": tag}
+""" % {"tag": tag})
def usage():
argv0 = os.path.basename(sys.argv[0])
- print '''\
+ print ('''\
%(argv0)s, for extracting OpenFlow error codes from header files
usage: %(argv0)s FILE [FILE...]
This program is specialized for reading lib/ofp-errors.h. It will not
work on arbitrary header files without extensions.\
-''' % {"argv0": argv0}
+''' % {"argv0": argv0})
sys.exit(0)
def extract_ofp_errors(filenames):
names = []
domain = {}
reverse = {}
- for domain_name in ("OF1.0", "OF1.1", "NX1.0", "NX1.1"):
+ for domain_name in ("OF1.0", "OF1.1", "OF1.2", "OF1.3",
+ "NX1.0", "NX1.1", "NX1.2", "NX1.3"):
domain[domain_name] = {}
reverse[domain_name] = {}
+ n_errors = 0
+ expected_errors = {}
+
global fileName
for fileName in filenames:
global inputFile
elif re.match('}', line):
break
- m = re.match('\s+/\* ((?:.(?!\. ))+.)\. (.*)$', line)
- if not m:
+ if not line.lstrip().startswith('/*'):
fatal("unexpected syntax between errors")
- dsts, comment = m.groups()
-
- comment.rstrip()
+ comment = line.lstrip()[2:].strip()
while not comment.endswith('*/'):
getLine()
if line.startswith('/*') or not line or line.isspace():
comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
comment = comment[:-2].rstrip()
+ m = re.match('Expected: (.*)\.$', comment)
+ if m:
+ expected_errors[m.group(1)] = (fileName, lineNumber)
+ continue
+
+ m = re.match('((?:.(?!\. ))+.)\. (.*)$', comment)
+ if not m:
+ fatal("unexpected syntax between errors")
+
+ dsts, comment = m.groups()
+
getLine()
m = re.match('\s+(?:OFPERR_((?:OFP|NX)[A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
line)
enum = m.group(1)
- comments.append(comment)
+ comments.append(re.sub('\[[^]]*\]', '', comment))
names.append(enum)
for dst in dsts.split(', '):
- m = re.match(r'([A-Z0-9.]+)\((\d+)(?:,(\d+))?\)$', dst)
+ m = re.match(r'([A-Z0-9.+]+)\((\d+|(0x)[0-9a-fA-F]+)(?:,(\d+))?\)$', dst)
if not m:
fatal("%s: syntax error in destination" % dst)
targets = m.group(1)
- type_ = int(m.group(2))
if m.group(3):
- code = int(m.group(3))
+ base = 16
+ else:
+ base = 10
+ type_ = int(m.group(2), base)
+ if m.group(4):
+ code = int(m.group(4))
else:
code = None
- target_map = {"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",)}
+ target_map = {"OF1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"),
+ "OF1.1+": ("OF1.1", "OF1.2", "OF1.3"),
+ "OF1.2+": ("OF1.2", "OF1.3"),
+ "OF1.3+": ("OF1.3",),
+ "OF1.0": ("OF1.0",),
+ "OF1.1": ("OF1.1",),
+ "OF1.2": ("OF1.2",),
+ "OF1.3": ("OF1.3",),
+ "NX1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"),
+ "NX1.1+": ("OF1.1", "OF1.2", "OF1.3"),
+ "NX1.2+": ("OF1.2", "OF1.3"),
+ "NX1.3+": ("OF1.3",),
+ "NX1.0": ("OF1.0",),
+ "NX1.1": ("OF1.1",),
+ "NX1.2": ("OF1.2",),
+ "NX1.3": ("OF1.3",)}
if targets not in target_map:
- fatal("%s: unknown error domain" % target)
+ fatal("%s: unknown error domain" % targets)
+ if targets.startswith('NX') and code < 0x100:
+ fatal("%s: NX domain code cannot be less than 0x100" % dst)
+ if targets.startswith('OF') and code >= 0x100:
+ fatal("%s: OF domain code cannot be greater than 0x100"
+ % dst)
for target in target_map[targets]:
- if type_ not in domain[target]:
- domain[target][type_] = {}
+ domain[target].setdefault(type_, {})
if code in domain[target][type_]:
- fatal("%s: duplicate assignment in domain" % dst)
- domain[target][type_][code] = enum
+ msg = "%d,%d in %s means both %s and %s" % (
+ type_, code, target,
+ domain[target][type_][code][0], enum)
+ if msg in expected_errors:
+ del expected_errors[msg]
+ else:
+ error("%s: %s." % (dst, msg))
+ sys.stderr.write("%s:%d: %s: Here is the location "
+ "of the previous definition.\n"
+ % (domain[target][type_][code][1],
+ domain[target][type_][code][2],
+ dst))
+ else:
+ domain[target][type_][code] = (enum, fileName,
+ lineNumber)
+
+ if enum in reverse[target]:
+ error("%s: %s in %s means both %d,%d and %d,%d." %
+ (dst, enum, target,
+ reverse[target][enum][0],
+ reverse[target][enum][1],
+ type_, code))
reverse[target][enum] = (type_, code)
inputFile.close()
- print """\
+ for fn, ln in expected_errors.values():
+ sys.stderr.write("%s:%d: expected duplicate not used.\n" % (fn, ln))
+ n_errors += 1
+
+ if n_errors:
+ sys.exit(1)
+
+ print ("""\
/* Generated automatically; do not modify! -*- buffer-read-only: t -*- */
#define OFPERR_N_ERRORS %d
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];
};
""" % (len(names),
'\n'.join(' "%s",' % name for name in names),
'\n'.join(' "%s",' % re.sub(r'(["\\])', r'\\\1', comment)
- for comment in comments))
+ for comment in comments)))
def output_domain(map, name, description, version):
- print """
+ print ("""
static enum ofperr
%s_decode(uint16_t type, uint16_t code)
{
- switch ((type << 16) | code) {""" % name
+ switch ((type << 16) | code) {""" % name)
+ found = set()
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 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:
+ value = (type_ << 16) | code
+ if value in found:
continue
- print " case %d:" % type_
- print " return OFPERR_%s;" % enum
- print """\
+ found.add(value)
+ print (" case (%d << 16) | %d:" % (type_, code))
+ print (" return OFPERR_%s;" % enum)
+ print ("""\
}
return 0;
-}"""
+}""")
- print """
-const struct ofperr_domain %s = {
+ print ("""
+static const struct ofperr_domain %s = {
"%s",
%d,
%s_decode,
- %s_decode_type,
- {""" % (name, description, version, name, name)
+ {""" % (name, description, version, name))
for enum in names:
if enum in map:
type_, code = map[enum]
code = -1
else:
type_ = code = -1
- print " { %2d, %3d }, /* %s */" % (type_, code, enum)
- print """\
+ 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)
+ output_domain(reverse["OF1.2"], "ofperr_of12", "OpenFlow 1.2", 0x03)
+ output_domain(reverse["OF1.3"], "ofperr_of13", "OpenFlow 1.3", 0x04)
if __name__ == '__main__':
if '--help' in sys.argv: