dpdk: Add support for Mellanox ConnectX-4 devices
[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 #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
71 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
72 static void
73 rte_delay_us_override_cb (unsigned us)
74 {
75   if (rte_delay_us_override (us) == 0)
76     rte_delay_us_block (us);
77 }
78 #endif
79 #endif
80
81 static void
82 vpe_main_init (vlib_main_t * vm)
83 {
84   if (CLIB_DEBUG > 0)
85     vlib_unix_cli_set_prompt ("DBGvpp# ");
86   else
87     vlib_unix_cli_set_prompt ("vpp# ");
88
89   /* Turn off network stack components which we don't want */
90   vlib_mark_init_function_complete (vm, srp_init);
91
92 #if DPDK
93 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0)
94   /* register custom delay function */
95   rte_delay_us_callback_register (rte_delay_us_override_cb);
96 #endif
97 #endif
98 }
99
100 /*
101  * Load plugins from /usr/lib/vpp_plugins by default
102  */
103 char *vlib_plugin_path = "/usr/lib/vpp_plugins";
104
105 void *
106 vnet_get_handoff_structure (void)
107 {
108   static vnet_plugin_handoff_t _rv, *rv = &_rv;
109
110   rv->vnet_main = vnet_get_main ();
111   rv->ethernet_main = &ethernet_main;
112   return (void *) rv;
113 }
114
115 int
116 main (int argc, char *argv[])
117 {
118   int i;
119   vlib_main_t *vm = &vlib_global_main;
120   void vl_msg_api_set_first_available_msg_id (u16);
121   uword main_heap_size = (1ULL << 30);
122   u8 *sizep;
123   u32 size;
124   void vlib_set_get_handoff_structure_cb (void *cb);
125
126 #if __x86_64__
127   CLIB_UNUSED (const char *msg)
128     = "ERROR: This binary requires CPU with %s extensions.\n";
129 #define _(a,b)                                  \
130     if (!clib_cpu_supports_ ## a ())            \
131       {                                         \
132         fprintf(stderr, msg, b);                \
133         exit(1);                                \
134       }
135
136 #if __AVX2__
137   _(avx2, "AVX2")
138 #endif
139 #if __AVX__
140     _(avx, "AVX")
141 #endif
142 #if __SSE4_2__
143     _(sse42, "SSE4.2")
144 #endif
145 #if __SSE4_1__
146     _(sse41, "SSE4.1")
147 #endif
148 #if __SSSE3__
149     _(ssse3, "SSSE3")
150 #endif
151 #if __SSE3__
152     _(sse3, "SSE3")
153 #endif
154 #undef _
155 #endif
156     /*
157      * Load startup config from file.
158      * usage: vpp -c /etc/vpp/startup.conf
159      */
160     if ((argc == 3) && !strncmp (argv[1], "-c", 2))
161     {
162       FILE *fp;
163       char inbuf[4096];
164       int argc_ = 1;
165       char **argv_ = NULL;
166       char *arg = NULL;
167       char *p;
168
169       fp = fopen (argv[2], "r");
170       if (fp == NULL)
171         {
172           fprintf (stderr, "open configuration file '%s' failed\n", argv[2]);
173           return 1;
174         }
175       argv_ = calloc (1, sizeof (char *));
176       if (argv_ == NULL)
177         return 1;
178       arg = strndup (argv[0], 1024);
179       if (arg == NULL)
180         return 1;
181       argv_[0] = arg;
182
183       while (1)
184         {
185           if (fgets (inbuf, 4096, fp) == 0)
186             break;
187           p = strtok (inbuf, " \t\n");
188           while (p != NULL)
189             {
190               if (*p == '#')
191                 break;
192               argc_++;
193               char **tmp = realloc (argv_, argc_ * sizeof (char *));
194               if (tmp == NULL)
195                 return 1;
196               argv_ = tmp;
197               arg = strndup (p, 1024);
198               if (arg == NULL)
199                 return 1;
200               argv_[argc_ - 1] = arg;
201               p = strtok (NULL, " \t\n");
202             }
203         }
204
205       fclose (fp);
206
207       char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *));
208       if (tmp == NULL)
209         return 1;
210       argv_ = tmp;
211       argv_[argc_] = NULL;
212
213       argc = argc_;
214       argv = argv_;
215     }
216
217   /*
218    * Look for and parse the "heapsize" config parameter.
219    * Manual since none of the clib infra has been bootstrapped yet.
220    *
221    * Format: heapsize <nn>[mM][gG]
222    */
223
224   for (i = 1; i < (argc - 1); i++)
225     {
226       if (!strncmp (argv[i], "plugin_path", 11))
227         {
228           if (i < (argc - 1))
229             vlib_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     }
257
258 defaulted:
259
260   /* Set up the plugin message ID allocator right now... */
261   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
262
263   /* Allocate main heap */
264   if (clib_mem_init (0, main_heap_size))
265     {
266       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
267       vpe_main_init (vm);
268 #if DPDK == 0
269       unix_physmem_init (vm, 0 /* fail_if_physical_memory_not_present */ );
270 #endif
271       vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure);
272       return vlib_unix_main (argc, argv);
273     }
274   else
275     {
276       {
277         int rv __attribute__ ((unused)) =
278           write (2, "Main heap allocation failure!\r\n", 31);
279       }
280       return 1;
281     }
282 }
283
284 static clib_error_t *
285 heapsize_config (vlib_main_t * vm, unformat_input_t * input)
286 {
287   u32 junk;
288
289   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
290     {
291       if (unformat (input, "%dm", &junk)
292           || unformat (input, "%dM", &junk)
293           || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk))
294         return 0;
295       else
296         return clib_error_return (0, "unknown input '%U'",
297                                   format_unformat_error, input);
298     }
299   return 0;
300 }
301
302 VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize");
303
304 static clib_error_t *
305 plugin_path_config (vlib_main_t * vm, unformat_input_t * input)
306 {
307   u8 *junk;
308
309   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
310     {
311       if (unformat (input, "%s", &junk))
312         {
313           vec_free (junk);
314           return 0;
315         }
316       else
317         return clib_error_return (0, "unknown input '%U'",
318                                   format_unformat_error, input);
319     }
320   return 0;
321 }
322
323 VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path");
324
325 void vl_msg_api_post_mortem_dump (void);
326
327 void
328 os_panic (void)
329 {
330   vl_msg_api_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       vhost_user_unmap_all ();
354       abort ();
355     }
356   exit (code);
357 }
358
359 void
360 vl_msg_api_barrier_sync (void)
361 {
362   vlib_worker_thread_barrier_sync (vlib_get_main ());
363 }
364
365 void
366 vl_msg_api_barrier_release (void)
367 {
368   vlib_worker_thread_barrier_release (vlib_get_main ());
369 }
370
371 /* This application needs 1 thread stack for the stats pthread */
372 u32
373 vlib_app_num_thread_stacks_needed (void)
374 {
375   return 1;
376 }
377
378 /*
379  * Depending on the configuration selected above,
380  * it may be necessary to generate stub graph nodes.
381  * It is never OK to ignore "node 'x' refers to unknown node 'y'
382  * messages!
383  */
384
385 #if CLIB_DEBUG > 0
386
387 static clib_error_t *
388 test_crash_command_fn (vlib_main_t * vm,
389                        unformat_input_t * input, vlib_cli_command_t * cmd)
390 {
391   u64 *p = (u64 *) 0xdefec8ed;
392
393   *p = 0xdeadbeef;
394
395   /* Not so much... */
396   return 0;
397 }
398
399 /* *INDENT-OFF* */
400 VLIB_CLI_COMMAND (test_crash_command, static) = {
401   .path = "test crash",
402   .short_help = "crash the bus!",
403   .function = test_crash_command_fn,
404 };
405 /* *INDENT-ON* */
406
407 #endif
408
409 /*
410  * fd.io coding-style-patch-verification: ON
411  *
412  * Local Variables:
413  * eval: (c-set-style "gnu")
414  * End:
415  */