【C语言】linux内核ipoib模块 - ipoib_ib_handle_rx_wc

一、中文注释

// 定义一个处理InfiniBand接收完成工作请求的函数
static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
{
    // 通过网络设备获取私有数据结构
    struct ipoib_dev_priv *priv = ipoib_priv(dev);
    // 获取工作请求ID,并屏蔽掉接收操作的标志位
    unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
    struct sk_buff *skb;
    u64 mapping[IPOIB_UD_RX_SG];
    union ib_gid *dgid;
    union ib_gid *sgid;
    // 调试输出接收完成信息
    ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
               wr_id, wc->status);
    // 检查工作请求ID是否超出接收队列大小
    if (unlikely(wr_id >= priv->recvq_size)) {
        ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n",
               wr_id, priv->recvq_size);
        return; // 超出则返回
    }
    // 获取与工作请求关联的socket缓冲区
    skb  = priv->rx_ring[wr_id].skb;
    // 检查工作请求的状态是否为成功
    if (unlikely(wc->status != IB_WC_SUCCESS)) {
        // 若失败且不是因为flush错误,打印警告信息
        if (wc->status != IB_WC_WR_FLUSH_ERR)
            ipoib_warn(priv,
                   "failed recv event (status=%d, wrid=%d vend_err %#x)\n",
                   wc->status, wr_id, wc->vendor_err);
        // 解除DMA映射并释放socket缓冲区
        ipoib_ud_dma_unmap_rx(priv, priv->rx_ring[wr_id].mapping);
        dev_kfree_skb_any(skb);
        // 将rx_ring中对应项的skb置为空
        priv->rx_ring[wr_id].skb = NULL;
        return; // 返回
    }
    // 复制DMA映射地址到本地变量
    memcpy(mapping, priv->rx_ring[wr_id].mapping,
           IPOIB_UD_RX_SG * sizeof(*mapping));
    /*
     * 如果无法分配新的接收缓冲区,则丢弃此数据包
     * 并重用旧缓冲区。
     */
    if (unlikely(!ipoib_alloc_rx_skb(dev, wr_id))) {
        // 增加丢弃的数据包计数
        ++dev->stats.rx_dropped;
        // 跳转到重新提交接收请求的代码段
        goto repost;
    }
    // 调试输出接收到的数据长度和源LID
    ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
               wc->byte_len, wc->slid);
    // 解除DMA映射
    ipoib_ud_dma_unmap_rx(priv, mapping);
    // 设定skb数据长度
    skb_put(skb, wc->byte_len);
    /* 第一个dgid字节的值为0xff时代表多播 */
    dgid = &((struct ib_grh *)skb->data)->dgid;
    // 根据GRH判断消息类型(单播、多播或广播)
    if (!(wc->wc_flags & IB_WC_GRH) || dgid->raw[0] != 0xff)
        skb->pkt_type = PACKET_HOST;
    else if (memcmp(dgid, dev->broadcast + 4, sizeof(union ib_gid)) == 0)
        skb->pkt_type = PACKET_BROADCAST;
    else
        skb->pkt_type = PACKET_MULTICAST;
    // 获取源GID
    sgid = &((struct ib_grh *)skb->data)->sgid;
    /*
     * 丢弃由此接口发送的数据包,即HCA已复制的多播数据包。
     */
    if (wc->slid == priv->local_lid && wc->src_qp == priv->qp->qp_num) {
        int need_repost = 1;
        if ((wc->wc_flags & IB_WC_GRH) &&
            sgid->global.interface_id != priv->local_gid.global.interface_id)
            need_repost = 0;
        if (need_repost) {
            // 释放skb并跳转至重新提交接收请求
            dev_kfree_skb_any(skb);
            goto repost;
        }
    }
    // 移除GRH头
    skb_pull(skb, IB_GRH_BYTES);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)) && ! defined(HAVE_SK_BUFF_CSUM_LEVEL)
    /* 仅适用于旧的内核版本,表示重新组装大小 */
    skb->truesize = SKB_TRUESIZE(skb->len);
