71434a9c065f5dae4e27ba34d940167f818a4e5c
[vpp.git] / src / vpp / vnet / main.c
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 #define _GNU_SOURCE
17 #include <pthread.h>
18 #ifdef __FreeBSD__
19 #include <pthread_np.h>
20 #endif /* __FreeBSD__ */
21 #include <sched.h>
22
23 #include <vppinfra/clib.h>
24 #include <vppinfra/cpu.h>
25 #include <vlib/vlib.h>
26 #include <vlib/unix/unix.h>
27 #include <vlib/threads.h>
28 #include <vnet/plugin/plugin.h>
29 #include <vnet/ethernet/ethernet.h>
30 #include <vpp/app/version.h>
31 #include <vpp/vnet/config.h>
32 #include <vlibmemory/memclnt.api_enum.h> /* To get the last static message id */
33 #include <limits.h>
34
35 /*
36  * Load plugins from /usr/lib/vpp_plugins by default
37  */
38 char *vlib_plugin_path = NULL;
39 char *vlib_plugin_app_version = VPP_BUILD_VER;
40 char *vat_plugin_path = NULL;
41
42 static void
43 vpp_find_plugin_path ()
44 {
45   extern char *vat_plugin_path;
46   char *p, path[PATH_MAX];
47   int rv;
48   u8 *s;
49
50   /* find executable path */
51   if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
52     return;
53
54   /* readlink doesn't provide null termination */
55   path[rv] = 0;
56
57   /* strip filename */
58   if ((p = strrchr (path, '/')) == 0)
59     return;
60   *p = 0;
61
62   /* strip bin/ */
63   if ((p = strrchr (path, '/')) == 0)
64     return;
65   *p = 0;
66
67   s = format (0, "%s/" CLIB_LIB_DIR "/vpp_plugins", path, path);
68   vec_add1 (s, 0);
69   vlib_plugin_path = (char *) s;
70
71   s = format (0, "%s/" CLIB_LIB_DIR "/vpp_api_test_plugins", path, path);
72   vec_add1 (s, 0);
73   vat_plugin_path = (char *) s;
74 }
75
76 static void
77 vpe_main_init (vlib_main_t * vm)
78 {
79 #if VPP_API_TEST_BUILTIN > 0
80   void vat_plugin_hash_create (void);
81 #endif
82
83   if (CLIB_DEBUG > 0)
84     vlib_unix_cli_set_prompt ("DBGvpp# ");
85   else
86     vlib_unix_cli_set_prompt ("vpp# ");
87
88   /* Turn off network stack components which we don't want */
89   vlib_mark_init_function_complete (vm, srp_init);
90
91   /*
92    * Create the binary api plugin hashes before loading plugins
93    */
94 #if VPP_API_TEST_BUILTIN > 0
95   vat_plugin_hash_create ();
96 #endif
97
98   if (!vlib_plugin_path)
99     vpp_find_plugin_path ();
100 }
101
102 /*
103  * Default path for runtime data
104  */
105 char *vlib_default_runtime_dir = "vpp";
106
107 int
108 main (int argc, char *argv[])
109 {
110   int i;
111   void vl_msg_api_set_first_available_msg_id (u16);
112   uword main_heap_size = (1ULL << 30);
113   u8 *sizep;
114   u32 size;
115   clib_mem_page_sz_t main_heap_log2_page_sz = CLIB_MEM_PAGE_SZ_DEFAULT;
116   clib_mem_page_sz_t default_log2_hugepage_sz = CLIB_MEM_PAGE_SZ_UNKNOWN;
117   unformat_input_t input, sub_input;
118   u8 *s = 0, *v = 0;
119   int main_core = ~0;
120   cpu_set_t cpuset;
121   void *main_heap;
122
123 #if __x86_64__
124   CLIB_UNUSED (const char *msg)
125     = "ERROR: This binary requires CPU with %s extensions.\n";
126 #define _(a,b)                                  \
127     if (!clib_cpu_supports_ ## a ())            \
128       {                                         \
129         fprintf(stderr, msg, b);                \
130         exit(1);                                \
131       }
132
133 #if __AVX2__
134   _(avx2, "AVX2")
135 #endif
136 #if __AVX__
137     _(avx, "AVX")
138 #endif
139 #if __SSE4_2__
140     _(sse42, "SSE4.2")
141 #endif
142 #if __SSE4_1__
143     _(sse41, "SSE4.1")
144 #endif
145 #if __SSSE3__
146     _(ssse3, "SSSE3")
147 #endif
148 #if __SSE3__
149     _(sse3, "SSE3")
150 #endif
151 #undef _
152 #endif
153     /*
154      * Load startup config from file.
155      * usage: vpp -c /etc/vpp/startup.conf
156      */
157     if ((argc == 3) && !strncmp (argv[1], "-c", 2))
158     {
159       FILE *fp;
160       char inbuf[4096];
161       int argc_ = 1;
162       char **argv_ = NULL;
163       char *arg = NULL;
164       char *p;
165
166       fp = fopen (argv[2], "r");
167       if (fp == NULL)
168         {
169           fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
170           return 1;
171         }
172       argv_ = calloc (1, sizeof (char *));
173       if (argv_ == NULL)
174         {
175           fclose (fp);
176           return 1;
177         }
178       arg = strndup (argv[0], 1024);
179       if (arg == NULL)
180         {
181           fclose (fp);
182           free (argv_);
183           return 1;
184         }
185       argv_[0] = arg;
186
187       while (1)
188         {
189           if (fgets (inbuf, 4096, fp) == 0)
190             break;
191           p = strtok (inbuf, " \t\n");
192           while (p != NULL)
193             {
194               if (*p == '#')
195                 break;
196               argc_++;
197               char **tmp = realloc (argv_, argc_ * sizeof (char *));
198               if (tmp == NULL)
199                 return 1;
200               argv_ = tmp;
201               arg = strndup (p, 1024);
202               if (arg == NULL)
203                 return 1;
204               argv_[argc_ - 1] = arg;
205               p = strtok (NULL, " \t\n");
206             }
207         }
208
209       fclose (fp);
210
211       char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
212       if (tmp == NULL)
213         return 1;
214       argv_ = tmp;
215       argv_[argc_] = NULL;
216
217       argc = argc_;
218       argv = argv_;
219     }
220
221   /*
222    * Look for and parse the "heapsize" config parameter.
223    * Manual since none of the clib infra has been bootstrapped yet.
224    *
225    * Format: heapsize <nn>[mM][gG]
226    */
227
228   for (i = 1; i < (argc - 1); i++)
229     {
230       if (!strncmp (argv[i], "plugin_path", 11))
231         {
232           if (i < (argc - 1))
233             vlib_plugin_path = argv[++i];
234         }
235       if (!strncmp (argv[i], "test_plugin_path", 16))
236         {
237           if (i < (argc - 1))
238             vat_plugin_path = argv[++i];
239         }
240       else if (!strncmp (argv[i], "heapsize", 8))
241         {
242           sizep = (u8 *) argv[i + 1];
243           size = 0;
244           while (*sizep >= '0' && *sizep <= '9')
245             {
246               size *= 10;
247               size += *sizep++ - '0';
248             }
249           if (size == 0)
250             {
251               fprintf
252                 (stderr,
253                  "warning: heapsize parse error '%s', use default %lld\n",
254                  argv[i], (long long int) main_heap_size);
255               goto defaulted;
256             }
257
258           main_heap_size = size;
259
260           if (*sizep == 'g' || *sizep == 'G')
261             main_heap_size <<= 30;
262           else if (*sizep == 'm' || *sizep == 'M')
263             main_heap_size <<= 20;
264         }
265       else if (!strncmp (argv[i], "main-core", 9))
266         {
267           if (i < (argc - 1))
268             {
269               errno = 0;
270               unsigned long x = strtol (argv[++i], 0, 0);
271               if (errno == 0)
272                 main_core = x;
273             }
274         }
275       else if (!strncmp (argv[i], "interactive", 11))
276         unix_main.flags |= UNIX_FLAG_INTERACTIVE;
277       else if (!strncmp (argv[i], "nosyslog", 8))
278         unix_main.flags |= UNIX_FLAG_NOSYSLOG;
279     }
280 defaulted:
281
282   /* temporary heap */
283   clib_mem_init (0, 1 << 20);
284   unformat_init_command_line (&input, (char **) argv);
285
286   while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
287     {
288       if (unformat (&input, "memory %v", &v))
289         {
290           unformat_init_vector (&sub_input, v);
291           v = 0;
292           while (unformat_check_input (&sub_input) != UNFORMAT_END_OF_INPUT)
293             {
294               if (unformat (&sub_input, "main-heap-size %U",
295                             unformat_memory_size, &main_heap_size))
296                 ;
297               else if (unformat (&sub_input, "main-heap-page-size %U",
298                                  unformat_log2_page_size,
299                                  &main_heap_log2_page_sz))
300                 ;
301               else if (unformat (&sub_input, "default-hugepage-size %U",
302                                  unformat_log2_page_size,
303                                  &default_log2_hugepage_sz))
304                 ;
305               else
306                 {
307                   fformat (stderr, "unknown 'memory' config input '%U'\n",
308                            format_unformat_error, &sub_input);
309                   exit (1);
310                 }
311
312             }
313           unformat_free (&sub_input);
314         }
315       else if (!unformat (&input, "%s %v", &s, &v))
316         break;
317
318       vec_reset_length (s);
319       vec_reset_length (v);
320     }
321   vec_free (s);
322   vec_free (v);
323
324   unformat_free (&input);
325
326   /* set process affinity for main thread */
327   if (main_core != ~0)
328     {
329       CPU_ZERO (&cpuset);
330       CPU_SET (main_core, &cpuset);
331       if (pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t),
332                                   &cpuset))
333         {
334           clib_unix_error (
335             "pthread_setaffinity_np() on cpu %d failed for main thread",
336             main_core);
337         }
338     }
339
340   /* Set up the plugin message ID allocator right now... */
341   vl_msg_api_set_first_available_msg_id (VL_MSG_MEMCLNT_LAST + 1);
342
343   /* destroy temporary heap and create main one */
344   clib_mem_destroy ();
345
346   if ((main_heap = clib_mem_init_with_page_size (main_heap_size,
347                                                  main_heap_log2_page_sz)))
348     {
349       /* Figure out which numa runs the main thread */
350       __os_numa_index = clib_get_current_numa_node ();
351
352       if (default_log2_hugepage_sz != CLIB_MEM_PAGE_SZ_UNKNOWN)
353         clib_mem_set_log2_default_hugepage_size (default_log2_hugepage_sz);
354
355       /* and use the main heap as that numa's numa heap */
356       clib_mem_set_per_numa_heap (main_heap);
357       vlib_main_init ();
358       vpe_main_init (vlib_get_first_main ());
359       return vlib_unix_main (argc, argv);
360     }
361   else
362     {
363       {
364         int rv __attribute__ ((unused)) =
365           write (2, "Main heap allocation failure!\r\n", 31);
366       }
367       return 1;
368     }
369 }
370
371 static clib_error_t *
372 memory_config (vlib_main_t * vm, unformat_input_t * input)
373 {
374   return 0;
375 }
376
377 VLIB_CONFIG_FUNCTION (memory_config, "memory");
378
379 static clib_error_t *
380 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
381 {
382   return 0;
383 }
384
385 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
386
387 static clib_error_t *
388 placeholder_path_config (vlib_main_t * vm, unformat_input_t * input)
389 {
390   u8 *junk;
391
392   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
393     {
394       if (unformat (input, "%s", &junk))
395         {
396           vec_free (junk);
397           return 0;
398         }
399       else
400         return clib_error_return (0, "unknown input '%U'",
401                                   format_unformat_error, input);
402     }
403   return 0;
404 }
405
406 static clib_error_t *
407 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
408 {
409   return placeholder_path_config (vm, input);
410 }
411
412 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
413
414 static clib_error_t *
415 test_plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
416 {
417   return placeholder_path_config (vm, input);
418 }
419
420 VLIB_CONFIG_FUNCTION (test_plugin_path_config, "test_plugin_path");
421
422 void vl_msg_api_post_mortem_dump (void);
423 void vlib_post_mortem_dump (void);
424
425 void
426 os_panic (void)
427 {
428   vl_msg_api_post_mortem_dump ();
429   vlib_post_mortem_dump ();
430   abort ();
431 }
432
433 void vhost_user_unmap_all (void) __attribute__ ((weak));
434 void
435 vhost_user_unmap_all (void)
436 {
437 }
438
439 void
440 os_exit (int code)
441 {
442   static int recursion_block;
443
444   if (code)
445     {
446       if (recursion_block)
447         abort ();
448
449       recursion_block = 1;
450
451       vl_msg_api_post_mortem_dump ();
452       vlib_post_mortem_dump ();
453       vhost_user_unmap_all ();
454       abort ();
455     }
456   exit (code);
457 }
458
459 #ifdef BARRIER_TRACING
460 void
461 vl_msg_api_barrier_trace_context (const char *context)
462 {
463   vlib_worker_threads[0].barrier_context = context;
464 }
465 #endif
466
467 void
468 vl_msg_api_barrier_sync (void)
469 {
470   vlib_worker_thread_barrier_sync (vlib_get_main ());
471 }
472
473 void
474 vl_msg_api_barrier_release (void)
475 {
476   vlib_worker_thread_barrier_release (vlib_get_main ());
477 }
478
479 /* This application needs 1 thread stack for the stats pthread */
480 u32
481 vlib_app_num_thread_stacks_needed (void)
482 {
483   return 1;
484 }
485
486 /*
487  * Depending on the configuration selected above,
488  * it may be necessary to generate stub graph nodes.
489  * It is never OK to ignore "node 'x' refers to unknown node 'y'
490  * messages!
491  */
492
493 #include <vppinfra/bihash_8_8.h>
494
495 static clib_error_t *
496 show_bihash_command_fn (vlib_main_t * vm,
497                         unformat_input_t * input, vlib_cli_command_t * cmd)
498 {
499   int i;
500   clib_bihash_8_8_t *h;
501   int verbose = 0;
502
503   if (unformat (input, "verbose"))
504     verbose = 1;
505
506   for (i = 0; i < vec_len (clib_all_bihashes); i++)
507     {
508       h = (clib_bihash_8_8_t *) clib_all_bihashes[i];
509       vlib_cli_output (vm, "\n%U", h->fmt_fn, h, verbose);
510     }
511
512   return 0;
513 }
514
515 VLIB_CLI_COMMAND (show_bihash_command, static) =
516 {
517   .path = "show bihash",
518   .short_help = "show bihash",
519   .function = show_bihash_command_fn,
520 };
521
522 #ifdef CLIB_SANITIZE_ADDR
523 /* default options for Address Sanitizer */
524 const char *
525 __asan_default_options (void)
526 {
527   return VPP_SANITIZE_ADDR_OPTIONS;
528 }
529 #endif /* CLIB_SANITIZE_ADDR */
530
531 /*
532  * fd.io coding-style-patch-verification: ON
533  *
534  * Local Variables:
535  * eval: (c-set-style "gnu")
536  * End:
537  */