六、vpp 流表+负载均衡

news2024/11/20 8:40:01

草稿!!!

vpp node其实就是三个部分
1、plugin init
2、set command
3、function 实现功能,比如这里的流表

今天我们再用VPP实现一个流表的功能

一、流表

1.1流表----plugin init

VLIB_REGISTER_NODE 注册流表节点

// 注册流表节点
VLIB_REGISTER_NODE(flowtable_node) = {
    .function = flowtable_getinfo, // 节点处理函数
    .name = "flow-table", // 节点名称
    .vector_size = sizeof(u32), // 向量大小
    .format_trace = format_flowtable_getinfo, // 跟踪格式函数
    .type = VLIB_NODE_TYPE_INTERNAL, // 节点类型为内部节点
    .n_errors = FLOWTABLE_N_ERROR, // 错误数目
    .error_strings = flowtable_error_strings, // 错误字符串数组
    .n_next_nodes = FT_NEXT_N_NEXT, // 下一个节点数目
    .next_nodes = {
        [FT_NEXT_IP4] = "ip4-lookup",
        [FT_NEXT_DROP] = "error-drop",
        [FT_NEXT_ETHERNET_INPUT] = "ethernet-input",
        [FT_NEXT_LOAD_BALANCER] = "load-balance",
        [FT_NEXT_INTERFACE_OUTPUT] = "interface-output",
    } // 下一个节点的映射
};


// 注册插件
VLIB_PLUGIN_REGISTER() = {
    .version = "1.0", // 插件版本
    .description = "sample of flowtable", // 插件描述
};

1.2 流表-----command 解析

接收到命令后,调用注册好的回调函数flowtable_command_enable_fn,最后会通过VPP自带的vnet_hw_interface_rx_redirect_to_node函数将硬件接口的接收流量重定向到指定节点,这里就是我们的流表节点

// 启用或禁用流表功能,将硬件接口的接收流量重定向到指定节点
int flowtable_enable(flowtable_main_t *fm,u32 sw_if_index,int enable){
	// 如果启用,获取流表节点的索引;如果禁用,则设置索引为无效值
	u32 node_index = enable ? flowtable_node.index : ~0;
	
	printf("debug:[%s:%s:%d] node_index:%d\n", __FILE__, __func__, __LINE__, flowtable_node.index);

	// 调用 VPP 的函数,将硬件接口的接收流量重定向到指定节点
	return vnet_hw_interface_rx_redirect_to_node(fm->vnet_main,sw_if_index,node_index);
}

static clib_error_t * flowtable_command_enable_fn(struct vlib_main_t *vm,
		unformat_input_t *input,struct vlib_cli_command_t *cmd){

	// 获取与流表相关的主数据结构
	flowtable_main_t * fm = &flowtable_main;
	u32 sw_if_index = ~0;// 初始化接口索引为无效值
	int enable_disable = 1;// 初始化启用/禁用标志为启用

	// 解析命令行输入,直到输入结束
	while(unformat_check_input(input) != UNFORMAT_END_OF_INPUT){
		// 如果输入中包含 "disable" 参数,则禁用流表功能
		if(unformat(input,"disable")){
			enable_disable = 0;
		}
		// 如果输入中包含接口索引,则解析并存储在 sw_if_index 中
		else if (unformat(input,"%U",unformat_vnet_sw_interface,fm->vnet_main,&sw_if_index)){
			
		}else
			break;
	}
	// 如果没有指定接口索引,则返回错误
	if(sw_if_index == ~0){
		return clib_error_return(0,"No Interface specified");
	}
	// 调用流表启用/禁用函数
	int rv = flowtable_enable(fm,sw_if_index,enable_disable);
	if(rv){
		if(rv == VNET_API_ERROR_INVALID_SW_IF_INDEX){
			return clib_error_return(0,"Invalid interface");
		}else if(rv == VNET_API_ERROR_UNIMPLEMENTED){
			return clib_error_return(0,"Device driver doesn't support redirection");
		}else{
			return clib_error_return(0,"flowtable_enable_disable returned %d\n",rv);
		}
	}
	return 0;
}

//命令行启动、关闭流表功能
VLIB_CLI_COMMAND(flowtable_interface_enable_disable_command) = {

	.path = "flowtable",
	.short_help = "flowtable <interface> [disable]",
	.function = flowtable_command_enable_fn, //对应的flowtable命令行回调函数
};

1.3 流表------function

