VPP学习-VPP初始化流程

概念

        VPP作为一个开源的、高性能的用户态网络协议栈,以进程的形式运行于Linux或(类unix)系统下,即VPP实际是一个用户进程,VPP启动后可通过"ps -ef | grep vpp"命令查看。

VPP启动

        用户态进程启动都有一个main函数即程序入口函数,VPP也不例外,VPP main函数位于/src/vpp/net/main.c中,主要做了如下工作:

        1)加载并解析VPP配置文件startup.conf,获取诸如heapsize、plugin_path等配置参数值。

        2)利用配置参数值完成内存堆初始化

        3)vlib_main_init

        4)vpe_main_init

        5)vlib_unix_main

        针对上述过程,分别了解学习

配置文件解析

        VPP配置文件在启动时通过 如下形式加载:

        vpp -c /etc/vpp/startup.conf

         关于配置文件形式、内容及参数含义可参考此前博客:VPP配置文件介绍

        配置文件读取、解析获取配置参数信息。 

堆初始化

        配置文件解析后,完成相关初始化工作,具体如下:

        1)设置堆大小,堆页大小参数,堆大小默认为1G,在main函数入口时设定uword main_heap_size = (1ULL << 30),

        2)设置主线程CPU亲和性

        3)根据此前设置好的堆相关参数,分配并完成堆的初始化

                a)main_heap = clib_mem_init_with_page_size (main_heap_size,
                         main_heap_log2_page_sz)

                        i) clib_mem_init_internal

                                1) clib_mem_main_init初始化VPP巨页大小及numa节点信息

                                2)clib_mem_create_heap_internal (base, size, log2_page_sz,
                     1 /*is_locked */ , "main heap") 分配创建堆,

                                        a)获取有效的页大小信息

                                        b)使得分配内存的大小对于页大小

                                        c)clib_mem_vm_map_internal分配heap内存

                                        d)初始化并返回结构体变量指针clib_mem_heap_t *h.

                b)获取当前numa 节点索引

                c)设置巨页大小

                d)根据此前分配的主堆设置每一个numa节点的main_heap:  clib_mem_set_per_numa_heap (main_heap);

vlib_main_init

        1)vgm->init_functions_called = hash_create (0, /* value bytes */ 0);创建hash表用于记录已被调用的初始化函数;当vpp启动后,可以通过命令行查看有哪些初始化函数,如下所示:

        2)vm = clib_mem_alloc_aligned (sizeof (*vm), CLIB_CACHE_LINE_BYTES); 分配vlib_main_t 结构体变量,用于指示每个线程的mains。

        3)将vm加入一个向量(vector)vgm->vlib_mains

vpe_main_init

        vpe_main_init函数完成插件路径的设置,具体实现如下:

vpe_main_init (vlib_main_t * vm)
{
#if VPP_API_TEST_BUILTIN > 0void vat_plugin_hash_create (void);
#endif/* 设置CLI客户端命令行提示符 */if (CLIB_DEBUG > 0)vlib_unix_cli_set_prompt ("DBGvpp# ");elsevlib_unix_cli_set_prompt ("vpp# ");/* Turn off network stack components which we don't want */vlib_mark_init_function_complete (vm, srp_init);/** Create the binary api plugin hashes before loading plugins*/
#if VPP_API_TEST_BUILTIN > 0vat_plugin_hash_create ();
#endif/* 设置插件路径 */if (!vlib_plugin_path)vpp_find_plugin_path ();
}

vlib_unix_main

        在vlib_unix_main函数中

        1)首先通过vlib_plugin_config函数从命令行加载和配置插件。

        2)调用vlib_plugin_early_init函数实现在main函数之前初始化插件。需要注意的是,vlib_plugin_early_init函数是通过调用vlib_load_new_plugins函数来加载插件目录,这个目录可以通过命令行指定,默认的插件路径是 /usr/lib/vpp_plugins;

        vlib_load_new_plugins函数将会调用load_one_plugin函数,load_one_plugin函数会通过dlopen函数加载插件目录下的所有插件(插件以动态库(.so)的形式存在的);

        dlopen每个插件后,VPP会获取函数vlib_plugin_registration的符号地址,每个插件都要求实现该函数,这个函数会传递非常重要的数据,包括插件的版本信息、early_init初始化函数指针、描述信息等

        3)vlib_unix_main函数调用vlib_call_all_config_functions来对命令行的选项进行解析,完成相应的配置。

        4)vlib_thread_stack_init函数初始化线程栈,并将os线程指定为索引0线程。vlib_unix_main最后调用clib_calljmp函数,clib_calljmp函数使用thread0作为回调函数,thread0也是初始化得到的线程;在thread0函数中,函数跳转到src/vlib/main.c中的vlib_main函数。具体实现如下:

static uword
thread0 (uword arg)
{vlib_main_t *vm = (vlib_main_t *) arg;vlib_global_main_t *vgm = vlib_get_global_main ();unformat_input_t input;int i;vlib_process_finish_switch_stack (vm);/* 初始化命令行参数 */unformat_init_command_line (&input, (char **) vgm->argv);/* 跳转到vlib_main函数处理 */i = vlib_main (vm, &input);unformat_free (&input);return i;
}

