diff --git a/utils/SConscript b/utils/SConscript index 11a0767af..2c4e42f67 100644 --- a/utils/SConscript +++ b/utils/SConscript @@ -18,7 +18,7 @@ env.Append(CCFLAGS = '-g') if 'install' in COMMAND_LINE_TARGETS: VRutilsEnv.Append(SRC_INSTALL_TARGET = '/utils/') -subdirs = ['dkms'] +subdirs = ['dkms', 'vtest'] for sdir in subdirs: env.SConscript(sdir + '/SConscript', exports='VRutilsEnv', diff --git a/utils/vtest/README.txt b/utils/vtest/README.txt new file mode 100644 index 000000000..6796dff1a --- /dev/null +++ b/utils/vtest/README.txt @@ -0,0 +1,225 @@ +The xml file specification +------------------------- + + + + Interface test + + + Add + Virtual + 4 + 0 + 00:01:02:03:04:05 + 1514 + + 0 + + + + + + Get + 4 + + + 0 + + + Virtual + 4 + 0 + 00:01:02:03:04:05 + 1514 + + + + + + +The generated code from sandesh file processing +----------------------------------------------- + +There is a sandesh compiler that parses the sandesh file and autogenerates +code to read values from specification file and assign it to corresponding +variables of the sandesh structure. It takes care of all known data types +of sandesh message (including list and string). As of now, the compiler +generates 'vt_gen_sandesh.c' (that contains the above described functionality) +, 'vt_gen_message_modules.c' (that contains the list of nodes under the message +module of vtest), 'vt_gen_message_modules.h' (a header file that contains all +the required declarations) and 'vt_gen_expect.c' that sanitizes the received +message with expected values from the specification file. + +The generator is still evolving. More functionality will be added to generator +on need basis. + + +Snap of code generated in 'vt_gen_sandesh.c' +------------------------------------------- + +.... + +void * +vr_nexthop_req_node(xmlNodePtr node, struct vtest *test) +{ + unsigned int list_size; + vr_nexthop_req *req; + + req = calloc(sizeof(*req), 1); + if (!req) + return NULL; + + node = node->xmlChildrenNode; + while (node) { + if (!node->content || !strlen(node->content)) { + return NULL; + } + + if (!strncmp(node->name, "h_op", strlen(node->content))) { + req->h_op = vt_gen_op(node->content); + } else if (!strncmp(node->name, "nhr_type", strlen(node->content))) { + req->nhr_type = strtoul(node->content, NULL, 0); + } else if (!strncmp(node->name, "nhr_family", strlen(node->content))) { + +.... + + } else if (!strncmp(node->name, "nhr_label_list", strlen(node->content))) { + req->nhr_label_list = vt_gen_list(node->content, GEN_TYPE_U32, &list_size); + req->nhr_label_list_size = list_size; + } + node = node->next; + } + + return (void *)req; +} + +Snap of code generated in 'vt_gen_message_modules.c' +---------------------------------------------------- + +/* + * Auto generated file + */ +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +struct vt_message_module vt_message_modules[] = { + { + .vmm_name = "vr_nexthop_req", + .vmm_node = vr_nexthop_req_node, + .vmm_expect = vr_nexthop_req_expect, + .vmm_size = sizeof(vr_nexthop_req), + }, + { + .vmm_name = "vr_interface_req", + .vmm_node = vr_interface_req_node, + +.... +.... + + { + .vmm_name = "expect", + .vmm_node = vt_expect_node, + .vmm_size = 0, + }, +}; + +unsigned int vt_message_modules_num = + sizeof(vt_message_modules) / sizeof(vt_message_modules[0]); + + +Snap of code generated in 'vt_gen_message_modules.h' +--------------------------------------------------- + +/* + * Auto generated file + */ +#ifndef __VT_GEN_MESSAGE_MODULES_H__ +#define __VT_GEN_MESSAGE_MODULES_H__ + +#include + +#include + +#include +#include + +#include +#include +#include + +struct vt_message_module { + char *vmm_name; + void *(*vmm_node)(xmlNodePtr, struct vtest *); + bool (*vmm_expect)(xmlNodePtr, struct vtest *, void *); + unsigned int vmm_size; +}; + +extern void *vr_nexthop_req_node(xmlNodePtr, struct vtest *); +extern bool vr_nexthop_req_expect(xmlNodePtr, struct vtest *, void *); + +.... +.... + +extern void *vt_return_node(xmlNodePtr, struct vtest *); +extern void *vt_expect_node(xmlNodePtr, struct vtest *); + +#endif + +Snap of code generated in 'vt_gen_sandesh_expect.c' +-------------------------------------------------- + +/* + * Auto generated file + */ +#include + +#include + +#include +#include + +#include +#include +#include + +bool +vr_nexthop_req_expect(xmlNodePtr node, struct vtest *test, void *buf) +{ + bool result = true; + unsigned int list_size; + vr_nexthop_req *req = (vr_nexthop_req *)buf; + + node = node->xmlChildrenNode; + while (node) { + if (!node->content || !strlen(node->content)) { + return NULL; + } + +.... +.... + + } else if (!strncmp(node->name, "nhr_label_list", strlen(node->content))) { + result = vt_gen_list_compare(req->nhr_label_list, + req->nhr_label_list_size, node->content, GEN_TYPE_U32); + } + + if (!result) + return result; + + node = node->next; + } + + return result; +} + + diff --git a/utils/vtest/SConscript b/utils/vtest/SConscript new file mode 100644 index 000000000..6ca32e52d --- /dev/null +++ b/utils/vtest/SConscript @@ -0,0 +1,50 @@ +# +# Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. +# +import os +Import('VRutilsEnv') +env = VRutilsEnv.Clone() +VTestEnv = env; + +src_root = Dir('#').srcnode().abspath +build_root = Dir(env['TOP']).abspath +sandesh_file = src_root + '/vrouter/sandesh/vr.sandesh' +build_dir = build_root + '/vrouter/utils/vtest/' + +system_header_path = GetOption('system-header-path') +if system_header_path: + env.Append(CPPPATH = system_header_path + '/include/') + +env.Append(CPPPATH = ['./include', build_dir, '/usr/include/libxml2']) +xml_cpppath = os.popen('xml2-config --cflags | sed \'s/\-I//g\'').read() +#env.Append(CPPPATH = xml_cpppath) + +# CFLAGS +env.Append(CCFLAGS = '-g') + +env.Replace(LIBPATH = env['TOP_LIB']) +env.Append(LIBPATH = ['.', '../../sandesh']) +env.Replace(LIBS = ['sandesh-c', 'dp_sandesh_c', 'xml2']) + +sandesh_gen = env.Program('sandesh_gen.c') + +sandesh_gen_cmd = build_root + '/vrouter/utils/vtest/sandesh_gen' + ' ' + sandesh_file +sandesh_gen_output = env.Command('sandesh_gen_output', None, + sandesh_gen_cmd, chdir=build_dir) + +vtest_src = [ + 'vt_main.c', + 'vt_message.c', + 'vt_gen_lib.c', + 'vt_gen_message_modules.c', + 'vt_gen_sandesh.c', + 'vt_gen_sandesh_expect.c', + ] + + +vtest = env.Program('vtest', vtest_src) +env.Requires(vtest, sandesh_gen_output) + +# Local Variables: +# mode: python +# End: diff --git a/utils/vtest/example.xml b/utils/vtest/example.xml new file mode 100644 index 000000000..2296baeb7 --- /dev/null +++ b/utils/vtest/example.xml @@ -0,0 +1,36 @@ + + + Interface test + + + Add + Virtual + 4 + 0 + 00:01:02:03:04:05 + 1514 + + 0 + + + + + + Get + 4 + + + 0 + + + Virtual + 4 + 0 + 00:01:02:03:04:05 + 1514 + + + + + + diff --git a/utils/vtest/include/vt_gen_lib.h b/utils/vtest/include/vt_gen_lib.h new file mode 100644 index 000000000..611aeb602 --- /dev/null +++ b/utils/vtest/include/vt_gen_lib.h @@ -0,0 +1,33 @@ +/* + * gen_lib.h -- + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved + */ + +#ifndef __GEN_LIB_H__ +#define __GEN_LIB_H__ + +enum gen_types { + GEN_TYPE_U8, + GEN_TYPE_U16, + GEN_TYPE_U32, + GEN_TYPE_U64, +}; + +unsigned char *vt_gen_skip_space(unsigned char *); +unsigned char *vt_gen_reach_char(unsigned char *, unsigned char); +unsigned char *vt_gen_reach_space(unsigned char *); +bool vt_gen_byte_compare(uint8_t, uint8_t); +bool vt_gen_short_compare(uint16_t, uint16_t); +bool vt_gen_int_compare(unsigned int, unsigned int); +bool vt_gen_int64_compare(uint64_t, uint64_t); +bool vt_gen_flow_op_compare(int, unsigned char *); +int vt_gen_flow_op(unsigned char *); +bool vt_gen_op_compare(int, unsigned char *); +int vt_gen_op(unsigned char *); +void *vt_gen_list(unsigned char *, unsigned int, unsigned int *); +bool vt_gen_list_compare(void *, unsigned int, unsigned char *, unsigned int); +void *vt_gen_string(char *); + +#endif /* __GEN_LIB_H__ */ diff --git a/utils/vtest/include/vtest.h b/utils/vtest/include/vtest.h new file mode 100644 index 000000000..3e2070c2f --- /dev/null +++ b/utils/vtest/include/vtest.h @@ -0,0 +1,30 @@ +/* + * vtest.h -- + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved + */ +#ifndef __VTEST_H__ +#define __VTEST_H__ + +#define VT_PROG_NAME "vtest" +#define VT_MAX_TEST_NAME_LEN 128 +#define VT_MAX_TEST_MODULE_NAME_LEN 128 + +struct vtest { + int vtest_return; + int vtest_iteration; + bool vtest_break; + unsigned char *vtest_name; + unsigned char *vtest_error_module; +}; + +struct vtest_module { + unsigned char *vt_name; + int (*vt_node)(xmlNodePtr, struct vtest *); + int (*vt_init)(void); +}; + +extern int vt_message(xmlNodePtr, struct vtest *); + +#endif /* __VTEST_H__ */ diff --git a/utils/vtest/sandesh_gen.c b/utils/vtest/sandesh_gen.c new file mode 100644 index 000000000..9765863a4 --- /dev/null +++ b/utils/vtest/sandesh_gen.c @@ -0,0 +1,611 @@ +/* + * sandesh_gen.c -- parse the sandesh file and generate code that takes + * the xml node and assigns the value to the corresponding member of + * the structure + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved + */ +#include +#include +#include +#include + +#define CHARS 80 + +static char line[CHARS]; +static char nest[] = " "; + +static char header[] = {"\ +/*\n\ + * Auto generated file\n\ + */\n" +}; + +static char includes[] = {"\ +#include \n\n\ +#include \n\n\ +\ +#include \n\ +#include \n\n\ +\ +#include \n\ +#include \n\ +#include \n\n" +}; + +static char message_gen[] = {"\ +#include \n\n\ +struct vt_message_module vt_message_modules[] = {\n\ +"}; + +static char vt_message_module_gen[] = {"\ +struct vt_message_module {\n\ + char *vmm_name;\n\ + void *(*vmm_node)(xmlNodePtr, struct vtest *);\n\ + bool (*vmm_expect)(xmlNodePtr, struct vtest *, void *);\n\ + unsigned int vmm_size;\n\ +};\n\n" +}; + +static char part_gen[] = {"\ + req = calloc(sizeof(*req), 1);\n\ + if (!req)\n\ + return NULL;\n\n\ + node = node->xmlChildrenNode;\n\ + while (node) {\n\ + if (!node->content || !strlen(node->content)) {\n\ + return NULL;\n\ + }\n\n\ +" +}; + +static char expect_gen[] = {"\ + node = node->xmlChildrenNode;\n\ + while (node) {\n\ + if (!node->content || !strlen(node->content)) {\n\ + return NULL;\n\ + }\n\n\ +" +}; + +static unsigned char * +gen_skip_space(unsigned char *string) +{ + unsigned int i = 0, len; + + if (!string) + return string; + + len = strlen(string); + if (!len) + return NULL; + + while ((i < len) && isspace(string[i])) { + i++; + } + + if (i == len) + return NULL; + + return &string[i]; +} + +static unsigned char * +gen_reach_char(unsigned char *string, unsigned char c) +{ + unsigned int i = 0, len; + + if (!string) + return string; + + len = strlen(string); + if (!len) + return string; + + while ((i < len) && (string[i] != c)) { + i++; + } + + return &string[i]; +} + +static unsigned char * +gen_reach_space(unsigned char *string) +{ + return gen_reach_char(string, ' '); +} + + +static void +gen_write(FILE *ofp, unsigned int nesting, unsigned char *string) +{ + unsigned int i; + + for (i = 0; i < nesting; i++) + fwrite(nest, 1, strlen(nest), ofp); + + fwrite(string, 1, strlen(string), ofp); + return; +} + +static void +gen_raw_write(FILE *ofp, unsigned int nesting, + unsigned char *string, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < nesting; i++) + fwrite(nest, 1, strlen(nest), ofp); + + fwrite(string, 1, len, ofp); + return; +} + +static void +gen_close(FILE *fp, bool header_file) +{ + if (header_file) { + gen_write(fp, 0, "\n#endif\n"); + } + + fclose(fp); + return; +} + +static FILE * +gen_open(unsigned char *name, bool header_file) +{ + unsigned char c[105]; + unsigned int i = 0, j = 0; + FILE *fp; + + if (header_file && (strlen(name) >= 100)) { + perror(name); + return NULL; + } + + fp = fopen(name, "w+"); + if (!fp) + return fp; + + gen_write(fp, 0, header); + + if (header_file) { + gen_write(fp, 0, "#ifndef "); + c[i++] = '_'; + c[i++] = '_'; + while ((c[i] = name[j]) != '\0') { + if (c[i] == '.') { + c[i] = '_'; + } else { + c[i] = toupper(c[i]); + } + i++, j++; + } + c[i++] = '_'; + c[i++] = '_'; + + c[i] = '\0'; + + gen_write(fp, 0, c); + gen_write(fp, 0, "\n"); + gen_write(fp, 0, "#define "); + gen_write(fp, 0, c); + gen_write(fp, 0, "\n\n"); + } + + gen_write(fp, 0, includes); + + return fp; +} + +static int +gen(FILE *fp) +{ + bool need_else = false; + + unsigned int len, start = 0, end = 0; + unsigned int type_len, sub_type_len = 0, var_len; + unsigned int nesting = 0; + + char *marker, *type, *var, *sub_type = NULL; + FILE *ofp, *fp_expect, *fp_message, *fp_message_hdr; + + ofp = gen_open("vt_gen_sandesh.c", false); + if (!ofp) { + perror("vt_gen_sandesh.c"); + return errno; + } + + fp_expect = gen_open("vt_gen_sandesh_expect.c", false); + if (!fp_expect) { + perror("vt_gen_sandesh_expect.c"); + return errno; + } + + fp_message = gen_open("vt_gen_message_modules.c", false); + if (!fp_message) { + perror("vt_message_modules.c"); + return errno; + } + gen_write(fp_message, 0, message_gen); + + fp_message_hdr = gen_open("vt_gen_message_modules.h", true); + if (!fp_message_hdr) { + perror("vt_gen_message_modules.h"); + return errno; + } + gen_write(fp_message_hdr, 0, vt_message_module_gen); + + while (fgets(line, sizeof(line), fp)) { + if (!strncmp("buffer sandesh", line, strlen("buffer sandesh"))) { + len = strlen("buffer sandesh"); + marker = gen_skip_space(&line[len]); + if (!marker) + break; + + start = marker - line; + marker = gen_reach_space(marker); + end = marker - line; + + gen_write(fp_message, 1, "{\n"); + gen_write(fp_message, 2, ".vmm_name"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "\""); + gen_raw_write(fp_message, 0, &line[start], end - start); + gen_write(fp_message, 0, "\",\n"); + + gen_write(fp_message, 2, ".vmm_node"); + gen_write(fp_message, 2, "="); + gen_raw_write(fp_message, 2, &line[start], end - start); + gen_write(fp_message, 0, "_node,\n"); + + gen_write(fp_message, 2, ".vmm_expect"); + gen_write(fp_message, 2, "="); + gen_raw_write(fp_message, 2, &line[start], end - start); + gen_write(fp_message, 0, "_expect,\n"); + + gen_write(fp_message, 2, ".vmm_size"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "sizeof("); + gen_raw_write(fp_message, 0, &line[start], end - start); + gen_write(fp_message, 0, "),\n"); + gen_write(fp_message, 1, "},\n"); + + gen_write(fp_message_hdr, 0, "extern void *"); + gen_raw_write(fp_message_hdr, 0, &line[start], end - start); + gen_write(fp_message_hdr, 0, "_node(xmlNodePtr, struct vtest *);\n"); + + gen_write(ofp, nesting, "void *\n"); + gen_raw_write(ofp, nesting, &line[start], end - start); + gen_write(ofp, nesting, "_node(xmlNodePtr node, struct vtest *test)\n"); + gen_write(ofp, nesting, "{\n"); + + gen_write(fp_message_hdr, 0, "extern bool "); + gen_raw_write(fp_message_hdr, 0, &line[start], end - start); + gen_write(fp_message_hdr, 0, "_expect(xmlNodePtr, struct vtest *, void *);\n"); + + gen_write(fp_expect, nesting, "bool\n"); + gen_raw_write(fp_expect, nesting, &line[start], end - start); + gen_write(fp_expect, nesting, "_expect(xmlNodePtr node, struct vtest *test, void *buf)\n"); + gen_write(fp_expect, nesting, "{\n"); + + gen_write(ofp, ++nesting, "unsigned int list_size;\n"); + gen_raw_write(ofp, nesting, &line[start], end - start); + gen_write(ofp, 0, " *req;\n\n"); + gen_write(ofp, 0, part_gen); + + gen_write(fp_expect, nesting, "bool result = true;\n"); + gen_write(fp_expect, nesting, "unsigned int list_size;\n"); + gen_raw_write(fp_expect, nesting, &line[start], end - start); + gen_write(fp_expect, 0, " *req = ("); + gen_raw_write(fp_expect, 0, &line[start], end - start); + gen_write(fp_expect, 0, " *)buf;\n\n"); + gen_write(fp_expect, 0, expect_gen); + + /* account for nesting inside part_gen */ + nesting++; + continue; + } + + if (start) { + if (!strncmp("}", line, strlen("}"))) { + start = end = 0; + gen_write(ofp, 0, "\n"); + gen_write(ofp, nesting, "node = node->next;\n"); + + gen_write(fp_expect, 0, "\n\n"); + gen_write(fp_expect, nesting, "if (!result)\n"); + gen_write(fp_expect, nesting + 1, "return result;\n\n"); + gen_write(fp_expect, nesting, "node = node->next;\n"); + + gen_write(ofp, --nesting, "}\n\n"); + gen_write(ofp, nesting, "return (void *)req;\n}\n\n"); + + gen_write(fp_expect, nesting, "}\n\n"); + gen_write(fp_expect, nesting, "return result;\n}\n\n"); + + --nesting; + need_else = false; + continue; + } + + marker = strchr(line, ':'); + if (!marker) { + return EINVAL; + } + + marker = gen_skip_space(++marker); + if (!marker) { + return EINVAL; + } + + type = marker; + marker = gen_reach_space(marker); + if (!marker) { + return EINVAL; + } + type_len = marker - type; + + if (!strncmp(type, "list", strlen("list"))) { + marker = type + strlen("list");; + marker = gen_skip_space(marker); + if (!marker) { + return EINVAL; + } + + if (*marker != '<') { + return EINVAL; + } + + sub_type = ++marker; + marker = gen_reach_char(marker, '>'); + if (!marker) { + return EINVAL; + } + sub_type_len = marker - sub_type; + marker = gen_reach_space(marker); + if (!marker) { + return EINVAL; + } + } + + marker = gen_skip_space(marker); + if (!marker) { + return EINVAL; + } + + var = marker; + marker = gen_reach_char(marker, ';'); + if (!marker) { + return EINVAL; + } + var_len = marker - var; + + if (need_else) { + gen_write(ofp, 0, " else "); + gen_write(fp_expect, 0, " else "); + } else { + gen_write(ofp, nesting, ""); + gen_write(fp_expect, nesting, ""); + } + + gen_write(ofp, 0, "if (!strncmp(node->name, "); + gen_write(ofp, 0, "\""); + gen_raw_write(ofp, 0, var, var_len); + gen_write(ofp, 0, "\""); + gen_write(ofp, 0, ", strlen(node->content))) {\n"); + + gen_write(fp_expect, 0, "if (!strncmp(node->name, "); + gen_write(fp_expect, 0, "\""); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, "\""); + gen_write(fp_expect, 0, ", strlen(node->content))) {\n"); + + gen_write(ofp, ++nesting, "req->"); + gen_raw_write(ofp, 0, var, var_len); + gen_write(ofp, 0, " = "); + + gen_write(fp_expect, nesting, ""); + + if (!strncmp(type, "i32", strlen("i32"))) { + gen_write(ofp, 0, "strtoul(node->content, NULL, 0);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_int_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 4, "strtoul(node->content, NULL, 0)"); + gen_write(fp_expect, 0, ");\n"); + + } else if (!strncmp(type, "u32", strlen("u32"))) { + gen_write(ofp, 0, "strtoul(node->content, NULL, 0);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_int_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 4, "strtoul(node->content, NULL, 0)"); + gen_write(fp_expect, 0, ");\n"); + + } else if (!strncmp(type, "i64", strlen("i64"))) { + gen_write(ofp, 0, "strtoull(node->content, NULL, 0);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_int64_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 4, "strtoul(node->content, NULL, 0)"); + gen_write(fp_expect, 0, ");\n"); + + } else if (!strncmp(type, "i16", strlen("i16"))) { + gen_write(ofp, 0, "strtoul(node->content, NULL, 0);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_short_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 4, "strtoul(node->content, NULL, 0));\n"); + + } else if (!strncmp(type, "byte", strlen("byte"))) { + gen_write(ofp, 0, "strtoul(node->content, NULL, 0);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_byte_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 4, "strtoul(node->content, NULL, 0)"); + gen_write(fp_expect, 0, ");\n"); + + } else if (!strncmp(type, "sandesh_op", strlen("sandesh_op"))) { + gen_write(ofp, 0, "vt_gen_op(node->content);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_op_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ", node->content);\n"); + + } else if (!strncmp(type, "flow_op", strlen("flow_op"))) { + gen_write(ofp, 0, "vt_gen_flow_op(node->content);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_flow_op_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ", node->content);\n"); + + } else if (!strncmp(type, "list", strlen("list"))) { + if (!strncmp(sub_type, "byte", strlen("byte"))) { + gen_write(ofp, 0, "vt_gen_list(node->content, GEN_TYPE_U8, &list_size);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_list_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 2, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, "_size"); + gen_write(fp_expect, 0, ", node->content, GEN_TYPE_U8);\n"); + + } else if (!strncmp(sub_type, "i16", strlen("i32"))) { + gen_write(ofp, 0, "vt_gen_list(node->content, GEN_TYPE_U16, &list_size);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_list_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 2, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, "_size"); + gen_write(fp_expect, 0, ", node->content, GEN_TYPE_U16);\n"); + + } else if (!strncmp(sub_type, "i32", strlen("i32"))) { + gen_write(ofp, 0, "vt_gen_list(node->content, GEN_TYPE_U32, &list_size);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_list_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 2, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, "_size"); + gen_write(fp_expect, 0, ", node->content, GEN_TYPE_U32);\n"); + + } else if (!strncmp(sub_type, "i64", strlen("i32"))) { + gen_write(ofp, 0, "vt_gen_list(node->content, GEN_TYPE_U64, &list_size);\n"); + + gen_write(fp_expect, 0, "result = vt_gen_list_compare("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ",\n"); + gen_write(fp_expect, nesting + 2, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, "_size"); + gen_write(fp_expect, 0, ", node->content, GEN_TYPE_U64);\n"); + + } + + gen_write(ofp, nesting, "req->"); + gen_raw_write(ofp, 0, var, var_len); + gen_write(ofp, 0, "_size = list_size;\n"); + } else if (!strncmp(type, "string", strlen("string"))) { + gen_write(ofp, 0, "vt_gen_string(node->content);\n"); + + gen_write(fp_expect, 0, "result = strcmp("); + gen_write(fp_expect, 0, "req->"); + gen_raw_write(fp_expect, 0, var, var_len); + gen_write(fp_expect, 0, ", node->content);\n"); + + } + + gen_write(ofp, --nesting, "}"); + gen_write(fp_expect, nesting, "}"); + need_else = true; + } + } + + gen_write(fp_message, 1, "{\n"); + gen_write(fp_message, 2, ".vmm_name"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "\"return\",\n"); + gen_write(fp_message, 2, ".vmm_node"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "vt_return_node,\n"); + gen_write(fp_message, 2, ".vmm_size"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "0,\n"); + gen_write(fp_message, 1, "},\n"); + gen_write(fp_message_hdr, 0, "extern void *"); + gen_write(fp_message_hdr, 0, "vt_return_node(xmlNodePtr, struct vtest *);\n"); + + gen_write(fp_message, 1, "{\n"); + gen_write(fp_message, 2, ".vmm_name"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "\"expect\",\n"); + gen_write(fp_message, 2, ".vmm_node"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "vt_expect_node,\n"); + gen_write(fp_message, 2, ".vmm_size"); + gen_write(fp_message, 2, "="); + gen_write(fp_message, 2, "0,\n"); + gen_write(fp_message, 1, "},\n"); + gen_write(fp_message_hdr, 0, "extern void *"); + gen_write(fp_message_hdr, 0, "vt_expect_node(xmlNodePtr, struct vtest *);\n"); + + gen_write(fp_message, 0, "};\n\n"); + gen_write(fp_message, 0, + "unsigned int vt_message_modules_num = \n"); + gen_write(fp_message, 2, "sizeof(vt_message_modules) / sizeof(vt_message_modules[0]);\n\n"); + gen_close(fp_message, false); + gen_close(fp_message_hdr, true); + + return 0; +} + +static void +Usage(void) +{ + printf("Usage: sandesh_gen \n"); + return; +} + +int +main(int argc, char *argv[]) +{ + int ret; + FILE *fp; + + if (argc != 2) { + Usage(); + return EINVAL; + } + + fp = fopen(argv[1], "r"); + if (!fp) { + perror(argv[1]); + return errno; + } + + ret = gen(fp); + return ret; +} diff --git a/utils/vtest/vt_gen_lib.c b/utils/vtest/vt_gen_lib.c new file mode 100644 index 000000000..efe8b5d31 --- /dev/null +++ b/utils/vtest/vt_gen_lib.c @@ -0,0 +1,298 @@ +/* + * vt_gen_lib.c -- + * + * Copyright(c) 2015, Juniper Networks, Inc. + * All rights reserved + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +unsigned char * +vt_gen_skip_space(unsigned char *string) +{ + unsigned int i = 0, len; + + if (!string) + return string; + + len = strlen(string); + if (!len) + return string; + + while ((i < len) && isspace(string[i])) { + i++; + } + + if (i == len) + return NULL; + + return &string[i]; +} + +unsigned char * +vt_gen_reach_char(unsigned char *string, unsigned char c) +{ + unsigned int i = 0, len; + + if (!string) + return string; + + len = strlen(string); + if (!len) + return string; + + while ((i < len) && (string[i] != c)) { + i++; + } + + return &string[i]; +} + +unsigned char * +vt_gen_reach_space(unsigned char *string) +{ + return vt_gen_reach_char(string, ' '); +} + +bool +vt_gen_byte_compare(uint8_t one, uint8_t two) +{ + return one == two; +} + +bool +vt_gen_short_compare(uint16_t one, uint16_t two) +{ + return one == two; +} + +bool +vt_gen_int_compare(unsigned int one, unsigned int two) +{ + return one == two; +} + +bool +vt_gen_int64_compare(uint64_t one, uint64_t two) +{ + return one == two; +} + +bool +vt_gen_flow_op_compare(int op, unsigned char *string) +{ + int expected_op = 0; + + if (!string) + return -1; + + if (!strncasecmp(string, "flow_set", strlen("flow_set"))) { + expected_op = FLOW_OP_FLOW_SET; + } else if (!strncasecmp(string, "flow_table_get", + strlen("flow_table_get"))) { + expected_op = FLOW_OP_FLOW_TABLE_GET; + } + + return op == expected_op; +} + +int +vt_gen_flow_op(unsigned char *string) +{ + if (!string) + return -1; + + if (!strncasecmp(string, "flow_set", strlen("flow_set"))) { + return FLOW_OP_FLOW_SET; + } else if (!strncasecmp(string, "flow_table_get", + strlen("flow_table_get"))) { + return FLOW_OP_FLOW_TABLE_GET; + } + + return -1; +} + +bool +vt_gen_op_compare(int op, unsigned char *string) +{ + int expected_op = 0; + + if (!strncasecmp(string, "Add", strlen("Add"))) { + expected_op = SANDESH_OP_ADD; + } else if (!strncasecmp(string, "Get", strlen("Get"))) { + expected_op = SANDESH_OP_GET; + } else if (!strncasecmp(string, "Delete", strlen("Delete"))) { + expected_op = SANDESH_OP_DELETE; + } else if (!strncasecmp(string, "Dump", strlen("Dump"))) { + expected_op = SANDESH_OP_DUMP; + } else if (!strncasecmp(string, "Reset", strlen("Reset"))) { + expected_op = SANDESH_OP_RESET; + } + + return op == expected_op; +} + +int +vt_gen_op(unsigned char *string) +{ + if (!string) + return -1; + + if (!strncasecmp(string, "Add", strlen("Add"))) { + return SANDESH_OP_ADD; + } else if (!strncasecmp(string, "Get", strlen("Get"))) { + return SANDESH_OP_GET; + } else if (!strncasecmp(string, "Delete", strlen("Delete"))) { + return SANDESH_OP_DELETE; + } else if (!strncasecmp(string, "Dump", strlen("Dump"))) { + return SANDESH_OP_DUMP; + } else if (!strncasecmp(string, "Reset", strlen("Reset"))) { + return SANDESH_OP_RESET; + } + + return -1; +} + +void * +vt_gen_list(unsigned char *list, unsigned int type, unsigned int *list_size) +{ + unsigned int i = 0, j = 0, type_size; + unsigned int string_size; + unsigned char *local_list = list, *end; + char *tmp; + + unsigned char *store; + uint8_t *store_b; + uint16_t *store_i16; + uint32_t *store_i32; + uint64_t *store_i64; + + *list_size = 0; + if (!list) + return NULL; + + switch (type) { + case GEN_TYPE_U8: + type_size = 1; + break; + + case GEN_TYPE_U16: + type_size = 2; + break; + + case GEN_TYPE_U32: + type_size = 4; + break; + + case GEN_TYPE_U64: + type_size = 8; + break; + + default: + return NULL; + } + + string_size = strlen(list); + end = list + string_size; + + while (1) { + local_list = vt_gen_skip_space(local_list); + if (!local_list) + break; + + j++; + + local_list = vt_gen_reach_space(local_list); + if (!local_list) + break; + } + + + store = calloc(j, type_size); + if (!store) + return NULL; + + *list_size = type_size * j; + + store_b = (uint8_t *)store; + store_i16 = (uint16_t *)store; + store_i32 = (uint32_t *)store; + store_i64 = (uint64_t *)store; + + local_list = list; + for (i = 0; i < j; i++) { + switch (type) { + case GEN_TYPE_U8: + store_b[i] = strtoul(local_list, &tmp, 0); + break; + + case GEN_TYPE_U16: + store_i16[i] = strtoul(local_list, &tmp, 0); + break; + + case GEN_TYPE_U32: + store_i32[i] = strtoul(local_list, &tmp, 0); + break; + + case GEN_TYPE_U64: + store_i64[i] = strtoul(local_list, &tmp, 0); + break; + } + + if (errno == ERANGE) { + free(store); + return NULL; + } + + local_list = tmp; + local_list = vt_gen_reach_space(local_list); + if (!local_list) + break; + } + + return store; +} + +bool +vt_gen_list_compare(void *list, unsigned int list_size, + unsigned char *string, unsigned int type) +{ + unsigned int buf_size; + void *buf; + + buf = vt_gen_list(string, type, &buf_size); + if (!buf) + return false; + + if (buf_size != list_size) + return false; + + if (memcmp(list, buf, list_size)) + return false; + + return true; +} + +void * +vt_gen_string(char *string) +{ + unsigned int string_len; + char *store; + + string_len = strlen(string); + store = malloc(string_len + 1); + if (!store) + return NULL; + + strcpy(store, string); + + return store; +} + diff --git a/utils/vtest/vt_main.c b/utils/vtest/vt_main.c new file mode 100644 index 000000000..e3719fddd --- /dev/null +++ b/utils/vtest/vt_main.c @@ -0,0 +1,214 @@ +/* + * vt_main.c -- test main function + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +static int vt_test_name(xmlNodePtr, struct vtest *); + +struct vtest_module vt_modules[] = { + { .vt_name = "test_name", + .vt_node = vt_test_name, + }, + { + .vt_name = "message", + .vt_node = vt_message, + }, +}; + +#define VTEST_NUM_MODULES sizeof(vt_modules) / sizeof(vt_modules[0]) + +void +vt_error(unsigned char *module, struct vtest *test, int ret) +{ + test->vtest_return = ret; + test->vtest_break = true; + test->vtest_error_module = malloc(strlen(module) + 1); + if (!test->vtest_error_module) { + printf("(Unrelated)Internal metadata allocation failure\n"); + return; + } + strcpy(test->vtest_error_module, module); + + return; +} + +static int +vt_test_name(xmlNodePtr node, struct vtest *test) +{ + xmlNodePtr child; + + child = node->xmlChildrenNode; + if (!child || !child->content || !strlen(child->content)) + return; + + printf("Running \"%s\"\n", (char *)child->content); + + return 0; +} + +static int +vt_process_node(xmlNodePtr node, struct vtest *test) +{ + unsigned int i; + + struct vtest_module *vt; + + for (i = 0; i < VTEST_NUM_MODULES; i++) { + if (!strncmp((char *)node->name, vt_modules[i].vt_name, + strlen(vt_modules[i].vt_name))) { + return vt_modules[i].vt_node(node, test); + } + } + + if (i == VTEST_NUM_MODULES) { + printf("Unrecognized node %s in xml\n", node->name); + return EINVAL; + } + + return 0; +} + +static int +vt_tree_traverse(xmlNodePtr node, struct vtest *test) +{ + int ret; + xmlNodePtr child; + + while (node) { + if (node->type == XML_ELEMENT_NODE) { + ret = vt_process_node(node, test); + if (ret) + return ret; + } + + node = node->next; + } + + return; +} + +static int +vt_parse_file(char *file, struct vtest *test) +{ + xmlDocPtr doc; + xmlNodePtr node; + + doc = xmlParseFile(file); + if (!doc) { + printf("xmlParseFile %s failed\n", file); + return EINVAL; + } + + node = xmlDocGetRootElement(doc); + if (!node) { + printf("NULL Root Element\n"); + return EINVAL; + } + + vt_tree_traverse(node->xmlChildrenNode, test); + + return 0; +} + +static int +vt_init(struct vtest *test) +{ + int error; + + memset(test, 0, sizeof(*test)); + + test->vtest_return = 0; + test->vtest_iteration = 0; + test->vtest_break = 0; + test->vtest_name = calloc(VT_MAX_TEST_NAME_LEN, 1); + if (!test->vtest_name) { + error = ENOMEM; + goto error; + } + + test->vtest_error_module = calloc(VT_MAX_TEST_MODULE_NAME_LEN, 1); + if (!test->vtest_error_module) { + error = ENOMEM; + goto error; + } + + return 0; + +error: + if (test->vtest_name) { + free(test->vtest_name); + test->vtest_name = NULL; + } + + if (test->vtest_error_module) { + free(test->vtest_error_module); + test->vtest_error_module = NULL; + } + + return error; +} + +static void +vt_Usage(void) +{ + printf("Usage: %s \n", + VT_PROG_NAME); + return; +} + +int +main(int argc, char *argv[]) +{ + int ret; + unsigned int i; + char *xml_file; + + struct stat stat_buf; + struct vtest vtest; + + if (argc != 2) { + vt_Usage(); + return EINVAL; + } + + xml_file = argv[1]; + ret = stat(xml_file, &stat_buf); + if (ret) { + perror(xml_file); + return errno; + } + + vt_init(&vtest); + + for (i = 0; i < VTEST_NUM_MODULES; i++) { + if (vt_modules[i].vt_init) { + ret = vt_modules[i].vt_init(); + if (ret) { + printf("%s: %s init failed\n", VT_PROG_NAME, + vt_modules[i].vt_name); + return ret; + } + } + } + + vt_parse_file(xml_file, &vtest); + + return 0; +} diff --git a/utils/vtest/vt_message.c b/utils/vtest/vt_message.c new file mode 100644 index 000000000..b9cba7d98 --- /dev/null +++ b/utils/vtest/vt_message.c @@ -0,0 +1,92 @@ +/* + * vt_message.c -- the messaging module + * + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved + */ +#include +#include + +#include +#include + +#include +#include + +#define RETURN "message.return" +#define EXPECT "message.expect" +#define MESSAGE "message" + +extern struct vt_message_module *vt_message_modules; +extern unsigned int vt_message_modules_num; + +void * +vt_expect_node(xmlNodePtr node, struct vtest *test) +{ + unsigned int i; + bool result; + /* TODO */ + void *buf = NULL; + + node = node->xmlChildrenNode; + while (node) { + for (i = 0; i < vt_message_modules_num; i++) { + if (!strncmp(node->name, vt_message_modules[i].vmm_name, + strlen(vt_message_modules[i].vmm_name))) { + result = vt_message_modules[i].vmm_expect(node, test, buf); + if (!result) { + vt_error(EXPECT, test, -EINVAL); + break; + } + } + } + } + + return NULL; +} + +void * +vt_return_node(xmlNodePtr node, struct vtest *test) +{ + int exp_ret; + + exp_ret = strtoul(node->content, NULL, 0); + if (exp_ret != test->vtest_return) { + printf("Expected return %d. Actual return %d\n", + exp_ret, test->vtest_return); + vt_error(RETURN, test, -EINVAL); + return NULL; + } + + return NULL; +} + +int +vt_message(xmlNodePtr node, struct vtest *test) +{ + int ret = 0; + unsigned int i; + + void *buf; + + node = node->xmlChildrenNode; + while (node) { + for (i = 0; i < vt_message_modules_num; i++) { + if (!strncmp(node->name, vt_message_modules[i].vmm_name, + strlen(vt_message_modules[i].vmm_name))) { + buf = vt_message_modules[i].vmm_node(node, test); + if (!buf && vt_message_modules[i].vmm_size) { + return -ENOMEM; + } + } + } + + if (test->vtest_break) + return 0; + + node = node->next; + } + + return -1; +} +