Open vSwitch 内核空间的流表同步

一、内核空间的流表同步

        在 Open vSwitch 的数据包转发过程中,当数据包在 Datapath 模块无法完全处理时,会通过 upcall 调用将数据包交给用户空间的 vswitchd 守护进程,由 vswitchd 守护进程生成相应的流表和行为,并发送回内核空间。在这个过程中,内核空间和用户空间之间采用 Netlink 进行通信,并且用户空间下发的流表并不会直接发送到 Datapath 模块,而是先发送给内核空间的流表缓存(我们称之为 Flow Table),再交给 Datapath 模块。所谓的 Open vSwitch 流表同步指的是:在内核空间中,将流表项从流表缓存中同步到 Datapath 模块的过程。

二、流表同步 ovs_flow_cmd_new()

        函数 ovs_flow_cmd_new() 负责处理 OVS 内核模块中的流表创建和更新操作,包括解析 Netlink 消息、分配和更新流表项、填充回复消息等内容,存储在 ovs-main/datapath/datapath.c 文件中:

static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) {struct net *net = sock_net(skb->sk);struct nlattr **a = info->attrs;struct ovs_header *ovs_header = info->userhdr;struct sw_flow *flow = NULL, *new_flow;struct sw_flow_mask mask;struct sk_buff *reply;struct datapath *dp;struct sw_flow_actions *acts;struct sw_flow_match match;u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);int error;bool log = !a[OVS_FLOW_ATTR_PROBE];/* Must have key and actions. */error = -EINVAL;if (!a[OVS_FLOW_ATTR_KEY]) {OVS_NLERR(log, "Flow key attr not present in new flow.");goto error;}if (!a[OVS_FLOW_ATTR_ACTIONS]) {OVS_NLERR(log, "Flow actions attr not present in new flow.");goto error;}/* Most of the time we need to allocate a new flow, do it before locking. */new_flow = ovs_flow_alloc();if (IS_ERR(new_flow)) {error = PTR_ERR(new_flow);goto error;}/* Extract key. */ovs_match_init(&match, &new_flow->key, false, &mask);error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],a[OVS_FLOW_ATTR_MASK], log);if (error)goto err_kfree_flow;/* Extract flow identifier. */error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],&new_flow->key, log);if (error)goto err_kfree_flow;/* unmasked key is needed to match when ufid is not used. */if (ovs_identifier_is_key(&new_flow->id))match.key = new_flow->id.unmasked_key;ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);/* Validate actions. */error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],&new_flow->key, &acts, log);if (error) {OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");goto err_kfree_flow;}reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false, ufid_flags);if (IS_ERR(reply)) {error = PTR_ERR(reply);goto err_kfree_acts;}ovs_lock();dp = get_dp(net, ovs_header->dp_ifindex);if (unlikely(!dp)) {error = -ENODEV;goto err_unlock_ovs;}/* Check if this is a duplicate flow */if (ovs_identifier_is_ufid(&new_flow->id))flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);if (!flow)flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);if (likely(!flow)) {rcu_assign_pointer(new_flow->sf_acts, acts);/* Put flow in bucket. */error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);if (unlikely(error)) {acts = NULL;goto err_unlock_ovs;}if (unlikely(reply)) {error = ovs_flow_cmd_fill_info(new_flow, ovs_header->dp_ifindex, reply, info->snd_portid, info->snd_seq, 0, OVS_FLOW_CMD_NEW, ufid_flags);BUG_ON(error < 0);}ovs_unlock();} else {struct sw_flow_actions *old_acts;/* Bail out if we're not allowed to modify an existing flow.* We accept NLM_F_CREATE in place of the intended NLM_F_EXCL because Generic Netlink treats the latter as a dump request. * We also accept NLM_F_EXCL in case that bug ever gets fixed.*/if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))) {error = -EEXIST;goto err_unlock_ovs;}/* The flow identifier has to be the same for flow updates.* Look for any overlapping flow.*/if (unlikely(!ovs_flow_cmp(flow, &match))) {if (ovs_identifier_is_key(&flow->id))flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);else /* UFID matches but key is different */flow = NULL;if (!flow) {error = -ENOENT;goto err_unlock_ovs;}}/* Update actions. */old_acts = ovsl_dereference(flow->sf_acts);rcu_assign_pointer(flow->sf_acts, acts);if (unlikely(reply)) {error = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, reply, info->snd_portid, info->snd_seq, 0, OVS_FLOW_CMD_NEW, ufid_flags);BUG_ON(error < 0);}ovs_unlock();ovs_nla_free_flow_actions_rcu(old_acts);ovs_flow_free(new_flow, false);}if (reply)ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);return 0;err_unlock_ovs:ovs_unlock();kfree_skb(reply);
err_kfree_acts:ovs_nla_free_flow_actions(acts);
err_kfree_flow:ovs_flow_free(new_flow, false);
error:return error;
}

        函数的第一个输入参数 struct sk_buff *skb 代表接收到的数据包(包含 Netlink 消息的 socket 缓冲区),第二个输入参数 struct genl_info *info 代表数据包相应的信息和属性(包含 Netlink 消息的元数据)。

        函数首先使用 ovs_flow_alloc() 分配一个新的 sw_flow 结构体,该函数存储在 ovs-main/datapath/flow_table.c 文件中:

