【C语言】ipoib驱动 - ipoib_cm_handle_rx_wc_rss

一、ipoib_cm_handle_rx_wc_rss函数定义

void ipoib_cm_handle_rx_wc_rss(struct net_device *dev, struct ib_wc *wc)
{
    struct ipoib_dev_priv *priv = ipoib_priv(dev);
    struct ipoib_cm_rx_buf *rx_ring;
    unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
    struct sk_buff *skb, *newskb;
    struct ipoib_cm_rx *p;
    unsigned long flags;
    u64 mapping[IPOIB_CM_RX_SG];
    int frags;
    int has_srq;
    struct sk_buff *small_skb;
    ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
               wr_id, wc->status);
    if (unlikely(wr_id >= priv->recvq_size)) {
        if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~(IPOIB_OP_CM | IPOIB_OP_RECV))) {
            spin_lock_irqsave(&priv->lock, flags);
            list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list);
            ipoib_cm_start_rx_drain(priv);
            queue_work(priv->wq, &priv->cm.rx_reap_task);
            spin_unlock_irqrestore(&priv->lock, flags);
        } else
            ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n",
                   wr_id, priv->recvq_size);
        return;
    }
    p = wc->qp->qp_context;
    has_srq = ipoib_cm_has_srq(dev);
    rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring;
    skb = rx_ring[wr_id].skb;
    if (unlikely(wc->status != IB_WC_SUCCESS)) {
        ipoib_dbg(priv, "cm recv error "
               "(status=%d, wrid=%d vend_err %x)\n",
               wc->status, wr_id, wc->vendor_err);
        ++priv->recv_ring[p->index].stats.rx_dropped;
        if (has_srq)
            goto repost;
        else {
            if (!--p->recv_count) {
                spin_lock_irqsave(&priv->lock, flags);
                list_move(&p->list, &priv->cm.rx_reap_list);
                spin_unlock_irqrestore(&priv->lock, flags);
                queue_work(priv->wq, &priv->cm.rx_reap_task);
            }
            return;
        }
    }
    if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
        if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
            spin_lock_irqsave(&priv->lock, flags);
            p->jiffies = jiffies;
            /* Move this entry to list head, but do not re-add it
             * if it has been moved out of list. */
            if (p->state == IPOIB_CM_RX_LIVE)
                list_move(&p->list, &priv->cm.passive_ids);
            spin_unlock_irqrestore(&priv->lock, flags);
        }
    }
    if (wc->byte_len < IPOIB_CM_COPYBREAK) {
        int dlen = wc->byte_len;
        small_skb = dev_alloc_skb(dlen + IPOIB_CM_RX_RESERVE);
        if (small_skb) {
            skb_reserve(small_skb, IPOIB_CM_RX_RESERVE);
            ib_dma_sync_single_for_cpu(priv->ca, rx_ring[wr_id].mapping[0],
                           dlen, DMA_FROM_DEVICE);
            skb_copy_from_linear_data(skb, small_skb->data, dlen);
            ib_dma_sync_single_for_device(priv->ca, rx_ring[wr_id].mapping[0],
                              dlen, DMA_FROM_DEVICE);
            skb_put(small_skb, dlen);
            skb = small_skb;
            goto copied;
        }
    }
    frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
                          (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
    newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags,
                       mapping, GFP_ATOMIC);
    if (unlikely(!newskb)) {
        /*
         * If we can't allocate a new RX buffer, dump
         * this packet and reuse the old buffer.
         */
        ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id);
        ++priv->recv_ring[p->index].stats.rx_dropped;
        goto repost;
    }
    ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping);
    memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
    ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
               wc->byte_len, wc->slid);
    skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb);
copied:
    skb->protocol = ((struct ipoib_header *) skb->data)->proto;
    skb_add_pseudo_hdr(skb);
    ++priv->recv_ring[p->index].stats.rx_packets;
    priv->recv_ring[p->index].stats.rx_bytes += skb->len;
    skb->dev = dev;
    /* XXX get correct PACKET_ type here */
    skb->pkt_type = PACKET_HOST;
    netif_receive_skb(skb);
repost:
    if (has_srq) {
        if (unlikely(ipoib_cm_post_receive_srq_rss(dev,
                            p->index,
                            wr_id)))
            ipoib_warn(priv, "ipoib_cm_post_receive_srq_rss failed "
                   "for buf %d\n", wr_id);
    } else {
        if (unlikely(ipoib_cm_post_receive_nonsrq_rss(dev, p,
                                  wr_id))) {
            --p->recv_count;
            ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq_rss failed "
                   "for buf %d\n", wr_id);
        }
    }
}

二、解读

