blob: 1287be9bdf085d2a1aa55b5dd451826c3e96adf8 [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>
18
19vat_main_t vat_main;
20
21#include <vlibapi/api_helper_macros.h>
Damjan Marion7cd468a2016-12-19 23:05:39 +010022
23void
24vat_suspend (vlib_main_t * vm, f64 interval)
25{
26 /* do nothing in the standalone version, just return */
27}
28
Damjan Marion7cd468a2016-12-19 23:05:39 +010029int
30connect_to_vpe (char *name)
31{
32 vat_main_t *vam = &vat_main;
33 api_main_t *am = &api_main;
34
35 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
36 return -1;
37
38 vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
39 vam->my_client_index = am->my_client_index;
40
41 return 0;
42}
43
44vlib_main_t vlib_global_main;
45vlib_main_t **vlib_mains;
46void
47vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
48{
49 clib_warning ("BUG");
50}
51
52
53static u8 *
54format_api_error (u8 * s, va_list * args)
55{
56 vat_main_t *vam = va_arg (*args, vat_main_t *);
57 i32 error = va_arg (*args, u32);
58 uword *p;
59
60 p = hash_get (vam->error_string_by_error_number, -error);
61
62 if (p)
63 s = format (s, "%s", p[0]);
64 else
65 s = format (s, "%d", error);
66 return s;
67}
68
69void
70do_one_file (vat_main_t * vam)
71{
72 int rv;
73 int (*fp) (vat_main_t * vam);
74 int arg_len;
75 unformat_input_t _input;
76 u8 *cmdp, *argsp;
77 uword *p;
78 u8 *this_cmd = 0;
79
80 vam->input = &_input;
81
82 /* Used by the "quit" command handler */
83 if (setjmp (vam->jump_buf) != 0)
84 return;
85
86 vam->jump_buf_set = 1;
87
88 while (1)
89 {
90 if (vam->ifp == stdin)
91 {
92 if (vam->exec_mode == 0)
93 rv = write (1, "vat# ", 5);
94 else
95 rv = write (1, "exec# ", 6);
96 }
97
98 _vec_len (vam->inbuf) = 4096;
99
100 if (vam->do_exit ||
101 fgets ((char *) vam->inbuf, vec_len (vam->inbuf), vam->ifp) == 0)
102 break;
103
104 vam->input_line_number++;
105
106 vec_free (this_cmd);
107
108 this_cmd =
Damjan Marionffe9d212018-05-30 09:26:11 +0200109 (u8 *) clib_macro_eval (&vam->macro_main, (i8 *) vam->inbuf,
Damjan Marion7cd468a2016-12-19 23:05:39 +0100110 1 /* complain */ );
111
112 if (vam->exec_mode == 0)
113 {
114 /* Split input into cmd + args */
115 cmdp = this_cmd;
116
117 while (cmdp < (this_cmd + vec_len (this_cmd)))
118 {
119 if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
120 {
121 cmdp++;
122 }
123 else
124 break;
125 }
126 argsp = cmdp;
127 while (argsp < (this_cmd + vec_len (this_cmd)))
128 {
129 if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n')
130 {
131 argsp++;
132 }
133 else
134 break;
135 }
136 *argsp++ = 0;
137 while (argsp < (this_cmd + vec_len (this_cmd)))
138 {
139 if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
140 {
141 argsp++;
142 }
143 else
144 break;
145 }
146
147
148 /* Blank input line? */
149 if (*cmdp == 0)
150 continue;
151
152 p = hash_get_mem (vam->function_by_name, cmdp);
153 if (p == 0)
154 {
155 errmsg ("'%s': function not found\n", cmdp);
156 continue;
157 }
158
159 arg_len = strlen ((char *) argsp);
160
161 unformat_init_string (vam->input, (char *) argsp, arg_len);
162 fp = (void *) p[0];
163 }
164 else
165 {
166 unformat_init_string (vam->input, (char *) this_cmd,
167 strlen ((char *) this_cmd));
168 cmdp = this_cmd;
169 fp = exec;
170 }
171
172 rv = (*fp) (vam);
173 if (rv < 0)
174 errmsg ("%s error: %U\n", cmdp, format_api_error, vam, rv);
175 unformat_free (vam->input);
176
177 if (vam->regenerate_interface_table)
178 {
179 vam->regenerate_interface_table = 0;
180 api_sw_interface_dump (vam);
181 }
Dave Barach59b25652017-09-10 15:04:27 -0400182
183 /* Hack to pick up new client index after memfd_segment_create pivot */
184 if (vam->client_index_invalid)
185 {
186 vat_main_t *vam = &vat_main;
187 api_main_t *am = &api_main;
188
189 vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
190 vam->my_client_index = am->my_client_index;
191 vam->client_index_invalid = 0;
192 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100193 }
194}
195
196static void
197init_error_string_table (vat_main_t * vam)
198{
199
200 vam->error_string_by_error_number = hash_create (0, sizeof (uword));
201
202#define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
203 foreach_vnet_api_error;
204#undef _
205
206 hash_set (vam->error_string_by_error_number, 99, "Misc");
207}
208
209static i8 *
210eval_current_file (macro_main_t * mm, i32 complain)
211{
212 vat_main_t *vam = &vat_main;
213 return ((i8 *) format (0, "%s%c", vam->current_file, 0));
214}
215
216static i8 *
217eval_current_line (macro_main_t * mm, i32 complain)
218{
219 vat_main_t *vam = &vat_main;
220 return ((i8 *) format (0, "%d%c", vam->input_line_number, 0));
221}
222
223static void
224signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
225{
226 vat_main_t *vam = &vat_main;
227
228 switch (signum)
229 {
230 /* these (caught) signals cause the application to exit */
231 case SIGINT:
232 case SIGTERM:
233 if (vam->jump_buf_set)
234 {
235 vam->do_exit = 1;
236 return;
237 }
238
239 /* FALLTHROUGH on purpose */
240
241 default:
242 break;
243 }
244
245 _exit (1);
246}
247
248static void
249setup_signal_handlers (void)
250{
251 uword i;
252 struct sigaction sa;
253
254 for (i = 1; i < 32; i++)
255 {
256 memset (&sa, 0, sizeof (sa));
257 sa.sa_sigaction = (void *) signal_handler;
258 sa.sa_flags = SA_SIGINFO;
259
260 switch (i)
261 {
262 /* these signals take the default action */
263 case SIGABRT:
264 case SIGKILL:
265 case SIGSTOP:
266 case SIGUSR1:
267 case SIGUSR2:
268 continue;
269
270 /* ignore SIGPIPE, SIGCHLD */
271 case SIGPIPE:
272 case SIGCHLD:
273 sa.sa_sigaction = (void *) SIG_IGN;
274 break;
275
276 /* catch and handle all other signals */
277 default:
278 break;
279 }
280
281 if (sigaction (i, &sa, 0) < 0)
282 clib_unix_warning ("sigaction %U", format_signal, i);
283 }
284}
285
286int
287main (int argc, char **argv)
288{
289 vat_main_t *vam = &vat_main;
290 unformat_input_t _argv, *a = &_argv;
291 u8 **input_files = 0;
292 u8 *output_file = 0;
293 u8 *chroot_prefix;
294 u8 *this_input_file;
295 u8 interactive = 1;
296 u8 json_output = 0;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100297 int i;
Dave Barachcf5e8482017-10-17 11:48:29 -0400298 f64 timeout;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100299
Dave Barach6a5adc32018-07-04 10:56:23 -0400300 clib_mem_init_thread_safe (0, 128 << 20);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100301
302 clib_macro_init (&vam->macro_main);
303 clib_macro_add_builtin (&vam->macro_main, "current_file",
304 eval_current_file);
305 clib_macro_add_builtin (&vam->macro_main, "current_line",
306 eval_current_line);
307
308 init_error_string_table (vam);
Dave Barach59b25652017-09-10 15:04:27 -0400309 vec_validate (vam->cmd_reply, 0);
310 vec_reset_length (vam->cmd_reply);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100311
312 unformat_init_command_line (a, argv);
313
314 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
315 {
316 if (unformat (a, "in %s", &this_input_file))
317 vec_add1 (input_files, this_input_file);
318 else if (unformat (a, "out %s", &output_file))
319 ;
320 else if (unformat (a, "script"))
321 interactive = 0;
322 else if (unformat (a, "json"))
323 json_output = 1;
Dave Barach59b25652017-09-10 15:04:27 -0400324 else if (unformat (a, "socket-name %s", &vam->socket_name))
325 ;
326 else if (unformat (a, "default-socket"))
327 {
328 vam->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
329 }
Damjan Marion7cd468a2016-12-19 23:05:39 +0100330 else if (unformat (a, "plugin_path %s", (u8 *) & vat_plugin_path))
331 vec_add1 (vat_plugin_path, 0);
332 else if (unformat (a, "plugin_name_filter %s",
333 (u8 *) & vat_plugin_name_filter))
334 vec_add1 (vat_plugin_name_filter, 0);
335 else if (unformat (a, "chroot prefix %s", &chroot_prefix))
336 {
337 vl_set_memory_root_path ((char *) chroot_prefix);
338 }
339 else
340 {
Dave Barach59b25652017-09-10 15:04:27 -0400341 fformat
342 (stderr,
343 "%s: usage [in <f1> ... in <fn>] [out <fn>] [script] [json]\n"
344 "[plugin_path <path>][default-socket][socket-name <name>]\n"
345 "[plugin_name_filter <filter>][chroot prefix <path>]\n",
346 argv[0]);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100347 exit (1);
348 }
349 }
350
351 if (output_file)
352 vam->ofp = fopen ((char *) output_file, "w");
353 else
354 vam->ofp = stdout;
355
356 if (vam->ofp == NULL)
357 {
358 fformat (stderr, "Couldn't open output file %s\n",
359 output_file ? (char *) output_file : "stdout");
360 exit (1);
361 }
362
363 clib_time_init (&vam->clib_time);
364
365 vat_api_hookup (vam);
366 vat_plugin_api_reference ();
367
368 setup_signal_handlers ();
369
Dave Barach59b25652017-09-10 15:04:27 -0400370 if (vam->socket_name && vat_socket_connect (vam))
371 fformat (stderr, "WARNING: socket connection failed");
372
Florin Coras90a63982017-12-19 04:50:01 -0800373 if ((!vam->socket_client_main || vam->socket_client_main->socket_fd == 0)
Dave Barach59b25652017-09-10 15:04:27 -0400374 && connect_to_vpe ("vpp_api_test") < 0)
Damjan Marion7cd468a2016-12-19 23:05:39 +0100375 {
376 svm_region_exit ();
377 fformat (stderr, "Couldn't connect to vpe, exiting...\n");
378 exit (1);
379 }
380
381 vam->json_output = json_output;
382
383 if (!json_output)
Dave Barach59b25652017-09-10 15:04:27 -0400384 api_sw_interface_dump (vam);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100385
386 vec_validate (vam->inbuf, 4096);
387
388 vam->current_file = (u8 *) "plugin-init";
389 vat_plugin_init (vam);
390
391 for (i = 0; i < vec_len (input_files); i++)
392 {
393 vam->ifp = fopen ((char *) input_files[i], "r");
394 if (vam->ifp == NULL)
395 {
396 fformat (stderr, "Couldn't open input file %s\n", input_files[i]);
397 continue;
398 }
399 vam->current_file = input_files[i];
400 vam->input_line_number = 0;
401 do_one_file (vam);
402 fclose (vam->ifp);
403 }
404
405 if (output_file)
406 fclose (vam->ofp);
407
408 if (interactive)
409 {
410 vam->ifp = stdin;
411 vam->ofp = stdout;
412 vam->current_file = (u8 *) "interactive";
413 do_one_file (vam);
414 fclose (vam->ifp);
415 }
416
Dave Barachcf5e8482017-10-17 11:48:29 -0400417 /*
418 * Particularly when running a script, don't be in a hurry to leave.
419 * A reply message queued to this process will end up constipating
420 * the allocation rings.
421 */
422 timeout = vat_time_now (vam) + 2.0;
423 while (vam->result_ready == 0 && vat_time_now (vam) < timeout)
424 ;
425
426 if (vat_time_now (vam) > timeout)
427 clib_warning ("BUG: message reply spin-wait timeout");
428
Damjan Marion7cd468a2016-12-19 23:05:39 +0100429 vl_client_disconnect_from_vlib ();
430 exit (0);
431}
432
433/*
434 * fd.io coding-style-patch-verification: ON
435 *
436 * Local Variables:
437 * eval: (c-set-style "gnu")
438 * End:
439 */