From 33a58171e5995d9e649b414bfc77f2aab26e4c58 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Wed, 4 Sep 2019 09:12:29 +0200 Subject: api: autogenerate api trace print/endian In addition to the external vppapitrace tool, VPP itself supports dumping of API trace files. In two formats, "custom-dump" and "dump". "dump" gives a human friendly list, and "custom-dump" is meant to give a list of commands that can be fed to VAT. This patch only deals with "dump". Prior to this fix, auto-generation was only done for the basic types. This fix adds support for any type, including lists, and supports pretty-printing of enums, strings, IP addresses, MAC addresses and so on. Usage: api trace dump For example Change-Id: I4e485680e6dcfce7489299ae6cf31d835071ac40 ---------- trace 48 ----------- vl_api_sw_interface_set_flags_t: _vl_msg_id: 75 client_index: 0 context: 10 sw_if_index: 1 flags: IF_STATUS_API_FLAG_ADMIN_UP ---------- trace 49 ----------- vl_api_sw_interface_add_del_address_t: _vl_msg_id: 88 client_index: 0 context: 11 sw_if_index: 1 is_add: 1 del_all: 0 prefix: 172.16.1.1/24 ---------- trace 51 ----------- vl_api_cli_inband_t: _vl_msg_id: 819 client_index: 0 context: 13 cmd: packet-generator capture pg0 pcap /tmp/vpp-unittest-TestMAP-YhcmDX/pg0_out.pcap disable ---------- trace 58 ----------- vl_api_ip_neighbor_add_del_t: _vl_msg_id: 199 client_index: 0 context: 20 is_add: 1 neighbor: sw_if_index: 2 flags: IP_API_NEIGHBOR_FLAG_NONE mac_address: 0202.0000.ff02 ip_address: fd01:2::2 Signed-off-by: Ole Troan Change-Id: I5556d06008de2762e7c2d35a8b0963ae670b3db1 Type: fix Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan Signed-off-by: Ole Troan --- src/tools/vppapigen/vppapigen.py | 79 ++++++- src/tools/vppapigen/vppapigen_c.py | 412 ++++++++++++++++++++++++++++------ src/tools/vppapigen/vppapigen_json.py | 18 +- src/tools/vppapitrace/vppapitrace.py | 11 +- 4 files changed, 434 insertions(+), 86 deletions(-) (limited to 'src/tools') diff --git a/src/tools/vppapigen/vppapigen.py b/src/tools/vppapigen/vppapigen.py index 2a939647c67..fa7e47afb73 100755 --- a/src/tools/vppapigen/vppapigen.py +++ b/src/tools/vppapigen/vppapigen.py @@ -8,6 +8,7 @@ import keyword import logging import binascii import os +import sys log = logging.getLogger('vppapigen') @@ -78,6 +79,16 @@ class VPPAPILexer(object): t_ignore_LINE_COMMENT = '//.*' + def t_FALSE(self, t): + r'false' + t.value = False + return t + + def t_TRUE(self, t): + r'false' + t.value = True + return t + def t_NUM(self, t): r'0[xX][0-9a-fA-F]+|-?\d+\.?\d*' base = 16 if t.value.startswith('0x') else 10 @@ -150,6 +161,14 @@ class Typedef(): self.manual_print = True elif f == 'manual_endian': self.manual_endian = True + for b in block: + # Tag length field of a VLA + if isinstance(b, Array): + if b.lengthfield: + for b2 in block: + if b2.fieldname == b.lengthfield: + b2.vla_len = True + global_type_add(name, self) self.vla = False @@ -176,10 +195,18 @@ class Typedef(): class Using(): - def __init__(self, name, alias): + def __init__(self, name, flags, alias): self.name = name self.vla = False + self.manual_print = False + self.manual_endian = False + for f in flags: + if f == 'manual_print': + self.manual_print = True + elif f == 'manual_endian': + self.manual_endian = True + if isinstance(alias, Array): a = {'type': alias.fieldtype, 'length': alias.length} @@ -194,11 +221,20 @@ class Using(): class Union(): - def __init__(self, name, block): + def __init__(self, name, flags, block): self.type = 'Union' self.manual_print = False self.manual_endian = False self.name = name + + self.manual_print = False + self.manual_endian = False + for f in flags: + if f == 'manual_print': + self.manual_print = True + elif f == 'manual_endian': + self.manual_endian = True + self.block = block self.crc = str(block).encode() global_type_add(name, self) @@ -250,6 +286,12 @@ class Define(): 'VLA field "{}" must be the last ' 'field in message "{}"' .format(b.fieldname, name)) + # Tag length field of a VLA + if isinstance(b, Array): + if b.lengthfield: + for b2 in block: + if b2.fieldname == b.lengthfield: + b2.vla_len = True def __repr__(self): return self.name + str(self.flags) + str(self.block) @@ -298,8 +340,10 @@ class Import(): class Option(): - def __init__(self, option): + def __init__(self, option, value): + self.type = 'Option' self.option = option + self.value = value self.crc = str(option).encode() def __repr__(self): @@ -524,9 +568,17 @@ class VPPAPIParser(object): '''typedef : TYPEDEF ID '{' block_statements_opt '}' ';' ''' p[0] = Typedef(p[2], [], p[4]) + def p_typedef_flist(self, p): + '''typedef : flist TYPEDEF ID '{' block_statements_opt '}' ';' ''' + p[0] = Typedef(p[3], p[1], p[5]) + def p_typedef_alias(self, p): '''typedef : TYPEDEF declaration ''' - p[0] = Using(p[2].fieldname, p[2]) + p[0] = Using(p[2].fieldname, [], p[2]) + + def p_typedef_alias_flist(self, p): + '''typedef : flist TYPEDEF declaration ''' + p[0] = Using(p[3].fieldname, p[1], p[3]) def p_block_statements_opt(self, p): '''block_statements_opt : block_statements ''' @@ -620,7 +672,7 @@ class VPPAPIParser(object): def p_option(self, p): '''option : OPTION ID '=' assignee ';' ''' - p[0] = Option([p[1], p[2], p[4]]) + p[0] = Option(p[2], p[4]) def p_assignee(self, p): '''assignee : NUM @@ -653,7 +705,11 @@ class VPPAPIParser(object): def p_union(self, p): '''union : UNION ID '{' block_statements_opt '}' ';' ''' - p[0] = Union(p[2], p[4]) + p[0] = Union(p[2], [], p[4]) + + def p_union_flist(self, p): + '''union : flist UNION ID '{' block_statements_opt '}' ';' ''' + p[0] = Union(p[3], p[1], p[5]) # Error rule for syntax errors def p_error(self, p): @@ -716,7 +772,7 @@ class VPPAPI(object): isinstance(o, Union)): s['types'].append(o) elif isinstance(o, Using): - s['Alias'][o.name] = o.alias + s['Alias'][o.name] = o else: if tname not in s: raise ValueError('Unknown class type: {} {}' @@ -802,6 +858,7 @@ class VPPAPI(object): isinstance(o, Using)): continue if isinstance(o, Import): + result.append(o) self.process_imports(o.result, True, result) else: result.append(o) @@ -894,8 +951,12 @@ def main(): # Build a list of objects. Hash of lists. result = [] - parser.process_imports(parsed_objects, False, result) - s = parser.process(result) + + if args.output_module == 'C': + s = parser.process(parsed_objects) + else: + parser.process_imports(parsed_objects, False, result) + s = parser.process(result) # Add msg_id field s['Define'] = add_msg_id(s['Define']) diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py index c1bc11d4a12..d6cdda8baac 100644 --- a/src/tools/vppapigen/vppapigen_c.py +++ b/src/tools/vppapigen/vppapigen_c.py @@ -2,6 +2,8 @@ import datetime import os import time +import sys +from io import StringIO datestring = datetime.datetime.utcfromtimestamp( int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))) @@ -86,16 +88,6 @@ def msg_name_crc_list(s, suffix): return output -def duplicate_wrapper_head(name): - s = "#ifndef _vl_api_defined_%s\n" % name - s += "#define _vl_api_defined_%s\n" % name - return s - - -def duplicate_wrapper_tail(): - return '#endif\n\n' - - def api2c(fieldtype): mappingtable = {'string': 'vl_api_string_t', } if fieldtype in mappingtable: @@ -111,22 +103,20 @@ def typedefs(objs, aliases, filename): /****** Typedefs ******/ #ifdef vl_typedefs -#ifndef included_{module} -#define included_{module} +#ifndef included_{module}_typedef +#define included_{module}_typedef ''' output = output.format(module=name) for k, v in aliases.items(): - output += duplicate_wrapper_head(k) - if 'length' in v: - output += 'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length']) + if 'length' in v.alias: + output += ('typedef %s vl_api_%s_t[%s];\n' + % (v.alias['type'], k, v.alias['length'])) else: - output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k) - output += duplicate_wrapper_tail() + output += 'typedef %s vl_api_%s_t;\n' % (v.alias['type'], k) for o in objs: tname = o.__class__.__name__ - output += duplicate_wrapper_head(o.name) if tname == 'Enum': if o.enumtype == 'u32': output += "typedef enum {\n" @@ -140,33 +130,43 @@ def typedefs(objs, aliases, filename): size1 = 'sizeof(vl_api_%s_t)' % o.name size2 = 'sizeof(%s)' % o.enumtype err_str = 'size of API enum %s is wrong' % o.name - output += 'STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str) + output += ('STATIC_ASSERT(%s == %s, "%s");\n' + % (size1, size2, err_str)) else: if tname == 'Union': output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name else: - output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name + output += ("typedef VL_API_PACKED(struct _vl_api_%s {\n" + % o.name) for b in o.block: + if b.type == 'Option': + continue if b.type == 'Field': - output += " %s %s;\n" % (api2c(b.fieldtype), b.fieldname) + output += " %s %s;\n" % (api2c(b.fieldtype), + b.fieldname) elif b.type == 'Array': if b.lengthfield: - output += " %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname) + output += " %s %s[0];\n" % (api2c(b.fieldtype), + b.fieldname) else: # Fixed length strings decay to nul terminated u8 if b.fieldtype == 'string': if b.modern_vla: - output += ' {} {};\n'.format(api2c(b.fieldtype), b.fieldname) + output += (' {} {};\n' + .format(api2c(b.fieldtype), + b.fieldname)) else: - output += ' u8 {}[{}];\n'.format(b.fieldname, b.length) + output += (' u8 {}[{}];\n' + .format(b.fieldname, b.length)) else: - output += " %s %s[%s];\n" % (api2c(b.fieldtype), b.fieldname, - b.length) + output += (" %s %s[%s];\n" % + (api2c(b.fieldtype), b.fieldname, + b.length)) else: - raise ValueError("Error in processing array type %s" % b) + raise ValueError("Error in processing type {} for {}" + .format(b, o.name)) output += '}) vl_api_%s_t;\n' % o.name - output += duplicate_wrapper_tail() output += "\n#endif" output += "\n#endif\n\n" @@ -175,6 +175,7 @@ def typedefs(objs, aliases, filename): format_strings = {'u8': '%u', + 'bool': '%u', 'i8': '%d', 'u16': '%u', 'i16': '%d', @@ -182,13 +183,136 @@ format_strings = {'u8': '%u', 'i32': '%ld', 'u64': '%llu', 'i64': '%llu', - 'f64': '%.2f', } + 'f64': '%.2f'} + +noprint_fields = {'_vl_msg_id': None, + 'client_index': None, + 'context': None} + + +class Printfun(): + _dispatch = {} + + def __init__(self, stream): + self.stream = stream + + def print_string(self, o, stream): + write = stream.write + if o.modern_vla: + write(' if (vl_api_string_len(&a->{f}) > 0) {{\n' + .format(f=o.fieldname)) + write(' s = format(s, "\\n%U{f}: %.*s", ' + 'format_white_space, indent, ' + 'vl_api_string_len(&a->{f}) - 1, ' + 'vl_api_from_api_string(&a->{f}));\n'.format(f=o.fieldname)) + write(' } else {\n') + write(' s = format(s, "\\n%U{f}:", ' + 'format_white_space, indent);\n'.format(f=o.fieldname)) + write(' }\n') + else: + write(' s = format(s, "\\n%U{f}: %s", ' + 'format_white_space, indent, a->{f});\n' + .format(f=o.fieldname)) + + def print_field(self, o, stream): + write = stream.write + if o.fieldname in noprint_fields: + return + if o.fieldtype in format_strings: + f = format_strings[o.fieldtype] + write(' s = format(s, "\\n%U{n}: {f}", ' + 'format_white_space, indent, a->{n});\n' + .format(n=o.fieldname, f=f)) + else: + write(' s = format(s, "\\n%U{n}: %U", ' + 'format_white_space, indent, ' + 'format_{t}, &a->{n}, indent);\n' + .format(n=o.fieldname, t=o.fieldtype)) + _dispatch['Field'] = print_field -def printfun(objs): - output = '''\ + def print_array(self, o, stream): + write = stream.write + + forloop = '''\ + for (i = 0; i < {lfield}; i++) {{ + s = format(s, "\\n%U{n}: %U", + format_white_space, indent, format_{t}, &a->{n}[i], indent); + }} +''' + + forloop_format = '''\ + for (i = 0; i < {lfield}; i++) {{ + s = format(s, "\\n%U{n}: {t}", + format_white_space, indent, a->{n}[i]); + }} +''' + + if o.fieldtype == 'string': + return self.print_string(o, stream) + + if o.fieldtype == 'u8': + if o.lengthfield: + write(' s = format(s, "\\n%U{n}: %U", format_white_space, ' + 'indent, format_hex_bytes, a->{n}, a->{lfield});\n' + .format(n=o.fieldname, lfield=o.lengthfield)) + else: + write(' s = format(s, "\\n%U{n}: %U", format_white_space, ' + 'indent, format_hex_bytes, a, {lfield});\n' + .format(n=o.fieldname, lfield=o.length)) + return + + lfield = 'a->' + o.lengthfield if o.lengthfield else o.length + if o.fieldtype in format_strings: + write(forloop_format.format(lfield=lfield, + t=format_strings[o.fieldtype], + n=o.fieldname)) + else: + write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname)) + + _dispatch['Array'] = print_array + + def print_alias(self, k, v, stream): + write = stream.write + if ('length' in v.alias and v.alias['length'] and + v.alias['type'] == 'u8'): + write(' return format(s, "%U", format_hex_bytes, a, {});\n' + .format(v.alias['length'])) + elif v.alias['type'] in format_strings: + write(' return format(s, "{}", *a);\n' + .format(format_strings[v.alias['type']])) + else: + write(' return format(s, "{} (print not implemented)"' + .format(k)) + + def print_enum(self, o, stream): + write = stream.write + write(" switch(*a) {\n") + for b in o: + write(" case %s:\n" % b[1]) + write(' return format(s, "{}");\n'.format(b[0])) + write(' }\n') + + _dispatch['Enum'] = print_enum + + def print_obj(self, o, stream): + write = stream.write + + if o.type in self._dispatch: + self._dispatch[o.type](self, o, stream) + else: + write(' s = format(s, "\\n{} {} {} (print not implemented");\n' + .format(o.type, o.fieldtype, o.fieldname)) + + +def printfun(objs, stream, modulename): + write = stream.write + + h = '''\ /****** Print functions *****/ #ifdef vl_printfun +#ifndef included_{module}_printfun +#define included_{module}_printfun #ifdef LP64 #define _uword_fmt \"%lld\" @@ -199,32 +323,103 @@ def printfun(objs): #endif ''' + + signature = '''\ +static inline void *vl_api_{name}_t_print (vl_api_{name}_t *a, void *handle) +{{ + u8 *s = 0; + u32 indent __attribute__((unused)) = 2; + int i __attribute__((unused)); +''' + + h = h.format(module=modulename) + write(h) + + pp = Printfun(stream) + for t in objs: + if t.manual_print: + write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name) + continue + write(signature.format(name=t.name)) + write(' /* Message definition: vl_api_{}_t: */\n'.format(t.name)) + write(" s = format(s, \"vl_api_%s_t:\");\n" % t.name) + for o in t.block: + pp.print_obj(o, stream) + write(' vec_add1(s, 0);\n') + write(' vl_print (handle, (char *)s);\n') + write(' vec_free (s);\n') + write(' return handle;\n') + write('}\n\n') + + write("\n#endif") + write("\n#endif /* vl_printfun */\n") + + return '' + + +def printfun_types(objs, aliases, stream, modulename): + write = stream.write + pp = Printfun(stream) + + h = '''\ +/****** Print functions *****/ +#ifdef vl_printfun +#ifndef included_{module}_printfun_types +#define included_{module}_printfun_types + +''' + h = h.format(module=modulename) + write(h) + + signature = '''\ +static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args) +{{ + vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *); + u32 indent __attribute__((unused)) = va_arg (*args, u32); + int i __attribute__((unused)); + indent += 2; +''' + + for k, v in aliases.items(): + if v.manual_print: + write("/***** manual: vl_api_%s_t_print *****/\n\n" % k) + continue + + write(signature.format(name=k)) + pp.print_alias(k, v, stream) + write('}\n\n') + for t in objs: if t.__class__.__name__ == 'Enum': + write(signature.format(name=t.name)) + pp.print_enum(t.block, stream) + write(' return s;\n') + write('}\n\n') continue + if t.manual_print: - output += "/***** manual: vl_api_%s_t_print *****/\n\n" % t.name + write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name) continue - output += duplicate_wrapper_head(t.name + '_t_print') - output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \ - (t.name, t.name) - output += "void *handle)\n{\n" - output += " vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name + write(signature.format(name=t.name)) for o in t.block: - if o.type != 'Field': - continue - if o.fieldtype in format_strings: - output += " vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \ - (o.fieldname, format_strings[o.fieldtype], - o.fieldname) - - output += ' return handle;\n' - output += '}\n\n' - output += duplicate_wrapper_tail() + pp.print_obj(o, stream) + + write(' return s;\n') + write('}\n\n') + + write("\n#endif") + write("\n#endif /* vl_printfun_types */\n") - output += "\n#endif /* vl_printfun */\n" +def imports(imports): + output = '/* Imported API files */\n' + output += '#ifndef vl_api_version\n' + + for i in imports: + s = i.filename.replace('plugins/', '') + output += '#include <{}.h>\n'.format(s) + output += '#endif\n' return output @@ -239,11 +434,64 @@ endian_strings = { } -def endianfun(objs): +def endianfun_array(o): + forloop = '''\ + for (i = 0; i < {length}; i++) {{ + a->{name}[i] = {format}(a->{name}[i]); + }} +''' + + forloop_format = '''\ + for (i = 0; i < {length}; i++) {{ + {type}_endian(&a->{name}[i]); + }} +''' + + output = '' + if o.fieldtype == 'u8' or o.fieldtype == 'string': + output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname) + else: + lfield = 'a->' + o.lengthfield if o.lengthfield else o.length + if o.fieldtype in endian_strings: + output += (forloop + .format(length=lfield, + format=endian_strings[o.fieldtype], + name=o.fieldname)) + else: + output += (forloop_format + .format(length=lfield, type=o.fieldtype, + name=o.fieldname)) + return output + + +def endianfun_obj(o): + output = '' + if o.type == 'Array': + return endianfun_array(o) + elif o.type != 'Field': + output += (' s = format(s, "\\n{} {} {} (print not implemented");\n' + .format(o.type, o.fieldtype, o.fieldname)) + return output + if o.fieldtype in endian_strings: + output += (' a->{name} = {format}(a->{name});\n' + .format(name=o.fieldname, + format=endian_strings[o.fieldtype])) + elif o.fieldtype.startswith('vl_api_'): + output += (' {type}_endian(&a->{name});\n' + .format(type=o.fieldtype, name=o.fieldname)) + else: + output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname) + + return output + + +def endianfun(objs, aliases, modulename): output = '''\ /****** Endian swap functions *****/\n\ #ifdef vl_endianfun +#ifndef included_{module}_endianfun +#define included_{module}_endianfun #undef clib_net_to_host_uword #ifdef LP64 @@ -253,30 +501,55 @@ def endianfun(objs): #endif ''' + output = output.format(module=modulename) + + signature = '''\ +static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a) +{{ + int i __attribute__((unused)); +''' + + for k, v in aliases.items(): + if v.manual_endian: + output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % k + continue + + output += signature.format(name=k) + if ('length' in v.alias and v.alias['length'] and + v.alias['type'] == 'u8'): + output += (' /* a->{name} = a->{name} (no-op) */\n' + .format(name=k)) + elif v.alias['type'] in format_strings: + output += (' *a = {}(*a);\n' + .format(endian_strings[v.alias['type']])) + else: + output += ' /* Not Implemented yet {} */'.format(k) + output += '}\n\n' for t in objs: if t.__class__.__name__ == 'Enum': + output += signature.format(name=t.name) + if t.enumtype in endian_strings: + output += (' *a = {}(*a);\n' + .format(endian_strings[t.enumtype])) + else: + output += (' /* a->{name} = a->{name} (no-op) */\n' + .format(name=t.name)) + + output += '}\n\n' continue + if t.manual_endian: output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name continue - output += duplicate_wrapper_head(t.name + '_t_endian') - output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \ - (t.name, t.name) - output += "\n{\n" - for o in t.block: - if o.type != 'Field': - continue - if o.fieldtype in endian_strings: - output += " a->%s = %s(a->%s);\n" % \ - (o.fieldname, endian_strings[o.fieldtype], o.fieldname) - else: - output += " /* a->%s = a->%s (no-op) */\n" % \ - (o.fieldname, o.fieldname) + output += signature.format(name=t.name) + for o in t.block: + output += endianfun_obj(o) output += '}\n\n' - output += duplicate_wrapper_tail() + + output += "\n#endif" output += "\n#endif /* vl_endianfun */\n\n" return output @@ -304,16 +577,23 @@ def version_tuple(s, module): # Plugin entry point # def run(input_filename, s): + stream = StringIO() basename = os.path.basename(input_filename) filename, file_extension = os.path.splitext(basename) + modulename = filename.replace('.', '_') + output = top_boilerplate.format(datestring=datestring, input_filename=basename) + output += imports(s['Import']) output += msg_ids(s) output += msg_names(s) output += msg_name_crc_list(s, filename) - output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension) - output += printfun(s['types'] + s['Define']) - output += endianfun(s['types'] + s['Define']) + output += typedefs(s['types'] + s['Define'], s['Alias'], + filename + file_extension) + printfun_types(s['types'], s['Alias'], stream, modulename) + printfun(s['Define'], stream, modulename) + output += stream.getvalue() + output += endianfun(s['types'] + s['Define'], s['Alias'], modulename) output += version_tuple(s, basename) output += bottom_boilerplate.format(input_filename=basename, file_crc=s['file_crc']) diff --git a/src/tools/vppapigen/vppapigen_json.py b/src/tools/vppapigen/vppapigen_json.py index 124c0d3a0bd..ef1c9823c33 100644 --- a/src/tools/vppapigen/vppapigen_json.py +++ b/src/tools/vppapigen/vppapigen_json.py @@ -26,12 +26,14 @@ def walk_services(s): return r -def walk_defs(s, is_message = False): +def walk_defs(s, is_message=False): r = [] for t in s: d = [] d.append(t.name) for b in t.block: + if b.type == 'Option': + continue if b.type == 'Field': if b.limit: d.append([b.fieldtype, b.fieldname, b.limit]) @@ -39,7 +41,8 @@ def walk_defs(s, is_message = False): d.append([b.fieldtype, b.fieldname]) elif b.type == 'Array': if b.lengthfield: - d.append([b.fieldtype, b.fieldname, b.length, b.lengthfield]) + d.append([b.fieldtype, b.fieldname, + b.length, b.lengthfield]) else: d.append([b.fieldtype, b.fieldname, b.length]) elif b.type == 'Union': @@ -62,12 +65,15 @@ def walk_defs(s, is_message = False): def run(filename, s): j = {} - j['types'] = walk_defs([o for o in s['types'] if o.__class__.__name__ == 'Typedef']) + j['types'] = (walk_defs([o for o in s['types'] + if o.__class__.__name__ == 'Typedef'])) j['messages'] = walk_defs(s['Define'], True) - j['unions'] = walk_defs([o for o in s['types'] if o.__class__.__name__ == 'Union']) - j['enums'] = walk_enums([o for o in s['types'] if o.__class__.__name__ == 'Enum']) + j['unions'] = (walk_defs([o for o in s['types'] + if o.__class__.__name__ == 'Union'])) + j['enums'] = (walk_enums([o for o in s['types'] + if o.__class__.__name__ == 'Enum'])) j['services'] = walk_services(s['Service']) j['options'] = s['Option'] - j['aliases'] = s['Alias'] + j['aliases'] = {k: v.alias for k, v in s['Alias'].items()} j['vl_api_version'] = hex(s['file_crc']) return json.dumps(j, indent=4, separators=(',', ': ')) diff --git a/src/tools/vppapitrace/vppapitrace.py b/src/tools/vppapitrace/vppapitrace.py index 640b820d994..8089b3a2236 100755 --- a/src/tools/vppapitrace/vppapitrace.py +++ b/src/tools/vppapitrace/vppapitrace.py @@ -102,6 +102,7 @@ def unserialize_msgtbl(data, offset): def serialize_msgtbl(messages): offset = 0 + # XXX 100K? data = bytearray(100000) nmsg = len(messages) data = struct.pack(">I", nmsg) @@ -380,8 +381,8 @@ def generate(args): filename, file_extension = os.path.splitext(args.input) input_type = JSON if file_extension == '.json' else APITRACE - filename, file_extension = os.path.splitext(args.output) + if args.todump: output_type = DUMP else: @@ -395,7 +396,7 @@ def generate(args): if input_type == output_type: sys.exit("error: Nothing to convert between") - if input_type == JSON and output_type == APITRACE: + if input_type != JSON and output_type == APITRACE: sys.exit("error: Input file must be JSON file: {}".format(args.input)) messages, services = init_api(args.apidir) @@ -407,11 +408,11 @@ def generate(args): i += 1 n, result = json2apitrace(messages, args.input) + msgtbl = serialize_msgtbl(messages) + print('API messages: {}'.format(n)) - header = struct.pack(">IIB", n, len(messages), 0) + header = struct.pack(">IIB", n, len(msgtbl), 0) - i = 0 - msgtbl = serialize_msgtbl(messages) with open(args.output, 'wb') as outfile: outfile.write(header) outfile.write(msgtbl) -- cgit 1.2.3-korg