api: vat2 and json autogeneration for api messages
[vpp.git] / src / vat2 / main.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stdio.h>
17 #include <stdbool.h>
18 #include <ctype.h>
19 #include <vlib/vlib.h>
20 #include <vlibapi/api_types.h>
21 #include <vppinfra/cJSON.h>
22
23 /* VPP API client includes */
24 #include <vpp-api/client/vppapiclient.h>
25
26 #include <limits.h>
27 #include "vat2.h"
28
29 uword *function_by_name;
30 bool debug = false;
31
32 char *vat2_plugin_path;
33 static void
34 vat2_find_plugin_path ()
35 {
36   char *p, path[PATH_MAX];
37   int rv;
38   u8 *s;
39
40   /* find executable path */
41   if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
42     return;
43
44   /* readlink doesn't provide null termination */
45   path[rv] = 0;
46
47   /* strip filename */
48   if ((p = strrchr (path, '/')) == 0)
49     return;
50   *p = 0;
51
52   /* strip bin/ */
53   if ((p = strrchr (path, '/')) == 0)
54     return;
55   *p = 0;
56
57   s = format (0, "%s/lib/" CLIB_TARGET_TRIPLET "/vat2_plugins:"
58               "%s/lib/vat2_plugins", path, path);
59   vec_add1 (s, 0);
60   vat2_plugin_path = (char *) s;
61 }
62
63 void
64 vac_callback (unsigned char *data, int len)
65 {
66   u16 result_msg_id = ntohs(*((u16 *)data));
67   DBG("Received something async: %d\n", result_msg_id);
68 }
69
70 int vat2_load_plugins (char *path, char *filter, int *loaded);
71
72 static int
73 register_function (void)
74 {
75   int loaded;
76
77   vat2_find_plugin_path();
78   DBG("Plugin Path %s\n", vat2_plugin_path);
79   int rv = vat2_load_plugins(vat2_plugin_path, 0, &loaded);
80   DBG("Loaded %u plugins\n", loaded);
81   return rv;
82 }
83
84 void
85 vat2_register_function(char *name, cJSON (*f)(cJSON *))
86 {
87   hash_set_mem(function_by_name, name, f);
88 }
89
90 int main (int argc, char **argv)
91 {
92   /* Create a heap of 64MB */
93   clib_mem_init (0, 64 << 20);
94   char *filename = 0;
95   int index;
96   int c;
97   opterr = 0;
98   cJSON *o = 0;
99   uword *p = 0;
100
101   while ((c = getopt (argc, argv, "df:")) != -1) {
102     switch (c) {
103       case 'd':
104         debug = true;
105         break;
106       case 'f':
107         filename = optarg;
108         break;
109       case '?':
110         if (optopt == 'f')
111           fprintf (stderr, "Option -%c requires an argument.\n", optopt);
112         else if (isprint (optopt))
113           fprintf (stderr, "Unknown option `-%c'.\n", optopt);
114         else
115           fprintf (stderr,
116                    "Unknown option character `\\x%x'.\n",
117                    optopt);
118         return 1;
119       default:
120         abort ();
121     }
122   }
123
124   DBG("debug = %d, filename = %s\n", debug, filename);
125
126   for (index = optind; index < argc; index++)
127     DBG ("Non-option argument %s\n", argv[index]);
128
129   index = optind;
130
131   /* Load plugins */
132   function_by_name = hash_create_string (0, sizeof (uword));
133   int res = register_function();
134   if (res < 0) {
135     fprintf(stderr, "%s: loading plugins failed\n", argv[0]);
136     exit(-1);
137   }
138
139   if (argc > index + 2) {
140     fprintf(stderr, "%s: Too many arguments\n", argv[0]);
141     exit(-1);
142   }
143
144   /* Read JSON from stdin, command line or file */
145   if (argc >= (index + 1)) {
146     p = hash_get_mem (function_by_name, argv[index]);
147     if (p == 0) {
148       fprintf(stderr, "%s: Unknown command: %s\n", argv[0], argv[index]);
149       exit(-1);
150     }
151   }
152
153   if (argc == (index + 2)) {
154     o = cJSON_Parse(argv[index+1]);
155     if (!o) {
156       fprintf(stderr, "%s: Failed parsing JSON input: %s\n", argv[0], cJSON_GetErrorPtr());
157       exit(-1);
158     }
159   }
160
161   if (filename) {
162     if (argc > index + 1) {
163       fprintf(stderr, "%s: Superfluous arguments when filename given\n", argv[0]);
164       exit(-1);
165     }
166
167     FILE *f = fopen(filename, "r");
168     size_t bufsize = 1024;
169     size_t n_read = 0;
170     size_t n;
171
172     if (!f) {
173       fprintf(stderr, "%s: can't open file: %s\n", argv[0], filename);
174       exit(-1);
175     }
176     char *buf = malloc(bufsize);
177     while ((n = fread(buf, 1, bufsize, f))) {
178       n_read += n;
179       if (n == bufsize)
180         buf = realloc(buf, bufsize);
181     }
182     fclose(f);
183     if (n_read) {
184       o = cJSON_Parse(buf);
185       free(buf);
186       if (!o) {
187         fprintf(stderr, "%s: Failed parsing JSON input: %s\n", argv[0], cJSON_GetErrorPtr());
188         exit(-1);
189       }
190     }
191   }
192
193   if (!o) {
194     fprintf(stderr, "%s: Failed parsing JSON input\n", argv[0]);
195     exit(-1);
196   }
197
198   if (vac_connect("vat2", 0, 0, 1024)) {
199     fprintf(stderr, "Failed connecting to VPP\n");
200     exit(-1);
201   }
202   if (!p) {
203     fprintf(stderr, "No such command\n");
204     exit(-1);
205   }
206
207   cJSON * (*fp) (cJSON *);
208   fp = (void *) p[0];
209   cJSON *r = (*fp) (o);
210
211   if (o)
212     cJSON_Delete(o);
213
214   if (r) {
215     char *output = cJSON_Print(r);
216     cJSON_Delete(r);
217     printf("%s\n", output);
218     free(output);
219   } else {
220     fprintf(stderr, "Call failed\n");
221     exit(-1);
222   }
223
224   vac_disconnect();
225   exit (0);
226
227 }