Mellanox ConnectX-6-dx智能网卡 openvswitch 流表卸载源码分析

news2024/12/23 18:22:26

Mellanox ConnectX-6-dx智能网卡 具备流表卸载能力。智能网卡的部署方式兼容当前服务器ovs部署方式。而DPU bluefield 2,其要求ovs从服务器上转移到DPU上,这影响现有上层neutron架构,改造量大。

前置信息

OFED代码版本:Linux InfiniBand Drivers。其中, openvswitch版本为2.17.2,dpdk版本为20.11。

卸载主流程

概述

目前,智能网卡ovs流表卸载有两种方式

  • netdev_offload_dpdk卸载。通过用户态网卡驱动进行流表卸载。
  • netdev_offload_tc卸载。通过内核态网卡驱动进行流表卸载。tc-flow是一个现有的内核模块。

netdev_offload_dpdk卸载源码分析

ovs-dpdk中的netdev_offload_dpdk的卸载流程,采用 offload_main线程+工作队列的方式进行异步卸载,避免阻塞包转发线程。

流程图

在这里插入图片描述

代码分析

主流程

// -------- ovs -----------------
// --- ovs vswitchd 主线程 -----------------
// 首包触发卸载,后续包走datapath转发或硬件转发
dp_netdev_flow_add
    dpcls_insert(cls, &flow->cr, &mask);  // datapath缓存流转发规则
	// 入队 卸载任务队列
    queue_netdev_flow_put(pmd, flow, match, actions, actions_len, DP_NETDEV_FLOW_OFFLOAD_OP_ADD);

// --- ovs offload_main 卸载线程 -----
dp_netdev_flow_offload_main    // 通过队列+poll的方式,该线程 异步处理 来自ovs主线程的卸载任务队列。
    dp_offload_flow(offload);
        // netdev offload
        dp_netdev_flow_offload_put  // 单独的一个线程 dp_netdev_flow_offload_main
        netdev_flow_put->flow_ flow_api->flow_put
            netdev_offload_dpdk_flow_put
                netdev_offload_dpdk_add_flow
                    netdev_offload_dpdk_action
                        netdev_offload_dpdk_flow_create
                            netdev_dpdk_rte_flow_create
                                // ---- dpdk rte_flow ----------------------
                                rte_flow_create()
                                 ==>mlx5_flow_create    // dpdk: drivers/net/mlx5/mlx5_flow.c
                                        mlx5_flow_list_create
                                            flow_idx = flow_list_create(dev, type, attr, items, original_actions, 
                                                                        external, wks, error);
                                                flow_drv_translate(dev, dev_flow,&attr_tx, items_tx.items,
                                                                   actions_hairpin_tx.actions, error);
                                                    fops->translate(dev, dev_flow, attr, items, actions, error);
                                                     ==>flow_dv_translate(dev, dev_flow, attr, items, actions, error)  # 详见下方
                                                flow_drv_validate()
                                                flow_drv_apply(dev, flow, error);
                                                    fops->apply(dev, flow, error);
                                                     ==>flow_dv_apply     # 详见下方

// 分析 flow_dv_translate 
	for (; !actions_end ; actions++) {
        // parse action
    }
	dev_flow->act_flags = action_flags;
	flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow, tunnel, attr->group, error)

// 分析 flow_dv_apply
flow_dv_apply
     mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,(void *)&dv->value, n,dv->actions, &dh->drv_flow);
		*flow = mlx5_glue->dv_create_flow(matcher, match_value,num_actions, actions);
			mlx5_glue_dv_create_flow
                mlx5dv_dr_rule_create(matcher, match_value, num_actions,(struct mlx5dv_dr_action **)actions);
                	==>用户态驱动 详见下小节
	                mlx5dv_dr_rule_create(matcher, match_value, num_actions,(struct mlx5dv_dr_action **)actions);
					==>内核态驱动 详见下下小节
					__mlx5_glue_dv_create_flow(matcher, match_value,num_actions, actions_attr);

