/* * Copyright (c) 2015 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #if DPDK #include /* * Called by the dpdk driver's rte_delay_us() function. * Return 0 to have the dpdk do a regular delay loop. * Return 1 if to skip the delay loop because we are suspending * the calling vlib process instead. */ int rte_delay_us_override (unsigned us) { vlib_main_t *vm; /* Don't bother intercepting for short delays */ if (us < 10) return 0; /* * Only intercept if we are in a vlib process. * If we are called from a vlib worker thread or the vlib main * thread then do not intercept. (Must not be called from an * independent pthread). */ if (os_get_cpu_number () == 0) { /* * We're in the vlib main thread or a vlib process. Make sure * the process is running and we're not still initializing. */ vm = vlib_get_main (); if (vlib_in_process_context (vm)) { /* Only suspend for the admin_down_process */ vlib_process_t *proc = vlib_get_current_process (vm); if (!(proc->flags & VLIB_PROCESS_IS_RUNNING) || (proc->node_runtime.function != admin_up_down_process)) return 0; f64 delay = 1e-6 * us; vlib_process_suspend (vm, delay); return 1; } } return 0; // no override } #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0) static void rte_delay_us_override_cb (unsigned us) { if (rte_delay_us_override (us) == 0) rte_delay_us_block (us); } #endif #endif static void vpe_main_init (vlib_main_t * vm) { if (CLIB_DEBUG > 0) vlib_unix_cli_set_prompt ("DBGvpp# "); else vlib_unix_cli_set_prompt ("vpp# "); /* Turn off network stack components which we don't want */ vlib_mark_init_function_complete (vm, srp_init); #if DPDK #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0) /* register custom delay function */ rte_delay_us_callback_register (rte_delay_us_override_cb); #endif #endif } /* * Load plugins from /usr/lib/vpp_plugins by default */ char *vlib_plugin_path = "/usr/lib/vpp_plugins"; void * vnet_get_handoff_structure (void) { static vnet_plugin_handoff_t _rv, *rv = &_rv; rv->vnet_main = vnet_get_main (); rv->ethernet_main = ðernet_main; return (void *) rv; } int main (int argc, char *argv[]) { int i; vlib_main_t *vm = &vlib_global_main; void vl_msg_api_set_first_available_msg_id (u16); uword main_heap_size = (1ULL << 30); u8 *sizep; u32 size; void vlib_set_get_handoff_structure_cb (void *cb); #if __x86_64__ const char *msg = "ERROR: This binary requires CPU with %s extensions.\n"; #define _(a,b) \ if (!clib_cpu_supports_ ## a ()) \ { \ fprintf(stderr, msg, b); \ exit(1); \ } #if __AVX2__ _(avx2, "AVX2") #endif #if __AVX__ _(avx, "AVX") #endif #if __SSE4_2__ _(sse42, "SSE4.2") #endif #if __SSE4_1__ _(sse41, "SSE4.1") #endif #if __SSSE3__ _(ssse3, "SSSE3") #endif #if __SSE3__ _(sse3, "SSE3") #endif #undef _ #endif /* * Load startup config from file. * usage: vpp -c /etc/vpp/startup.conf */ if ((argc == 3) && !strncmp (argv[1], "-c", 2)) { FILE *fp; char inbuf[4096]; int argc_ = 1; char **argv_ = NULL; char *arg = NULL; char *p; fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf (stderr, "open configuration file '%s' failed\n", argv[2]); return 1; } argv_ = calloc (1, sizeof (char *)); if (argv_ == NULL) return 1; arg = strndup (argv[0], 1024); if (arg == NULL) return 1; argv_[0] = arg; while (1) { if (fgets (inbuf, 4096, fp) == 0) break; p = strtok (inbuf, " \t\n"); while (p != NULL) { if (*p == '#') break; argc_++; char **tmp = realloc (argv_, argc_ * sizeof (char *)); if (tmp == NULL) return 1; argv_ = tmp; arg = strndup (p, 1024); if (arg == NULL) return 1; argv_[argc_ - 1] = arg; p = strtok (NULL, " \t\n"); } } fclose (fp); char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *)); if (tmp == NULL) return 1; argv_ = tmp; argv_[argc_] = NULL; argc = argc_; argv = argv_; } /* * Look for and parse the "heapsize" config parameter. * Manual since none of the clib infra has been bootstrapped yet. * * Format: heapsize [mM][gG] */ for (i = 1; i < (argc - 1); i++) { if (!strncmp (argv[i], "plugin_path", 11)) { if (i < (argc - 1)) vlib_plugin_path = argv[++i]; } else if (!strncmp (argv[i], "heapsize", 8)) { sizep = (u8 *) argv[i + 1]; size = 0; while (*sizep >= '0' && *sizep <= '9') { size *= 10; size += *sizep++ - '0'; } if (size == 0) { fprintf (stderr, "warning: heapsize parse error '%s', use default %lld\n", argv[i], (long long int) main_heap_size); goto defaulted; } main_heap_size = size; if (*sizep == 'g' || *sizep == 'G') main_heap_size <<= 30; else if (*sizep == 'm' || *sizep == 'M') main_heap_size <<= 20; } } defaulted: /* Set up the plugin message ID allocator right now... */ vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE); /* Allocate main heap */ if (clib_mem_init (0, main_heap_size)) { vm->init_functions_called = hash_create (0, /* value bytes */ 0); vpe_main_init (vm); #if DPDK == 0 unix_physmem_init (vm, 0 /* fail_if_physical_memory_not_present */ ); #endif vlib_set_get_handoff_structure_cb (&vnet_get_handoff_structure); return vlib_unix_main (argc, argv); } else { { int rv __attribute__ ((unused)) = write (2, "Main heap allocation failure!\r\n", 31); } return 1; } } static clib_error_t * heapsize_config (vlib_main_t * vm, unformat_input_t * input) { u32 junk; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "%dm", &junk) || unformat (input, "%dM", &junk) || unformat (input, "%dg", &junk) || unformat (input, "%dG", &junk)) return 0; else return clib_error_return (0, "unknown input '%U'", format_unformat_error, input); } return 0; } VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize"); static clib_error_t * plugin_path_config (vlib_main_t * vm, unformat_input_t * input) { u8 *junk; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "%s", &junk)) { vec_free (junk); return 0; } else return clib_error_return (0, "unknown input '%U'", format_unformat_error, input); } return 0; } VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path"); void vl_msg_api_post_mortem_dump (void); void os_panic (void) { vl_msg_api_post_mortem_dump (); abort (); } void vhost_user_unmap_all (void) __attribute__ ((weak)); void vhost_user_unmap_all (void) { } void os_exit (int code) { static int recursion_block; if (code) { if (recursion_block) abort (); recursion_block = 1; vl_msg_api_post_mortem_dump (); vhost_user_unmap_all (); abort (); } exit (code); } void vl_msg_api_barrier_sync (void) { vlib_worker_thread_barrier_sync (vlib_get_main ()); } void vl_msg_api_barrier_release (void) { vlib_worker_thread_barrier_release (vlib_get_main ()); } /* This application needs 1 thread stack for the stats pthread */ u32 vlib_app_num_thread_stacks_needed (void) { return 1; } /* * Depending on the configuration selected above, * it may be necessary to generate stub graph nodes. * It is never OK to ignore "node 'x' refers to unknown node 'y' * messages! */ #if CLIB_DEBUG > 0 static clib_error_t * test_crash_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { u64 *p = (u64 *) 0xdefec8ed; *p = 0xdeadbeef; /* Not so much... */ return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (test_crash_command, static) = { .path = "test crash", .short_help = "crash the bus!", .function = test_crash_command_fn, }; /* *INDENT-ON* */ #endif /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */