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