rdma-core走用户态驱动控制硬件

现有mlx网卡的用户态驱动都放在rdma-core中,因为rdma本身就要求使用用户态驱动,绕过内核TCP/IP协议栈(除非是iWARP)。

// --- rdma-core --------
mlx5dv_dr_rule_create(matcher, match_value, num_actions,(struct mlx5dv_dr_action **)actions);
    dr_rule_create_rule(matcher, value, num_actions, actions);
        dr_rule_create_rule_fdb(rule, &param,num_actions, actions);
            dr_rule_create_rule_nic(rule, &rule->tx, &copy_param,num_actions, actions);
                dr_rule_send_update_list(&send_ste_list, dmn, true, nic_rule->lock_index);
                    dr_rule_handle_one_ste_in_update_list(ste_info,dmn,send_ring_idx);
                        dr_send_postsend_ste(dmn, ste_info->ste, ste_info->data,ste_info->size,
                                             ste_info->offset,send_ring_idx);
                            dr_postsend_icm_data(dmn, &send_info, ring_idx);	
                                dr_post_send(send_ring->qp, send_info);   // 走rdma通道 
                                    /* Write. false, because we delay the post_send_db till the coming READ */
                                    dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey,
                                             &send_info->write, MLX5_OPCODE_RDMA_WRITE, false);
                                    /* Read. true, because we send WRITE + READ together */
                                    dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey,
                                             &send_info->read, MLX5_OPCODE_RDMA_READ, true);

rdma-core走内核态驱动控制硬件(old)

早期网卡没有专门的用户态驱动在用户空间操作硬件。针对这些网卡,mlx在rdma-core用户空间中 封装了一层用户态驱动,其原理是在用户空间通过ioctl/netlink的方式调用 已有的内核驱动。
代码流程如下:
在这里插入图片描述

// --- dpdk ---------------
mlx5_glue_dv_create_flow()
	__mlx5_glue_dv_create_flow(matcher, match_value,num_actions, actions_attr);
// --- rdma mlx5dv_create_flow in rdma-core providers/mlx5/verbs.c ---
	dvops->create_flow(flow_matcher,match_value,num_actions,actions_attr,NULL);
        _mlx5dv_create_flow
            fill_attr_in_uint32(cmd,MLX5_IB_ATTR_CREATE_FLOW_FLAGS,MLX5_IB_ATTR_CREATE_FLOW_FLAGS_DEFAULT_MISS);
            execute_ioctl(flow_matcher->context, cmd); // call kernel ioctl
// --- kernel space -- mlx5_ib.ko mlx_core.ko -------------
// ib_core dispatch message to mlx5_ib
UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)   // drivers/infiniband/hw/mlx5/fs.c
	get_dests
    	uverbs_get_flags32
    		uverbs_get_flags64(&flags, attrs_bundle, idx, allowed_bits);
            raw_fs_rule_add(dev, fs_matcher, &flow_context, &flow_act,counter_id, cmd_in, inlen, dest_id, dest_type);
                _create_raw_flow_rule
                    mlx5_add_flow_rules(ft, spec,flow_act, dst, dst_num);  // drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
                        rule = add_rule_fg(g, spec, flow_act, dest, dest_num, fte);
                            handle = add_rule_fte(fte, fg, dest, dest_num,old_action != flow_act->action);
                                root->cmds->update_fte(root, ft, fg, modify_mask, fte)
                                    mlx5_cmd_update_fte
                                        mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, fg->id, fte);
                                            mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
                                                mlx5_cmd_do(dev, in, in_size, out, out_size);
                                                    cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, false);
                                                        cmd_work_handler
                                                            lay = get_inst(cmd, ent->idx);
                                                                return cmd->cmd_buf + (idx << cmd->log_stride);
                                                            memset(lay, 0, sizeof(*lay));
                                                            memcpy(lay->in, ent->in->first.data, sizeof(lay->in));
                                                            lay->status_own = CMD_OWNER_HW; // transfer ownership to hardware
                                                            iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell);
                                                            // polling reg for completion
                                                            mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, ent->ret == -ETIMEDOUT ?
                                                                      MLX5_CMD_COMP_TYPE_FORCED : MLX5_CMD_COMP_TYPE_POLLING);

