diff options
author | Dave Barach <dave@barachs.net> | 2016-11-10 14:22:49 -0500 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2016-11-21 18:11:41 +0000 |
commit | 557d128b68a1213e056f5eed9fe6f230ca3f3144 (patch) | |
tree | 6b31ac462efacf3f6937788c9b7af1420497c9fc /vppapigen | |
parent | fca670b0ec9f74aa977fe479a5517ad6367ee898 (diff) |
Add client-side msg_name_and_crc -> msg_index table
vppapigen now generates per-message crcs. Verified that whitespace
and real changes in message A don't change the crc for message B, etc.
Fixed the sample and flowperpkt plugins to participate. Others need
the same treatment. They don't build due to python/java language binding
build issues.
To use the scheme:
Client connects as usual.
Then call: u32 vl_api_get_msg_index(char * name_and_crc)
name_and_crc is a string like: "flowperpkt_tx_interface_add_del_753301f3",
aka the message name with _%08x <expected crc> appended.
Try these vpp-api-test commands to play with it:
vat# dump_msg_api_table
<snip>
[366]: punt_reply_cca27fbe
[367]: ipsec_spd_dump_5e9ae88e
[368]: ipsec_spd_details_6f7821b0
[369]: sample_macswap_enable_disable_0f2813e2
[370]: sample_macswap_enable_disable_reply_476738e5
[371]: flowperpkt_tx_interface_add_del_753301f3
[372]: flowperpkt_tx_interface_add_del_reply_d47e6e0b
vat# get_msg_id sample_macswap_enable_disable_reply_476738e5
'sample_macswap_enable_disable_reply_476738e5' has message index 370
vat# get_msg_id sample_macswap_enable_disable_reply_476738e3
'sample_macswap_enable_disable_reply_476738e3' not found
CRCs may vary, etc.
vppapigen is used to build a set of JSON representations
of each API file from vpp-api/Makefile.am and that is in
turn used by each language binding (Java, Python, Lua).
Change-Id: I3d64582e779dac5f20cddec79c562c288d8fd9c6
Signed-off-by: Dave Barach <dave@barachs.net>
Signed-off-by: Ole Troan <ot@cisco.com>
Diffstat (limited to 'vppapigen')
-rw-r--r-- | vppapigen/lex.c | 105 | ||||
-rw-r--r-- | vppapigen/lex.h | 1 | ||||
-rw-r--r-- | vppapigen/node.c | 146 | ||||
-rw-r--r-- | vppapigen/node.h | 4 |
4 files changed, 219 insertions, 37 deletions
diff --git a/vppapigen/lex.c b/vppapigen/lex.c index b011044dd01..e807d46b9a0 100644 --- a/vppapigen/lex.c +++ b/vppapigen/lex.c @@ -28,7 +28,7 @@ #include "node.h" #include "gram.h" -FILE *ifp, *ofp, *pythonfp; +FILE *ifp, *ofp, *pythonfp, *jsonfp; char *vlib_app_name = "vpp"; int dump_tree; time_t starttime; @@ -36,6 +36,7 @@ char *input_filename; char *current_filename; int current_filename_allocated; unsigned long input_crc; +unsigned long message_crc; int yydebug; /* @@ -258,6 +259,7 @@ int main (int argc, char **argv) int curarg = 1; char *ofile=0; char *pythonfile=0; + char *jsonfile=0; char *show_name=0; while (curarg < argc) { @@ -349,6 +351,27 @@ int main (int argc, char **argv) } continue; } + if (!strncmp (argv [curarg], "--json", 6)) { + curarg++; + if (curarg < argc) { + if (!strcmp(argv[curarg], "-")) { + jsonfp = stdout; + } else { + jsonfp = fopen(argv[curarg], "w"); + jsonfile = argv[curarg]; + } + if (jsonfp == NULL) { + fprintf (stderr, "Couldn't open JSON output file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --json\n"); + exit(1); + } + continue; + } if (!strncmp (argv [curarg], "--app", 4)) { curarg++; if (curarg < argc) { @@ -370,6 +393,9 @@ int main (int argc, char **argv) if (pythonfp == NULL) { pythonfile = 0; } + if (jsonfp == NULL) { + jsonfile = 0; + } if (ifp == NULL) { fprintf(stderr, "No input file specified...\n"); exit(1); @@ -391,6 +417,10 @@ int main (int argc, char **argv) printf ("Python bindings written to %s\n", pythonfile); fclose (pythonfp); } + if (jsonfile) { + printf ("JSON bindings written to %s\n", jsonfile); + fclose (jsonfp); + } } else { fclose (ifp); @@ -404,6 +434,10 @@ int main (int argc, char **argv) printf ("Removing %s\n", pythonfile); unlink (pythonfile); } + if (jsonfile) { + printf ("Removing %s\n", jsonfile); + unlink (jsonfile); + } exit (1); } exit (0); @@ -415,7 +449,8 @@ int main (int argc, char **argv) static void usage (char *progname) { fprintf (stderr, - "usage: %s --input <filename> [--output <filename>] [--python <filename>]\n%s", + "usage: %s --input <filename> [--output <filename>] " + "[--json <filename>] [--python <filename>]\n%s", progname, " [--yydebug] [--dump-tree]\n"); exit (1); @@ -818,18 +853,18 @@ int yylex (void) */ unsigned long crc = input_crc; int node_type = yylex_1 (); + unsigned long crc2 = message_crc; + int use_helper_string = 0; + unsigned short code; switch (node_type) { case PRIMTYPE: case NAME: case NUMBER: case STRING: - case HELPER_STRING: { - /* We know these types accumulated token text into namebuf */ - /* HELPER_STRING may still contain C comments. Argh. */ - crc = crc_eliding_c_comments (namebuf, crc); + case HELPER_STRING: + use_helper_string = 1; break; - } /* Other node types have no "substate" */ /* This code is written in this curious fashion because we @@ -837,30 +872,25 @@ int yylex (void) * values a particular version of lex/bison assigned to various states. */ - /* case NAME: crc = CRC16 (crc, 257); break; */ - case RPAR: crc = CRC16 (crc, 258); break; - case LPAR: crc = CRC16 (crc, 259); break; - case SEMI: crc = CRC16 (crc, 260); break; - case LBRACK: crc = CRC16 (crc, 261); break; - case RBRACK: crc = CRC16 (crc, 262); break; - /* case NUMBER: crc = CRC16 (crc, 263); break; */ - /* case PRIMTYPE: crc = CRC16 (crc, 264); break; */ - case BARF: crc = CRC16 (crc, 265); break; - case TPACKED: crc = CRC16 (crc, 266); break; - case DEFINE: crc = CRC16 (crc, 267); break; - case LCURLY: crc = CRC16 (crc, 268); break; - case RCURLY: crc = CRC16 (crc, 269); break; - /* case STRING: crc = CRC16 (crc, 270); break; */ - case UNION: crc = CRC16 (crc, 271); break; - /* case HELPER_STRING: crc = CRC16 (crc, 272); break; */ - case COMMA: crc = CRC16 (crc, 273); break; - case NOVERSION: crc = CRC16 (crc, 274); break; - case MANUAL_PRINT: crc = CRC16 (crc, 275); break; - case MANUAL_ENDIAN: crc = CRC16 (crc, 276); break; - case TYPEONLY: crc = CRC16 (crc, 278); break; - case DONT_TRACE: crc = CRC16 (crc, 279); break; + case RPAR: code = 258; break; + case LPAR: code = 259; break; + case SEMI: code = 260; break; + case LBRACK: code = 261; break; + case RBRACK: code = 262; break; + case BARF: code = 265; break; + case TPACKED: code = 266; break; + case DEFINE: code = 267; break; + case LCURLY: code = 268; break; + case RCURLY: code = 269; break; + case UNION: code = 271; break; + case COMMA: code = 273; break; + case NOVERSION: code = 274; break; + case MANUAL_PRINT: code = 275; break; + case MANUAL_ENDIAN: code = 276; break; + case TYPEONLY: code = 278; break; + case DONT_TRACE: code = 279; break; - case EOF: crc = CRC16 (crc, ~0); break; /* hysterical compatibility */ + case EOF: code = ~0; break; /* hysterical compatibility */ default: fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n", @@ -868,11 +898,23 @@ int yylex (void) exit(1); } + if (use_helper_string) + { + /* We know these types accumulated token text into namebuf */ + /* HELPER_STRING may still contain C comments. Argh. */ + crc = crc_eliding_c_comments (namebuf, crc); + crc2 = crc_eliding_c_comments (namebuf, crc2); + } else + { + crc = CRC16 (crc, code); + crc2 = CRC16 (crc2, code); + } + input_crc = crc; + message_crc = crc2; return (node_type); } - /* * name_check -- see if the name we just ate * matches a known keyword. If so, set yylval @@ -943,6 +985,7 @@ static int name_check (const char *s, YYSTYPE *token_value) return (TPACKED); case NODE_DEFINE: + message_crc = 0; *token_value = make_node(subclass_id); return(DEFINE); diff --git a/vppapigen/lex.h b/vppapigen/lex.h index 5bf38fe8093..e9b0954c0b9 100644 --- a/vppapigen/lex.h +++ b/vppapigen/lex.h @@ -45,5 +45,6 @@ enum lex_state { #define MAXNAME 64000 extern unsigned long input_crc; +extern unsigned long message_crc; #endif /* _LEX_H_ */ diff --git a/vppapigen/node.c b/vppapigen/node.c index fa7146ae497..4460fd5f933 100644 --- a/vppapigen/node.c +++ b/vppapigen/node.c @@ -18,6 +18,7 @@ */ #include <stdio.h> +#include <stdbool.h> #include <ctype.h> #include <time.h> #include <string.h> @@ -33,6 +34,7 @@ FILE *ofp; FILE *pythonfp; +FILE *jsonfp; time_t starttime; char *vlib_app_name; char *input_filename; @@ -130,6 +132,12 @@ void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp, fputs("', ", pythonfp); break; + case JSON_PASS: + fputs("[\"", jsonfp); + fputs((char *)type_name, jsonfp); + fputs("\", ", jsonfp); + break; + default: fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which); break; @@ -377,6 +385,24 @@ void node_define_generate (node_t *this, enum passid which, FILE *fp) fprintf(fp, "),\n\n"); break; + case JSON_PASS: + fprintf(fp, "[\"%s\",\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + fprintf(fp, ",\n"); + } + indent_me(fp); + fprintf (fp, "{\"crc\" : \"0x%08x\"}\n", (u32)(u64)CDATA3); + indent -= 4; + indent_me(fp); + fprintf(fp, "]"); + break; + default: fprintf(stderr, "node_define_generate: unimp pass %d\n", which); break; @@ -537,6 +563,10 @@ void node_scalar_generate (node_t *this, enum passid which, FILE *fp) fprintf(fp, "'%s'),\n", CDATA0); break; + case JSON_PASS: + fprintf(fp, "\"%s\"]", CDATA0); + break; + default: fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which); } @@ -658,6 +688,14 @@ void node_vector_generate (node_t *this, enum passid which, FILE *fp) } break; + case JSON_PASS: + if (CDATA2 != 0) { /* variable length vector */ + fprintf(fp, "\"%s\", %d, \"%s\"]", CDATA0, IDATA1, CDATA2); + } else { + fprintf(fp, "\"%s\", %d]", CDATA0, IDATA1); + } + break; + default: fprintf(stderr, "node_vector_generate: unimp pass %d\n", which); } @@ -746,6 +784,15 @@ void node_complex_generate (node_t *this, enum passid which, FILE *fp) } break; + case JSON_PASS: + fprintf(fp, "[\"%s\", ", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + default: fprintf(stderr, "node_complex_generate unimp pass %d...\n", which); break; @@ -879,6 +926,7 @@ YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2) np = make_node(NODE_DEFINE); np->data[0] = a1; + np->data[3] = (void *) message_crc; deeper((YYSTYPE)np, a2); return ((YYSTYPE) np); } @@ -1065,15 +1113,11 @@ void generate_top_boilerplate(FILE *fp) fprintf (fp, " * Input file: %s\n", input_filename); fprintf (fp, " * Automatically generated: please edit the input file "); fprintf (fp, "NOT this file!\n"); - - /* Moron Acme trigger workaround */ - fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop", - &datestring[20]); fprintf (fp, " */\n\n"); fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||"); fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||"); fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n"); - fprintf (fp, " ||defined(vl_msg_name)\n"); + fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)\n"); fprintf (fp, "/* ok, something was selected */\n"); fprintf (fp, "#else\n"); fprintf (fp, "#warning no content included from %s\n", input_filename); @@ -1141,6 +1185,37 @@ void generate_msg_names(YYSTYPE a1, FILE *fp) fprintf (fp, "#endif\n\n"); } +void generate_msg_name_crc_list (YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + char *unique_suffix, *cp; + + unique_suffix = sxerox(fixed_name); + + cp = unique_suffix; + while (*cp && (*cp != '.')) + cp++; + if (*cp == '.') + *cp = 0; + + fprintf (fp, "\n/****** Message name, crc list ******/\n\n"); + + fprintf (fp, "#ifdef vl_msg_name_crc_list\n"); + fprintf (fp, "#define foreach_vl_msg_name_crc_%s ", unique_suffix); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "\\\n_(VL_API_%s, %s, %08x) ", + uppercase (np->data[0]), (i8 *) np->data[0], + (u32)(u64)np->data[3]); + } + } + np = np->peer; + } + fprintf (fp, "\n#endif\n\n"); +} + void generate_typedefs(YYSTYPE a1, FILE *fp) { node_t *np = (node_t *)a1; @@ -1341,6 +1416,47 @@ void generate_python_msg_definitions(YYSTYPE a1, FILE *fp) fprintf (fp, "\n]\n"); } +static bool +is_typeonly_check(node_t *np, bool typeonly) +{ + bool is_typeonly = (np->flags & NODE_FLAG_TYPEONLY); + return (is_typeonly == typeonly); +} + +static void +generate_json_definitions(YYSTYPE a1, FILE *fp, bool typeonly) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + indent_me(fp); + if (typeonly) + fprintf (fp, "\"types\" : [\n"); + else + fprintf (fp, "\"messages\" : [\n"); + + /* Walk the top-level node-list */ + bool comma = false; + indent += 4; + while (np) { + if (np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + indent_me(fp); + vftp->generate(np, JSON_PASS, fp); + comma = true; + } + np = np->peer; + if (comma && np && + np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) + fprintf (fp, ",\n"); + + } + indent -= 4; + fprintf (fp, "\n"); + indent_me(fp); + fprintf(fp, "]"); +} + void generate_python_typeonly_definitions(YYSTYPE a1, FILE *fp) { node_t *np = (node_t *)a1; @@ -1368,6 +1484,22 @@ void generate_python(YYSTYPE a1, FILE *fp) fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc); } +void generate_json(YYSTYPE a1, FILE *fp) +{ + fprintf (fp, "{\n"); + indent += 4; + generate_json_definitions(a1, fp, true); + fprintf (fp, ",\n"); + generate_json_definitions(a1, fp, false); + + /* + * API CRC signature + */ + fprintf (fp, ",\n\"vl_api_version\" :\"0x%08x\"\n", + (unsigned int)input_crc); + fprintf (fp, "}\n"); +} + void generate(YYSTYPE a1) { if (dump_tree) { @@ -1381,6 +1513,7 @@ void generate(YYSTYPE a1) generate_msg_ids(a1, ofp); generate_msg_names(a1, ofp); + generate_msg_name_crc_list(a1, ofp); generate_typedefs(a1, ofp); generate_uniondefs(a1, ofp); generate_printfun(a1, ofp); @@ -1391,4 +1524,7 @@ void generate(YYSTYPE a1) if (pythonfp) { generate_python(a1, pythonfp); } + if (jsonfp) { + generate_json(a1, jsonfp); + } } diff --git a/vppapigen/node.h b/vppapigen/node.h index f80985e1009..297d603615b 100644 --- a/vppapigen/node.h +++ b/vppapigen/node.h @@ -61,6 +61,7 @@ enum passid { ENDIANFUN_PASS, PRINTFUN_PASS, PYTHON_PASS, + JSON_PASS, }; extern void *make_node (enum node_subclass type); @@ -70,13 +71,14 @@ typedef struct node_ { struct node_ *peer; struct node_ *deeper; int flags; - void *data[3]; + void *data[4]; } node_t; /* To shut up gcc-4.2.x warnings */ #define CDATA0 ((char *)(this->data[0])) #define IDATA1 ((int)(uword)(this->data[1])) #define CDATA2 ((char *)(this->data[2])) +#define CDATA3 ((char *)(this->data[3])) #define NODE_FLAG_MANUAL_PRINT (1<<0) #define NODE_FLAG_MANUAL_ENDIAN (1<<1) |