Open vSwitch 行为匹配的实现

 一、Datapath 模块的行为匹配

        在 Open vSwitch 的数据包转发流程中,存在快速路径和慢速路径两种模式,如下图所示:

        其中,快速路径直接在 Datapath 模块完成行为匹配,将数据包转发出去。而慢速路径的数据包无法在 Datapath 模块完全处理,需要通过 upcall 调用将数据包交给用户空间的 vswitchd 守护进程,但是最终守护进程会将处理后的数据包和流表发回 Datapath 模块,然后再次进行行为匹配和数据包的转发。

        对于快速路径而言,行为匹配发生在 Datapath 模块接收和检查筛选之后,即在数据包处理 ovs_dp_process_packet() 函数中调用:

void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) {......error = ovs_execute_actions(dp, skb, sf_acts, key);......
}

        对于慢速路径而言,行为匹配发生在流表下发到 Datapath 模块和数据包通过 reinject 发回之后,即在数据包接收和执行 ovs_packet_cmd_execute() 函数中调用:

static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) {......err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);......
}

        相应的调用关系如下图所示:

        也就是说,无论是快速路径还是慢速路径,最终都会由 Datapath 模块进行行为匹配,只不过不同的路径需要走不同的流程,会有不同的函数实现。

二、行为匹配 ovs_execute_actions()

        函数 ovs_execute_actions() 是 Datapath 模块的核心部分,主要负责行为的匹配和执行,存储在 ovs-main/datapath/actions.c 文件中:

