summaryrefslogtreecommitdiffstats
path: root/src/vat2/main.c
diff options
context:
space:
mode:
authorOle Troan <ot@cisco.com>2020-11-18 19:17:48 +0100
committerNeale Ranns <nranns@cisco.com>2020-11-25 08:25:50 +0000
commitdf87f8092f5b6b54eef0d5acf3c27c2e398a401a (patch)
tree762a3da5d6757c6f475ffce6dcfae2b65b2c3850 /src/vat2/main.c
parentc95cfa218b214bd1c67dc165b4ed1fb7a224bdad (diff)
api: vat2 and json autogeneration for api messages
VAT2: A completely auto-generated replacement of VAT. Reads input message in JSON from stdin and outputs received messages in JSON. A VAT2 plugin is automatically built for a .api file. There no longer a need for a separate _test.c. Example: vat2 show_version {} { "_msgname": "show_version_reply", "retval": 0, "program": "vpe", "version": "21.01-rc0~411-gf6eb348a6", "build_date": "2020-11-19T09:49:25", "build_directory": "/vpp/autogen3" } vat2 sw_interface_dump '{"sw_if_index": -1, "name_filter_valid": 0, "name_filter": ""}' [{ "_msgname": "sw_interface_details", "sw_if_index": 0, "sup_sw_if_index": 0, "l2_address": "00:00:00:00:00:00", "flags": "Invalid ENUM", "type": "IF_API_TYPE_HARDWARE", "link_duplex": "LINK_DUPLEX_API_UNKNOWN", "link_speed": 0, "link_mtu": 0, "mtu": [0, 0, 0, 0], "sub_id": 0, "sub_number_of_tags": 0, "sub_outer_vlan_id": 0, "sub_inner_vlan_id": 0, "sub_if_flags": "Invalid ENUM", "vtr_op": 0, "vtr_push_dot1q": 0, "vtr_tag1": 0, "vtr_tag2": 0, "outer_tag": 0, "b_dmac": "00:00:00:00:00:00", "b_smac": "00:00:00:00:00:00", "b_vlanid": 0, "i_sid": 0, "interface_name": "local0", "interface_dev_type": "local", "tag": "" }] This is the first phase and vat2 is not integrated in packaging yet. Type: feature Signed-off-by: Ole Troan <ot@cisco.com> Change-Id: Ib45ddeafb180ea7da8c5dc274a9274d7a4edc876 Signed-off-by: Ole Troan <ot@cisco.com>
Diffstat (limited to 'src/vat2/main.c')
-rw-r--r--src/vat2/main.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/vat2/main.c b/src/vat2/main.c
new file mode 100644
index 00000000000..5b042e23503
--- /dev/null
+++ b/src/vat2/main.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <vlib/vlib.h>
+#include <vlibapi/api_types.h>
+#include <vppinfra/cJSON.h>
+
+/* VPP API client includes */
+#include <vpp-api/client/vppapiclient.h>
+
+#include <limits.h>
+#include "vat2.h"
+
+uword *function_by_name;
+bool debug = false;
+
+char *vat2_plugin_path;
+static void
+vat2_find_plugin_path ()
+{
+ char *p, path[PATH_MAX];
+ int rv;
+ u8 *s;
+
+ /* find executable path */
+ if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
+ return;
+
+ /* readlink doesn't provide null termination */
+ path[rv] = 0;
+
+ /* strip filename */
+ if ((p = strrchr (path, '/')) == 0)
+ return;
+ *p = 0;
+
+ /* strip bin/ */
+ if ((p = strrchr (path, '/')) == 0)
+ return;
+ *p = 0;
+
+ s = format (0, "%s/lib/" CLIB_TARGET_TRIPLET "/vat2_plugins:"
+ "%s/lib/vat2_plugins", path, path);
+ vec_add1 (s, 0);
+ vat2_plugin_path = (char *) s;
+}
+
+void
+vac_callback (unsigned char *data, int len)
+{
+ u16 result_msg_id = ntohs(*((u16 *)data));
+ DBG("Received something async: %d\n", result_msg_id);
+}
+
+int vat2_load_plugins (char *path, char *filter, int *loaded);
+
+static int
+register_function (void)
+{
+ int loaded;
+
+ vat2_find_plugin_path();
+ DBG("Plugin Path %s\n", vat2_plugin_path);
+ int rv = vat2_load_plugins(vat2_plugin_path, 0, &loaded);
+ DBG("Loaded %u plugins\n", loaded);
+ return rv;
+}
+
+void
+vat2_register_function(char *name, cJSON (*f)(cJSON *))
+{
+ hash_set_mem(function_by_name, name, f);
+}
+
+int main (int argc, char **argv)
+{
+ /* Create a heap of 64MB */
+ clib_mem_init (0, 64 << 20);
+ char *filename = 0;
+ int index;
+ int c;
+ opterr = 0;
+ cJSON *o = 0;
+ uword *p = 0;
+
+ while ((c = getopt (argc, argv, "df:")) != -1) {
+ switch (c) {
+ case 'd':
+ debug = true;
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+ case '?':
+ if (optopt == 'f')
+ fprintf (stderr, "Option -%c requires an argument.\n", optopt);
+ else if (isprint (optopt))
+ fprintf (stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf (stderr,
+ "Unknown option character `\\x%x'.\n",
+ optopt);
+ return 1;
+ default:
+ abort ();
+ }
+ }
+
+ DBG("debug = %d, filename = %s\n", debug, filename);
+
+ for (index = optind; index < argc; index++)
+ DBG ("Non-option argument %s\n", argv[index]);
+
+ index = optind;
+
+ /* Load plugins */
+ function_by_name = hash_create_string (0, sizeof (uword));
+ int res = register_function();
+ if (res < 0) {
+ fprintf(stderr, "%s: loading plugins failed\n", argv[0]);
+ exit(-1);
+ }
+
+ if (argc > index + 2) {
+ fprintf(stderr, "%s: Too many arguments\n", argv[0]);
+ exit(-1);
+ }
+
+ /* Read JSON from stdin, command line or file */
+ if (argc >= (index + 1)) {
+ p = hash_get_mem (function_by_name, argv[index]);
+ if (p == 0) {
+ fprintf(stderr, "%s: Unknown command: %s\n", argv[0], argv[index]);
+ exit(-1);
+ }
+ }
+
+ if (argc == (index + 2)) {
+ o = cJSON_Parse(argv[index+1]);
+ if (!o) {
+ fprintf(stderr, "%s: Failed parsing JSON input: %s\n", argv[0], cJSON_GetErrorPtr());
+ exit(-1);
+ }
+ }
+
+ if (filename) {
+ if (argc > index + 1) {
+ fprintf(stderr, "%s: Superfluous arguments when filename given\n", argv[0]);
+ exit(-1);
+ }
+
+ FILE *f = fopen(filename, "r");
+ size_t bufsize = 1024;
+ size_t n_read = 0;
+ size_t n;
+
+ if (!f) {
+ fprintf(stderr, "%s: can't open file: %s\n", argv[0], filename);
+ exit(-1);
+ }
+ char *buf = malloc(bufsize);
+ while ((n = fread(buf, 1, bufsize, f))) {
+ n_read += n;
+ if (n == bufsize)
+ buf = realloc(buf, bufsize);
+ }
+ fclose(f);
+ if (n_read) {
+ o = cJSON_Parse(buf);
+ free(buf);
+ if (!o) {
+ fprintf(stderr, "%s: Failed parsing JSON input: %s\n", argv[0], cJSON_GetErrorPtr());
+ exit(-1);
+ }
+ }
+ }
+
+ if (!o) {
+ fprintf(stderr, "%s: Failed parsing JSON input\n", argv[0]);
+ exit(-1);
+ }
+
+ if (vac_connect("vat2", 0, 0, 1024)) {
+ fprintf(stderr, "Failed connecting to VPP\n");
+ exit(-1);
+ }
+ if (!p) {
+ fprintf(stderr, "No such command\n");
+ exit(-1);
+ }
+
+ cJSON * (*fp) (cJSON *);
+ fp = (void *) p[0];
+ cJSON *r = (*fp) (o);
+
+ if (o)
+ cJSON_Delete(o);
+
+ if (r) {
+ char *output = cJSON_Print(r);
+ cJSON_Delete(r);
+ printf("%s\n", output);
+ free(output);
+ } else {
+ fprintf(stderr, "Call failed\n");
+ exit(-1);
+ }
+
+ vac_disconnect();
+ exit (0);
+
+}