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)循环中处理不同类型的图结点。
bootstrapped· VLIB_NODE_TYPE_PRE_INPUT:类似DBG_CLI的结点
· VLIB_NODE_TYPE_INPUT:这些是主要结点,主要从⽹卡或者硬件加速器获取数据包
· 进程等待信号,这个很重要,因为所有的客户端都要通过共享内存和VPP通信。客户端向共享内存发送⼀些API消息,并且向VPP发送信号(SIGUSR1)。
输⼊结点组织数据包,并且将他们发送到合适的中间结点。由dispatch_pending_node()进⼀步处理这些数据包。
1int
2 main (int argc, char *argv[])
3 {
4int i;
5 vlib_main_t *vm = &vlib_global_main;
6void vl_msg_api_set_first_available_msg_id (u16);
7 uword main_heap_size = (1ULL << 30);
8 u8 *sizep;
9 u32 size;
10int 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
22for (i = 1; i < (argc - 1); i++)
23 {
24if (!strncmp (argv[i], "plugin_path", 11))
25 {
26if (i < (argc - 1))
27 vlib_plugin_path = argv[++i];
28 }
29if (!strncmp (argv[i], "test_plugin_path", 16))
30 {
31if (i < (argc - 1))
32 vat_plugin_path = argv[++i];
33 }
34else if (!strncmp (argv[i], "heapsize", 8))
35 {
36 sizep = (u8 *) argv[i + 1];
37 size = 0;
38while (*sizep >= '0' && *sizep <= '9')
39 {
40 size *= 10;
41 size += *sizep++ - '0';
42 }
43if (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);
49goto defaulted;
50 }
51
52 main_heap_size = size;
53
54if (*sizep == 'g' || *sizep == 'G')
55 main_heap_size <<= 30;
56else if (*sizep == 'm' || *sizep == 'M')
57 main_heap_size <<= 20;
58 }
59else if (!strncmp (argv[i], "main-core", 9))
60 {
60 {
61if (i < (argc - 1))
62 {
63 errno = 0;
64 unsigned long x = strtol (argv[++i], 0, 0);
65if (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 */
79 vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE); 80
81/* Allocate main heap */
82if (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);
86return vlib_unix_main (argc, argv);
87 }
88else
89 {
90 {
91int rv __attribute__ ((unused)) =
92 write (2, "Main heap allocation failure!\r\n", 31);
93 }
94return1;
95 }
96 }
vlib_unix_main函数
1int
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;
7int 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);
17if ((e = vlib_plugin_config (vm, &input)))
18 {
19 clib_error_report (e);
20return1;
21 }
22 unformat_free (&input);
23
24 i = vlib_plugin_early_init (vm);
25if (i)
26return i;
27
28 unformat_init_command_line (&input, (char **) vm->argv);
29if (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 */ );
32if (e != 0)
33 {
34 clib_error_report (e);
35return1;
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));
51return i;
52 }
thread0 -> vlib_main() 下⾯介绍vlib_main函数
vlib_main
1int
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. */
12if (!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);
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. */
20if (!vm->name)
21 vm->name = "VLIB";
22
23if ((error = vlib_physmem_init (vm)))
24 {
25 clib_error_report (error);
26goto done;
27 }
28
29if ((error = vlib_map_stat_segment_init (vm)))
30 {
31 clib_error_report (error);
32goto done;
33 }
34
35if ((error = vlib_buffer_main_init (vm)))
36 {
37 clib_error_report (error);
38goto done;
39 }
40
41if ((error = vlib_thread_init (vm)))
42 {
43 clib_error_report (error);
44goto 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. */ 52if (!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. */
57if ((error = vlib_node_main_init (vm)))
58 {
59/* Arrange for graph hook up error to not be fatal when debugging. */ 60if (CLIB_DEBUG > 0)
61 clib_error_report (error);
62else
63goto done;
64 }
65
66/* Direct call / weak reference, for vlib standalone use-cases */
67if ((error = vpe_api_init (vm)))
68 {
69 clib_error_report (error);
70goto done;
71 }
72
73if ((error = vlibmemory_init (vm)))
74 {
75 clib_error_report (error);
76goto done;
77 }
78
79if ((error = map_api_segment_init (vm)))
80 {
81 clib_error_report (error);
82goto done;
83 }
84
85/* See unix/main.c; most likely already set up */
86if (vm->init_functions_called == 0)
87 vm->init_functions_called = hash_create (0, /* value bytes */0);
88if ((error = vlib_call_all_init_functions (vm)))
89goto done;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论