经过上面,这是当网卡接收到数据,就会传到我们指定的流表功能函数进行处理

static uword flowtable_getinfo(struct vlib_main_t *vm,
			struct vlib_node_runtime_t *node,struct vlib_frame_t *frame){

	u32 n_left_from, *from,*to_next;
	u32 next_index = node->cached_next_index;
	
	printf("flowtable_getinfo cached_next_index: %u\n", next_index);
	from = vlib_frame_vector_args(frame);//获取指向帧向量数据的指针,即第一个数据包的地址
    n_left_from = frame->n_vectors;	// 获取向量数量,即有多少个数据包

	while(n_left_from > 0){
		u32 n_left_to_next;
		/*
		获取下一个节点的帧和向量,然后vlib_put_next_frame将当前节点处理的数据包添加到这个帧中,
		以便后续的节点可以处理这些数据包,最开始这里是获取的第一帧,一帧里面有多个vlib_buffer
		可以看做为二维数组
		*/
		vlib_get_next_frame(vm,node,next_index,to_next,n_left_to_next);

		/*n_left_to_next 是当前帧中剩余的空闲槽位数量,当值为0后,需要vlib_put_next_frame获取一个
		新的帧来继续传递数据包
		*/
            while(n_left_from > 0 && n_left_to_next > 0){

			vlib_buffer_t *b0;
			u32 bi0,next0 = 0;

			bi0 = to_next[0] = from[0];
			from += 1;
			to_next += 1;
			n_left_to_next -= 1;
			n_left_from -= 1;

			//它将 DPDK 的 rte_mbuf 转换为 VPP 的 vlib_buffer_t,vlib_buffer_t里面有多个rte_mbuf(数据包)
			b0 = vlib_get_buffer(vm,bi0);

			//取出当前需要处理的数据包
			ip4_header_t *ip0 = vlib_buffer_get_current(b0);
			ip4_address_t ip_src = ip0->src_address;
			ip4_address_t ip_dst = ip0->dst_address;
			//获取处理的数据包所到达的接口的软件索引,并将其存储在变量 sw_if_index0 中
			u32 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];

			//对每个数据包打印其源ip及目的ip
			struct in_addr addr;
			addr.s_addr = ip_src.as_u32;
			printf("sw_if_index0: %d, ip_src: %s ", sw_if_index0, inet_ntoa(addr));

			addr.s_addr = ip_dst.as_u32;
			printf(" ip_dst: %s \n", inet_ntoa(addr));

			/*
			将当前处理的缓冲区 bi0 传递到下一个节点,同时更新 to_next 数组、n_left_to_next 计数
			和下一个节点的下一个节点索引 next0。这样,数据包将会在当前节点处理后传递到下一个节点进行进一步处理
			*/
			vlib_validate_buffer_enqueue_x1(vm,node,next_index,
				to_next,n_left_to_next,bi0,next0);
		}
		/*
		vlib_get_next_frame获取下一个节点的帧和向量,然后vlib_put_next_frame将当前节点处理的数据
		包添加到这个帧中,		以便后续的节点可以处理这些数据包
		*/
		vlib_put_next_frame(vm,node,next_index,n_left_to_next);
	}
	return frame->n_vectors; //这里决定接下来继续走哪一个node
}

这里的function函数有个返回值,根据返回值决定下一个节点走哪里
flowtable_getinfo这里处理函数返回2 ,则下一步走这个节点[FT_NEXT_ETHERNET_INPUT] = “ethernet-input”,
在这里插入图片描述

浅谈node

在一些系统中,节点的执行顺序可能是在程序初始化的时候静态确定的,特别是在构建数据处理流水线时。这种情况下,节点的顺序是在配置或初始化阶段定义的,然后在整个程序运行期间保持不变。

然而,在某些系统中,特别是对于一些灵活的数据流框架,节点的执行顺序可能是在程序运行时动态决定的。这可以通过某种策略或运行时的条件来调整节点的执行顺序,以适应实时需求或系统的动态变化。

总的来说,节点的执行顺序是取决于应用程序设计和需求的。一些系统更倾向于静态的、在初始化时确定的执行顺序,而其他系统则更注重在运行时根据动态需求来调整节点的执行顺序

在许多系统中,插件和节点的初始化顺序通常是通过配置文件、命令行参数或其他配置机制来确定的。这些配置通常在应用程序启动时被解析,并在初始化过程中用于指导插件和节点的加载和初始化。