struct sw_flow *ovs_flow_alloc(void) {struct sw_flow *flow;struct sw_flow_stats *stats;flow = kmem_cache_zalloc(flow_cache, GFP_KERNEL);if (!flow)return ERR_PTR(-ENOMEM);flow->stats_last_writer = -1;/* Initialize the default stat node. */stats = kmem_cache_alloc_node(flow_stats_cache, GFP_KERNEL | __GFP_ZERO, node_online(0) ? 0 : NUMA_NO_NODE);if (!stats)goto err;spin_lock_init(&stats->lock);RCU_INIT_POINTER(flow->stats[0], stats);cpumask_set_cpu(0, &flow->cpu_used_mask);return flow;
err:kmem_cache_free(flow_cache, flow);return ERR_PTR(-ENOMEM);
}

        相应的 sw_flow 结构体定义在 ovs-main/datapath/flow.h 头文件中: 

struct sw_flow {struct rcu_head rcu;struct {struct hlist_node node[2];u32 hash;} flow_table, ufid_table;int stats_last_writer;		/* CPU id of the last writer on 'stats[0]'. */struct sw_flow_key key;struct sw_flow_id id;struct cpumask cpu_used_mask;struct sw_flow_mask *mask;struct sw_flow_actions __rcu *sf_acts;struct sw_flow_stats __rcu *stats[]; /* One for each CPU.  * First one is allocated at flow creation time, the rest are allocated on demand while holding the 'stats[0].lock'. */
};

        然后函数对 Netlink 消息进行解析,并将解析结果存储在这个 sw_flow 结构体中(相应函数细节此处不做展开):

  • 函数 ovs_nla_get_match() 用于从 Netlink 消息中解析 flow 的匹配键 match 和掩码 mask
  • 函数 ovs_nla_get_identifier() 用于从 Netlink 消息中解析 flow 的标识符 id
  • 函数 ovs_flow_mask_key() 用于掩码化 flow 的匹配键 match
  • 函数 ovs_nla_copy_actions() 用于从 Netlink 消息中解析 flow 的行为 acts

        接下来函数分配一个 sk_buff 用于回复消息,并使用 ovs_flow_cmd_alloc_info() 填充相关信息。然后获取 Datapath 的指针并进行搜索,将 sw_flow 结构体中记录的流表项同步到 Datapath 模块(相应函数细节此处不做展开):

  • 如果在 Datapath 中找不到对应的流表项,则将新创建的 flow 插入到 flow 表中
  • 如果在 Datapath 中找得到对应的流表项,则更新现有 flow 的动作,并检查是否允许修改

        最后,如果有需要的话,则使用 ovs_flow_cmd_fill_info() 填充回复信息,并通过 ovs_notify() 将消息发送出去。此外还要进行错误处理和资源回收。

总结:

        通过前面的分析可以看到,在 Open vSwitch 的内核空间中,流表解析和流表同步之间的过程衔接是非常紧密的(实现在同一个函数 ovs_flow_cmd_new() 中)。这个函数首先根据接收的 Netlink 消息将信息存入缓存,也就是上面提到的 sw_flow 结构体(存储在 Flow Table 中),然后将这个结构体的信息同步到 Datapath 内核模块。也就是说,Flow Table 和 Datapath 之间不涉及复杂的分层设计和通信机制,仅仅是在内核空间增加了一个额外的缓存,用于将从用户空间发送过来的数据进行整理,然后再同步到 Datapath 模块。

