9d77a44c2ced642650590afabe6e579e05310678
[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 = "/usr/lib/vpp_plugins";
33 char *vlib_plugin_app_version = VPP_BUILD_VER;
34
35 static void
36 vpp_find_plugin_path ()
37 {
38   extern char *vat_plugin_path;
39   char *p, path[PATH_MAX];
40   int rv;
41   u8 *s;
42
43   /* find executable path */
44   if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1)
45     return;
46
47   /* readlink doesn't provide null termination */
48   path[rv] = 0;
49
50   /* strip filename */
51   if ((p = strrchr (path, '/')) == 0)
52     return;
53   *p = 0;
54
55   /* strip bin/ */
56   if ((p = strrchr (path, '/')) == 0)
57     return;
58   *p = 0;
59
60   s = format (0, "%s/lib/vpp_plugins", path);
61 #if uword_bits == 64
62   s = format (s, ":%s/lib64/vpp_plugins", path);
63 #endif
64   vec_add1 (s, 0);
65   vlib_plugin_path = (char *) s;
66
67   s = format (0, "%s/lib/vpp_api_test_plugins", path);
68 #if uword_bits == 64
69   s = format (s, ":%s/lib64/vpp_api_test_plugins", path);
70 #endif
71   vec_add1 (s, 0);
72   vat_plugin_path = (char *) s;
73 }
74
75 static void
76 vpe_main_init (vlib_main_t * vm)
77 {
78   void vat_plugin_hash_create (void);
79
80   if (CLIB_DEBUG > 0)
81     vlib_unix_cli_set_prompt ("DBGvpp# ");
82   else
83     vlib_unix_cli_set_prompt ("vpp# ");
84
85   /* Turn off network stack components which we don't want */
86   vlib_mark_init_function_complete (vm, srp_init);
87
88   /*
89    * Create the binary api plugin hashes before loading plugins
90    */
91   vat_plugin_hash_create ();
92
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
113 #if __x86_64__
114   CLIB_UNUSED (const char *msg)
115     = "ERROR: This binary requires CPU with %s extensions.\n";
116 #define _(a,b)                                  \
117     if (!clib_cpu_supports_ ## a ())            \
118       {                                         \
119         fprintf(stderr, msg, b);                \
120         exit(1);                                \
121       }
122
123 #if __AVX2__
124   _(avx2, "AVX2")
125 #endif
126 #if __AVX__
127     _(avx, "AVX")
128 #endif
129 #if __SSE4_2__
130     _(sse42, "SSE4.2")
131 #endif
132 #if __SSE4_1__
133     _(sse41, "SSE4.1")
134 #endif
135 #if __SSSE3__
136     _(ssse3, "SSSE3")
137 #endif
138 #if __SSE3__
139     _(sse3, "SSE3")
140 #endif
141 #undef _
142 #endif
143     /*
144      * Load startup config from file.
145      * usage: vpp -c /etc/vpp/startup.conf
146      */
147     if ((argc == 3) && !strncmp (argv[1], "-c", 2))
148     {
149       FILE *fp;
150       char inbuf[4096];
151       int argc_ = 1;
152       char **argv_ = NULL;
153       char *arg = NULL;
154       char *p;
155
156       fp = fopen (argv[2], "r");
157       if (fp == NULL)
158         {
159           fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
160           return 1;
161         }
162       argv_ = calloc (1, sizeof (char *));
163       if (argv_ == NULL)
164         return 1;
165       arg = strndup (argv[0], 1024);
166       if (arg == NULL)
167         return 1;
168       argv_[0] = arg;
169
170       while (1)
171         {
172           if (fgets (inbuf, 4096, fp) == 0)
173             break;
174           p = strtok (inbuf, " \t\n");
175           while (p != NULL)
176             {
177               if (*p == '#')
178                 break;
179               argc_++;
180               char **tmp = realloc (argv_, argc_ * sizeof (char *));
181               if (tmp == NULL)
182                 return 1;
183               argv_ = tmp;
184               arg = strndup (p, 1024);
185               if (arg == NULL)
186                 return 1;
187               argv_[argc_ - 1] = arg;
188               p = strtok (NULL, " \t\n");
189             }
190         }
191
192       fclose (fp);
193
194       char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
195       if (tmp == NULL)
196         return 1;
197       argv_ = tmp;
198       argv_[argc_] = NULL;
199
200       argc = argc_;
201       argv = argv_;
202     }
203
204   /*
205    * Look for and parse the "heapsize" config parameter.
206    * Manual since none of the clib infra has been bootstrapped yet.
207    *
208    * Format: heapsize <nn>[mM][gG]
209    */
210
211   for (i = 1; i < (argc - 1); i++)
212     {
213       if (!strncmp (argv[i], "plugin_path", 11))
214         {
215           if (i < (argc - 1))
216             vlib_plugin_path = argv[++i];
217         }
218       else if (!strncmp (argv[i], "heapsize", 8))
219         {
220           sizep = (u8 *) argv[i + 1];
221           size = 0;
222           while (*sizep >= '0' && *sizep <= '9')
223             {
224               size *= 10;
225               size += *sizep++ - '0';
226             }
227           if (size == 0)
228             {
229               fprintf
230                 (stderr,
231                  "warning: heapsize parse error '%s', use default %lld\n",
232                  argv[i], (long long int) main_heap_size);
233               goto defaulted;
234             }
235
236           main_heap_size = size;
237
238           if (*sizep == 'g' || *sizep == 'G')
239             main_heap_size <<= 30;
240           else if (*sizep == 'm' || *sizep == 'M')
241             main_heap_size <<= 20;
242         }
243       else if (!strncmp (argv[i], "main-core", 9))
244         {
245           if (i < (argc - 1))
246             {
247               errno = 0;
248               unsigned long x = strtol (argv[++i], 0, 0);
249               if (errno == 0)
250                 main_core = x;
251             }
252         }
253     }
254
255 defaulted:
256
257   /* set process affinity for main thread */
258   CPU_ZERO (&cpuset);
259   CPU_SET (main_core, &cpuset);
260   pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
261
262   /* Set up the plugin message ID allocator right now... */
263   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
264
265   /* Allocate main heap */
266   if (clib_mem_init_thread_safe (0, main_heap_size))
267     {
268       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
269       vpe_main_init (vm);
270       return vlib_unix_main (argc, argv);
271     }
272   else
273     {
274       {
275         int rv __attribute__ ((unused)) =
276           write (2, "Main heap allocation failure!\r\n", 31);
277       }
278       return 1;
279     }
280 }
281
282 static clib_error_t *
283 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
284 {
285   u32 junk;
286
287   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
288     {
289       if (unformat (input, "%dm", &junk)
290           || unformat (input, "%dM", &junk)
291           || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
292         return 0;
293       else
294         return clib_error_return (0, "unknown input '%U'",
295                                   format_unformat_error, input);
296     }
297   return 0;
298 }
299
300 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
301
302 static clib_error_t *
303 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
304 {
305   u8 *junk;
306
307   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
308     {
309       if (unformat (input, "%s", &junk))
310         {
311           vec_free (junk);
312           return 0;
313         }
314       else
315         return clib_error_return (0, "unknown input '%U'",
316                                   format_unformat_error, input);
317     }
318   return 0;
319 }
320
321 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
322
323 void vl_msg_api_post_mortem_dump (void);
324 void elog_post_mortem_dump (void);
325
326 void
327 os_panic (void)
328 {
329   vl_msg_api_post_mortem_dump ();
330   elog_post_mortem_dump ();
331   abort ();
332 }
333
334 void vhost_user_unmap_all (void) __attribute__ ((weak));
335 void
336 vhost_user_unmap_all (void)
337 {
338 }
339
340 void
341 os_exit (int code)
342 {
343   static int recursion_block;
344
345   if (code)
346     {
347       if (recursion_block)
348         abort ();
349
350       recursion_block = 1;
351
352       vl_msg_api_post_mortem_dump ();
353       elog_post_mortem_dump ();
354       vhost_user_unmap_all ();
355       abort ();
356     }
357   exit (code);
358 }
359
360 #ifdef BARRIER_TRACING
361 void
362 vl_msg_api_barrier_trace_context (const char *context)
363 {
364   vlib_worker_threads[0].barrier_context = context;
365 }
366 #endif
367
368 void
369 vl_msg_api_barrier_sync (void)
370 {
371   vlib_worker_thread_barrier_sync (vlib_get_main ());
372 }
373
374 void
375 vl_msg_api_barrier_release (void)
376 {
377   vlib_worker_thread_barrier_release (vlib_get_main ());
378 }
379
380 /* This application needs 1 thread stack for the stats pthread */
381 u32
382 vlib_app_num_thread_stacks_needed (void)
383 {
384   return 1;
385 }
386
387 /*
388  * Depending on the configuration selected above,
389  * it may be necessary to generate stub graph nodes.
390  * It is never OK to ignore "node 'x' refers to unknown node 'y'
391  * messages!
392  */
393
394 #if CLIB_DEBUG > 0
395
396 static clib_error_t *
397 test_crash_command_fn (vlib_main_t * vm,
398                        unformat_input_t * input, vlib_cli_command_t * cmd)
399 {
400   u64 *p = (u64 *) 0xdefec8ed;
401
402   ELOG_TYPE_DECLARE (e) =
403   {
404   .format = "deliberate crash: touching %x",.format_args = "i4",};
405
406   elog (&vm->elog_main, &e, 0xdefec8ed);
407
408   *p = 0xdeadbeef;
409
410   /* Not so much... */
411   return 0;
412 }
413
414 /* *INDENT-OFF* */
415 VLIB_CLI_COMMAND (test_crash_command, static) = {
416   .path = "test crash",
417   .short_help = "crash the bus!",
418   .function = test_crash_command_fn,
419 };
420 /* *INDENT-ON* */
421
422 #endif
423
424 /*
425  * fd.io coding-style-patch-verification: ON
426  *
427  * Local Variables:
428  * eval: (c-set-style "gnu")
429  * End:
430  */