netdev_offload_tc卸载源码分析

netdev_offload_tc内核卸载是通过tc-flow模块。

流程图

在这里插入图片描述

代码分析

// ovs kernel datapath 路径
// -- user space ---
dpif_netlink_operate
 -->try_send_to_netdev   // 先卸载。这里会卡住。
    dpif_netlink_operate_chunks // 再转发
	    dpif_netlink_operate__
    		dpif_netlink_init_flow_put  // netlink
// -- kernel space ---
    ovs_flow_cmd_new()
    	ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
		ovs_flow_tbl_insert(&dp->table, new_flow, &mask);

// ovs卸载路径
// --- user space ---
dpif_netlink_operate
    try_send_to_netdev
		parse_flow_put(dpif, put);
			netdev_flow_put(dev, &match,...)
			flow_api->flow_put(netdev,...netdev_tc_flow_put()
					tc_replace_flower(&id, &flower);   // netlink 通信。组装tc-flow指令给tc内核模块
// --- kernel space ------
tc_ctl_tfilter // tc module。不属于ovs代码
    // 代表口卸载
    mlx5e_rep_indr_setup_tc_cb  // mlx5_core.ko
        mlx5e_rep_indr_offload(priv->netdev, type_data, priv,flags);
            mlx5e_configure_flower(netdev, priv, flower, flags)
                mlx5e_tc_add_flow(priv, f, flags, dev, &flow);
                    mlx5e_add_fdb_flow(priv, f, flow_flags,filter_dev, flow);
                        mlx5e_tc_offload_fdb_rules
                            mlx5_eswitch_add_offloaded_rule
                             ==>mlx5_add_flow_rules   //与 rte_flow/ib一样的底层调用接口
                               
// data structure
const struct net_device_ops mlx5e_netdev_ops = {
    .ndo_setup_tc            = mlx5e_setup_tc,
}

netdev_offload_dpdk卸载 vs netdev_offload_tc卸载对比

  • 异步IO方式。netdev_offload_dpdk卸载是异步的由专门的线程offload_main处理。而tc-flow内核卸载是同步,卸载面会卡住数据面。netdev_offload_tc卸载依赖netlink系统调用通道,其依赖发送等待应答机制,发消息后还要等待应答。而且netdev_offload_tc使用。
  • 进(线)程间通信方式。netdev_offload_dpdk线程间的通信方式是共享内存(无锁队列)的方式,ovs-pmd与offload_main线程直接内存交互,无需系统调用。而netdev_offload_tc卸载是通过netlink系统调用与内核态网卡驱动交互。
  • CPU核隔离。netdev_offload_dpdk卸载隔离业务面与数据面。netdev_offload_dpdk卸载及其相应的转发面(ovs-dpdk)都是运行在专门的核上,不会抢占业务核。
  • netdev_offload_dpdk适合高并发的模型。netdev_offload_tc是netlink交互,netlink通道可成为性能瓶颈。
  • 隔离内核空间。避免卡内核bug

ovs revalidato线程分析

ovs revalidator 负责更新每条已卸载流的统计,以及异步删除超时流。
对于已卸载到硬件的流表,其流统计信息存于硬件寄存器中。ovs revalidator线程中会定时轮询,从硬件寄存器中获取流统计信息。

流程图

在这里插入图片描述

代码分析

udpif_revalidator()
    revalidate(revalidator);
        dpif_flow_dump_next
            dpif->dpif_class->flow_dump_next(thread, flows, max_flows);
                dpif_netdev_flow_dump_next
                    dp_netdev_flow_to_dpif_flow
                        get_dpif_flow_status()
                            dpif_netdev_get_flow_offload_status()
                                netdev_offload_dpdk_flow_get
                                    netdev_dpdk_rte_flow_query_count
                                     ==>rte_flow_query()
// --- rte_flow_query in dpdk -----------
rte_flow_query
	flow_dv_query
		flow_dv_query_count
			_flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
				cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
					MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);  // 直接读硬件统计寄存器

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

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

