blob: aaedf6c450b355859c8730bf916f94f0a3857976 [file] [log] [blame]
Damjan Marion7cd468a2016-12-19 23:05:39 +01001/*
2 * Copyright (c) 2015 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#include "vat.h"
16#include "plugin.h"
17#include <signal.h>
Damjan Marion4d2f86a2019-01-18 13:28:22 +010018#include <limits.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010019
20vat_main_t vat_main;
21
22#include <vlibapi/api_helper_macros.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010023
24void
25vat_suspend (vlib_main_t * vm, f64 interval)
26{
27 /* do nothing in the standalone version, just return */
28}
29
Damjan Marion7cd468a2016-12-19 23:05:39 +010030int
31connect_to_vpe (char *name)
32{
33 vat_main_t *vam = &vat_main;
Dave Barach39d69112019-11-27 11:42:13 -050034 api_main_t *am = vlibapi_get_main ();
Damjan Marion7cd468a2016-12-19 23:05:39 +010035
36 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
37 return -1;
38
39 vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
40 vam->my_client_index = am->my_client_index;
41
42 return 0;
43}
44
45vlib_main_t vlib_global_main;
46vlib_main_t **vlib_mains;
47void
48vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
49{
50 clib_warning ("BUG");
51}
52
53
54static u8 *
55format_api_error (u8 * s, va_list * args)
56{
57 vat_main_t *vam = va_arg (*args, vat_main_t *);
58 i32 error = va_arg (*args, u32);
59 uword *p;
60
61 p = hash_get (vam->error_string_by_error_number, -error);
62
63 if (p)
64 s = format (s, "%s", p[0]);
65 else
66 s = format (s, "%d", error);
67 return s;
68}
69
70void
71do_one_file (vat_main_t * vam)
72{
73 int rv;
74 int (*fp) (vat_main_t * vam);
75 int arg_len;
76 unformat_input_t _input;
77 u8 *cmdp, *argsp;
78 uword *p;
79 u8 *this_cmd = 0;
80
81 vam->input = &_input;
82
83 /* Used by the "quit" command handler */
84 if (setjmp (vam->jump_buf) != 0)
85 return;
86
87 vam->jump_buf_set = 1;
88
89 while (1)
90 {
91 if (vam->ifp == stdin)
92 {
93 if (vam->exec_mode == 0)
94 rv = write (1, "vat# ", 5);
95 else
96 rv = write (1, "exec# ", 6);
97 }
98
99 _vec_len (vam->inbuf) = 4096;
100
101 if (vam->do_exit ||
102 fgets ((char *) vam->inbuf, vec_len (vam->inbuf), vam->ifp) == 0)
103 break;
104
105 vam->input_line_number++;
106
107 vec_free (this_cmd);
108
109 this_cmd =
Damjan Marionffe9d212018-05-30 09:26:11 +0200110 (u8 *) clib_macro_eval (&vam->macro_main, (i8 *) vam->inbuf,
Dave Barachb30b9542020-06-22 10:02:25 -0400111 1 /* complain */ ,
112 0 /* level */ ,
113 8 /* max_level */ );
Damjan Marion7cd468a2016-12-19 23:05:39 +0100114
115 if (vam->exec_mode == 0)
116 {
117 /* Split input into cmd + args */
118 cmdp = this_cmd;
119
120 while (cmdp < (this_cmd + vec_len (this_cmd)))
121 {
122 if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
123 {
124 cmdp++;
125 }
126 else
127 break;
128 }
129 argsp = cmdp;
130 while (argsp < (this_cmd + vec_len (this_cmd)))
131 {
132 if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n')
133 {
134 argsp++;
135 }
136 else
137 break;
138 }
139 *argsp++ = 0;
140 while (argsp < (this_cmd + vec_len (this_cmd)))
141 {
142 if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
143 {
144 argsp++;
145 }
146 else
147 break;
148 }
149
150
151 /* Blank input line? */
152 if (*cmdp == 0)
153 continue;
154
155 p = hash_get_mem (vam->function_by_name, cmdp);
156 if (p == 0)
157 {
158 errmsg ("'%s': function not found\n", cmdp);
159 continue;
160 }
161
162 arg_len = strlen ((char *) argsp);
163
164 unformat_init_string (vam->input, (char *) argsp, arg_len);
165 fp = (void *) p[0];
166 }
167 else
168 {
169 unformat_init_string (vam->input, (char *) this_cmd,
170 strlen ((char *) this_cmd));
171 cmdp = this_cmd;
172 fp = exec;
173 }
174
175 rv = (*fp) (vam);
176 if (rv < 0)
177 errmsg ("%s error: %U\n", cmdp, format_api_error, vam, rv);
178 unformat_free (vam->input);
179
180 if (vam->regenerate_interface_table)
181 {
182 vam->regenerate_interface_table = 0;
183 api_sw_interface_dump (vam);
184 }
Dave Barach59b25652017-09-10 15:04:27 -0400185
186 /* Hack to pick up new client index after memfd_segment_create pivot */
187 if (vam->client_index_invalid)
188 {
189 vat_main_t *vam = &vat_main;
Dave Barach39d69112019-11-27 11:42:13 -0500190 api_main_t *am = vlibapi_get_main ();
Dave Barach59b25652017-09-10 15:04:27 -0400191
192 vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
193 vam->my_client_index = am->my_client_index;
194 vam->client_index_invalid = 0;
195 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100196 }
197}
198
199static void
200init_error_string_table (vat_main_t * vam)
201{
202
203 vam->error_string_by_error_number = hash_create (0, sizeof (uword));
204
205#define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
206 foreach_vnet_api_error;
207#undef _
208
209 hash_set (vam->error_string_by_error_number, 99, "Misc");
210}
211
212static i8 *
Dave Barach961e3c82020-06-18 17:04:18 -0400213eval_current_file (clib_macro_main_t * mm, i32 complain)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100214{
215 vat_main_t *vam = &vat_main;
216 return ((i8 *) format (0, "%s%c", vam->current_file, 0));
217}
218
219static i8 *
Dave Barach961e3c82020-06-18 17:04:18 -0400220eval_current_line (clib_macro_main_t * mm, i32 complain)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100221{
222 vat_main_t *vam = &vat_main;
223 return ((i8 *) format (0, "%d%c", vam->input_line_number, 0));
224}
225
226static void
227signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
228{
229 vat_main_t *vam = &vat_main;
230
231 switch (signum)
232 {
233 /* these (caught) signals cause the application to exit */
234 case SIGINT:
235 case SIGTERM:
236 if (vam->jump_buf_set)
237 {
238 vam->do_exit = 1;
239 return;
240 }
241
242 /* FALLTHROUGH on purpose */
243
244 default:
245 break;
246 }
247
248 _exit (1);
249}
250
251static void
252setup_signal_handlers (void)
253{
254 uword i;
255 struct sigaction sa;
256
257 for (i = 1; i < 32; i++)
258 {
Dave Barachb7b92992018-10-17 10:38:51 -0400259 clib_memset (&sa, 0, sizeof (sa));
Damjan Marion7cd468a2016-12-19 23:05:39 +0100260 sa.sa_sigaction = (void *) signal_handler;
261 sa.sa_flags = SA_SIGINFO;
262
263 switch (i)
264 {
265 /* these signals take the default action */
266 case SIGABRT:
267 case SIGKILL:
268 case SIGSTOP:
269 case SIGUSR1:
270 case SIGUSR2:
Jieqiang Wang6f533d72020-01-20 13:43:38 +0800271 case SIGPROF:
Damjan Marion7cd468a2016-12-19 23:05:39 +0100272 continue;
273
274 /* ignore SIGPIPE, SIGCHLD */
275 case SIGPIPE:
276 case SIGCHLD:
ezkexma7d3161a2019-03-26 10:24:38 -0400277 case SIGWINCH:
Damjan Marion7cd468a2016-12-19 23:05:39 +0100278 sa.sa_sigaction = (void *) SIG_IGN;
279 break;
280
281 /* catch and handle all other signals */
282 default:
283 break;
284 }
285
286 if (sigaction (i, &sa, 0) < 0)
287 clib_unix_warning ("sigaction %U", format_signal, i);
288 }
289}
290
Damjan Marion4d2f86a2019-01-18 13:28:22 +0100291static void
292vat_find_plugin_path ()
293{
Damjan Marion4d2f86a2019-01-18 13:28:22 +0100294 char *p, path[PATH_MAX];
295 int rv;
296 u8 *s;
297
298 /* find executable path */
299 if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
300 return;
301
302 /* readlink doesn't provide null termination */
303 path[rv] = 0;
304
305 /* strip filename */
306 if ((p = strrchr (path, '/')) == 0)
307 return;
308 *p = 0;
309
310 /* strip bin/ */
311 if ((p = strrchr (path, '/')) == 0)
312 return;
313 *p = 0;
314
315 s = format (0, "%s/lib/" CLIB_TARGET_TRIPLET "/vpp_api_test_plugins:"
316 "%s/lib/vpp_api_test_plugins", path, path);
317 vec_add1 (s, 0);
318 vat_plugin_path = (char *) s;
319}
320
Ole Troan3d812672020-09-15 10:53:34 +0200321static void
322load_features (void)
323{
324 vat_registered_features_t *f;
325 vat_main_t *vam = &vat_main;
326 clib_error_t *error;
327
328 f = vam->feature_function_registrations;
329
330 while (f)
331 {
332 error = f->function (vam);
333 if (error)
334 {
335 clib_warning ("INIT FAILED");
336 }
337 f = f->next;
338 }
339}
340
Damjan Marion7cd468a2016-12-19 23:05:39 +0100341int
342main (int argc, char **argv)
343{
344 vat_main_t *vam = &vat_main;
345 unformat_input_t _argv, *a = &_argv;
346 u8 **input_files = 0;
347 u8 *output_file = 0;
348 u8 *chroot_prefix;
349 u8 *this_input_file;
350 u8 interactive = 1;
351 u8 json_output = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100352 int i;
Dave Barachcf5e8482017-10-17 11:48:29 -0400353 f64 timeout;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100354
Dave Barach6a5adc32018-07-04 10:56:23 -0400355 clib_mem_init_thread_safe (0, 128 << 20);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100356
357 clib_macro_init (&vam->macro_main);
358 clib_macro_add_builtin (&vam->macro_main, "current_file",
359 eval_current_file);
360 clib_macro_add_builtin (&vam->macro_main, "current_line",
361 eval_current_line);
362
363 init_error_string_table (vam);
Dave Barach59b25652017-09-10 15:04:27 -0400364 vec_validate (vam->cmd_reply, 0);
365 vec_reset_length (vam->cmd_reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100366
Damjan Marion4d2f86a2019-01-18 13:28:22 +0100367 vat_find_plugin_path ();
368
Damjan Marion7cd468a2016-12-19 23:05:39 +0100369 unformat_init_command_line (a, argv);
370
371 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
372 {
373 if (unformat (a, "in %s", &this_input_file))
374 vec_add1 (input_files, this_input_file);
375 else if (unformat (a, "out %s", &output_file))
376 ;
377 else if (unformat (a, "script"))
378 interactive = 0;
379 else if (unformat (a, "json"))
380 json_output = 1;
Dave Barach59b25652017-09-10 15:04:27 -0400381 else if (unformat (a, "socket-name %s", &vam->socket_name))
382 ;
383 else if (unformat (a, "default-socket"))
384 {
385 vam->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
386 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100387 else if (unformat (a, "plugin_path %s", (u8 *) & vat_plugin_path))
388 vec_add1 (vat_plugin_path, 0);
389 else if (unformat (a, "plugin_name_filter %s",
390 (u8 *) & vat_plugin_name_filter))
391 vec_add1 (vat_plugin_name_filter, 0);
392 else if (unformat (a, "chroot prefix %s", &chroot_prefix))
393 {
394 vl_set_memory_root_path ((char *) chroot_prefix);
395 }
396 else
397 {
Dave Barach59b25652017-09-10 15:04:27 -0400398 fformat
399 (stderr,
400 "%s: usage [in <f1> ... in <fn>] [out <fn>] [script] [json]\n"
401 "[plugin_path <path>][default-socket][socket-name <name>]\n"
402 "[plugin_name_filter <filter>][chroot prefix <path>]\n",
403 argv[0]);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100404 exit (1);
405 }
406 }
407
408 if (output_file)
409 vam->ofp = fopen ((char *) output_file, "w");
410 else
411 vam->ofp = stdout;
412
413 if (vam->ofp == NULL)
414 {
415 fformat (stderr, "Couldn't open output file %s\n",
416 output_file ? (char *) output_file : "stdout");
417 exit (1);
418 }
419
420 clib_time_init (&vam->clib_time);
421
422 vat_api_hookup (vam);
423 vat_plugin_api_reference ();
424
425 setup_signal_handlers ();
426
Dave Barach59b25652017-09-10 15:04:27 -0400427 if (vam->socket_name && vat_socket_connect (vam))
428 fformat (stderr, "WARNING: socket connection failed");
429
Florin Coras90a63982017-12-19 04:50:01 -0800430 if ((!vam->socket_client_main || vam->socket_client_main->socket_fd == 0)
Dave Barach59b25652017-09-10 15:04:27 -0400431 && connect_to_vpe ("vpp_api_test") < 0)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100432 {
433 svm_region_exit ();
434 fformat (stderr, "Couldn't connect to vpe, exiting...\n");
435 exit (1);
436 }
437
438 vam->json_output = json_output;
439
440 if (!json_output)
Dave Barach59b25652017-09-10 15:04:27 -0400441 api_sw_interface_dump (vam);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100442
443 vec_validate (vam->inbuf, 4096);
444
Ole Troan3d812672020-09-15 10:53:34 +0200445 load_features ();
446
Damjan Marion7cd468a2016-12-19 23:05:39 +0100447 vam->current_file = (u8 *) "plugin-init";
448 vat_plugin_init (vam);
449
450 for (i = 0; i < vec_len (input_files); i++)
451 {
452 vam->ifp = fopen ((char *) input_files[i], "r");
453 if (vam->ifp == NULL)
454 {
455 fformat (stderr, "Couldn't open input file %s\n", input_files[i]);
456 continue;
457 }
458 vam->current_file = input_files[i];
459 vam->input_line_number = 0;
460 do_one_file (vam);
461 fclose (vam->ifp);
462 }
463
464 if (output_file)
465 fclose (vam->ofp);
466
467 if (interactive)
468 {
469 vam->ifp = stdin;
470 vam->ofp = stdout;
471 vam->current_file = (u8 *) "interactive";
472 do_one_file (vam);
473 fclose (vam->ifp);
474 }
475
Dave Barachcf5e8482017-10-17 11:48:29 -0400476 /*
477 * Particularly when running a script, don't be in a hurry to leave.
478 * A reply message queued to this process will end up constipating
479 * the allocation rings.
480 */
481 timeout = vat_time_now (vam) + 2.0;
482 while (vam->result_ready == 0 && vat_time_now (vam) < timeout)
483 ;
484
485 if (vat_time_now (vam) > timeout)
486 clib_warning ("BUG: message reply spin-wait timeout");
487
Damjan Marion7cd468a2016-12-19 23:05:39 +0100488 vl_client_disconnect_from_vlib ();
489 exit (0);
490}
491
492/*
493 * fd.io coding-style-patch-verification: ON
494 *
495 * Local Variables:
496 * eval: (c-set-style "gnu")
497 * End:
498 */