VPP初始化
VLIB_INIT_FUNCTION用來定義構造函數,注冊函數到vlib_main_t->init_function_registrations,這個鏈表在main()函數之前創建。
vlib_main()-> vlib_call_all_init_functions()注冊的函數在這里被調用初始化,最后執行函數vlib_main_loop()。
像這樣由宏定義和構造函數創建的全局鏈表的方式還有如下幾個:
· VLIB_API_INIT_FUNCTION
· VLIB_CLI_COMMAND
· VLIB_CONFIG_FUNCTION
· VLIB_EARLY_CONFIG_FUNCTION
· VLIB_MAIN_LOOP_ENTER_FUNCTION
· VLIB_MAIN_LOOP_EXIT_FUNCTION
· VLIB_REGISTER_NODE
vpp/vnet/main.c的main()函數
程序的入口,設置vlib_plugin_main.handoff_structure_get_cb函數指針,指向vpp/vnet/main.c中的函數vnet_get_handoff_structure。
vlib/unix/plugin.c中的vnet_get_handoff_structure()函數調用上面的的函數指針handoff_structure_get_cb。
vnet_get_handoff_structure() 定義了一個靜態變量,這個靜態變量包含了主要數據指針,比如vlib_main,vnet_main和ethernet_main(看代碼沒有vlib_main)。每個插件注冊的時候,都會通過vlib_plugin_register()將以上數據傳遞給插件。
最后調用vlib_unix_main()。
vlib/unix/main.c的vlib_unix_main()函數
vlib_plugin_early_init()函數會通過dlopen加載插件目錄下的所有插件,這個目錄可以通過命令行指定。默認的插件路徑是 /usr/lib/vpp_plugins。
dlopen每個插件后,VPP會獲取函數vlib_plugin_register的符號地址,所以每個插件都要求實現該函數,之前說過這個函數會傳遞非常重要的數據。
vlib_call_all_config_functions()函數解析所有的命令行選項,並且針對前期需求配置。
為以下線程創建線程棧,主要有三種類型的線程需要實現:
普通線程:比如統計采集。
EAL線程:處理包的工作。
Processes:這些都是定期執行、相互協作的多線程。比如DHCP租期續訂的線程等。VPP主線程的超時到期之后會執行這些。
最后,該函數跳轉到thread0()函數。
vlib/unix/main.c的thread0()函數
調用vlib/main.c的vlib_main()函數
vlib/main.c的vlib_main()函數
VLIB_REGISTER_NODE定義圖節點,注冊到vlib_main_t->node_registrations,vlib_register_all_static_nodes()遍歷這個鏈表,創建圖結點(不是連接,是創建)。
VLIB_INIT_FUNCTION聲明的函數,由vlib_call_all_init_functions()調用初始化。
如果結點被創建,vlib/node.c的vlib_node_main_init()會對圖結點進行初始化。
VLIB_MAIN_LOOP_ENTER_FUNCTION注冊一個鏈表,vlib_call_all_main_loop_enter_functions()函數遍歷該鏈表。
調用vlib_main_loop()
vlib/main.c的vlib_main_loop()函數
創建前面提到的相互協作的多線程,在while(1)循環中處理不同類型的圖結點。
· VLIB_NODE_TYPE_PRE_INPUT:類似DBG_CLI的結點
· VLIB_NODE_TYPE_INPUT:這些是主要結點,主要從網卡或者硬件加速器獲取數據包
· 進程等待信號,這個很重要,因為所有的客戶端都要通過共享內存和VPP通信。客戶端向共享內存發送一些API消息,並且向VPP發送信號(SIGUSR1)。
輸入結點組織數據包,並且將他們發送到合適的中間結點。由dispatch_pending_node()進一步處理這些數據包。
1 int 2 main (int argc, char *argv[]) 3 { 4 int i; 5 vlib_main_t *vm = &vlib_global_main; 6 void vl_msg_api_set_first_available_msg_id (u16); 7 uword main_heap_size = (1ULL << 30); 8 u8 *sizep; 9 u32 size; 10 int main_core = 1; 11 cpu_set_t cpuset; 12 13 .......... 14 15 /* 16 * Look for and parse the "heapsize" config parameter. 17 * Manual since none of the clib infra has been bootstrapped yet. 18 * 19 * Format: heapsize <nn>[mM][gG] 20 */ 21 22 for (i = 1; i < (argc - 1); i++) 23 { 24 if (!strncmp (argv[i], "plugin_path", 11)) 25 { 26 if (i < (argc - 1)) 27 vlib_plugin_path = argv[++i]; 28 } 29 if (!strncmp (argv[i], "test_plugin_path", 16)) 30 { 31 if (i < (argc - 1)) 32 vat_plugin_path = argv[++i]; 33 } 34 else if (!strncmp (argv[i], "heapsize", 8)) 35 { 36 sizep = (u8 *) argv[i + 1]; 37 size = 0; 38 while (*sizep >= '0' && *sizep <= '9') 39 { 40 size *= 10; 41 size += *sizep++ - '0'; 42 } 43 if (size == 0) 44 { 45 fprintf 46 (stderr, 47 "warning: heapsize parse error '%s', use default %lld\n", 48 argv[i], (long long int) main_heap_size); 49 goto defaulted; 50 } 51 52 main_heap_size = size; 53 54 if (*sizep == 'g' || *sizep == 'G') 55 main_heap_size <<= 30; 56 else if (*sizep == 'm' || *sizep == 'M') 57 main_heap_size <<= 20; 58 } 59 else if (!strncmp (argv[i], "main-core", 9)) 60 { 61 if (i < (argc - 1)) 62 { 63 errno = 0; 64 unsigned long x = strtol (argv[++i], 0, 0); 65 if (errno == 0) 66 main_core = x; 67 } 68 } 69 } 70 71 defaulted: 72 73 /* set process affinity for main thread */ 74 CPU_ZERO (&cpuset); 75 CPU_SET (main_core, &cpuset); 76 pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset); 77 78 /* Set up the plugin message ID allocator right now... */ 79 vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE); 80 81 /* Allocate main heap */ 82 if (clib_mem_init_thread_safe (0, main_heap_size)) 83 { 84 vm->init_functions_called = hash_create (0, /* value bytes */ 0); 85 vpe_main_init (vm); 86 return vlib_unix_main (argc, argv); 87 } 88 else 89 { 90 { 91 int rv __attribute__ ((unused)) = 92 write (2, "Main heap allocation failure!\r\n", 31); 93 } 94 return 1; 95 } 96 }
vlib_unix_main函數
1 int 2 vlib_unix_main (int argc, char *argv[]) 3 { 4 vlib_main_t *vm = &vlib_global_main; /* one and only time for this! */ 5 unformat_input_t input; 6 clib_error_t *e; 7 int i; 8 9 vm->argv = (u8 **) argv; 10 vm->name = argv[0]; 11 vm->heap_base = clib_mem_get_heap (); 12 vm->heap_aligned_base = (void *) 13 (((uword) vm->heap_base) & ~(VLIB_FRAME_ALIGN - 1)); 14 ASSERT (vm->heap_base); 15 16 unformat_init_command_line (&input, (char **) vm->argv); 17 if ((e = vlib_plugin_config (vm, &input))) 18 { 19 clib_error_report (e); 20 return 1; 21 } 22 unformat_free (&input); 23 24 i = vlib_plugin_early_init (vm); 25 if (i) 26 return i; 27 28 unformat_init_command_line (&input, (char **) vm->argv); 29 if (vm->init_functions_called == 0) 30 vm->init_functions_called = hash_create (0, /* value bytes */ 0); 31 e = vlib_call_all_config_functions (vm, &input, 1 /* early */ ); 32 if (e != 0) 33 { 34 clib_error_report (e); 35 return 1; 36 } 37 unformat_free (&input); 38 39 /* always load symbols, for signal handler and mheap memory get/put backtrace */ 40 clib_elf_main_init (vm->name); 41 42 vec_validate (vlib_thread_stacks, 0); 43 vlib_thread_stack_init (0); 44 45 __os_thread_index = 0; 46 vm->thread_index = 0; 47 48 i = clib_calljmp (thread0, (uword) vm, 49 (void *) (vlib_thread_stacks[0] + 50 VLIB_THREAD_STACK_SIZE)); 51 return i; 52 }
thread0 -> vlib_main() 下面介紹vlib_main函數
vlib_main
1 int 2 vlib_main (vlib_main_t * volatile vm, unformat_input_t * input) 3 { 4 clib_error_t *volatile error; 5 vlib_node_main_t *nm = &vm->node_main; 6 7 vm->queue_signal_callback = dummy_queue_signal_callback; 8 9 clib_time_init (&vm->clib_time); 10 11 /* Turn on event log. */ 12 if (!vm->elog_main.event_ring_size) 13 vm->elog_main.event_ring_size = 128 << 10; 14 elog_init (&vm->elog_main, vm->elog_main.event_ring_size); 15 elog_enable_disable (&vm->elog_main, 1); 16 vl_api_set_elog_main (&vm->elog_main); 17 (void) vl_api_set_elog_trace_api_messages (1); 18 19 /* Default name. */ 20 if (!vm->name) 21 vm->name = "VLIB"; 22 23 if ((error = vlib_physmem_init (vm))) 24 { 25 clib_error_report (error); 26 goto done; 27 } 28 29 if ((error = vlib_map_stat_segment_init (vm))) 30 { 31 clib_error_report (error); 32 goto done; 33 } 34 35 if ((error = vlib_buffer_main_init (vm))) 36 { 37 clib_error_report (error); 38 goto done; 39 } 40 41 if ((error = vlib_thread_init (vm))) 42 { 43 clib_error_report (error); 44 goto done; 45 } 46 47 /* Register static nodes so that init functions may use them. */ 48 vlib_register_all_static_nodes (vm); 49 50 /* Set seed for random number generator. 51 Allow user to specify seed to make random sequence deterministic. */ 52 if (!unformat (input, "seed %wd", &vm->random_seed)) 53 vm->random_seed = clib_cpu_time_now (); 54 clib_random_buffer_init (&vm->random_buffer, vm->random_seed); 55 56 /* Initialize node graph. */ 57 if ((error = vlib_node_main_init (vm))) 58 { 59 /* Arrange for graph hook up error to not be fatal when debugging. */ 60 if (CLIB_DEBUG > 0) 61 clib_error_report (error); 62 else 63 goto done; 64 } 65 66 /* Direct call / weak reference, for vlib standalone use-cases */ 67 if ((error = vpe_api_init (vm))) 68 { 69 clib_error_report (error); 70 goto done; 71 } 72 73 if ((error = vlibmemory_init (vm))) 74 { 75 clib_error_report (error); 76 goto done; 77 } 78 79 if ((error = map_api_segment_init (vm))) 80 { 81 clib_error_report (error); 82 goto done; 83 } 84 85 /* See unix/main.c; most likely already set up */ 86 if (vm->init_functions_called == 0) 87 vm->init_functions_called = hash_create (0, /* value bytes */ 0); 88 if ((error = vlib_call_all_init_functions (vm))) 89 goto done; 90 91 nm->timing_wheel = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)), 92 CLIB_CACHE_LINE_BYTES); 93 94 vec_validate (nm->data_from_advancing_timing_wheel, 10); 95 _vec_len (nm->data_from_advancing_timing_wheel) = 0; 96 97 /* Create the process timing wheel */ 98 TW (tw_timer_wheel_init) ((TWT (tw_timer_wheel) *) nm->timing_wheel, 99 0 /* no callback */ , 100 10e-6 /* timer period 10us */ , 101 ~0 /* max expirations per call */ ); 102 103 vec_validate (vm->pending_rpc_requests, 0); 104 _vec_len (vm->pending_rpc_requests) = 0; 105 vec_validate (vm->processing_rpc_requests, 0); 106 _vec_len (vm->processing_rpc_requests) = 0; 107 108 if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ ))) 109 goto done; 110 111 /* Sort per-thread init functions before we start threads */ 112 vlib_sort_init_exit_functions (&vm->worker_init_function_registrations); 113 114 /* Call all main loop enter functions. */ 115 { 116 clib_error_t *sub_error; 117 sub_error = vlib_call_all_main_loop_enter_functions (vm); 118 if (sub_error) 119 clib_error_report (sub_error); 120 } 121 122 switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE)) 123 { 124 case VLIB_MAIN_LOOP_EXIT_NONE: 125 vm->main_loop_exit_set = 1; 126 break; 127 128 case VLIB_MAIN_LOOP_EXIT_CLI: 129 goto done; 130 131 default: 132 error = vm->main_loop_error; 133 goto done; 134 } 135 136 vlib_main_loop (vm); 137 138 done: 139 /* Call all exit functions. */ 140 { 141 clib_error_t *sub_error; 142 sub_error = vlib_call_all_main_loop_exit_functions (vm); 143 if (sub_error) 144 clib_error_report (sub_error); 145 } 146 147 if (error) 148 clib_error_report (error); 149 150 return 0; 151 }