#endif
    // 设置协议头
    skb->protocol = ((struct ipoib_header *) skb->data)->proto;
    // 添加伪头
    skb_add_pseudo_hdr(skb);
    // 更新接收统计信息
    ++dev->stats.rx_packets;
    dev->stats.rx_bytes += skb->len;
    // 如果收到的是多播包,增加多播计数
    if (skb->pkt_type == PACKET_MULTICAST)
        dev->stats.multicast++;

    // 处理ARP协议包,用于路径发现
    if (unlikely(be16_to_cpu(skb->protocol) == ETH_P_ARP))
        ipoib_create_repath_ent(dev, skb, wc->slid);

    // 设置数据包关联的网络设备
    skb->dev = dev;
    // 如果设备支持接收校验和处理,且工作请求指示校验和ok,则跳过校验和处理
    if ((dev->features & NETIF_F_RXCSUM) &&
            likely(wc->wc_flags & IB_WC_IP_CSUM_OK))
        skb->ip_summed = CHECKSUM_UNNECESSARY;
#ifdef CONFIG_COMPAT_LRO_ENABLED_IPOIB
    // 如果设备支持大接收下偏移(LRO),则使用LRO处理skb,否则使用普通的接收处理
    if (dev->features & NETIF_F_LRO)
        lro_receive_skb(&priv->lro.lro_mgr, skb, NULL);
    else
        netif_receive_skb(skb);
#else
    // 使用NAPI通用接收处理接收到的数据包
    napi_gro_receive(&priv->recv_napi, skb);
#endif

// 重新提交接收请求的代码段
repost:
    // 重用前面设置好的缓冲区,提交新的接收工作请求
    if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
        // 如果提交失败,打印警告信息
        ipoib_warn(priv, "ipoib_ib_post_receive failed "
               "for buf %d\n", wr_id);
}

以上注释形式遵循C语言的单行注释模式,对函数中的每个主要步骤提供了简要的中文解释。此函数是针对IP over InfiniBand (IPoIB) 设备的InfiniBand接收完成处理函数。它处理从InfiniBand网络接收到的数据包,进行协议处理,并最终将收到的数据包发送到上层网络栈。此外,函数还负责根据当前的工作请求和状态更新设备的统计信息,并处理特殊的ARP数据包,进行资源回收以及重用缓冲区来提交新的接收请求。

二、中文讲解

这个函数`ipoib_ib_handle_rx_wc`是处理InfiniBand接口上的接收完成工作请求(Work Completion, WC)的函数,主要用于接收数据包并处理。下面将该函数的主要部分用中文解释:

1. 获取私有数据结构和工作请求ID(wr_id):

   struct ipoib_dev_priv *priv = ipoib_priv(dev);
   unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;

   提取出工作请求ID,这用于索引接收队列。

2. 日志记录:   

   ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n", wr_id, wc->status);

   如果工作请求ID超出了预期范围,则记录一条警告信息。

3. 检查工作请求完成状态:

   if (unlikely(wc->status != IB_WC_SUCCESS)) { ... }

   如果状态不是成功的,清理相应的资源并返回。

4. 定位接收缓冲区并尝试分配新的RX缓冲区:

   skb  = priv->rx_ring[wr_id].skb;
   if (unlikely(!ipoib_alloc_rx_skb(dev, wr_id))) { goto repost; }

   如果分配失败,则丢弃这个数据包并重用旧的缓冲区。

5. 记录接收到的数据包大小和源本地ID(SLID):

   ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid);

6. 根据数据包第一个字节是否为0xff判断是否为多播,并设置skb的包类型:

   if (!(wc->wc_flags & IB_WC_GRH) || dgid->raw[0] != 0xff) { ... }

   根据比较目的全局ID(dgid),确认包的类型(单播、广播或者多播)。

7. 如果数据包是由本接口发送(例如多播包被IO控制器复制了),则丢弃该包:

   if (wc->slid == priv->local_lid && wc->src_qp == priv->qp->qp_num) { ... }

8. 从数据包中移除Global Routing Header (GRH):

   skb_pull(skb, IB_GRH_BYTES);

9. 设置数据包的协议类型,统计信息,并将包交付到网络层:

   skb->protocol = ((struct ipoib_header *) skb->data)->proto;
   netif_receive_skb(skb);

10. 在必要的情况下,重新将RX缓冲区提交给硬件:

    if (unlikely(ipoib_ib_post_receive(dev, wr_id))) { ... }

    如果重新提交RX缓冲区失败,则记录警告信息。
整体来说,这个函数负责管理InfiniBand接口接收到的数据包,包括分配和管理资源,以及将接收到的数据递交给更高层的网络协议处理。

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

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

相关文章

【Flink精讲】Flink 内存管理

面临的问题 目前&#xff0c; 大数据计算引擎主要用 Java 或是基于 JVM 的编程语言实现的&#xff0c;例如 Apache Hadoop、 Apache Spark、 Apache Drill、 Apache Flink 等。 Java 语言的好处在于程序员不需要太关注底层内存资源的管理&#xff0c;但同样会面临一个问题&…

纳斯达克大屏-投放需要知道的几个条件-大舍传媒

引言 随着移动互联网的快速发展&#xff0c;数字广告媒体广告越来越受到企业的关注。纳斯达克大屏作为全球最大的数字媒体广告投放平台之一&#xff0c;拥有广泛的受众和优质的媒体资源&#xff0c;吸引了众多企业的眼球。要想在纳斯达克大屏上投放广告&#xff0c;企业需要了…

java数据结构与算法刷题-----LeetCode617. 合并二叉树

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 此题如果使用广度优先遍历&#xff0c;一定需要创建很多队列&…

21.scala泛型结合隐式转换使用

目录 概述实践代码执行 结束 概述 scala泛型结合隐式转换使用 实践 代码 package com.fun.scala/*** 视图界定*/ object Genericity04 {def main(args: Array[String]): Unit {val s1 new Stu("test", 33)val s2 new Stu("test2", 32)println(new M…

WSL2配置Linux、Docker、VS Code、zsh、oh my zsh(附Docker开机自启设置)

0. 写在前面 本篇笔记来自于UP主麦兜搞IT的合集视频Windows10开发环境搭建中的部分内容 1. 安装WSL2 按照微软官方文档进行操作&#xff0c;当然也可以直接wsl --install 也可以按照 旧版手动安装的步骤 来进行操作 选择安装的是Ubuntu 20.04 LTS 注&#xff1a;WSL默认安装…

HDL FPGA 学习 - Quartus II 工程搭建,ModelSim 仿真,时序分析,IP 核使用,Nios II 软核使用,更多技巧和规范总结

目录 工程搭建、仿真与时钟约束 一点技巧 ModelSim 仿真 Timing Analyzer 时钟信号约束 SignalTap II 使用 In-System Memory Content Editor 使用 记录 QII 的 IP 核使用 记录 Qsys/Nios II 相关 记录 Qsys 的 IP 核使用 封装 Avalon IP 更多小技巧教程文章 更多好…

buuctf_N1BOOK_粗心的小李

题目&#xff1a; 看完题目&#xff0c;git下载文件&#xff1f;然后将.git文件传到线上环境&#xff1f;&#xff08;which 会造成git泄露的安全威胁&#xff09;<这个背景抱歉我不太了解哈&#xff0c;可能后续有补充> 这里主要记录做法过程&#xff1a; 工具&#xf…

vue3获取环境变量import.meta.env

vitevue的时候环境变量的获取方式变成如下&#xff1a; console.log(import.meta.env)

手机单目相机内参标定

使用软件&#xff1a; 参考我之前的文章&#xff1a; 软件地址:https://github.com/DavidGillsjo/VideoIMUCapture-Android/releases 棋盘标定板下载 链接: https://pan.baidu.com/s/1wiPJsEf87Vc0D7KwJnt3GA?pwd1234 提取码: 1234 过程 1.使用下载的软件录制一段视频&am…

第6.4章:StarRocks查询加速——Colocation Join

目录 一、StarRocks数据划分 1.1 分区 1.2 分桶 二、Colocation Join实现原理 2.1 Colocate Join概述 2.2 Colocate Join实现原理 三、应用案例 注&#xff1a;本篇文章阐述的是StarRocks-3.2版本的Colocation Join 官网文章地址&#xff1a; Colocate Join | StarRoc…

【国密算法】理解国密算法的基础概念

目录 1.1 什么是国密算法&#xff1f; 1.1.1 国密算法的定义 1.1.2 国密算法的作用与重要性 1.2 国密算法的工作原理 1.2.1 对称加密与非对称加密 1.2.2 国密算法的特点与优势 1.2.3 国密算法的基本流程 1.3 国密算法与数据传输安全 1.3.1 数据传输中的风险与威胁 1.…

element table数据量太大,造成浏览器崩溃。解决方案

这是渲染出来的数据 其实解决思路大致就是&#xff1a;把后台返回的上万条数据&#xff0c;进行分割&#xff08;前端分页&#xff09;&#xff0c;这样先加载几十条&#xff0c;然后再用懒加载的方式去concat&#xff0c;完美解决 上代码 <template><div class&quo…

七分钟交友匿名聊天室源码

应用介绍 本文来自&#xff1a;七分钟交友匿名聊天室源码 - 源码1688 简介&#xff1a; 多人在线聊天交友工具&#xff0c;无需注册即可畅所欲言&#xff01;你也可以放心讲述自己的故事&#xff0c;说出自己的秘密&#xff0c;因为谁也不知道对方是谁。 运行说明&#xff…

Nginx----高性能的WEB服务端(一)

目录 一、Nginx介绍 1、什么是Nginx 2、Nginx并发连接 3、Nginx应用场景 4、nginx的HTTP七层代理和四层代理 5、反向代理 1.反向代理定义 2.反向代理优点 6、yum安装 7、官网文件安装 二、Nginx和Apache的优缺点比较 1、nginx相对于apache的优点&#xff1a; 2、a…

Java 学习和实践笔记(20):static的含义和使用

static的本义是静止的。在计算机里就表示静态变量。 在Java中&#xff0c;从内存分析图上可以看到&#xff0c;它与类、常量池放在一个区里&#xff1a; 从图可以看到&#xff0c;普通的方法和对象属性&#xff0c;都在heep里&#xff0c;而static则在方法区里。 static声明的…

Sora 横空出世!国内一批创新公司要挂了吗?

2月16日凌晨&#xff0c;OpenAI 发布了自己的首个AI视频生成模型—Sora&#xff0c;这是一个历史性的里程碑&#xff0c;扩散模型结合OpenAI大获成功的transformer&#xff0c;在视觉领域实现了与大语言模型类似的突破。毫无疑问&#xff0c;视觉生成领域将有一次大的技术和商业…

09 呼吸灯

呼吸灯简介 呼吸灯实际展示的效果就是一个 LED 灯的亮度由亮到暗&#xff0c;再由暗到亮的变化过程&#xff0c;并且该过程是循环往复的&#xff0c;像呼吸一样那么有节奏。 呼吸灯通常是采用 PWM(Pulse Width Modulation&#xff0c;即脉冲宽度调制) 的方式实现&#xff0c;在…

C语言实现直接插入排序

直接插入排序 其平均复杂度是 O(n2)&#xff0c;因此应用场景较少。 接插入排序的思路是&#xff1a; 每次处理一个数据&#xff0c;将其插入到一个已经排好序的子序列中&#xff0c;直到数据处理完毕。 下面给出一个动画示例&#xff1a; 这里写图片描述&#xff1a;从上面来…

C#之WPF学习之路(5)

目录 内容控件&#xff08;2&#xff09; TextBlock文字块 TextBox文本框 TextBoxBase基类 TextBox控件 RichTextBox富文本框 ToolTip控件&#xff08;提示工具&#xff09; Popup弹出窗口 Image图像控件 属性成员 事件成员 内容控件&#xff08;2&#xff09; Tex…

基于SSM的车位租赁系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的车位租赁系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…