以下是一些可能的方式来决定插件和节点的顺序:

配置文件: 应用程序可能会有一个配置文件,其中包含有关插件和节点的信息,包括它们的加载顺序。在应用程序启动时,解析配置文件并按照其中定义的顺序加载插件和节点。

命令行参数: 应用程序可能允许通过命令行参数来指定插件和节点的加载顺序。例如,通过在启动命令中指定参数来控制加载的插件和它们的顺序。

硬编码: 在某些情况下,加载顺序可能是硬编码在应用程序的源代码中的,即在代码中明确指定加载和初始化的顺序。

依赖关系: 插件和节点之间可能存在依赖关系,系统可以根据这些依赖关系来确定加载和初始化的顺序。例如,某个插件可能依赖于另一个插件的某些功能,因此必须在其之前加载。

具体的实现方式取决于系统的设计和开发者的选择。在某些情况下,可能会结合使用上述多种机制来达到更大的灵活性。

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

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

相关文章

15-自动化测试——理论知识

目录 1.什么是自动化测试&#xff1f; 2.常见的自动化测试分类 2.1.单元测试&#xff08;Java、Python&#xff09; 2.2.接口测试&#xff08;Java、Python&#xff09; 2.3.UI测试&#xff08;移动端、网站&#xff09; 3.如何实施自动化测试&#xff1f; 4.自动化测试…

测开 | Vue速查知识点

文章目录 Vue知识1. Vue 概述2. Vue 代码格式3. Vue 指令3.1 v-bind & v-model3.2 v-on3.3 v-if和v-show3.4 v-for 4. 生命周期 Vue知识 1. Vue 概述 简介&#xff1a; Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套构建用户界面的 渐进式框架。与其他…

[QT编程系列-44]: Windows + QT软件闪退的检测方法

目录 一、Windows程序闪退的问题定位方法 1.1 Windows程序闪退 1.2 要找到Windows程序的crash点 1.3 当Windows程序崩溃时&#xff0c;可以尝试以下方法获取出错信息&#xff1a; 二、关键工具的进一步分析 2.1 Windows事件查看器&#xff08;Event Viewer&#xff09; …

openGauss学习笔记-87 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用简单概述

文章目录 openGauss学习笔记-87 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用简单概述87.1 授予用户权限87.2 创建/删除MOT87.3 为MOT创建索引 openGauss学习笔记-87 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用简单概述 使用…

【python的输入】sys.stdin与sys.argv

在老师的课堂里碰到了sys.stdin与sys.argv&#xff0c;虽然是很简单的东西&#xff0c;还是花了大半天的时间才勉强理解。在这里记录一下学习过程&#xff0c;方便以后用到复习。 一、sys.stdin 根据python3 library里的解释&#xff0c; sys.stdin可用于所有交互式的输入。 …

Vscode爆红Delete `␍`eslintprettier/prettier

一、先看报错 文件中爆红&#xff0c;提示 Delete ␍eslintprettier/prettier 二、解决方案 项目根目录下&#xff0c;.prettierrc.js 文件中&#xff1a; endOfLine: auto,三、重启VsCode 此时不在爆红&#xff0c;问题完美解决

STM32CubeMX学习笔记-USB接口使用(HID按键)

STM32CubeMX学习笔记-USB接口使用&#xff08;HID按键&#xff09; 一、USB简介1.1 USB HID简介 二、新建工程1. 打开 STM32CubeMX 软件&#xff0c;点击“新建工程”2. 选择 MCU 和封装3. 配置时钟4. 配置调试模式 三、USB3.1 参数配置3.2 引脚配置3.3 配置时钟3.4 USB Device…

数据分析与挖掘: 红楼梦人物关系(Python)词云图

一: 角色剧本 第一代&#xff1a;水字辈祖宗创下基业 贾源、贾演兄弟二人帮先帝打江山立下战功&#xff0c;贾演被封为宁国公&#xff08;大约有平定江山安宁天下之意&#xff09;&#xff0c;贾源被封荣国公&#xff08;大约有强国富民之功&#xff09;。贾源贾演二兄弟皆是一…

项目进展(五)-修复PCB电路板,学习32位ADC芯片ADS1285

一、前言 上个月29号放假了&#xff0c;和朋友一起去了南京(人是真滴多)&#xff0c;师兄晚放假几天&#xff0c;结果在测试时不小心把12V和GND碰触到一起了&#xff0c;导致12V短路&#xff0c;电路板几乎瘫痪了。 今天下午到学校之后就开始着手寻找问题和修复&#xff0c;最…

