dpdk: add rte_delay_us_callback
[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     {
41 #if RTE_VERSION < RTE_VERSION_NUM(16, 11, 0, 0)
42       rte_delay_us_block (us);
43 #endif
44       return 0;
45     }
46
47   /*
48    * Only intercept if we are in a vlib process.
49    * If we are called from a vlib worker thread or the vlib main
50    * thread then do not intercept. (Must not be called from an
51    * independent pthread).
52    */
53   if (os_get_cpu_number () == 0)
54     {
55       /*
56        * We're in the vlib main thread or a vlib process. Make sure
57        * the process is running and we're not still initializing.
58        */
59       vm = vlib_get_main ();
60       if (vlib_in_process_context (vm))
61         {
62           /* Only suspend for the admin_down_process */
63           vlib_process_t *proc = vlib_get_current_process (vm);
64           if (!(proc->flags & VLIB_PROCESS_IS_RUNNING) ||
65               (proc->node_runtime.function != admin_up_down_process))
66             return 0;
67
68           f64 delay = 1e-6 * us;
69           vlib_process_suspend (vm, delay);
70           return 1;
71         }
72     }
73   return 0;                     // no override
74 }
75 #endif
76
77 static void
78 vpe_main_init (vlib_main_t * vm)
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 #if DPDK
89 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
90   /* register custom delay function */
91   rte_delay_us_callback_register ((void (*)) rte_delay_us_override);
92 #endif
93 #endif
94 }
95
96 /*
97  * Load plugins from /usr/lib/vpp_plugins by default
98  */
99 char *vlib_plugin_path = "/usr/lib/vpp_plugins";
100
101 void *
102 vnet_get_handoff_structure (void)
103 {
104   static vnet_plugin_handoff_t _rv, *rv = &_rv;
105
106   rv->vnet_main = vnet_get_main ();
107   rv->ethernet_main = &ethernet_main;
108   return (void *) rv;
109 }
110
111 int
112 main (int argc, char *argv[])
113 {
114   int i;
115   vlib_main_t *vm = &vlib_global_main;
116   void vl_msg_api_set_first_available_msg_id (u16);
117   uword main_heap_size = (1ULL << 30);
118   u8 *sizep;
119   u32 size;
120   void vlib_set_get_handoff_structure_cb (void *cb);
121
122 #if __x86_64__
123   const char *msg = "ERROR: This binary requires CPU with %s extensions.\n";
124 #define _(a,b)                                  \
125     if (!clib_cpu_supports_ ## a ())            \
126       {                                         \
127         fprintf(stderr, msg, b);                \
128         exit(1);                                \
129       }
130
131 #if __AVX2__
132   _(avx2, "AVX2")
133 #endif
134 #if __AVX__
135     _(avx, "AVX")
136 #endif
137 #if __SSE4_2__
138     _(sse42, "SSE4.2")
139 #endif
140 #if __SSE4_1__
141     _(sse41, "SSE4.1")
142 #endif
143 #if __SSSE3__
144     _(ssse3, "SSSE3")
145 #endif
146 #if __SSE3__
147     _(sse3, "SSE3")
148 #endif
149 #undef _
150 #endif
151     /*
152      * Load startup config from file.
153      * usage: vpp -c /etc/vpp/startup.conf
154      */
155     if ((argc == 3) && !strncmp (argv[1], "-c", 2))
156     {
157       FILE *fp;
158       char inbuf[4096];
159       int argc_ = 1;
160       char **argv_ = NULL;
161       char *arg = NULL;
162       char *p;
163
164       fp = fopen (argv[2], "r");
165       if (fp == NULL)
166         {
167           fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
168           return 1;
169         }
170       argv_ = calloc (1, sizeof (char *));
171       if (argv_ == NULL)
172         return 1;
173       arg = strndup (argv[0], 1024);
174       if (arg == NULL)
175         return 1;
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       else if (!strncmp (argv[i], "heapsize", 8))
227         {
228           sizep = (u8 *) argv[i + 1];
229           size = 0;
230           while (*sizep >= '0' && *sizep <= '9')
231             {
232               size *= 10;
233               size += *sizep++ - '0';
234             }
235           if (size == 0)
236             {
237               fprintf
238                 (stderr,
239                  "warning: heapsize parse error '%s', use default %lld\n",
240                  argv[i], (long long int) main_heap_size);
241               goto defaulted;
242             }
243
244           main_heap_size = size;
245
246           if (*sizep == 'g' || *sizep == 'G')
247             main_heap_size <<= 30;
248           else if (*sizep == 'm' || *sizep == 'M')
249             main_heap_size <<= 20;
250         }
251     }
252
253 defaulted:
254
255   /* Set up the plugin message ID allocator right now... */
256   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
257
258   /* Allocate main heap */
259   if (clib_mem_init (0, main_heap_size))
260     {
261       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
262       vpe_main_init (vm);
263 #if DPDK == 0
264       unix_physmem_init (vm, 0 /* fail_if_physical_memory_not_present */ );
265 #endif
266       vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure);
267       return vlib_unix_main (argc, argv);
268     }
269   else
270     {
271       {
272         int rv __attribute__ ((unused)) =
273           write (2, "Main heap allocation failure!\r\n", 31);
274       }
275       return 1;
276     }
277 }
278
279 static clib_error_t *
280 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
281 {
282   u32 junk;
283
284   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
285     {
286       if (unformat (input, "%dm", &junk)
287           || unformat (input, "%dM", &junk)
288           || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
289         return 0;
290       else
291         return clib_error_return (0, "unknown input '%U'",
292                                   format_unformat_error, input);
293     }
294   return 0;
295 }
296
297 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
298
299 static clib_error_t *
300 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
301 {
302   u8 *junk;
303
304   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
305     {
306       if (unformat (input, "%s", &junk))
307         {
308           vec_free (junk);
309           return 0;
310         }
311       else
312         return clib_error_return (0, "unknown input '%U'",
313                                   format_unformat_error, input);
314     }
315   return 0;
316 }
317
318 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
319
320 void vl_msg_api_post_mortem_dump (void);
321
322 void
323 os_panic (void)
324 {
325   vl_msg_api_post_mortem_dump ();
326   abort ();
327 }
328
329 void vhost_user_unmap_all (void) __attribute__ ((weak));
330 void
331 vhost_user_unmap_all (void)
332 {
333 }
334
335 void
336 os_exit (int code)
337 {
338   static int recursion_block;
339
340   if (code)
341     {
342       if (recursion_block)
343         abort ();
344
345       recursion_block = 1;
346
347       vl_msg_api_post_mortem_dump ();
348       vhost_user_unmap_all ();
349       abort ();
350     }
351   exit (code);
352 }
353
354 void
355 vl_msg_api_barrier_sync (void)
356 {
357   vlib_worker_thread_barrier_sync (vlib_get_main ());
358 }
359
360 void
361 vl_msg_api_barrier_release (void)
362 {
363   vlib_worker_thread_barrier_release (vlib_get_main ());
364 }
365
366 /* This application needs 1 thread stack for the stats pthread */
367 u32
368 vlib_app_num_thread_stacks_needed (void)
369 {
370   return 1;
371 }
372
373 /*
374  * Depending on the configuration selected above,
375  * it may be necessary to generate stub graph nodes.
376  * It is never OK to ignore "node 'x' refers to unknown node 'y'
377  * messages!
378  */
379
380 #if CLIB_DEBUG > 0
381
382 static clib_error_t *
383 test_crash_command_fn (vlib_main_t * vm,
384                        unformat_input_t * input, vlib_cli_command_t * cmd)
385 {
386   u64 *p = (u64 *) 0xdefec8ed;
387
388   *p = 0xdeadbeef;
389
390   /* Not so much... */
391   return 0;
392 }
393
394 /* *INDENT-OFF* */
395 VLIB_CLI_COMMAND (test_crash_command, static) = {
396   .path = "test crash",
397   .short_help = "crash the bus!",
398   .function = test_crash_command_fn,
399 };
400 /* *INDENT-ON* */
401
402 #endif
403
404 /*
405  * fd.io coding-style-patch-verification: ON
406  *
407  * Local Variables:
408  * eval: (c-set-style "gnu")
409  * End:
410  */