Tips:流表同步相关的整个过程都是在内核空间中进行的。

        由于本人水平有限,以上内容如有不足之处欢迎大家指正(评论区/私信均可)。

参考资料:

Open vSwitch 官网

Open vSwitch 源代码 GitHub

ovs upcall 处理流程-CSDN博客

Open vSwitch v2.17.10 LTS 源代码

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

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

相关文章

什么是空间复杂度?

空间复杂度 是指算法在计算机中执行时所需额外空间的度量&#xff0c;记作S(n)。这个空间包括算法在执行时所使用的所有额外存储空间&#xff0c;包括变量&#xff08;包括静态变量和动态变量&#xff09;、递归调用栈、以及输入输出数据所占据的存储空间等。其中&#xff0c;n…

指针并不是用来存储数据的,而是用来存储数据在内存中地址(内存操作/函数指针/指针函数)

推荐&#xff1a;1、4、5号书籍 1. 基本概念 首先&#xff0c;让小明了解指针的基本概念&#xff1a; 指针的定义&#xff1a;指针是一个变量&#xff0c;它存储的是另一个变量的地址。指针的声明&#xff1a;例如&#xff0c;int *p表示一个指向整数的指针变量p。 2. 形象…

生命在于学习——Python人工智能原理(2.6.1)

六 Python的文件系统 6.1 打开文件 在Python中&#xff0c;可以使用内置的open函数来打开文件&#xff0c;open函数的基本语法如下&#xff1a; file open(file_name, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone)参数说明&#…

【Web3】Web3.js 启动!并解决Web3 is not a constructor报错

苏泽 大家好 这里是苏泽 一个钟爱区块链技术的后端开发者 本篇专栏 ←持续记录本人自学智能合约学习笔记和经验总结 如果喜欢拜托三连支持~ 本节教大家如何启动Web3.js 目录 Web3 启动&#xff01; 于是很愉快的报错 创建实例&#xff01; 出来了 Web3&#xff1a;模块…

【Android】设置光标颜色和图标

创建主题 该主题可以更改文字下方拖拽手柄的颜色 <?xml version"1.0" encoding"utf-8"?> <resources><style name"RedTextCursor"><item name"android:colorControlActivated">#FF0000</item></…

《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》

期刊&#xff1a;CVPR 年份&#xff1a;2023 代码&#xff1a;https://github.com/XuJiacong/PIDNet 摘要 双分支网络架构已经证明了它在实时语义分割任务中的有效性和有效性。然而&#xff0c;高分辨率细节和低频上下文的直接融合的缺点是细节特征很容易被周围的上下文信息…

快储存,分布式文件系统,对象储存

Ceph块存储 镜像快照 快照可以保存某一时间点时的状态数据快照是映像在特定时间点的只读逻辑副本希望回到以前的一个状态&#xff0c;可以恢复快照使用镜像、快照综合示例 rbd create img1 --size 10G 创建镜像rbd ls 查看镜像 rbd info img1 #查看…

Win32消息机制原理及消息运转

一.消息机制原理 1.消息类型&#xff1a; WIndows定义的一系列WM_XXX开头的&#xff0c;用来表示键盘按键&#xff0c;鼠标点击&#xff0c;窗口变化&#xff0c;用户自定义等各种消息; 2.消息队列&#xff1a; Windows为每一个正在运行的程序维护一个消息队列应用程序的消…

让DroidVNC-NG支持中文输入

DroidVNC-NG支持控制端输入内容&#xff0c;但是仅支持英文字符&#xff0c;如果需要控制输入法软键盘输入中文的话就没办法了&#xff0c;经过摸索找到了解决办法。 这个解决办法有个条件就是让DroidVNC-NG成为系统级应用&#xff08;这个条件比较苛刻&#xff09;&#xff…

【Linux】性能分析器 perf 详解(三)