Kafka日志索引详解以及生产常见问题分析与总结

文章目录 1、Kafka的Log日志梳理1.1、Topic下的消息是如何存储的&#xff1f;1.1.1、 log文件追加记录所有消息1.1.2、 index和timeindex加速读取log消息日志。 1.2、文件清理机制1.2.1、如何判断哪些日志文件过期了1.2.2、过期的日志文件如何处理 1.3、Kafka的文件高效读写机制…

腾讯云服务器南京地域详细介绍、测试IP和Ping值测速

腾讯云服务器南京地域怎么样&#xff1f;南京地域很不错&#xff0c;正好处于中间的位置&#xff0c;南方北方用户均可以选择&#xff0c;网络延迟更低速度更快&#xff0c;并且目前南京地域有活动&#xff0c;南京地域可用区可选南京一区、南京二区和南京三区&#xff0c;腾讯…

软件设计模式系列之二十四——模板方法模式

在软件设计领域&#xff0c;设计模式是一组被反复使用、多次实践验证的经典问题解决方案。其中&#xff0c;模板方法模式是一种行为型设计模式&#xff0c;用于定义一个算法的骨架&#xff0c;将算法中的某些步骤延迟到子类中实现&#xff0c;从而使子类可以重新定义算法的某些…

互联网Java工程师面试题·Zookeeper 篇·第二弹

目录 13. 服务器角色 14. Zookeeper 下 Server 工作状态 15. 数据同步 16. zookeeper 是如何保证事务的顺序一致性的&#xff1f; 17. 分布式集群中为什么会有 Master&#xff1f; 18. zk 节点宕机如何处理&#xff1f; 19. zookeeper 负载均衡和 nginx 负载均衡区别 20…

代码随想录算法训练营第五十七天 | 392.判断子序列 115.不同的子序列

1. 判断子序列 392. 判断子序列 - 力扣&#xff08;LeetCode&#xff09; dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度。 class Solution {public boolean isSubsequence(String s, String t) {//dp[i][j] 表示…

Spring MVC:数据绑定

Spring MVC 数据绑定数据类型转换数据格式化数据校验 附 数据绑定 数据绑定&#xff0c;指 Web 页面上请求和响应的数据与 Controller 中对应处理方法上的对象绑定&#xff08;即是将用户提交的表单数据绑定到 Java 对象中&#xff09;。 过程如下&#xff1a; ServletRequest…

代数科学计算:LiveMath Maker v3.6.0 cRACK

LiveMath Maker 是一个数学计算机程序&#xff0c;您可以使用它来制作(并探索、实验和创建)LiveMath。您和LiveMath Maker制作的任何LiveMath都可以通过互联网与世界共享。 用LiveMath Maker 来进行数学研究&#xff0c;函数学习&#xff0c;深入探索、实验和创建你的LiveMath…

通用收藏管理器Koillection

什么是 Koillection &#xff1f; Koillection 是一个自托管的收藏管理器&#xff0c;旨在跟踪任何类型的物理&#xff08;主要&#xff09;收藏&#xff0c;如书籍、DVD、邮票、游戏……&#xff0c;由于 Koillection 旨在用于任何类型的收藏&#xff0c;它不支持自动下载元数…

计算机网络-计算机网络体系结构-概述,模型

目录 一、计算机网络概述 二、性能指标 速率 带宽 吞吐量 时延 往返时延RTT 利用率 三、计算机网络体系结构 分层结构 IOS模型 应用层-> 表示层-> 会话层-> 传输层-> 网络层-> 数据链路层-> 物理层-> TCP/IP模型 一、计算机网络概述 计…

用向量数据库Milvus Cloud搭建检索知识库机器人

检索知识库 Milvus 中已经存储了文本块向量,现在可以进行向量查询了。 以下函数创建了 1 个查询 pipeline。注意,这是本教程中最为关键的一个步骤! ops.ann_search.osschat_milvus(host=MILVUS_HOST, port=MILVUS_PORT, **{metric_type: IP, limit: 3, output_fields: [text…

设计模式11、享元模式Flyweight

解释说明&#xff1a;享元模式&#xff08;Flyweight Pattern&#xff09;运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象&#xff0c;而这些对象都很相似&#xff0c;状态变化很小&#xff0c;可以实现对象的多次复用。 抽象享元类&#xff08;Flyweight&…