FD.io VPP  v17.01.1-3-gc6833f8
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 
50 /** Default CLI pager limit is not configured in startup.conf */
51 #define UNIX_CLI_DEFAULT_PAGER_LIMIT 100000
52 
53 /** Default CLI history depth if not configured in startup.conf */
54 #define UNIX_CLI_DEFAULT_HISTORY 50
55 
56 
58 
59 static clib_error_t *
61 {
62  unix_main_t *um = &unix_main;
63  um->vlib_main = vm;
65 }
66 
68 
69 static void
70 unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
71 {
72  uword fatal;
73  u8 *msg = 0;
74 
75  msg = format (msg, "received signal %U, PC %U",
76  format_signal, signum, format_ucontext_pc, uc);
77 
78  if (signum == SIGSEGV)
79  msg = format (msg, ", faulting address %p", si->si_addr);
80 
81  switch (signum)
82  {
83  /* these (caught) signals cause the application to exit */
84  case SIGTERM:
85  if (unix_main.vlib_main->main_loop_exit_set)
86  {
87  syslog (LOG_ERR | LOG_DAEMON, "received SIGTERM, exiting...");
88 
91  }
92  /* fall through */
93  case SIGQUIT:
94  case SIGINT:
95  case SIGILL:
96  case SIGBUS:
97  case SIGSEGV:
98  case SIGHUP:
99  case SIGFPE:
100  fatal = 1;
101  break;
102 
103  /* by default, print a message and continue */
104  default:
105  fatal = 0;
106  break;
107  }
108 
109  /* Null terminate. */
110  vec_add1 (msg, 0);
111 
112  if (fatal)
113  {
114  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
115  os_exit (1);
116  }
117  else
118  clib_warning ("%s", msg);
119 
120  vec_free (msg);
121 }
122 
123 static clib_error_t *
125 {
126  uword i;
127  struct sigaction sa;
128 
129  for (i = 1; i < 32; i++)
130  {
131  memset (&sa, 0, sizeof (sa));
132  sa.sa_sigaction = (void *) unix_signal_handler;
133  sa.sa_flags = SA_SIGINFO;
134 
135  switch (i)
136  {
137  /* these signals take the default action */
138  case SIGABRT:
139  case SIGKILL:
140  case SIGSTOP:
141  case SIGUSR1:
142  case SIGUSR2:
143  continue;
144 
145  /* ignore SIGPIPE, SIGCHLD */
146  case SIGPIPE:
147  case SIGCHLD:
148  sa.sa_sigaction = (void *) SIG_IGN;
149  break;
150 
151  /* catch and handle all other signals */
152  default:
153  break;
154  }
155 
156  if (sigaction (i, &sa, 0) < 0)
157  return clib_error_return_unix (0, "sigaction %U", format_signal, i);
158  }
159 
160  return 0;
161 }
162 
163 static void
164 unix_error_handler (void *arg, u8 * msg, int msg_len)
165 {
166  unix_main_t *um = arg;
167 
168  /* Echo to stderr when interactive. */
169  if (um->flags & UNIX_FLAG_INTERACTIVE)
170  {
171  CLIB_UNUSED (int r) = write (2, msg, msg_len);
172  }
173  else
174  {
175  char save = msg[msg_len - 1];
176 
177  /* Null Terminate. */
178  msg[msg_len - 1] = 0;
179 
180  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
181 
182  msg[msg_len - 1] = save;
183  }
184 }
185 
186 void
188 {
189  unix_main_t *um = &unix_main;
190 
191  if (um->flags & UNIX_FLAG_INTERACTIVE || error == 0)
192  return;
193 
194  {
195  char save;
196  u8 *msg;
197  u32 msg_len;
198 
199  msg = error->what;
200  msg_len = vec_len (msg);
201 
202  /* Null Terminate. */
203  save = msg[msg_len - 1];
204  msg[msg_len - 1] = 0;
205 
206  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
207 
208  msg[msg_len - 1] = save;
209  }
210 }
211 
212 static uword
215 {
216  unix_main_t *um = &unix_main;
217  u8 *buf = 0;
218  uword l, n = 1;
219 
220  vlib_process_suspend (vm, 2.0);
221 
222  while (um->unix_config_complete == 0)
223  vlib_process_suspend (vm, 0.1);
224 
225  if (um->startup_config_filename)
226  {
227  unformat_input_t sub_input;
228  int fd;
229  struct stat s;
230  char *fn = (char *) um->startup_config_filename;
231 
232  fd = open (fn, O_RDONLY);
233  if (fd < 0)
234  {
235  clib_warning ("failed to open `%s'", fn);
236  return 0;
237  }
238 
239  if (fstat (fd, &s) < 0)
240  {
241  clib_warning ("failed to stat `%s'", fn);
242  bail:
243  close (fd);
244  return 0;
245  }
246 
247  if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
248  {
249  clib_warning ("not a regular file: `%s'", fn);
250  goto bail;
251  }
252 
253  while (n > 0)
254  {
255  l = vec_len (buf);
256  vec_resize (buf, 4096);
257  n = read (fd, buf + l, 4096);
258  if (n > 0)
259  {
260  _vec_len (buf) = l + n;
261  if (n < 4096)
262  break;
263  }
264  else
265  break;
266  }
267  if (um->log_fd && vec_len (buf))
268  {
269  u8 *lv = 0;
270  lv = format (lv, "%U: ***** Startup Config *****\n%v",
271  format_timeval, 0 /* current bat-time */ ,
272  0 /* current bat-format */ ,
273  buf);
274  {
275  int rv __attribute__ ((unused)) =
276  write (um->log_fd, lv, vec_len (lv));
277  }
278  vec_reset_length (lv);
279  lv = format (lv, "%U: ***** End Startup Config *****\n",
280  format_timeval, 0 /* current bat-time */ ,
281  0 /* current bat-format */ );
282  {
283  int rv __attribute__ ((unused)) =
284  write (um->log_fd, lv, vec_len (lv));
285  }
286  vec_free (lv);
287  }
288 
289  if (vec_len (buf))
290  {
291  unformat_init_vector (&sub_input, buf);
292  vlib_cli_input (vm, &sub_input, 0, 0);
293  /* frees buf for us */
294  unformat_free (&sub_input);
295  }
296  close (fd);
297  }
298  return 0;
299 }
300 
301 /* *INDENT-OFF* */
303  .function = startup_config_process,
304  .type = VLIB_NODE_TYPE_PROCESS,
305  .name = "startup-config-process",
306 };
307 /* *INDENT-ON* */
308 
309 static clib_error_t *
311 {
312  unix_main_t *um = &unix_main;
313  clib_error_t *error = 0;
314 
315  /* Defaults */
318 
320  {
321  char *cli_prompt;
322  if (unformat (input, "interactive"))
324  else if (unformat (input, "nodaemon"))
325  um->flags |= UNIX_FLAG_NODAEMON;
326  else if (unformat (input, "cli-prompt %s", &cli_prompt))
327  vlib_unix_cli_set_prompt (cli_prompt);
328  else
329  if (unformat (input, "cli-listen %s", &um->cli_listen_socket.config))
330  ;
331  else if (unformat (input, "cli-line-mode"))
332  um->cli_line_mode = 1;
333  else if (unformat (input, "cli-no-banner"))
334  um->cli_no_banner = 1;
335  else if (unformat (input, "cli-no-pager"))
336  um->cli_no_pager = 1;
337  else if (unformat (input, "cli-pager-buffer-limit %d",
339  ;
340  else
341  if (unformat (input, "cli-history-limit %d", &um->cli_history_limit))
342  ;
343  else if (unformat (input, "full-coredump"))
344  {
345  int fd;
346 
347  fd = open ("/proc/self/coredump_filter", O_WRONLY);
348  if (fd >= 0)
349  {
350  if (write (fd, "0x6f\n", 5) != 5)
351  clib_unix_warning ("coredump filter write failed!");
352  close (fd);
353  }
354  else
355  clib_unix_warning ("couldn't open /proc/self/coredump_filter");
356  }
357  else if (unformat (input, "startup-config %s",
359  ;
360  else if (unformat (input, "exec %s", &um->startup_config_filename))
361  ;
362  else if (unformat (input, "log %s", &um->log_filename))
363  {
364  um->log_fd = open ((char *) um->log_filename,
365  O_CREAT | O_WRONLY | O_APPEND, 0644);
366  if (um->log_fd < 0)
367  {
368  clib_warning ("couldn't open log '%s'\n", um->log_filename);
369  um->log_fd = 0;
370  }
371  else
372  {
373  u8 *lv = 0;
374  lv = format (0, "%U: ***** Start: PID %d *****\n",
375  format_timeval, 0 /* current bat-time */ ,
376  0 /* current bat-format */ ,
377  getpid ());
378  {
379  int rv __attribute__ ((unused)) =
380  write (um->log_fd, lv, vec_len (lv));
381  }
382  vec_free (lv);
383  }
384  }
385  else
386  return clib_error_return (0, "unknown input `%U'",
387  format_unformat_error, input);
388  }
389 
390  if (!(um->flags & UNIX_FLAG_INTERACTIVE))
391  {
392  error = setup_signal_handlers (um);
393  if (error)
394  return error;
395 
396  openlog (vm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
398 
399  if (!(um->flags & UNIX_FLAG_NODAEMON) && daemon ( /* chdir to / */ 0,
400  /* stdin/stdout/stderr -> /dev/null */
401  0) < 0)
402  clib_error_return (0, "daemon () fails");
403  }
404  um->unix_config_complete = 1;
405 
406  return 0;
407 }
408 
409 /* unix { ... } configuration. */
410 /*?
411  *
412  * @cfgcmd{interactive}
413  * Attach CLI to stdin/out and provide a debugging command line interface.
414  * Implies @c nodaemon.
415  *
416  * @cfgcmd{nodaemon}
417  * Do not fork or background the VPP process. Typically used when invoking
418  * VPP applications from a process monitor.
419  *
420  * @cfgcmd{exec, &lt;filename&gt;}
421  * @par <code>startup-config &lt;filename&gt;</code>
422  * Read startup operational configuration from @c filename.
423  * The contents of the file will be performed as though entered at the CLI.
424  * The two keywords are aliases for the same function; if both are specified,
425  * only the last will have an effect.
426  *
427  * @cfgcmd{log, &lt;filename&gt;}
428  * Logs the startup configuration and all subsequent CLI commands in
429  * @c filename.
430  * Very useful in situations where folks don't remember or can't be bothered
431  * to include CLI commands in bug reports.
432  *
433  * @cfgcmd{full-coredump}
434  * Ask the Linux kernel to dump all memory-mapped address regions, instead
435  * of just text+data+bss.
436  *
437  * @cfgcmd{cli-listen, &lt;address:port&gt;}
438  * Bind the CLI to listen at the address and port given. @clocalhost
439  * on TCP port @c 5002, given as <tt>cli-listen localhost:5002</tt>,
440  * is typical.
441  *
442  * @cfgcmd{cli-line-mode}
443  * Disable character-by-character I/O on stdin. Useful when combined with,
444  * for example, <tt>emacs M-x gud-gdb</tt>.
445  *
446  * @cfgcmd{cli-prompt, &lt;string&gt;}
447  * Configure the CLI prompt to be @c string.
448  *
449  * @cfgcmd{cli-history-limit, &lt;nn&gt;}
450  * Limit commmand history to @c nn lines. A value of @c 0
451  * disables command history. Default value: @c 50
452  *
453  * @cfgcmd{cli-no-banner}
454  * Disable the login banner on stdin and Telnet connections.
455  *
456  * @cfgcmd{cli-no-pager}
457  * Disable the output pager.
458  *
459  * @cfgcmd{cli-pager-buffer-limit, &lt;nn&gt;}
460  * Limit pager buffer to @c nn lines of output.
461  * A value of @c 0 disables the pager. Default value: @c 100000
462 ?*/
464 
465 static clib_error_t *
467 {
468  /* Close syslog connection. */
469  closelog ();
470  return 0;
471 }
472 
474 
476 
477 static uword
479 {
480  vlib_main_t *vm = (vlib_main_t *) arg;
481  unformat_input_t input;
482  int i;
483 
484  unformat_init_command_line (&input, (char **) vm->argv);
485  i = vlib_main (vm, &input);
486  unformat_free (&input);
487 
488  return i;
489 }
490 
491 int
492 vlib_unix_main (int argc, char *argv[])
493 {
494  vlib_main_t *vm = &vlib_global_main; /* one and only time for this! */
496  unformat_input_t input;
497  u8 *thread_stacks;
498  clib_error_t *e;
499  int i;
500 
501  vm->argv = (u8 **) argv;
502  vm->name = argv[0];
503  vm->heap_base = clib_mem_get_heap ();
504  ASSERT (vm->heap_base);
505 
506  i = vlib_plugin_early_init (vm);
507  if (i)
508  return i;
509 
510  unformat_init_command_line (&input, (char **) vm->argv);
511  if (vm->init_functions_called == 0)
512  vm->init_functions_called = hash_create (0, /* value bytes */ 0);
513  e = vlib_call_all_config_functions (vm, &input, 1 /* early */ );
514  if (e != 0)
515  {
516  clib_error_report (e);
517  return 1;
518  }
519  unformat_free (&input);
520 
521  /*
522  * allocate n x VLIB_THREAD_STACK_SIZE stacks, aligned to a
523  * VLIB_THREAD_STACK_SIZE boundary
524  * See also: os_get_cpu_number() in vlib/vlib/threads.c
525  */
526  thread_stacks = clib_mem_alloc_aligned
528  VLIB_THREAD_STACK_SIZE);
529 
531  for (i = 0; i < vec_len (vlib_thread_stacks); i++)
532  {
533  vlib_thread_stacks[i] = thread_stacks;
534 
535  /*
536  * Disallow writes to the bottom page of the stack, to
537  * catch stack overflows.
538  */
539  if (mprotect (thread_stacks, clib_mem_get_page_size (), PROT_READ) < 0)
540  clib_unix_warning ("thread stack");
541 
542  thread_stacks += VLIB_THREAD_STACK_SIZE;
543  }
544 
545  i = clib_calljmp (thread0, (uword) vm,
546  (void *) (vlib_thread_stacks[0] +
547  VLIB_THREAD_STACK_SIZE));
548  return i;
549 }
550 
551 /*
552  * fd.io coding-style-patch-verification: ON
553  *
554  * Local Variables:
555  * eval: (c-set-style "gnu")
556  * End:
557  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1025
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
u32 flags
Definition: unix.h:83
volatile int unix_config_complete
Definition: unix.h:106
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u32 cli_pager_buffer_limit
Definition: unix.h:122
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:482
#define VLIB_MAIN_LOOP_EXIT_CLI
Definition: main.h:92
static vlib_node_registration_t startup_config_node
(constructor) VLIB_REGISTER_NODE (startup_config_node)
Definition: main.c:302
void clib_longjmp(clib_longjmp_t *save, uword return_value)
u8 ** vlib_thread_stacks
Definition: main.c:475
#define clib_error_report(e)
Definition: error.h:125
clib_socket_t cli_listen_socket
Definition: unix.h:92
int log_fd
Definition: unix.h:110
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u8 * what
Definition: error.h:78
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:432
u8 * format_timeval(u8 *s, va_list *args)
Definition: unix-formats.c:748
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_warning(format, args...)
Definition: error.h:59
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:201
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
Definition: main.c:1599
vlib_main_t * vlib_main
Definition: unix.h:81
#define vlib_call_init_function(vm, x)
Definition: init.h:161
#define UNIX_FLAG_NODAEMON
Definition: unix.h:86
#define UNIX_CLI_DEFAULT_PAGER_LIMIT
Default CLI pager limit is not configured in startup.conf.
Definition: main.c:51
static clib_error_t * unix_config(vlib_main_t *vm, unformat_input_t *input)
Definition: main.c:310
char * name
Definition: main.h:98
int cli_line_mode
Definition: unix.h:113
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1001
void vlib_unix_cli_set_prompt(char *prompt)
Set the CLI prompt.
Definition: cli.c:2536
static void unix_signal_handler(int signum, siginfo_t *si, ucontext_t *uc)
Definition: main.c:70
#define clib_error_return_unix(e, args...)
Definition: error.h:114
int cli_no_banner
Definition: unix.h:119
u8 * startup_config_filename
Definition: unix.h:103
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:118
static uword thread0(uword arg)
Definition: main.c:478
uword * init_functions_called
Definition: main.h:156
vlib_thread_main_t vlib_thread_main
Definition: threads.c:55
u32 cli_history_limit
Definition: unix.h:116
u8 ** argv
Definition: main.h:175
int vlib_plugin_early_init(vlib_main_t *vm)
Definition: plugin.c:207
static clib_error_t * unix_input_init(vlib_main_t *vm)
Definition: input.c:252
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
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:115
static clib_error_t * unix_main_init(vlib_main_t *vm)
Definition: main.c:60
#define clib_unix_warning(format, args...)
Definition: error.h:68
vlib_main_t vlib_global_main
Definition: main.c:1562
static void * clib_mem_get_heap(void)
Definition: mem.h:217
#define hash_create(elts, value_bytes)
Definition: hash.h:658
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void os_exit(int code)
Definition: main.c:340
void clib_error_register_handler(clib_error_handler_func_t func, void *arg)
Definition: error.c:75
unix_main_t unix_main
Definition: main.c:57
u64 uword
Definition: types.h:112
#define UNIX_FLAG_INTERACTIVE
Definition: unix.h:85
static clib_error_t * setup_signal_handlers(unix_main_t *um)
Definition: main.c:124
static void unix_error_handler(void *arg, u8 *msg, int msg_len)
Definition: main.c:164
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u8 * format_signal(u8 *s, va_list *args)
Definition: unix-formats.c:834
int vlib_unix_main(int argc, char *argv[])
Definition: main.c:492
#define VLIB_THREAD_STACK_SIZE
Definition: threads.h:66
void vlib_unix_error_report(vlib_main_t *vm, clib_error_t *error)
Definition: main.c:187
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)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
static uword startup_config_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: main.c:213
static clib_error_t * unix_exit(vlib_main_t *vm)
Definition: main.c:466
#define clib_error_return(e, args...)
Definition: error.h:111
clib_longjmp_t main_loop_exit
Definition: main.h:88
struct _unformat_input_t unformat_input_t
#define UNIX_CLI_DEFAULT_HISTORY
Default CLI history depth if not configured in startup.conf.
Definition: main.c:54
uword clib_mem_get_page_size(void)
Definition: mem_mheap.c:110
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_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:539
u8 * log_filename
Definition: unix.h:109
u8 * format_ucontext_pc(u8 *s, va_list *args)
Definition: unix-formats.c:885