FD.io VPP  v17.07-30-g839fa73
Vector Packet Processing
main.c
Go to the documentation of this file.
1 /*
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 /*
16  * main.c: Unix main routine
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 #include <vlib/vlib.h>
40 #include <vlib/unix/unix.h>
41 #include <vlib/unix/plugin.h>
42 
43 #include <signal.h>
44 #include <sys/ucontext.h>
45 #include <syslog.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <sys/time.h>
50 #include <sys/resource.h>
51 #include <unistd.h>
52 
53 /** Default CLI pager limit is not configured in startup.conf */
54 #define UNIX_CLI_DEFAULT_PAGER_LIMIT 100000
55 
56 /** Default CLI history depth if not configured in startup.conf */
57 #define UNIX_CLI_DEFAULT_HISTORY 50
58 
59 
61 
62 static clib_error_t *
64 {
65  unix_main_t *um = &unix_main;
66  um->vlib_main = vm;
68 }
69 
71 
72 static void
73 unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
74 {
75  uword fatal;
76  u8 *msg = 0;
77 
78  msg = format (msg, "received signal %U, PC %U",
79  format_signal, signum, format_ucontext_pc, uc);
80 
81  if (signum == SIGSEGV)
82  msg = format (msg, ", faulting address %p", si->si_addr);
83 
84  switch (signum)
85  {
86  /* these (caught) signals cause the application to exit */
87  case SIGTERM:
88  if (unix_main.vlib_main->main_loop_exit_set)
89  {
90  syslog (LOG_ERR | LOG_DAEMON, "received SIGTERM, exiting...");
91 
94  }
95  /* fall through */
96  case SIGQUIT:
97  case SIGINT:
98  case SIGILL:
99  case SIGBUS:
100  case SIGSEGV:
101  case SIGHUP:
102  case SIGFPE:
103  fatal = 1;
104  break;
105 
106  /* by default, print a message and continue */
107  default:
108  fatal = 0;
109  break;
110  }
111 
112  /* Null terminate. */
113  vec_add1 (msg, 0);
114 
115  if (fatal)
116  {
117  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
118  os_exit (1);
119  }
120  else
121  clib_warning ("%s", msg);
122 
123  vec_free (msg);
124 }
125 
126 static clib_error_t *
128 {
129  uword i;
130  struct sigaction sa;
131 
132  for (i = 1; i < 32; i++)
133  {
134  memset (&sa, 0, sizeof (sa));
135  sa.sa_sigaction = (void *) unix_signal_handler;
136  sa.sa_flags = SA_SIGINFO;
137 
138  switch (i)
139  {
140  /* these signals take the default action */
141  case SIGABRT:
142  case SIGKILL:
143  case SIGSTOP:
144  case SIGUSR1:
145  case SIGUSR2:
146  continue;
147 
148  /* ignore SIGPIPE, SIGCHLD */
149  case SIGPIPE:
150  case SIGCHLD:
151  sa.sa_sigaction = (void *) SIG_IGN;
152  break;
153 
154  /* catch and handle all other signals */
155  default:
156  break;
157  }
158 
159  if (sigaction (i, &sa, 0) < 0)
160  return clib_error_return_unix (0, "sigaction %U", format_signal, i);
161  }
162 
163  return 0;
164 }
165 
166 static void
167 unix_error_handler (void *arg, u8 * msg, int msg_len)
168 {
169  unix_main_t *um = arg;
170 
171  /* Echo to stderr when interactive. */
172  if (um->flags & UNIX_FLAG_INTERACTIVE)
173  {
174  CLIB_UNUSED (int r) = write (2, msg, msg_len);
175  }
176  else
177  {
178  char save = msg[msg_len - 1];
179 
180  /* Null Terminate. */
181  msg[msg_len - 1] = 0;
182 
183  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
184 
185  msg[msg_len - 1] = save;
186  }
187 }
188 
189 void
191 {
192  unix_main_t *um = &unix_main;
193 
194  if (um->flags & UNIX_FLAG_INTERACTIVE || error == 0)
195  return;
196 
197  {
198  char save;
199  u8 *msg;
200  u32 msg_len;
201 
202  msg = error->what;
203  msg_len = vec_len (msg);
204 
205  /* Null Terminate. */
206  save = msg[msg_len - 1];
207  msg[msg_len - 1] = 0;
208 
209  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
210 
211  msg[msg_len - 1] = save;
212  }
213 }
214 
215 static uword
218 {
219  unix_main_t *um = &unix_main;
220  u8 *buf = 0;
221  uword l, n = 1;
222 
223  vlib_process_suspend (vm, 2.0);
224 
225  while (um->unix_config_complete == 0)
226  vlib_process_suspend (vm, 0.1);
227 
228  if (um->startup_config_filename)
229  {
230  unformat_input_t sub_input;
231  int fd;
232  struct stat s;
233  char *fn = (char *) um->startup_config_filename;
234 
235  fd = open (fn, O_RDONLY);
236  if (fd < 0)
237  {
238  clib_warning ("failed to open `%s'", fn);
239  return 0;
240  }
241 
242  if (fstat (fd, &s) < 0)
243  {
244  clib_warning ("failed to stat `%s'", fn);
245  bail:
246  close (fd);
247  return 0;
248  }
249 
250  if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
251  {
252  clib_warning ("not a regular file: `%s'", fn);
253  goto bail;
254  }
255 
256  while (n > 0)
257  {
258  l = vec_len (buf);
259  vec_resize (buf, 4096);
260  n = read (fd, buf + l, 4096);
261  if (n > 0)
262  {
263  _vec_len (buf) = l + n;
264  if (n < 4096)
265  break;
266  }
267  else
268  break;
269  }
270  if (um->log_fd && vec_len (buf))
271  {
272  u8 *lv = 0;
273  lv = format (lv, "%U: ***** Startup Config *****\n%v",
274  format_timeval, 0 /* current bat-time */ ,
275  0 /* current bat-format */ ,
276  buf);
277  {
278  int rv __attribute__ ((unused)) =
279  write (um->log_fd, lv, vec_len (lv));
280  }
281  vec_reset_length (lv);
282  lv = format (lv, "%U: ***** End Startup Config *****\n",
283  format_timeval, 0 /* current bat-time */ ,
284  0 /* current bat-format */ );
285  {
286  int rv __attribute__ ((unused)) =
287  write (um->log_fd, lv, vec_len (lv));
288  }
289  vec_free (lv);
290  }
291 
292  if (vec_len (buf))
293  {
294  unformat_init_vector (&sub_input, buf);
295  vlib_cli_input (vm, &sub_input, 0, 0);
296  /* frees buf for us */
297  unformat_free (&sub_input);
298  }
299  close (fd);
300  }
301  return 0;
302 }
303 
304 /* *INDENT-OFF* */
306  .function = startup_config_process,
307  .type = VLIB_NODE_TYPE_PROCESS,
308  .name = "startup-config-process",
309 };
310 /* *INDENT-ON* */
311 
312 static clib_error_t *
314 {
315  unix_main_t *um = &unix_main;
316  clib_error_t *error = 0;
317  gid_t gid;
318 
319  /* Defaults */
322 
324  {
325  char *cli_prompt;
326  if (unformat (input, "interactive"))
328  else if (unformat (input, "nodaemon"))
329  um->flags |= UNIX_FLAG_NODAEMON;
330  else if (unformat (input, "cli-prompt %s", &cli_prompt))
331  vlib_unix_cli_set_prompt (cli_prompt);
332  else
333  if (unformat (input, "cli-listen %s", &um->cli_listen_socket.config))
334  ;
335  else if (unformat (input, "cli-line-mode"))
336  um->cli_line_mode = 1;
337  else if (unformat (input, "cli-no-banner"))
338  um->cli_no_banner = 1;
339  else if (unformat (input, "cli-no-pager"))
340  um->cli_no_pager = 1;
341  else if (unformat (input, "cli-pager-buffer-limit %d",
343  ;
344  else
345  if (unformat (input, "cli-history-limit %d", &um->cli_history_limit))
346  ;
347  else if (unformat (input, "coredump-size"))
348  {
349  uword coredump_size = 0;
350  if (unformat (input, "unlimited"))
351  {
352  coredump_size = RLIM_INFINITY;
353  }
354  else
355  if (!unformat (input, "%U", unformat_memory_size, &coredump_size))
356  {
357  return clib_error_return (0,
358  "invalid coredump-size parameter `%U'",
359  format_unformat_error, input);
360  }
361  const struct rlimit new_limit = { coredump_size, coredump_size };
362  if (0 != setrlimit (RLIMIT_CORE, &new_limit))
363  {
364  clib_unix_warning ("prlimit() failed");
365  }
366  }
367  else if (unformat (input, "full-coredump"))
368  {
369  int fd;
370 
371  fd = open ("/proc/self/coredump_filter", O_WRONLY);
372  if (fd >= 0)
373  {
374  if (write (fd, "0x6f\n", 5) != 5)
375  clib_unix_warning ("coredump filter write failed!");
376  close (fd);
377  }
378  else
379  clib_unix_warning ("couldn't open /proc/self/coredump_filter");
380  }
381  else if (unformat (input, "startup-config %s",
383  ;
384  else if (unformat (input, "exec %s", &um->startup_config_filename))
385  ;
386  else if (unformat (input, "log %s", &um->log_filename))
387  {
388  um->log_fd = open ((char *) um->log_filename,
389  O_CREAT | O_WRONLY | O_APPEND, 0644);
390  if (um->log_fd < 0)
391  {
392  clib_warning ("couldn't open log '%s'\n", um->log_filename);
393  um->log_fd = 0;
394  }
395  else
396  {
397  u8 *lv = 0;
398  lv = format (0, "%U: ***** Start: PID %d *****\n",
399  format_timeval, 0 /* current bat-time */ ,
400  0 /* current bat-format */ ,
401  getpid ());
402  {
403  int rv __attribute__ ((unused)) =
404  write (um->log_fd, lv, vec_len (lv));
405  }
406  vec_free (lv);
407  }
408  }
409  else if (unformat (input, "gid %U", unformat_unix_gid, &gid))
410  {
411  if (setegid (gid) == -1)
412  return clib_error_return_unix (0, "setegid");
413  }
414  else
415  return clib_error_return (0, "unknown input `%U'",
416  format_unformat_error, input);
417  }
418 
419  error = setup_signal_handlers (um);
420  if (error)
421  return error;
422 
423  if (!(um->flags & UNIX_FLAG_INTERACTIVE))
424  {
425  openlog (vm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
427 
428  if (!(um->flags & UNIX_FLAG_NODAEMON) && daemon ( /* chdir to / */ 0,
429  /* stdin/stdout/stderr -> /dev/null */
430  0) < 0)
431  clib_error_return (0, "daemon () fails");
432  }
433  um->unix_config_complete = 1;
434 
435  return 0;
436 }
437 
438 /* unix { ... } configuration. */
439 /*?
440  *
441  * @cfgcmd{interactive}
442  * Attach CLI to stdin/out and provide a debugging command line interface.
443  * Implies @c nodaemon.
444  *
445  * @cfgcmd{nodaemon}
446  * Do not fork or background the VPP process. Typically used when invoking
447  * VPP applications from a process monitor.
448  *
449  * @cfgcmd{exec, &lt;filename&gt;}
450  * @par <code>startup-config &lt;filename&gt;</code>
451  * Read startup operational configuration from @c filename.
452  * The contents of the file will be performed as though entered at the CLI.
453  * The two keywords are aliases for the same function; if both are specified,
454  * only the last will have an effect.
455  *
456  * @cfgcmd{log, &lt;filename&gt;}
457  * Logs the startup configuration and all subsequent CLI commands in
458  * @c filename.
459  * Very useful in situations where folks don't remember or can't be bothered
460  * to include CLI commands in bug reports.
461  *
462  * @cfgcmd{full-coredump}
463  * Ask the Linux kernel to dump all memory-mapped address regions, instead
464  * of just text+data+bss.
465  *
466  * @cfgcmd{cli-listen, &lt;address:port&gt;}
467  * Bind the CLI to listen at the address and port given. @clocalhost
468  * on TCP port @c 5002, given as <tt>cli-listen localhost:5002</tt>,
469  * is typical.
470  *
471  * @cfgcmd{cli-line-mode}
472  * Disable character-by-character I/O on stdin. Useful when combined with,
473  * for example, <tt>emacs M-x gud-gdb</tt>.
474  *
475  * @cfgcmd{cli-prompt, &lt;string&gt;}
476  * Configure the CLI prompt to be @c string.
477  *
478  * @cfgcmd{cli-history-limit, &lt;nn&gt;}
479  * Limit commmand history to @c nn lines. A value of @c 0
480  * disables command history. Default value: @c 50
481  *
482  * @cfgcmd{cli-no-banner}
483  * Disable the login banner on stdin and Telnet connections.
484  *
485  * @cfgcmd{cli-no-pager}
486  * Disable the output pager.
487  *
488  * @cfgcmd{cli-pager-buffer-limit, &lt;nn&gt;}
489  * Limit pager buffer to @c nn lines of output.
490  * A value of @c 0 disables the pager. Default value: @c 100000
491 ?*/
493 
494 static clib_error_t *
496 {
497  /* Close syslog connection. */
498  closelog ();
499  return 0;
500 }
501 
503 
505 
506 static uword
508 {
509  vlib_main_t *vm = (vlib_main_t *) arg;
510  unformat_input_t input;
511  int i;
512 
513  unformat_init_command_line (&input, (char **) vm->argv);
514  i = vlib_main (vm, &input);
515  unformat_free (&input);
516 
517  return i;
518 }
519 
520 u8 *
522 {
523  vec_validate (vlib_thread_stacks, thread_index);
526 
527  /*
528  * Disallow writes to the bottom page of the stack, to
529  * catch stack overflows.
530  */
531  if (mprotect (vlib_thread_stacks[thread_index],
532  clib_mem_get_page_size (), PROT_READ) < 0)
533  clib_unix_warning ("thread stack");
534  return vlib_thread_stacks[thread_index];
535 }
536 
537 int
538 vlib_unix_main (int argc, char *argv[])
539 {
540  vlib_main_t *vm = &vlib_global_main; /* one and only time for this! */
541  unformat_input_t input;
542  clib_error_t *e;
543  int i;
544 
545  vm->argv = (u8 **) argv;
546  vm->name = argv[0];
547  vm->heap_base = clib_mem_get_heap ();
548  ASSERT (vm->heap_base);
549 
550  unformat_init_command_line (&input, (char **) vm->argv);
551  if ((e = vlib_plugin_config (vm, &input)))
552  {
553  clib_error_report (e);
554  return 1;
555  }
556  unformat_free (&input);
557 
558  i = vlib_plugin_early_init (vm);
559  if (i)
560  return i;
561 
562  unformat_init_command_line (&input, (char **) vm->argv);
563  if (vm->init_functions_called == 0)
564  vm->init_functions_called = hash_create (0, /* value bytes */ 0);
565  e = vlib_call_all_config_functions (vm, &input, 1 /* early */ );
566  if (e != 0)
567  {
568  clib_error_report (e);
569  return 1;
570  }
571  unformat_free (&input);
572 
574 
575  __os_thread_index = 0;
576 
577  i = clib_calljmp (thread0, (uword) vm,
578  (void *) (vlib_thread_stacks[0] +
580  return i;
581 }
582 
583 /*
584  * fd.io coding-style-patch-verification: ON
585  *
586  * Local Variables:
587  * eval: (c-set-style "gnu")
588  * End:
589  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
static clib_error_t * unix_main_init(vlib_main_t *vm)
Definition: main.c:63
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define CLIB_UNUSED(x)
Definition: clib.h:79
static clib_error_t * unix_input_init(vlib_main_t *vm)
Definition: input.c:269
void vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:643
u32 flags
Definition: unix.h:83
volatile int unix_config_complete
Definition: unix.h:106
static uword startup_config_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: main.c:216
unix_main_t unix_main
Definition: main.c:60
u32 cli_pager_buffer_limit
Definition: unix.h:122
void vlib_unix_cli_set_prompt(char *prompt)
Set the CLI prompt.
Definition: cli.c:2693
u32 main_loop_exit_set
Definition: main.h:87
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
clib_error_t * vlib_plugin_config(vlib_main_t *vm, unformat_input_t *input)
Definition: plugin.c:462
unformat_function_t unformat_unix_gid
Definition: format.h:315
#define VLIB_MAIN_LOOP_EXIT_CLI
Definition: main.h:92
void clib_longjmp(clib_longjmp_t *save, uword return_value)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
void clib_error_register_handler(clib_error_handler_func_t func, void *arg)
Definition: error.c:75
clib_socket_t cli_listen_socket
Definition: unix.h:92
#define UNIX_FLAG_NODAEMON
Definition: unix.h:86
int log_fd
Definition: unix.h:110
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:448
u8 * format_timeval(u8 *s, va_list *args)
Definition: unix-formats.c:749
static vlib_node_registration_t startup_config_node
(constructor) VLIB_REGISTER_NODE (startup_config_node)
Definition: main.c:305
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define clib_error_return(e, args...)
Definition: error.h:99
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:241
vlib_main_t * vlib_main
Definition: unix.h:81
#define vlib_call_init_function(vm, x)
Definition: init.h:162
int vlib_plugin_early_init(vlib_main_t *vm)
Definition: plugin.c:349
char * name
Definition: main.h:98
int cli_line_mode
Definition: unix.h:113
#define UNIX_CLI_DEFAULT_PAGER_LIMIT
Default CLI pager limit is not configured in startup.conf.
Definition: main.c:54
vlib_main_t vlib_global_main
Definition: main.c:1653
static clib_error_t * unix_config(vlib_main_t *vm, unformat_input_t *input)
Definition: main.c:313
struct _unformat_input_t unformat_input_t
#define clib_error_return_unix(e, args...)
Definition: error.h:102
int cli_no_banner
Definition: unix.h:119
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1007
static void unix_signal_handler(int signum, siginfo_t *si, ucontext_t *uc)
Definition: main.c:73
u8 * startup_config_filename
Definition: unix.h:103
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
static clib_error_t * setup_signal_handlers(unix_main_t *um)
Definition: main.c:127
uword * init_functions_called
Definition: main.h:156
u32 cli_history_limit
Definition: unix.h:116
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1031
static clib_error_t * unix_exit(vlib_main_t *vm)
Definition: main.c:495
u8 ** argv
Definition: main.h:176
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
void * heap_base
Definition: main.h:101
int cli_no_pager
Definition: unix.h:125
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
Definition: init.h:116
#define clib_warning(format, args...)
Definition: error.h:59
u8 * vlib_thread_stack_init(uword thread_index)
Definition: main.c:521
static void * clib_mem_get_heap(void)
Definition: mem.h:217
#define hash_create(elts, value_bytes)
Definition: hash.h:658
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1692
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define UNIX_CLI_DEFAULT_HISTORY
Default CLI history depth if not configured in startup.conf.
Definition: main.c:57
#define UNIX_FLAG_INTERACTIVE
Definition: unix.h:85
void os_exit(int code)
Definition: main.c:273
#define clib_error_report(e)
Definition: error.h:113
u64 uword
Definition: types.h:112
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u8 ** vlib_thread_stacks
Definition: main.c:504
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
u8 * format_signal(u8 *s, va_list *args)
Definition: unix-formats.c:835
clib_error_t * vlib_call_all_config_functions(vlib_main_t *vm, unformat_input_t *input, int is_early)
Definition: init.c:94
void vlib_unix_error_report(vlib_main_t *vm, clib_error_t *error)
Definition: main.c:190
#define clib_unix_warning(format, args...)
Definition: error.h:68
#define VLIB_THREAD_STACK_SIZE
Definition: threads.h:66
unformat_function_t unformat_memory_size
Definition: format.h:294
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:117
uword clib_calljmp(uword(*func)(uword func_arg), uword func_arg, void *stack)
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
static void unix_error_handler(void *arg, u8 *msg, int msg_len)
Definition: main.c:167
clib_longjmp_t main_loop_exit
Definition: main.h:88
uword clib_mem_get_page_size(void)
Definition: mem_mheap.c:110
static uword thread0(uword arg)
Definition: main.c:507
u8 * log_filename
Definition: unix.h:109
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u8 * format_ucontext_pc(u8 *s, va_list *args)
Definition: unix-formats.c:886
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
int vlib_unix_main(int argc, char *argv[])
Definition: main.c:538