相关文章

Scratch 猴子踢球

scratch 猴子踢球 本程序转为HTML后运行&#xff0c;“猴子”角色跟随鼠标移动&#xff0c;“沙滩球”角色开始时生成20个并移动到随机位置&#xff0c;在碰到“猴子”角色时开始移动&#xff0c;碰到边缘或其它角色时反弹。 图形化程序如下 “沙滩球”角色 “猴子”角色

spring 详解四 IOC(spring Bean生命周期)

spring生命周期概述 spring Bean的生命周期是从Bean实例化之后&#xff0c;即通过反射创建对象之后&#xff0c;到Bean成为一个完整对象&#xff0c;最终存储在单例池中&#xff0c;然后在销毁的过程被称为spring Bean的生命周期&#xff0c;这部分不会介绍销毁过程&#xff0…

Spring限流之限流方案分析

文章目录 1 限流方案1.1 引言1.2 常用限流策略1.3 基于guava限流实现1.3.1 引入guava依赖1.3.2 自定义限流注解1.3.3 限流AOP类1.3.4 测试接口 1.4 基于sentinel限流实现1.4.1 引入sentinel核心依赖包1.4.2 自定义限流注解1.4.3 自定义AOP类实现限流1.4.4 自定义测试接口 1.5 基…

独立和相关(线性)的关系

相关(线性)>不独立 不相关(线性) 推不出 独立 (是因为不一定线性相关,可以沿曲线相关)

一起学SF框架系列5.7-模块Beans-BeanDefinition解析

开发人员按元数据规则定义了应用bean&#xff0c;了解SF如何根据定义解析成BeanDefiniton有助于深入理解框架实现。解析过程如下&#xff1a; 资源加载 从资源文件加载bean的元数据配置&#xff0c;实际过程如下图&#xff1a; 实际从指定的XML文件加载bean定义是从XmlBeanD…

电脑pdf如何转换成word格式?分享这三个方法给大家!

记灵在线工具是一个非常方便的PDF转Word工具&#xff0c;它可以帮助用户快速、准确地将PDF文件转换为Word格式。以下是使用步骤&#xff1a; 打开您的网络浏览器&#xff0c;访问记灵在线工具的官方网站。 在首页上找到并点击“PDF转Word”选项。 在新打开的页面中&#xff0…

如何在 SwiftUI 中配置 SwiftData

文章目录 前言创建模型模式和版本控制迈出关键的一步创建迁移计划创建模型容器从视图中查询模型从视图中访问模型上下文总结 前言 在 WWDC 2023 上&#xff0c;Apple 宣布了一个备受期待的新持久性刷新&#xff0c;以一种新的框架形式出现&#xff1a;SwiftData。SwiftData 从…

【设计模式】设计模式前置知识:UML类图入门

UML类图 介绍 UML–Unified modeling language UMl(统一建模语言)&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c;它用于帮助软件开发人员进行思考和记录思路的结果UML本身是一套符号的规定&#xff0c;就像数学符号和化学符号一样&#xff0c;这些符号用于…

来啦!OceanBase 第7期技术征文活动获奖名单公布!

“小鱼”的诞生与成长离不开广大开发者的陪伴与支持&#xff0c;我们非常兴奋能把 4.1 版本的这一系列新能力带给大家&#xff0c;“小鱼”会游得更快更远&#xff0c;也会陪伴更多数据库开发者一同成长。 OceanBase 联合墨天轮技术社区&#xff0c;举行「4.1 上手体验」第五届…

基于SpringBoot+Hadoop+Vue的企业网盘系统

完整资料进入【数字空间】查看——baidu搜索"writebug" 1.1.1 选题的背景 随着信息网络技术的迅猛发展&#xff0c;云计算技术从它的概念提出已经开始在实际生产环境中使用了。大部分的东西都已经慢慢云端化&#xff0c;这种新型的技术也受到许多互联网人员的关注&a…

初阶C语言——三子棋

我们今天讲一个小游戏&#xff0c;三子棋大家应该都玩过吧&#xff0c;就是行和列&#xff0c;或者对角线上有一样大的字符时&#xff0c;就为获胜&#xff0c;今天我们就来写这样的一个代码实现这样的功能 首先我们要创建两个源文件和一个头文件 头文件game.h用来包含我们的头…

EmEditor制表符设置为空格

以下是具体操作 工具 - 当前配置属性 - 常规 - 制表符/缩进 - 将制表符转换为空格 前打对钩

作业怎么清除试卷笔迹?拿捏可以擦除答案的方法

在日常学习中&#xff0c;我们经常会遇到需要修改或擦除试卷上的笔迹的情况。本文将介绍一种简单实用的方法&#xff0c;即使用手机拍照扫描试卷并擦除答案。 手机拍照扫描试卷 首先&#xff0c;我们需要使用手机拍照扫描试卷。这一步非常简单&#xff0c;只需要将试卷平铺在桌…

集成学习-BaggingVoting和多个模型的混淆矩阵

当涉及到集成学习时&#xff0c;投票法和袋装法是两种常见的技术&#xff0c;用于将多个基学习器&#xff08;base learner&#xff09;组合成一个强大的集成模型。 投票法&#xff08;Voting&#xff09;&#xff1a;投票法是一种简单且常用的集成学习方法。在投票法中&#…

Django_设置和读取cookie

设置cookie 在响应对象中使用set_cookie方法设置cookie from django.http import HttpResponsedef set_cookie(request):rsp HttpResponse("set cookie")rsp.set_cookie("set_cookie", "hello python", max_age3600)return rsp 注&#xff1…

Latex更改字体颜色以及快速生成 SCI 论文的 revised version 和 pure version

记录一下如何更改 Latex 字体颜色&#xff0c;在返修 SCI 论文时&#xff0c;如何较为快捷地完成 revised version 和 pure version 两个不同版本修改稿件的编辑与生成。 更改字体颜色 导入宏包 在 LaTeX 中&#xff0c;使用 \textcolor 命令或 \color 命令可以改变文本的颜…

十大机器学习算法之一:线性回归

十大机器学习算法之一&#xff1a;线性回归 1 知识预警1.1 线性代数1.2 矩阵微积分 2 什么是回归分析&#xff1f;3 线性回归3.1 一元线性回归3.2 多元线性回归 4 多项式回归 1 知识预警 1.1 线性代数 ( A T ) T A (A^\mathrm{T})^\mathrm{T}A (AT)TA$ ( A B ) T A T B T…

OpenHarmony社区运营报告(2023年6月)

本月快讯 • 6月12日&#xff0c;以“OpenHarmony共建开放&#xff0c;共享未来”为主题的2023开放原子全球开源峰会OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;分论坛在北京北人亦创国际会展中心第一报告厅圆满落幕&#xff0c;根深叶茂&#xff0c…

【Java】面向对象编程 面向对象基础

一、面向对象基础 面向对象编程&#xff0c;是一种通过对象的方式&#xff0c;把现实世界映射到计算机模型的一种编程方法。 现实世界中&#xff0c;我们定义了“人”这种抽象概念&#xff0c;而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以&#xff0c;…

uni-app 从零开始第三章:底部 tabBar

pages.json 页面路由 | uni-app官网 一、新建 home页面 找到pages目录&#xff0c;新增一个home的页面&#xff0c;勾选上同时新建文件夹 新建完成后&#xff0c;pages.json 中 会自动添加上刚刚新建的文件信息 二、新增tabBar数据 在 pages.json中新增以下代码 "tabB…