vlib_main

        在vlib_main函数中:

        1)通过vlib_register_all_static_nodes注册所有的静态节点

        2)通过vlib_node_main_init函数初始化节点图,

        3)通过vlib_call_all_config_functions配置子系统,

        4) 然后进入vlib_call_all_init_functions,完成所有函数的初始化。

        5)vlib_main函数最后调用vlib_main_loop函数,此函数是thread0的主循环。

        vlib_main具体实现如下:

int 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;}/* 注册所有节点的节点函数变量 */vlib_register_all_node_march_variants (vm);/* 注册所有静态节点 */vlib_register_all_static_nodes (vm);/* 设置随机生成器的种子       */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);elsegoto 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->data_from_advancing_timing_wheel, 10);vec_set_len (nm->data_from_advancing_timing_wheel, 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;
}
  vlib_main_loop

        在src/vlib/main.c函数中定义了两个循环函数,vlib_main_loop与vlib_worker_loop。vlib_main_loop对应的就是thread0线程,即控制平面;而vlib_worker_loop对应的是worker线程,即数据平面。

        两个函数都调用vlib_main_or_worker_loop函数进入循环,这里仅关注vlib_main_loop的循环,如下所示:

static void
vlib_main_loop (vlib_main_t * vm)
{/* is_main 为1 表示main_loop */vlib_main_or_worker_loop (vm, /* is_main */ 1);
}

        主要涉及以下内容:

        1) 启动所有线程:dispatch_process (vm, nm->processes[i], /* frame */ 0, cpu_time_now);创建相互协作的多线程,VPP主要有三种类型的线程:

        普通线程:比如统计采集。

        EAL线程:处理包的工作。

        Processes:这些都是定期执行、相互协作的多线程,VPP主线程的超时到期之后会执行这些。

        2)在while循环中处理不同类型的节点;

while(1) { //PRE_INPUT是在调用INPUT之前需要处理的node,例如清除网卡发送队列等dispatch_node (...,  VLIB_NODE_TYPE_PRE_INPUT, ....); //处理所有INPUT类型的NODE,例如DPDK的nodedispatch_node (...,  VLIB_NODE_TYPE_INPUT, ....);//处理所有INTERNAL类型的NODE,所有业务相关的都是该类型的NODE,例如ACL、ROUTE等的nodedispatch_pending_node (VLIB_NODE_TYPE_INTERNAL);//处理所有PROCESS类型的NODE,对应产生事件的node,恢复到该node的睡眠点执行。例如定时器等//仅在主线程中处理该类型的nodedispatch_suspended_process (VLIB_NODE_TYPE_PROCESS);
}

参考链接

阐述一下VPP初始化流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2775197.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【网络】:序列化和反序列化

序列化和反序列化 一.json库 二.简单使用json库 前面已经讲过TCP和UDP&#xff0c;也写过代码能够进行双方的通信了&#xff0c;那么有没有可能这种通信是不安全的呢&#xff1f;如果直接通信&#xff0c;可能会被底层捕捉&#xff1b;可能由于网络问题&#xff0c;一方只接收到…

分享88个行业PPT,总有一款适合您

分享88个行业PPT&#xff0c;总有一款适合您 88个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/1BBvTepkj_BHq0rjtJ-lgLQ?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

【华为云】云上两地三中心实践实操

写在前面 应用上云之后&#xff0c;如何进行数据可靠性以及业务连续性的保障是非常关键的&#xff0c;通过华为云云上两地三中心方案了解相关方案认证地址&#xff1a;https://connect.huaweicloud.com/courses/learn/course-v1:HuaweiXCBUCNXI057Self-paced/about当前内容为华…

高级数据结构与算法 | 布谷鸟过滤器(Cuckoo Filter):原理、实现、LSM Tree 优化

文章目录 Cuckoo Filter基本介绍布隆过滤器局限变体 布谷鸟哈希布谷鸟过滤器 实现数据结构优化项Victim Cache备用位置计算半排序桶 插入查找删除 应用场景&#xff1a;LSM 优化 Cuckoo Filter 基本介绍 如果对布隆过滤器不太了解&#xff0c;可以看看往期博客&#xff1a;海量…

【QT+QGIS跨平台编译】之三十一:【FreeXL+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、FreeXL介绍二、文件下载三、文件分析四、pro文件五、编译实践一、FreeXL介绍 【FreeXL跨平台编译】:Windows环境下编译成果(支撑QGIS跨平台编译,以及二次研发) 【FreeXL跨平台编译】:Linux环境下编译成果(支撑QGIS跨平台编译,以及二次研发) 【FreeXL跨平台…

【驱动】块设备驱动(二)-通用块层

前言 通用块层是一个内核组件&#xff0c;处理来自系统其他组件发出的块设备请求。换句话说&#xff0c;通用块层包含了块设备操作的一些通用函数和数据结构&#xff0c;如通用磁盘结构gendisk&#xff0c;请求队列结构request_queue、请求结构request、块设备I/O操作结构bio和…

Log4j2漏洞(二)3种方式复现反弹shell

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、前言 明天就是除夕了&#xff0c;提前祝大家&#x…

