FD.io VPP  v16.06
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 unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
70 {
71  uword fatal;
72  u8 * msg = 0;
73 
74  msg = format (msg, "received signal %U, PC %U",
75  format_signal, signum,
76  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  case SIGQUIT:
93  case SIGINT:
94  case SIGILL:
95  case SIGBUS:
96  case SIGSEGV:
97  case SIGHUP:
98  case SIGFPE:
99  fatal = 1;
100  break;
101 
102  /* by default, print a message and continue */
103  default:
104  fatal = 0;
105  break;
106  }
107 
108  /* Null terminate. */
109  vec_add1 (msg, 0);
110 
111  if (fatal)
112  {
113  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
114  os_exit (1);
115  }
116  else
117  clib_warning ("%s", msg);
118 
119  vec_free (msg);
120 }
121 
122 static clib_error_t *
124 {
125  uword i;
126  struct sigaction sa;
127 
128  for (i = 1; i < 32; i++)
129  {
130  memset (&sa, 0, sizeof (sa));
131  sa.sa_sigaction = (void *) unix_signal_handler;
132  sa.sa_flags = SA_SIGINFO;
133 
134  switch (i)
135  {
136  /* these signals take the default action */
137  case SIGABRT:
138  case SIGKILL:
139  case SIGSTOP:
140  case SIGUSR1:
141  case SIGUSR2:
142  continue;
143 
144  /* ignore SIGPIPE, SIGCHLD */
145  case SIGPIPE:
146  case SIGCHLD:
147  sa.sa_sigaction = (void *) SIG_IGN;
148  break;
149 
150  /* catch and handle all other signals */
151  default:
152  break;
153  }
154 
155  if (sigaction (i, &sa, 0) < 0)
156  return clib_error_return_unix (0, "sigaction %U", format_signal, i);
157  }
158 
159  return 0;
160 }
161 
162 static void unix_error_handler (void * arg, u8 * msg, int msg_len)
163 {
164  unix_main_t * um = arg;
165 
166  /* Echo to stderr when interactive. */
167  if (um->flags & UNIX_FLAG_INTERACTIVE)
168  {
169  CLIB_UNUSED (int r) = write (2, msg, msg_len);
170  }
171  else
172  {
173  char save = msg[msg_len - 1];
174 
175  /* Null Terminate. */
176  msg[msg_len-1] = 0;
177 
178  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
179 
180  msg[msg_len-1] = save;
181  }
182 }
183 
185 {
186  unix_main_t * um = &unix_main;
187 
188  if (um->flags & UNIX_FLAG_INTERACTIVE || error == 0)
189  return;
190 
191  {
192  char save;
193  u8 * msg;
194  u32 msg_len;
195 
196  msg = error->what;
197  msg_len = vec_len(msg);
198 
199  /* Null Terminate. */
200  save = msg[msg_len-1];
201  msg[msg_len-1] = 0;
202 
203  syslog (LOG_ERR | LOG_DAEMON, "%s", msg);
204 
205  msg[msg_len-1] = save;
206  }
207 }
208 
209 static uword
211  vlib_node_runtime_t * rt,
212  vlib_frame_t * f)
213 {
214  unix_main_t * um = &unix_main;
215  u8 * buf = 0;
216  uword l, n = 1;
217 
218  vlib_process_suspend (vm, 2.0);
219 
220  while (um->unix_config_complete == 0)
221  vlib_process_suspend (vm, 0.1);
222 
223  if (um->startup_config_filename) {
224  unformat_input_t sub_input;
225  int fd;
226  struct stat s;
227  char *fn = (char *)um->startup_config_filename;
228 
229  fd = open (fn, O_RDONLY);
230  if (fd < 0) {
231  clib_warning ("failed to open `%s'", fn);
232  return 0;
233  }
234 
235  if (fstat (fd, &s) < 0) {
236  clib_warning ("failed to stat `%s'", fn);
237  bail:
238  close(fd);
239  return 0;
240  }
241 
242  if (! (S_ISREG (s.st_mode) || S_ISLNK (s.st_mode))) {
243  clib_warning ("not a regular file: `%s'", fn);
244  goto bail;
245  }
246 
247  while (n > 0)
248  {
249  l = vec_len (buf);
250  vec_resize (buf, 4096);
251  n = read (fd, buf + l, 4096);
252  if (n > 0)
253  {
254  _vec_len (buf) = l + n;
255  if (n < 4096)
256  break;
257  }
258  else
259  break;
260  }
261  if (um->log_fd && vec_len (buf))
262  {
263  u8 * lv = 0;
264  lv = format (lv, "%U: ***** Startup Config *****\n%v",
266  0 /* current bat-time */,
267  0 /* current bat-format */,
268  buf);
269  {
270  int rv __attribute__((unused)) =
271  write (um->log_fd, lv, vec_len(lv));
272  }
273  vec_reset_length (lv);
274  lv = format (lv, "%U: ***** End Startup Config *****\n",
276  0 /* current bat-time */,
277  0 /* current bat-format */);
278  {
279  int rv __attribute__((unused)) =
280  write (um->log_fd, lv, vec_len(lv));
281  }
282  vec_free (lv);
283  }
284 
285  if (vec_len(buf))
286  {
287  unformat_init_vector (&sub_input, buf);
288  vlib_cli_input (vm, &sub_input, 0, 0);
289  /* frees buf for us */
290  unformat_free (&sub_input);
291  }
292  close(fd);
293  }
294  return 0;
295 }
296 
298  .function = startup_config_process,
299  .type = VLIB_NODE_TYPE_PROCESS,
300  .name = "startup-config-process",
301 };
302 
303 static clib_error_t *
305 {
306  unix_main_t * um = &unix_main;
307  clib_error_t * error = 0;
308 
309  /* Defaults */
312 
314  {
315  char * cli_prompt;
316  if (unformat (input, "interactive"))
318  else if (unformat (input, "nodaemon"))
319  um->flags |= UNIX_FLAG_NODAEMON;
320  else if (unformat (input, "cli-prompt %s", &cli_prompt))
321  vlib_unix_cli_set_prompt (cli_prompt);
322  else if (unformat (input, "cli-listen %s", &um->cli_listen_socket.config))
323  ;
324  else if (unformat (input, "cli-line-mode"))
325  um->cli_line_mode = 1;
326  else if (unformat (input, "cli-no-banner"))
327  um->cli_no_banner = 1;
328  else if (unformat (input, "cli-no-pager"))
329  um->cli_no_pager = 1;
330  else if (unformat (input, "cli-pager-buffer-limit %d",
332  ;
333  else if (unformat (input, "cli-history-limit %d", &um->cli_history_limit))
334  ;
335  else if (unformat (input, "full-coredump"))
336  {
337  int fd;
338 
339  fd = open ("/proc/self/coredump_filter", O_WRONLY);
340  if (fd > 0)
341  {
342  if (write (fd, "0x6f\n", 5) != 5)
343  clib_unix_warning ("coredump filter write failed!");
344  close(fd);
345  }
346  else
347  clib_unix_warning ("couldn't open /proc/self/coredump_filter");
348  }
349  else if (unformat (input, "startup-config %s",
351  ;
352  else if (unformat (input, "exec %s",
354  ;
355  else if (unformat (input, "log %s", &um->log_filename))
356  {
357  um->log_fd = open ((char *) um->log_filename,
358  O_CREAT | O_WRONLY | O_APPEND, 0644);
359  if (um->log_fd < 0)
360  {
361  clib_warning ("couldn't open log '%s'\n", um->log_filename);
362  um->log_fd = 0;
363  }
364  else
365  {
366  u8 * lv = 0;
367  lv = format (0, "%U: ***** Start: PID %d *****\n",
369  0 /* current bat-time */,
370  0 /* current bat-format */,
371  getpid());
372  {
373  int rv __attribute__((unused)) =
374  write (um->log_fd, lv, vec_len(lv));
375  }
376  vec_free (lv);
377  }
378  }
379  else
380  return clib_error_return (0, "unknown input `%U'",
381  format_unformat_error, input);
382  }
383 
384  if (! (um->flags & UNIX_FLAG_INTERACTIVE))
385  {
386  error = setup_signal_handlers (um);
387  if (error)
388  return error;
389 
390  openlog (vm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
392 
393  if (! (um->flags & UNIX_FLAG_NODAEMON)
394  && daemon (/* chdir to / */ 0,
395  /* stdin/stdout/stderr -> /dev/null */ 0) < 0)
396  clib_error_return (0, "daemon () fails");
397  }
398  um->unix_config_complete = 1;
399 
400  return 0;
401 }
402 
403 /* unix { ... } configuration. */
405 
406 static clib_error_t *
408 {
409  /* Close syslog connection. */
410  closelog ();
411  return 0;
412 }
413 
415 
417 
418 static uword thread0 (uword arg)
419 {
420  vlib_main_t * vm = (vlib_main_t *)arg;
421  unformat_input_t input;
422  int i;
423 
424  unformat_init_command_line (&input, (char **)vm->argv);
425  i = vlib_main (vm, &input);
426  unformat_free (&input);
427 
428  return i;
429  }
430 
431 int vlib_unix_main (int argc, char * argv[])
432 {
433  vlib_main_t * vm = &vlib_global_main; /* one and only time for this! */
434 
437  unformat_input_t input;
438  u8 * thread_stacks;
439  clib_error_t * e;
440  int i;
441 
442  vm->argv = (u8 **)argv;
443  vm->name = argv[0];
444  vm->heap_base = clib_mem_get_heap ();
445  ASSERT(vm->heap_base);
446 
447  i = vlib_plugin_early_init (vm);
448  if (i)
449  return i;
450 
451  unformat_init_command_line (&input, (char **)vm->argv);
452  if (vm->init_functions_called == 0)
453  vm->init_functions_called = hash_create (0, /* value bytes */ 0);
454  e = vlib_call_all_config_functions (vm, &input, 1 /* early */);
455  if (e != 0)
456  {
458  return 1;
459  }
460  unformat_free (&input);
461 
462  /* allocate N x 1mb stacks, aligned e.g. to a 16mb boundary */
463  thread_stacks = clib_mem_alloc_aligned
466 
467  sm->vm_base = thread_stacks;
469 
471  for (i = 0; i < vec_len (vlib_thread_stacks); i++)
472  {
473  vlib_thread_stacks[i] = thread_stacks;
474 
475  /*
476  * Disallow writes to the bottom page of the stack, to
477  * catch stack overflows.
478  */
479  if (mprotect (thread_stacks, clib_mem_get_page_size(), PROT_READ) < 0)
480  clib_unix_warning ("thread stack");
481 
482  thread_stacks += VLIB_THREAD_STACK_SIZE;
483  }
484 
485  i = clib_calljmp (thread0, (uword) vm,
487  return i;
488 }
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
#define VLIB_THREAD_STACK_SIZE
Definition: threads.h:65
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1000
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
u32 flags
Definition: unix.h:79
volatile int unix_config_complete
Definition: unix.h:101
#define VLIB_LOG2_THREAD_STACK_SIZE
Definition: threads.h:64
always_inline void unformat_free(unformat_input_t *i)
Definition: format.h:160
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
u32 cli_pager_buffer_limit
Definition: unix.h:117
u32 main_loop_exit_set
Definition: main.h:86
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define VLIB_MAIN_LOOP_EXIT_CLI
Definition: main.h:91
vlib_node_registration_t startup_config_node
(constructor) VLIB_REGISTER_NODE (startup_config_node)
Definition: main.c:297
void clib_longjmp(clib_longjmp_t *save, uword return_value)
u8 ** vlib_thread_stacks
Definition: main.c:416
#define clib_error_report(e)
Definition: error.h:126
always_inline uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Definition: node_funcs.h:326
clib_socket_t cli_listen_socket
Definition: unix.h:88
int log_fd
Definition: unix.h:105
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u8 * what
Definition: error.h:77
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
u8 * format_timeval(u8 *s, va_list *args)
Definition: unix-formats.c:748
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
#define clib_warning(format, args...)
Definition: error.h:59
int vlib_main(vlib_main_t *vm, unformat_input_t *input)
Definition: main.c:1538
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:199
vlib_main_t * vlib_main
Definition: unix.h:77
#define vlib_call_init_function(vm, x)
Definition: init.h:159
#define UNIX_FLAG_NODAEMON
Definition: unix.h:82
#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:304
always_inline void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:113
clib_smp_main_t clib_smp_main
Definition: mem_mheap.c:46
char * name
Definition: main.h:97
int cli_line_mode
Definition: unix.h:108
void * vm_base
Definition: smp.h:67
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:975
void vlib_unix_cli_set_prompt(char *prompt)
Set the CLI prompt.
Definition: cli.c:2189
static void unix_signal_handler(int signum, siginfo_t *si, ucontext_t *uc)
Definition: main.c:69
#define clib_error_return_unix(e, args...)
Definition: error.h:115
int cli_no_banner
Definition: unix.h:114
u8 * startup_config_filename
Definition: unix.h:98
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:116
static uword thread0(uword arg)
Definition: main.c:418
uword * init_functions_called
Definition: main.h:156
always_inline void * clib_mem_get_heap(void)
Definition: mem.h:187
u32 cli_history_limit
Definition: unix.h:111
u8 ** argv
Definition: main.h:175
int vlib_plugin_early_init(vlib_main_t *vm)
Definition: plugin.c:195
static clib_error_t * unix_input_init(vlib_main_t *vm)
Definition: input.c:245
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
void * heap_base
Definition: main.h:100
int cli_no_pager
Definition: unix.h:120
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
Definition: init.h:113
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
#define VLIB_MAX_CPUS
Definition: threads.h:54
vlib_main_t vlib_global_main
Definition: main.c:1505
#define hash_create(elts, value_bytes)
Definition: hash.h:615
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
void os_exit(int code)
Definition: main.c:264
void clib_error_register_handler(clib_error_handler_func_t func, void *arg)
Definition: error.c:73
unix_main_t unix_main
Definition: main.c:57
u8 log2_n_per_cpu_vm_bytes
Definition: smp.h:60
u64 uword
Definition: types.h:112
#define UNIX_FLAG_INTERACTIVE
Definition: unix.h:81
static clib_error_t * setup_signal_handlers(unix_main_t *um)
Definition: main.c:123
static void unix_error_handler(void *arg, u8 *msg, int msg_len)
Definition: main.c:162
#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:431
vlib_thread_main_t vlib_thread_main
Definition: threads.c:59
void vlib_unix_error_report(vlib_main_t *vm, clib_error_t *error)
Definition: main.c:184
uword clib_calljmp(uword(*func)(uword func_arg), uword func_arg, void *stack)
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
static uword startup_config_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: main.c:210
static clib_error_t * unix_exit(vlib_main_t *vm)
Definition: main.c:407
#define clib_error_return(e, args...)
Definition: error.h:112
clib_longjmp_t main_loop_exit
Definition: main.h:87
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:111
clib_error_t * vlib_call_all_config_functions(vlib_main_t *vm, unformat_input_t *input, int is_early)
Definition: init.c:90
void vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:504
u8 * log_filename
Definition: unix.h:104
u8 * format_ucontext_pc(u8 *s, va_list *args)
Definition: unix-formats.c:885