32332cb66181a04ea93e4d2c9c196c636067e6ed
[vpp.git] / 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 #include <vppinfra/cpu.h>
17 #include <vlib/vlib.h>
18 #include <vlib/unix/unix.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vnet/ethernet/ethernet.h>
21
22 #include <vpp-api/vpe_msg_enum.h>
23
24 #if DPDK
25 #include <vnet/devices/dpdk/dpdk.h>
26
27 /*
28  * Called by the dpdk driver's rte_delay_us() function.
29  * Return 0 to have the dpdk do a regular delay loop.
30  * Return 1 if to skip the delay loop because we are suspending
31  * the calling vlib process instead.
32  */
33 int
34 rte_delay_us_override (unsigned us)
35 {
36   vlib_main_t *vm;
37
38   /* Don't bother intercepting for short delays */
39   if (us < 10)
40     return 0;
41
42   /*
43    * Only intercept if we are in a vlib process.
44    * If we are called from a vlib worker thread or the vlib main
45    * thread then do not intercept. (Must not be called from an
46    * independent pthread).
47    */
48   if (os_get_cpu_number () == 0)
49     {
50       /*
51        * We're in the vlib main thread or a vlib process. Make sure
52        * the process is running and we're not still initializing.
53        */
54       vm = vlib_get_main ();
55       if (vlib_in_process_context (vm))
56         {
57           /* Only suspend for the admin_down_process */
58           vlib_process_t *proc = vlib_get_current_process (vm);
59           if (!(proc->flags & VLIB_PROCESS_IS_RUNNING) ||
60               (proc->node_runtime.function != admin_up_down_process))
61             return 0;
62
63           f64 delay = 1e-6 * us;
64           vlib_process_suspend (vm, delay);
65           return 1;
66         }
67     }
68   return 0;                     // no override
69 }
70 #endif
71
72 static void
73 vpe_main_init (vlib_main_t * vm)
74 {
75   if (CLIB_DEBUG > 0)
76     vlib_unix_cli_set_prompt ("DBGvpp# ");
77   else
78     vlib_unix_cli_set_prompt ("vpp# ");
79
80   /* Turn off network stack components which we don't want */
81   vlib_mark_init_function_complete (vm, srp_init);
82 }
83
84 /*
85  * Load plugins from /usr/lib/vpp_plugins by default
86  */
87 char *vlib_plugin_path = "/usr/lib/vpp_plugins";
88
89 void *
90 vnet_get_handoff_structure (void)
91 {
92   static vnet_plugin_handoff_t _rv, *rv = &_rv;
93
94   rv->vnet_main = vnet_get_main ();
95   rv->ethernet_main = &ethernet_main;
96   return (void *) rv;
97 }
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   void vlib_set_get_handoff_structure_cb (void *cb);
109
110 #if __x86_64__
111   const char *msg = "ERROR: This binary requires CPU with %s extensions.\n";
112 #define _(a,b)                                  \
113     if (!clib_cpu_supports_ ## a ())            \
114       {                                         \
115         fprintf(stderr, msg, b);                \
116         exit(1);                                \
117       }
118
119 #if __AVX2__
120   _(avx2, "AVX2")
121 #endif
122 #if __AVX__
123     _(avx, "AVX")
124 #endif
125 #if __SSE4_2__
126     _(sse42, "SSE4.2")
127 #endif
128 #if __SSE4_1__
129     _(sse41, "SSE4.1")
130 #endif
131 #if __SSSE3__
132     _(ssse3, "SSSE3")
133 #endif
134 #if __SSE3__
135     _(sse3, "SSE3")
136 #endif
137 #undef _
138 #endif
139     /*
140      * Load startup config from file.
141      * usage: vpp -c /etc/vpp/startup.conf
142      */
143     if ((argc == 3) && !strncmp (argv[1], "-c", 2))
144     {
145       FILE *fp;
146       char inbuf[4096];
147       int argc_ = 1;
148       char **argv_ = NULL;
149       char *arg = NULL;
150       char *p;
151
152       fp = fopen (argv[2], "r");
153       if (fp == NULL)
154         {
155           fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
156           return 1;
157         }
158       argv_ = calloc (1, sizeof (char *));
159       if (argv_ == NULL)
160         return 1;
161       arg = strndup (argv[0], 1024);
162       if (arg == NULL)
163         return 1;
164       argv_[0] = arg;
165
166       while (1)
167         {
168           if (fgets (inbuf, 4096, fp) == 0)
169             break;
170           p = strtok (inbuf, " \t\n");
171           while (p != NULL)
172             {
173               if (*p == '#')
174                 break;
175               argc_++;
176               char **tmp = realloc (argv_, argc_ * sizeof (char *));
177               if (tmp == NULL)
178                 return 1;
179               argv_ = tmp;
180               arg = strndup (p, 1024);
181               if (arg == NULL)
182                 return 1;
183               argv_[argc_ - 1] = arg;
184               p = strtok (NULL, " \t\n");
185             }
186         }
187
188       fclose (fp);
189
190       char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
191       if (tmp == NULL)
192         return 1;
193       argv_ = tmp;
194       argv_[argc_] = NULL;
195
196       argc = argc_;
197       argv = argv_;
198     }
199
200   /*
201    * Look for and parse the "heapsize" config parameter.
202    * Manual since none of the clib infra has been bootstrapped yet.
203    *
204    * Format: heapsize <nn>[mM][gG]
205    */
206
207   for (i = 1; i < (argc - 1); i++)
208     {
209       if (!strncmp (argv[i], "plugin_path", 11))
210         {
211           if (i < (argc - 1))
212             vlib_plugin_path = argv[++i];
213         }
214       else if (!strncmp (argv[i], "heapsize", 8))
215         {
216           sizep = (u8 *) argv[i + 1];
217           size = 0;
218           while (*sizep >= '0' && *sizep <= '9')
219             {
220               size *= 10;
221               size += *sizep++ - '0';
222             }
223           if (size == 0)
224             {
225               fprintf
226                 (stderr,
227                  "warning: heapsize parse error '%s', use default %lld\n",
228                  argv[i], (long long int) main_heap_size);
229               goto defaulted;
230             }
231
232           main_heap_size = size;
233
234           if (*sizep == 'g' || *sizep == 'G')
235             main_heap_size <<= 30;
236           else if (*sizep == 'm' || *sizep == 'M')
237             main_heap_size <<= 20;
238         }
239     }
240
241 defaulted:
242
243   /* Set up the plugin message ID allocator right now... */
244   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
245
246   /* Allocate main heap */
247   if (clib_mem_init (0, main_heap_size))
248     {
249       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
250       vpe_main_init (vm);
251 #if DPDK == 0
252       unix_physmem_init (vm, 0 /* fail_if_physical_memory_not_present */ );
253 #endif
254       vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure);
255       return vlib_unix_main (argc, argv);
256     }
257   else
258     {
259       {
260         int rv __attribute__ ((unused)) =
261           write (2, "Main heap allocation failure!\r\n", 31);
262       }
263       return 1;
264     }
265 }
266
267 static clib_error_t *
268 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
269 {
270   u32 junk;
271
272   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
273     {
274       if (unformat (input, "%dm", &junk)
275           || unformat (input, "%dM", &junk)
276           || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
277         return 0;
278       else
279         return clib_error_return (0, "unknown input '%U'",
280                                   format_unformat_error, input);
281     }
282   return 0;
283 }
284
285 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
286
287 static clib_error_t *
288 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
289 {
290   u8 *junk;
291
292   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
293     {
294       if (unformat (input, "%s", &junk))
295         {
296           vec_free (junk);
297           return 0;
298         }
299       else
300         return clib_error_return (0, "unknown input '%U'",
301                                   format_unformat_error, input);
302     }
303   return 0;
304 }
305
306 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
307
308 void vl_msg_api_post_mortem_dump (void);
309
310 void
311 os_panic (void)
312 {
313   vl_msg_api_post_mortem_dump ();
314   abort ();
315 }
316
317 void vhost_user_unmap_all (void) __attribute__ ((weak));
318 void
319 vhost_user_unmap_all (void)
320 {
321 }
322
323 void
324 os_exit (int code)
325 {
326   static int recursion_block;
327
328   if (code)
329     {
330       if (recursion_block)
331         abort ();
332
333       recursion_block = 1;
334
335       vl_msg_api_post_mortem_dump ();
336       vhost_user_unmap_all ();
337       abort ();
338     }
339   exit (code);
340 }
341
342 void
343 vl_msg_api_barrier_sync (void)
344 {
345   vlib_worker_thread_barrier_sync (vlib_get_main ());
346 }
347
348 void
349 vl_msg_api_barrier_release (void)
350 {
351   vlib_worker_thread_barrier_release (vlib_get_main ());
352 }
353
354 /* This application needs 1 thread stack for the stats pthread */
355 u32
356 vlib_app_num_thread_stacks_needed (void)
357 {
358   return 1;
359 }
360
361 /*
362  * Depending on the configuration selected above,
363  * it may be necessary to generate stub graph nodes.
364  * It is never OK to ignore "node 'x' refers to unknown node 'y'
365  * messages!
366  */
367
368 #if CLIB_DEBUG > 0
369
370 static clib_error_t *
371 test_crash_command_fn (vlib_main_t * vm,
372                        unformat_input_t * input, vlib_cli_command_t * cmd)
373 {
374   u64 *p = (u64 *) 0xdefec8ed;
375
376   *p = 0xdeadbeef;
377
378   /* Not so much... */
379   return 0;
380 }
381
382 /* *INDENT-OFF* */
383 VLIB_CLI_COMMAND (test_crash_command, static) = {
384   .path = "test crash",
385   .short_help = "crash the bus!",
386   .function = test_crash_command_fn,
387 };
388 /* *INDENT-ON* */
389
390 #endif
391
392 /*
393  * fd.io coding-style-patch-verification: ON
394  *
395  * Local Variables:
396  * eval: (c-set-style "gnu")
397  * End:
398  */