这个函数 ipoib_cm_handle_rx_wc_rss 是处理 IP over InfiniBand (IPoIB) 在连通模式(Connected Mode, CM)下收到的网络包的函数。它利用了RSS功能来实现多核CPU处理网络流量的分发。在InfiniBand网络中,Completion Work Queues(CQ)包含用来标识网络操作完成情况的工作完成结构(Work Completion, WC)。当一个接收操作完成后,会调用这个函数来处理WC。以下是函数的详细描述:
1. 函数接收两个参数:
   - *dev: 指向`net_device`结构体的指针,与InfiniBand设备相关联。
   - *wc: 指向`ib_wc` (IB Work Completion)结构体的指针,它包含了完成接收操作的状态信息。
2. 函数首先通过调用`ipoib_priv(dev)`获取到针对`net_device`的私有IPoIB结构(ipoib_dev_priv)的指针。
3. wr_id是工作请求的ID,通过将WC的`wr_id`字段与定义好的掩码进行逻辑与操作,去除特定的标记位(如 IPOIB_OP_CM 和 IPOIB_OP_RECV)。
4. 如果`wr_id`超出了接收队列(recvq_size)的大小范围,那么会打印一条警告信息,并且根据情况要么处理排干(drain)操作,要么直接返回。
5. wc->qp->qp_context获取到了与此WC相关的队列对(Queue Pair, QP)上下文,这通常是一个指向`ipoib_cm_rx`结构体的指针。
6. has_srq变量用来检测当前设备是否使用了共享接收队列(Shared Receive Queue, SRQ)。根据这个变量的值,`rx_ring`变量会指向不同的接收缓冲区。
7. 接下来,根据`wr_id`在接收缓冲区中找到与此WC关联的socket缓冲区(sk_buff,简称skb)。
8. 如果`wc->status`不等于`IB_WC_SUCCESS`,表示接收操作出错,它会递增丢包计数,并根据是否使用SRQ采取不同的行动。
9. 如果`wr_id`满足特定条件,定期将对应的`ipoib_cm_rx`结构移动到活着的ID列表中。
10. 如果接收到的包的长度小于`IPOIB_CM_COPYBREAK`(一种阈值),函数会尝试分配一个新的skb来拷贝数据,而不是用分散/聚集(scatter-gather)机制。
11. 如果数据包较长,则会尝试为其分配一个新的skb,并重新映射内存,保证足够的空间来接收数据。
12. 在成功接收数据包后,函数设置skb的协议类型,并添加伪头部(pseudo header)之后,通过 netif_receive_skb 函数将skb传递给网络子系统进一步处理。
13. 在最后的`repost`标签处,根据是否使用SRQ,把缓冲区重新投递给硬件,以便可以接收更多的数据包。
函数最后的操作是通过 netif_receive_skb 进行网络接收,这个函数的作用是将接收到的数据包交给上层网络协议栈处理。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot框架中Controller层API接口如何支持使用多个@RequestBody注解接受请求体参数

一、前言 众所周知&#xff0c;在Spring Boot框架中&#xff0c;Controller层API接口编码获取请求体参数时&#xff0c;在参数上会使用RequestBody注解&#xff1b;如果一次请求中&#xff0c;请求体参数携带的内容需要用多个参数接收时&#xff0c;能不能多次使用RequestBody…

通过OpenIddict设计一个授权服务器02-创建asp.net项目

在这一部分中&#xff0c;我们将创建一个ASPNET核心项目&#xff0c;作为我们授权服务器的最低设置。我们将使用MVC来提供页面&#xff0c;并将身份验证添加到项目中&#xff0c;包括一个基本的登录表单。 创建一个空的asp.net core项目 正如前一篇文章中所说&#xff0c;授权…

智能时代,让AI为你撰写专业应用文

大家好我是在看&#xff0c;记录普通人学习探索AI之路。 何谓应用文&#xff1f;简单来说&#xff0c;应用文是指在日常生活中以及工作中撰写的&#xff0c;旨在传递信息、处理事务的一种文体类型。其范畴广泛&#xff0c;涵盖了诸如请假条、通知书、辞职信、检查报告、欠条、…

【控制篇 / 分流】(7.4) ❀ 01. 对指定IP网段访问进行分流 ❀ FortiGate 防火墙

【简介】公司有两条宽带&#xff0c;一条ADSL拨号用来上网&#xff0c;一条移动SDWAN&#xff0c;已经连通总部内网服务器&#xff0c;领导要求&#xff0c;只有访问公司服务器IP时走移动SDWAN&#xff0c;其它访问都走ADSL拨号&#xff0c;如果你是管理员&#xff0c;你知道有…

vuex前端开发,getters是什么?怎么调用?简单的案例操作

vuex前端开发,getters是什么&#xff1f;怎么调用&#xff1f;简单的案例操作&#xff01; 下面通过一些简单的案例&#xff0c;来了解一下&#xff0c;vuex当中的getters到底是什么意思&#xff0c;有哪些实际的操作案例。 Vuex的getters主要用于对store中的state进行计算或过…

LNMP环境下综合部署动态网站

目录 LNMP部署--nginx 搭建mysql数据库 安装mysql的过程&#xff1a; 部署PHP&#xff1a; ​编辑​编辑php的配置文件在哪 wordpress程序安装 LNMP部署--nginx 纯净--联网状态 环境变量中没有nginx 安装形式的选择&#xff1a; yum安装&#xff1a;自动下载安装包及…

2024年美赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

Qt/QML编程之路:slider(34)

滑条slider&#xff0c;有时也成为进度条progressbar&#xff0c;在GUI界面中也是经常用到的。 import QtQuick 2.9 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.2ApplicationWindow {id:rootvisible: truewidth: 1920height: 720//title: qsTr("Hello World&q…

网络安全中的“三高一弱”和“两高一弱”是什么?

大家在一些网络安全检查中&#xff0c;可能经常会遇到“三高一弱”这个说法。那么&#xff0c;三高一弱指的是什么呢&#xff1f; 三高&#xff1a;高危漏洞、高危端口、高风险外连 一弱&#xff1a;弱口令 一共是4个网络安全风险&#xff0c;其中的“高危漏洞、高危端口、弱…

力扣精选算法100题——等于目标值的两个数or三数之和(双指针专题)

目录 &#x1f6a9;等于目标值的俩个数 第一步&#xff1a;了解题意 第二步&#xff1a;算法原理 第三步&#xff1a;代码实现 &#x1f6a9;三数之和 第一步&#xff1a;了解题意 第二步&#xff1a;算法原理 思路&#xff1a; ❗不漏&#xff1a; ❗去重: &#xf…

2. goLand安装及外配置参数通用用法

目录 概述测试代码解决外配置参数结束 概述 选择版本安装 go 安装的版本 1.go安装及相关配置 goLand 对于 习惯 idea 系列使用的人&#xff0c;还是很友好的。 测试代码 package mainimport ("flag""fmt""os" )func main() {name : flag.St…

C++核心编程(包含:内存、函数、引用、类与对象、文件操作等)【持续更新】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;C从基础到进阶 C核心编程&#x1f30f;1 内存分区模型&#x1f384;1.1 程序运行前&#x1f384;1.2 程序运行后&#x1f384;1.3 new操作符 &#x1f30f;2 引用&#x1f384;2.1 引用的基…

使用composer生成的DMG和PKG格式软件包有何区别

在使用Composer从包源构建软件包时候&#xff0c;有两种不同类型的包&#xff1a;PKG和DMG。你知道两者之间的区别吗? 以及如何选取吗&#xff1f; 每种格式都有各自的优势具体取决于软件包的预期用途以及用于部署软件包的工具。下面我们来了解一下PKG和DMG格式的区别和用途。…

C++I/O流——(4)格式化输入/输出(第一节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 含泪播种的人一定能含笑收获&#xff…

如何快速看懂一篇英文AI论文?

已经2024年了&#xff0c;该出现一个写论文解读AI Agent了。 大家肯定也在经常刷论文吧。 但真正尝试过用GPT去刷论文、写论文解读的小伙伴&#xff0c;一定深有体验——费劲。其他agents也没有能搞定的&#xff0c;今天我发现了一个超级厉害的写论文解读的agent &#xff0c…

使用micro-app将现有项目改造成微前端,对现有项目实现增量升级

使用micro-app将现有项目改造成微前端&#xff0c;对现有项目实现增量升级 基座应用 1、安装依赖 npm i micro-zoe/micro-app --save2、在入口引入 //main.js import microApp from micro-zoe/micro-appnew Vue({ }) //在new Vue 下面执行 microApp.start()3、新增一个vue页…

harbor https

harbor https部署 准备docker-compose安装https 证书harbor安装访问harbor推镜像到harbor 准备 192.168.112.99&#xff0c;harbor&#xff0c;centos7 192.168.112.3&#xff0c;测试机&#xff0c;centos7 docker版本&#xff1a;docker-ce 20.10.16&#xff08;部署参考&a…

imgaug库指南(28):从入门到精通的【图像增强】之旅(万字长文)

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

在Excel中如何打开VBA,这里提供两种方法

想在Excel中创建或添加自己的自定义Visual Basic脚本吗&#xff1f;第一步是了解如何在Excel中打开VBA编辑器。 在易用性和整体功能方面&#xff0c;没有其他电子表格应用程序能与Excel相提并论。无论你想做什么&#xff0c;只要你能深入挖掘Excel的深层菜单&#xff0c;就有很…

PTA——7-31 三角形判断

7-31 三角形判断 (15分) 给定平面上任意三个点的坐标(x​1​​,y​1​​)、(x​2​​,y​2​​)、(x​3​​,y​3​​)&#xff0c;检验它们能否构成三角形。 输入格式: 输入在一行中顺序给出六个[−100,100]范围内的数字&#xff0c;即三个点的坐标x​1​​、y​1​​、x​2​…