admin管理员组文章数量:1487745
深入浅出思科VPP24.02系列:vlib
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配置文件,解析配置参数,并进行相应的初始化操作。通过相关的函数完成主函数堆的分配,确保系统资源的正确初始化。
代码逻辑展示:
代码语言:javascript代码运行次数:0运行复制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_get_global_main()获取全局主结构体vlib_global_main_t的指针。
- 设置一个占位符回调函数placeholder_queue_signal_callback用于队列信号。
- 如果配置了事件日志环(elog ring)的大小,并且当前大小与配置不一致,则调整其大小。
- 设置日志系统和跟踪API消息的开关。
业务逻辑代码
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);
- 设置默认名称:
- 如果没有设置全局主结构体的名称,则默认设置为"VLIB"。
业务逻辑代码展示:
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;
}
- 注册节点和处理函数:
- 注册所有节点的指令集变体(march variants)和静态节点。
- 根据用户输入或当前时间设置随机数生成器的种子。
业务逻辑代码:
/* 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);
- 初始化节点图和定时器:
- 初始化节点管理,如果在调试模式下遇到错误,则仅报告错误而不停止执行。
- 初始化其他模块,如VPE API、内存管理和API段映射。
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);
- 主循环和退出处理:
- vlib_main_loop函数是主循环的入口,处理数据包和其他任务。
- 主循环结束后,同步工作线程,调用所有主循环退出函数,并报告可能存在的错误。
/* 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骨干网核心交换路由器人员
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2024-10-12,如有侵权请联系 cloudcommunity@tencent 删除函数配置errorgotoinit本文标签: 深入浅出思科VPP2402系列vlib
版权声明:本文标题:深入浅出思科VPP24.02系列:vlib 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/shuma/1754862216a3180537.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论