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