谷歌seo搜索引擎优化有什么思路?

正常做seo哪有那么多思路&#xff0c;其实就那么几种方法&#xff0c;无非就关键词&#xff0c;站内优化&#xff0c;外链&#xff0c;可以说万变不离其宗&#xff0c;但如果交给我们&#xff0c;你就可以实现其他的思路&#xff0c;或者说玩法 收录可以说是一个网站的基础&…

Vue3中路由配置Catch all routes (“*“) must .....问题

Vue3中路由配置Catch all routes (“*”) must …问题 文章目录 Vue3中路由配置Catch all routes ("*") must .....问题1. 业务场景描述1. 加载并添加异步路由场景2. vue2中加载并添加异步路由(OK)3. 转vue3后不好使(Error)1. 代码2. 错误 2. 处理方式1. 修改前2. 修…

vue3+elementplus el-upload组件上传第三方oss存储问题

文件上传功能属于一项基本功能&#xff0c;而随着对象存储的发展&#xff0c;现在项目开发中&#xff0c;大部分都是把文件上传到第三方的oss系统或者自己搭建的oss系统。 而el-upload组件是elementui提供的一个文件上传的组件&#xff0c;其有很多属性和事件&#xff0c;如下…

C语言:分支与循环

创造不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; C语⾔是结构化的程序设计语⾔&#xff0c;这⾥的结构指的是顺序结构、选择结构、循环结构&#xff0c;C语⾔是能够实 现这三种结构的&#xff0c;其实我们如果仔细分析&#xff0c;我们⽇常所⻅的事情都可以拆分…

CF1891B Deja Vu

题目 You are given an array a of length n , consisting of positive integers, and an array x of length q , also consisting of positive integers. There are q modification. On the i -th modification ( 1≤i≤q ), for each j ( 1≤j≤n ), such that aj​ is div…

Pymysql之Cursor常用API

Cursor常用API 1、cursor.execute(query, argsNone)&#xff1a;执行sql语句。 参数: query (str)&#xff1a;sql语句。 args (tuple, list or dict)&#xff1a;sql语句中如果有变量&#xff0c;或者格式化输出&#xff0c;会在这里填充数据。 Returns&#xff1a;返…

基于YOLOv8的暗光低光环境下(ExDark数据集)检测,加入多种优化方式---自研CPMS注意力,效果优于CBAM ,助力自动驾驶(二)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了暗光低光数据集检测整个过程&#xff0c;从数据集到训练模型到结果可视化分析&#xff0c;以及如何优化提升检测性能。 &#x1f4a1;&#x1f4a1;&#x1f4a1;加入 自研CPMS注意力 mAP0.5由原始的0.682提升…

Unity学习笔记之【IK反向动力学操作】

反向动力学Inverse Kinematics 反向动力学&#xff0c;简称IK。相较于正向动力学&#xff0c;反向动力学旨在子级对父级产生的影响。 使用IK&#xff0c;可以实现根据目标位置或方向来计算并调整角色的关节&#xff08;骨骼&#xff09;链&#xff0c;以使角色的末端&#xff…

Redis(02)——事务管理

事务概念 Redis事务的本质是一组命令的集合。事务支持一次执行多个命令&#xff0c;一个事务中所有命令都会被序列化&#xff0c;在事务执行过程中&#xff0c;会按照顺序串行化执行队列中的命令&#xff0c;其他客户端提交的命令请求不会插入到事务执行命令序列中 Redis事务…

Mac 使用AccessClient打开 windows 堡垒机的方式

使用AccessClient打开连接到 windows 页面 需要下载Microsoft remote Desktop 远程连接工具 在国内,无法下载正式版,beta 版本不需要从 app Store 下载 macOS 客户端下载地址 | Microsoft Learn 在浏览器点击对应的windows机器打开即可,会自动唤醒 Microsoft remote Desktop 进…

【高阶数据结构】位图布隆过滤器

文章目录 1. 位图1.1什么是位图1.2为什么会有位图1.3 实现位图1.4 位图的应用 2. 布隆过滤器2.1 什么是布隆过滤器2.2 为什么会有布隆过滤器2.3 布隆过滤器的插入2.4 布隆过滤器的查找2.5 布隆过滤器的模拟实现2.6 布隆过滤器的优点2.7 布隆过滤器缺陷 3. 海量数据面试题3.1 哈…

静态时序分析:静态时序分析的原理及其两种模式PBA、GBA

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 静态时序分析有两种模式&#xff1a;PBA(Path Based Analysis)和GBA(Graph Based Analysis)&#xff0c;PBA是基于路径的分析模式而GBA则是基于图的分析模式。在…

SpringOne2023解读-01-使用spring-cloud-contract与TestContainer构建可靠程序

个人创作公约&#xff1a;本人声明创作的所有文章皆为自己原创&#xff0c;如果有参考任何文章的地方&#xff0c;会标注出来&#xff0c;如果有疏漏&#xff0c;欢迎大家批判。如果大家发现网上有抄袭本文章的&#xff0c;欢迎举报&#xff0c;并且积极向这个 github 仓库 提交…