/* Execute a list of actions against 'skb'. */
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, const struct sw_flow_actions *acts, struct sw_flow_key *key) {int err, level;level = __this_cpu_inc_return(exec_actions_level);if (unlikely(level > OVS_RECURSION_LIMIT)) {net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n", ovs_dp_name(dp));kfree_skb(skb);err = -ENETDOWN;goto out;}OVS_CB(skb)->acts_origlen = acts->orig_len;err = do_execute_actions(dp, skb, key, acts->actions, acts->actions_len);if (level == 1)process_deferred_actions(dp);out:__this_cpu_dec(exec_actions_level);return err;
}

        函数的第一个输入参数 struct datapath *dp 表示 datapath 对象(代表一个 Open vSwitch 实例在内核空间的实现),第二个输入参数 struct sk_buff *skb 表示要处理的数据包,第三个输入参数 const struct sw_flow_actions *acts 表示要执行的动作,第四个输入参数 struct sw_flow_key *key 表示数据包的流关键字信息。

        函数首先维护一个当前 CPU 核心的 exec_actions_level 计数器,并进行一些预处理。然后调用 do_execute_actions(dp, skb, key, acts->actions, acts->actions_len) 函数来执行动作列表,并通过判断 exec_actions_level 计数器的值来限制递归次数。最后如果 exec_actions_level 计数器的值为 1 即表示最外层调用,则调用 process_deferred_actions(dp) 函数来处理延迟的动作。

Tips:这里的 exec_actions_level 计数器主要用于递归限制
        Open vSwitch 的 Datapath 模块支持递归执行,以处理嵌套的动作。但为了防止无限递归,代码设置了 OVS_RECURSION_LIMIT 的限制。如果递归深度超过该限制,则会打印警告日志,释放数据包,并返回相应错误码 -ENETDOWN。

Tips:延迟动作处理

        数据包的某些行为在匹配完成后,可能需要在后续处理过程中执行而不是立即执行(比如转发行为)。对于 Datapath 模块而言,这些行为会被推迟到最外层调用时统一处理,由 process_deferred_actions() 函数负责处理这些延迟的动作,该函数存储在 ovs-main/datapath/actions.c 文件中:

static void process_deferred_actions(struct datapath *dp) {struct action_fifo *fifo = this_cpu_ptr(action_fifos);/* Do not touch the FIFO in case there is no deferred actions. */if (action_fifo_is_empty(fifo))return;/* Finishing executing all deferred actions. */do {struct deferred_action *da = action_fifo_get(fifo);struct sk_buff *skb = da->skb;struct sw_flow_key *key = &da->pkt_key;const struct nlattr *actions = da->actions;int actions_len = da->actions_len;if (actions)do_execute_actions(dp, skb, key, actions, actions_len);elseovs_dp_process_packet(skb, key);} while (!action_fifo_is_empty(fifo));/* Reset FIFO for the next packet.  */action_fifo_init(fifo);
}

三、行为执行 do_execute_actions()

        函数 do_execute_actions() 的主要作用是针对不同的数据包类型执行相应的行为,存储在 ovs-main/datapath/actions.c 文件中:

/* Execute a list of actions against 'skb'. */
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, int len) {const struct nlattr *a;int rem;for (a = attr, rem = len; rem > 0; a = nla_next(a, &rem)) {int err = 0;switch (nla_type(a)) {case OVS_ACTION_ATTR_OUTPUT: {int port = nla_get_u32(a);struct sk_buff *clone;/* Every output action needs a separate clone of 'skb', In case the output action is the last action, cloning can be avoided. */if (nla_is_last(a, rem)) {do_output(dp, skb, port, key);/* 'skb' has been used for output. */return 0;}clone = skb_clone(skb, GFP_ATOMIC);if (clone)do_output(dp, clone, port, key);OVS_CB(skb)->cutlen = 0;break;}case OVS_ACTION_ATTR_TRUNC: {struct ovs_action_trunc *trunc = nla_data(a);if (skb->len > trunc->max_len)OVS_CB(skb)->cutlen = skb->len - trunc->max_len;break;}case OVS_ACTION_ATTR_USERSPACE:output_userspace(dp, skb, key, a, attr, len, OVS_CB(skb)->cutlen);OVS_CB(skb)->cutlen = 0;break;case OVS_ACTION_ATTR_HASH:execute_hash(skb, key, a);break;case OVS_ACTION_ATTR_PUSH_MPLS:err = push_mpls(skb, key, nla_data(a));break;case OVS_ACTION_ATTR_POP_MPLS:err = pop_mpls(skb, key, nla_get_be16(a));break;case OVS_ACTION_ATTR_PUSH_VLAN:err = push_vlan(skb, key, nla_data(a));break;case OVS_ACTION_ATTR_POP_VLAN:err = pop_vlan(skb, key);break;case OVS_ACTION_ATTR_RECIRC: {bool last = nla_is_last(a, rem);err = execute_recirc(dp, skb, key, a, last);if (last) {/* If this is the last action, the skb has been consumed or freed.* Return immediately. */return err;}break;}case OVS_ACTION_ATTR_SET:err = execute_set_action(skb, key, nla_data(a));break;case OVS_ACTION_ATTR_SET_MASKED:case OVS_ACTION_ATTR_SET_TO_MASKED:err = execute_masked_set_action(skb, key, nla_data(a));break;case OVS_ACTION_ATTR_SAMPLE: {bool last = nla_is_last(a, rem);err = sample(dp, skb, key, a, last);if (last)return err;break;}case OVS_ACTION_ATTR_CT:if (!is_flow_key_valid(key)) {err = ovs_flow_key_update(skb, key);if (err)return err;}err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, nla_data(a));/* Hide stolen IP fragments from user space. */if (err)return err == -EINPROGRESS ? 0 : err;break;case OVS_ACTION_ATTR_CT_CLEAR:err = ovs_ct_clear(skb, key);break;case OVS_ACTION_ATTR_PUSH_ETH:err = push_eth(skb, key, nla_data(a));break;case OVS_ACTION_ATTR_POP_ETH:err = pop_eth(skb, key);break;case OVS_ACTION_ATTR_PUSH_NSH: {u8 buffer[NSH_HDR_MAX_LEN];struct nshhdr *nh = (struct nshhdr *)buffer;err = nsh_hdr_from_nlattr(nla_data(a), nh, NSH_HDR_MAX_LEN);if (unlikely(err))break;err = push_nsh(skb, key, nh);break;}case OVS_ACTION_ATTR_POP_NSH:err = pop_nsh(skb, key);break;case OVS_ACTION_ATTR_METER:if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) {consume_skb(skb);return 0;}break;case OVS_ACTION_ATTR_CLONE: {bool last = nla_is_last(a, rem);err = clone(dp, skb, key, a, last);if (last)return err;break;}case OVS_ACTION_ATTR_CHECK_PKT_LEN: {bool last = nla_is_last(a, rem);err = execute_check_pkt_len(dp, skb, key, a, last);if (last)return err;break;}}if (unlikely(err)) {kfree_skb(skb);return err;}}consume_skb(skb);return 0;
}

        函数的第一个输入参数 struct datapath *dp 表示 datapath 对象(代表一个 Open vSwitch 实例在内核空间的实现),第二个输入参数 struct sk_buff *skb 表示要处理的数据包,第三个输入参数 struct sw_flow_key *key 表示数据包的流关键字信息,第四个输入参数 const struct nlattr *attr 表示要执行的操作列表,第五个输入参数 int len 表示操作列表的长度。

        函数使用 for 循环遍历操作列表,对于每个操作而言,它都会根据 nla_type(a) 类型执行相应的行为。支持的操作类型包括:

  • OVS_ACTION_ATTR_OUTPUT 将数据包发送到指定端口
  • OVS_ACTION_ATTR_TRUNC 截断数据包长度
  • OVS_ACTION_ATTR_USERSPACE 将数据包发送到用户空间
  • OVS_ACTION_ATTR_HASH 计算数据包的哈希值
  • OVS_ACTION_ATTR_PUSH_MPLS 为数据包添加 MPLS 头部
  • OVS_ACTION_ATTR_POP_MPLS 从数据包中删除 MPLS 头部
  • OVS_ACTION_ATTR_PUSH_VLAN 为数据包添加 VLAN 头部
  • OVS_ACTION_ATTR_POP_VLAN 从数据包中删除 VLAN 头部
  • OVS_ACTION_ATTR_RECIRC 重新循环处理数据包
  • OVS_ACTION_ATTR_SET 设置数据包的特定字段
  • OVS_ACTION_ATTR_SET_MASKED 使用掩码设置数据包的特定字段
  • OVS_ACTION_ATTR_SAMPLE 对数据包进行采样操作
  • OVS_ACTION_ATTR_CT 执行连接跟踪操作
  • OVS_ACTION_ATTR_CT_CLEAR 清除数据包的连接跟踪状态
  • OVS_ACTION_ATTR_PUSH_ETH 为数据包添加以太网头部
  • OVS_ACTION_ATTR_POP_ETH 从数据包中删除以太网头部
  • OVS_ACTION_ATTR_PUSH_NSH 为数据包添加 NSH (网络服务头) 头部
  • OVS_ACTION_ATTR_POP_NSH 从数据包中删除 NSH 头部
  • OVS_ACTION_ATTR_METER 执行数据包计量操作
  • OVS_ACTION_ATTR_CLONE 克隆数据包
  • OVS_ACTION_ATTR_CHECK_PKT_LEN 检查数据包长度

        对于每个操作而言,如果执行过程中发生错误,则直接释放数据包并返回错误代码。如果所有操作都执行成功,则最终释放原始数据包。 

总结:

        在 Open vSwitch 的 Datapath 模块中,主要通过 ovs_execute_actions() 函数进行相应行为的匹配和执行,这是数据包在 Datapath 模块中必须执行的步骤。

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

参考资料:

Open vSwitch 官网

Open vSwitch 源代码 GitHub

Open vSwitch 数据包接收的实现-CSDN博客

Open vSwitch 的 reinject 数据包发回-CSDN博客

Open vSwitch v2.17.10 LTS 源代码

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

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

相关文章

厦门新能安科技Ampace校招实习待遇及Verify测评SHL演绎数字推理历年真题题库

一、厦门新能安科技公司介绍 厦门新能安科技有限公司主要业务包括电池制造和销售,电容器及其配套设备制造与销售,电池零配件生产与销售。此外,公司还提供包括技术服务、技术开发、技术咨询、技术交流、技术转让和技术推广在内的全方位服务。公…

HarmonyOS Next开发学习手册——选项卡 (Tabs)

当页面信息较多时,为了让用户能够聚焦于当前显示的内容,需要对页面内容进行分类,提高页面空间利用率。 Tabs 组件可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息…

微软推出集成GPT-4o的文本转语音虚拟数字人服务

微软近日宣布,其全新的文本转语音虚拟数字人服务正式上线,并集成了GPT-4o技术。这一服务为用户提供了创建实时互动数字人的可能。通过先进的自然语言处理技术,数字人能够将文本转化为自然流畅的语音,并配以生动的虚拟形象&#xf…

[数据集][目标检测]猪只状态吃喝睡站检测数据集VOC+YOLO格式530张4类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):530 标注数量(xml文件个数):530 标注数量(txt文件个数):530 标注类别…

在Redis中使用Lua脚本实现多条命令的原子性操作

Redis作为一个高性能的键值对数据库,被广泛应用于各种场景。然而,在某些情况下,我们需要执行一系列Redis命令,并确保这些命令的原子性。这时,Lua脚本就成为了一个非常实用的解决方案。 问题的提出 假设我们有一个计数…

爱奇艺 Opal 机器学习平台:特征中心建设实践

01 综述 Opal 是爱奇艺大数据团队研发的一站式机器学习平台,旨在提升特征迭代、模型训练效率,帮助业务提高收益。整个平台覆盖了机器学习生命周期中特征生产、样本构建、模型探索、模型训练、模型部署等在内的多个关键环节。其中特征作为模型训练的基石…

基于星火大模型的群聊对话分角色要素提取挑战赛-Lora微调与prompt构造

赛题连接 https://challenge.xfyun.cn/topic/info?typerole-element-extraction&optionphb 数据集预处理 由于赛题官方限定使用了星火大模型,所以只能调用星火大模型的API或者使用零代码微调 首先训练数据很少是有129条,其中只有chat_text和info…

