VPP-main() 源碼學習


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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM