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
",
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!
", 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 }

 

原文地址:https://www.cnblogs.com/mysky007/p/12735682.html