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