上一篇:【Linux】性能分析器 perf 详解(二) 1、perf kmem 1.1 简介 kmem 用于跟踪/测量内核内存属性的工具,如分配、释放、碎片率等。可以帮助开发者和系统管理员理解内核内存的分配和释放模式,从而诊断内存泄漏、过度分配等问题。 功能: 跟踪内存分配和释放:监控内…

AI的赚钱风向,彻底变了!

从2023年3月起&#xff0c;生成式AI技术的浪潮席卷全球&#xff0c;让不少人开始焦虑中国AI技术与美国的差距。然而&#xff0c;最近的趋势显示&#xff0c;AI创业的盈利模式已经发生了根本性的变化。今年&#xff0c;我们见证了AIGC&#xff08;人工智能生成内容&#xff09;企…

ExtractAItoTEXT 提取Adobe illustrator AI文件中的文字到文本文件翻译并写回到Adobe illustrator AI文件

Extract Text from Adobe illustrator to text for translate and write back to Adobe illustrator after translate in text file. Originally script from marceloliaohotmail.com during his work in SDL. Updated by me. 从Adobe illustrator中提取文本以进行翻译&#x…

【JavaScript】一键入门

目录 一、JS起源 二、JS特点 三、JS组成部分 四、JS引入方式 一、JS起源 Java Script是由网景公司的Live Script发展而来的一种运行在客户端浏览器上的脚本语言&#xff0c;可以实现网页如文本内容、数据动态变化和动画特效等即浏览器与用户交互的这种体验。 二、JS特点 …

当了面试官才知道:做好这3点,面试成功率至少提高50%

关于辉哥&#xff1a; 资深IT从业者&#xff0c; 曾就职于阿里、腾讯、美团、中信科等互联网公司和央企&#xff1b; 两岁小男孩的父亲。 不定期分享职场 | 婚姻 | 育儿 | 个人成长心得体会 关注我&#xff0c;一起学习和成长。 最近作为公司社招面…

【chatgpt】遗传编程(Genetic Programming, GP)和编译原理的相似之处

遗传编程&#xff08;Genetic Programming, GP&#xff09;和编译原理之间有一些相似之处&#xff0c;主要体现在以下几个方面&#xff1a; 语法树结构&#xff1a; GP&#xff1a;使用语法树&#xff08;Parse Trees&#xff09;来表示程序&#xff0c;其中节点代表操作符或函…

昇思25天学习打卡营第9天|使用静态图加速

一、简介&#xff1a; AI编译框架分为两种运行模式&#xff0c;分别是动态图模式以及静态图模式。MindSpore默认情况下是以动态图模式运行&#xff0c;但也支持手工切换为静态图模式。两种运行模式的详细介绍如下&#xff1a; &#xff08;1&#xff09;动态图&#xff1a; …

JS面试题2——判断变量是不是数组有哪些方法

1. isArray var arr [1,2,3]; console.log( Array.isArray( arr ) ); <script> var arr [1,2,3]; var str 你好; console.log( Array.isArray( arr ) ); // true console.log( Array.isArray( str ) ); // false </script> 2. instanceof var arr [1,2,3]; co…

QQ等级评估源码+软件

今天&#xff0c;我将和大家探讨一个与直播、撸礼物相关的主题&#xff0c;它涉及到的是一种特殊的软件及其源码——QQ等级评估工具。在我们的生活中&#xff0c;直播已经成为了一种越来越流行的娱乐方式。不论是音乐会、电子竞技&#xff0c;还是日常生活分享&#xff0c;你都…

7、广告-流量对接

在程序化广告中&#xff0c;技术的应用至关重要&#xff0c;尤其是流量对接的过程。本章详细介绍DSP与AdX/SSP对接、Trading Desk对接DSP以及PDB对接的技术细节和流程。 流量对接&#xff08;Traffic Integration&#xff09; 流量对接是程序化广告投放中至关重要的一环。它包…

ubuntu22.04 怎么查看visio 的文件

要在Ubuntu 22.04上查看Visio文件&#xff0c;可以使用以下方法之一&#xff1a; 1. 使用LibreOffice Draw LibreOffice Draw可以打开Microsoft Visio文件&#xff08;.vsd和.vsdx&#xff09;。默认情况下&#xff0c;LibreOffice可能已经安装在您的Ubuntu系统上。如果没有&…