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