summaryrefslogtreecommitdiffstats
path: root/vppapigen
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2016-11-10 14:22:49 -0500
committerDamjan Marion <dmarion.lists@gmail.com>2016-11-21 18:11:41 +0000
commit557d128b68a1213e056f5eed9fe6f230ca3f3144 (patch)
tree6b31ac462efacf3f6937788c9b7af1420497c9fc /vppapigen
parentfca670b0ec9f74aa977fe479a5517ad6367ee898 (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.c105
-rw-r--r--vppapigen/lex.h1
-rw-r--r--vppapigen/node.c146
-rw-r--r--vppapigen/node.h4
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)