【Mac】Listen 1 for Mac(最强的音乐搜索工具)软件介绍

软件介绍 Listen 1 for Mac 是一款非常方便的音乐播放软件,主要功能是集成多个音乐平台,让用户可以方便地搜索、播放和管理音乐。它是一个用 Python 语言开发的免费开源综合音乐搜索工具项目,最大的亮点在于可以搜索和播放来自网易云音乐&am…

实用的vueuseHooks,提高编码效率

文章目录 写在前面vueuse 官网安装HooksuseStorage [地址](https://vueuse.org/core/useStorage/)传统方法数据持久化 举例子传统持久化的弊端useStorage 数据持久化 举例子使用useStorage 更改存储数据使用useStorage 删除存储数据 useScriptTag [地址](https://vueuse.org/co…

matlab中simulink仿真软件的基础操作

(本内容源自《详解MATLAB/SIMULINK 通信系统建模与仿真》 刘学勇编著的第二章内容,有兴趣的可以阅读该书) 例:简单系统输入为两个不同频率的正弦、余弦信号,输出为两信号之和,建立模型。 在…

论文阅读_OpenAI嵌入+Lucene

英文名称: Vector Search with OpenAI Embeddings: Lucene Is All You Need 中文名称: 使用OpenAI嵌入进行向量搜索:只需Lucene 链接: http://arxiv.org/abs/2308.14963v1 作者: Jimmy Lin, Ronak Pradeep, Tommaso Teofili, Jasper Xian 机构: 滑铁卢大学戴维切里顿…

锁机制 -- 概述篇

锁机制 1、概述 ​  加锁是为了解决并发场景下,多个线程对同一资源同时进行操作,而导致同一线程多次操作出现结果不唯一的情况(一次操作包含多条指令)。结果不唯一发生的原因在于指令的错乱,前提条件是多线程环境及…

双指针算法第一弹(移动零 复写零 快乐数)

目录 前言 1. 移动零 (1)题目及示例 (2)一般思路 (3)双指针解法 2. 复写零 (1)题目及示例 (2)一般解法 (3)双指针解法 3. 快…

Hadoop 安装与伪分布的搭建

目录 1 SSH免密登录 1.1 修改主机名称 1.2 修改hosts文件 1.3 创建hadoop用户 1.4 生成密钥对免密登录 2 搭建hadoop环境与jdk环境 2.1 将下载好的压缩包进行解压 2.2 编写hadoop环境变量脚本文件 2.3 修改hadoop配置文件,指定jdk路径 2.4 查看环境是否搭建完成 3 …

基于Spring Boot的药房信息管理系统

1 项目介绍 1.1 研究的背景及意义 随着社会的飞速进步和药房行业竞争的白热化,传统的手工管理模式已难以适应药房信息管理的现代化需求。在计算机科学技术日臻完善的背景下,药房信息管理者们日益认识到运用计算机技术进行信息管理的迫切性和重要性。计…

快手正式推出Vision Pro版本,引领虚拟现实社交新潮流

6月28日,快手正式推出其专为Apple Vision Pro打造的版本——快手vp版app,成为国内首批登陆Apple Vision Pro的短视频平台。 借助先进的虚拟现实技术,用户可以在快手上体验更真实生动的视频内容,无论是观看趣味短视频内容&#xf…

产品是应该有生命力的

产品是应该有生命力的 在日新月异的商业环境中,产品被寄予厚望,不仅仅满足基本功能需求,而是要能够自我革新,适应市场和技术的快速变化,以及持续吸引并留住用户。 这种生命力体现在产品的迭代升级能力、对用户需求的精…

[鹏城杯 2022]babybit

发现一个压缩包提取出来提取出来两个压缩包里面是注册表使用MiTeC Windows Registry Recovery 恢复注册表 flag在ROOT\ControlSet001\Control\FVEStats里的OsvEncryptInit和OsvEncryptComplete中 NSSCTF{2022/6/13_15:17:39_2022/6/13_15:23:46}

互联网信任危机:Perplexity搜索引擎如何破坏内容创作者的权益

前段时间,Perplexity搜索引擎还是一颗冉冉升起的明日之星,手握巨额投资,有很美好的未来前景,这时,如果不出意外的话,要出意外。 喜好儿网 Perplexity这家公司,它正试图通过创建一个新型的“答…

LoRaWAN网关源码分析(基础概念篇)

目录 一、简介 1、lora_gateway 2、packet_forwarder 二、目录结构 1、lora_gateway 2、packet_forwarder 一、简介 LoRaWAN网关的实现主要依赖两个源代码:lora_gateway和packet_forwarder。接下来,我们将从分析源代码入手,移植LoRaWAN源…