01=上期内容回顾
在往期的内容中,我们介绍了思科VPP软件核心函数thread0的业务逻辑介绍,
深入浅出思科VPP24.02系列:vlib_unix_main初始化介绍
深入浅出思科VPP24.02系列:thread0函数业务逻辑介绍
本期我们将继续深入浅出思科vpp24.02系列专题,介绍VPP核心业务vlib_main函数的业务逻辑介绍。
02=VPP函数vlib_main()介绍
函数路径介绍:thread0函数位于vlib/main.c中
函数功能介绍:该负责启动和初始化VPP的各种组件,是VPP程序的入口点。该函数首先加载VPP配置文件,解析配置参数,并进行相应的初始化操作。通过相关的函数完成主函数堆的分配,确保系统资源的正确初始化。
代码逻辑展示:
vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
{
vlib_global_main_t *vgm = vlib_get_global_main ();
clib_error_t *volatile error;
vlib_node_main_t *nm = &vm->node_main;
vm->queue_signal_callback = placeholder_queue_signal_callback;
/* Reconfigure event log which is enabled very early */
if (vgm->configured_elog_ring_size &&
vgm->configured_elog_ring_size != vgm->elog_main.event_ring_size)
elog_resize (&vgm->elog_main, vgm->configured_elog_ring_size);
vl_api_set_elog_main (vlib_get_elog_main ());
(void) vl_api_set_elog_trace_api_messages (1);
/* Default name. */
if (!vgm->name)
vgm->name = "VLIB";
if ((error = vlib_physmem_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_log_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_stats_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_buffer_main_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_thread_init (vm)))
{
clib_error_report (error);
goto done;
}
/* Register node ifunction variants */
vlib_register_all_node_march_variants (vm);
/* Register static nodes so that init functions may use them. */
vlib_register_all_static_nodes (vm);
/* Set seed for random number generator.
Allow user to specify seed to make random sequence deterministic. */
if (!unformat (input, "seed %wd", &vm->random_seed))
vm->random_seed = clib_cpu_time_now ();
clib_random_buffer_init (&vm->random_buffer, vm->random_seed);
/* Initialize node graph. */
if ((error = vlib_node_main_init (vm)))
{
/* Arrange for graph hook up error to not be fatal when debugging. */
if (CLIB_DEBUG > 0)
clib_error_report (error);
else
goto done;
}
/* Direct call / weak reference, for vlib standalone use-cases */
if ((error = vpe_api_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlibmemory_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = map_api_segment_init (vm)))
{
clib_error_report (error);
goto done;
}
/* See unix/main.c; most likely already set up */
if (vgm->init_functions_called == 0)
vgm->init_functions_called = hash_create (0, /* value bytes */ 0);
if ((error = vlib_call_all_init_functions (vm)))
goto done;
nm->timing_wheel = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
CLIB_CACHE_LINE_BYTES);
vec_validate (nm->process_restore_current, 10);
vec_validate (nm->process_restore_next, 10);
vec_set_len (nm->process_restore_current, 0);
vec_set_len (nm->process_restore_next, 0);
/* Create the process timing wheel */
TW (tw_timer_wheel_init)
((TWT (tw_timer_wheel) *) nm->timing_wheel,
process_expired_timer_cb /* callback */, 10e-6 /* timer period 10us */,
~0 /* max expirations per call */);
vec_validate (vm->pending_rpc_requests, 0);
vec_set_len (vm->pending_rpc_requests, 0);
vec_validate (vm->processing_rpc_requests, 0);
vec_set_len (vm->processing_rpc_requests, 0);
/* Default params for the buffer allocator fault injector, if configured */
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
{
vm->buffer_alloc_success_seed = 0xdeaddabe;
vm->buffer_alloc_success_rate = 0.80;
}
if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
goto done;
/*
* Use exponential smoothing, with a half-life of 1 second
* reported_rate(t) = reported_rate(t-1) * K + rate(t)*(1-K)
*
* Sample every 20ms, aka 50 samples per second
* K = exp (-1.0/20.0);
* K = 0.95
*/
vm->damping_constant = exp (-1.0 / 20.0);
/* Sort per-thread init functions before we start threads */
vlib_sort_init_exit_functions (&vgm->worker_init_function_registrations);
/* Call all main loop enter functions. */
{
clib_error_t *sub_error;
sub_error = vlib_call_all_main_loop_enter_functions (vm);
if (sub_error)
clib_error_report (sub_error);
}
switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE))
{
case VLIB_MAIN_LOOP_EXIT_NONE:
vm->main_loop_exit_set = 1;
break;
case VLIB_MAIN_LOOP_EXIT_CLI:
goto done;
default:
error = vm->main_loop_error;
goto done;
}
vlib_main_loop (vm);
done:
/* Stop worker threads, barrier will not be released */
vlib_worker_thread_barrier_sync (vm);
/* Call all exit functions. */
{
clib_error_t *sub_error;
sub_error = vlib_call_all_main_loop_exit_functions (vm);
if (sub_error)
clib_error_report (sub_error);
}
if (error)
clib_error_report (error);
return vm->main_loop_exit_status;
}
03=VPP函数vlib_main()逻辑解析
vlib_main是vpp的一个核心函数,下面是该函数的详细解释其业务逻辑:
业务逻辑代码
vlib_global_main_t *vgm = vlib_get_global_main ();
clib_error_t *volatile error;
vlib_node_main_t *nm = &vm->node_main;
vm->queue_signal_callback = placeholder_queue_signal_callback;
/* Reconfigure event log which is enabled very early */
if (vgm->configured_elog_ring_size &&
vgm->configured_elog_ring_size != vgm->elog_main.event_ring_size)
elog_resize (&vgm->elog_main, vgm->configured_elog_ring_size);
vl_api_set_elog_main (vlib_get_elog_main ());
(void) vl_api_set_elog_trace_api_messages (1);
业务逻辑代码展示:
if (!vgm->name)
vgm->name = "VLIB";
if ((error = vlib_physmem_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_log_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_stats_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_buffer_main_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_thread_init (vm)))
{
clib_error_report (error);
goto done;
}
业务逻辑代码:
/* Register node ifunction variants */
vlib_register_all_node_march_variants (vm);
/* Register static nodes so that init functions may use them. */
vlib_register_all_static_nodes (vm);
/* Set seed for random number generator.
Allow user to specify seed to make random sequence deterministic. */
if (!unformat (input, "seed %wd", &vm->random_seed))
vm->random_seed = clib_cpu_time_now ();
clib_random_buffer_init (&vm->random_buffer, vm->random_seed);
if ((error = vlib_node_main_init (vm)))
{
/* Arrange for graph hook up error to not be fatal when debugging. */
if (CLIB_DEBUG > 0)
clib_error_report (error);
else
goto done;
}
/* Direct call / weak reference, for vlib standalone use-cases */
if ((error = vpe_api_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = vlibmemory_init (vm)))
{
clib_error_report (error);
goto done;
}
if ((error = map_api_segment_init (vm)))
{
clib_error_report (error);
goto done;
}
if (vgm->init_functions_called == 0)
vgm->init_functions_called = hash_create (0, /* value bytes */ 0);
if ((error = vlib_call_all_init_functions (vm)))
goto done;
nm->timing_wheel = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
CLIB_CACHE_LINE_BYTES);
代码逻辑:
vec_validate (nm->process_restore_current, 10);
vec_validate (nm->process_restore_next, 10);
vec_set_len (nm->process_restore_current, 0);
vec_set_len (nm->process_restore_next, 0);
/* Create the process timing wheel */
TW (tw_timer_wheel_init)
((TWT (tw_timer_wheel) *) nm->timing_wheel,
process_expired_timer_cb /* callback */, 10e-6 /* timer period 10us */,
~0 /* max expirations per call */);
vec_validate (vm->pending_rpc_requests, 0);
vec_set_len (vm->pending_rpc_requests, 0);
vec_validate (vm->processing_rpc_requests, 0);
vec_set_len (vm->processing_rpc_requests, 0);
/* Default params for the buffer allocator fault injector, if configured */
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
{
vm->buffer_alloc_success_seed = 0xdeaddabe;
vm->buffer_alloc_success_rate = 0.80;
}
if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
goto done;
/*
* Use exponential smoothing, with a half-life of 1 second
* reported_rate(t) = reported_rate(t-1) * K + rate(t)*(1-K)
*
* Sample every 20ms, aka 50 samples per second
* K = exp (-1.0/20.0);
* K = 0.95
*/
vm->damping_constant = exp (-1.0 / 20.0);
/* Sort per-thread init functions before we start threads */
vlib_sort_init_exit_functions (&vgm->worker_init_function_registrations);
/* Call all main loop enter functions. */
{
clib_error_t *sub_error;
sub_error = vlib_call_all_main_loop_enter_functions (vm);
if (sub_error)
clib_error_report (sub_error);
}
switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE))
{
case VLIB_MAIN_LOOP_EXIT_NONE:
vm->main_loop_exit_set = 1;
break;
case VLIB_MAIN_LOOP_EXIT_CLI:
goto done;
default:
error = vm->main_loop_error;
goto done;
}
vlib_main_loop (vm);
done:
/* Stop worker threads, barrier will not be released */
vlib_worker_thread_barrier_sync (vm);
/* Call all exit functions. */
{
clib_error_t *sub_error;
sub_error = vlib_call_all_main_loop_exit_functions (vm);
if (sub_error)
clib_error_report (sub_error);
}
if (error)
clib_error_report (error);
return vm->main_loop_exit_status;
03=本章小结
本章节我们主要介绍了VPP的核心函数vlib_main()的业务处理逻辑,其总结为思维导图的模式如下所示:
该函数负责初始化整个系统,设置必要的参数和回调函数,然后进入主循环处理数据包和其他任务。在主循环结束后,它会执行清理工作,释放资源,并报告错误(如果使能的条件下)。小伙伴们,你们学会了吗?
作者简介
作者:通信行业搬砖工
前深圳某大型通信设备厂商从业人员
前H3Com骨干网核心交换路由器人员