【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;}// 调试输出接收到的数据长度和源LIDipoib_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;elseskb->pkt_type = PACKET_MULTICAST;// 获取源GIDsgid = &((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);elsenetif_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);

在`ipoib_ib_handle_rx_wc`函数处理并交付到网络层之前,接收到的数据包已经包含了IP封装。InfiniBand 在网络层之下运行,提供高速传输能力,IP over InfiniBand (IPoIB) 是在InfiniBand基础之上实现IP网络的一种技术。
在这个函数的上下文中,数据包以Global Routing Header (GRH)开始,然后是IPoIB头部,随后是实际的IP数据报文。函数中有这样几个步骤:
1. skb_pull(skb, IB_GRH_BYTES);这行代码移除了GRH,这意味着在处理后的`skb`(socket buffer)数据是从IPoIB头部开始的。
2. skb->protocol = ((struct ipoib_header *) skb->data)->proto;这行代码将`skb`中的协议字段设置为IPoIB头部指定的协议值,这通常是以太网层协议标识,如IPv4或IPv6。
3. 在分析和调整`skb`结构后,数据包随后被交付给网络层,例如`netif_receive_skb(skb);或napi_gro_receive(&priv->recv_napi, skb);。网络层会解析数据包的网络协议头部(如IPv4/IPv6),然后将其传递给适当的协议栈。如果InfiniBand硬件支持校验和卸载,在此之前已经检查了校验和是否正确,并将skb->ip_summed`设为`CHECKSUM_UNNECESSARY`,表示IP栈不需要再次计算校验和。
总结来说,当`ipoib_ib_handle_rx_wc`函数处理完毕,交付给网络层的数据包确实已经是IP封装了,并且已经去除了它前面的InfiniBand和IPoIB特定的头部。 

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

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

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

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

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

相关文章

Python实现时间序列分析进行平稳性检验(ADF和KPSS)和差分去趋势(adfuller和kpss算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 时间序列分析中的平稳性检验是评估一个时间序列是否具有稳定的均值和方差。在经济学、金融学以及其他诸…

使用Git从其他分支merge个别文件

项目背景 产品经理&#xff1a;我们本次开发三个功能&#xff0c;列表页功能、详情页功能、系统消息功能&#xff0c;分两次上线&#xff0c;先上列表功能&#xff0c;再上详情页和系统消息。 小明&#xff1a;好的吧。 紧接着&#xff0c;小明就将本次需求分为2个分支&…

SpringBootWeb响应(黑马学习笔记)

前面我们学习过HTTP协议的交互方式&#xff1a;请求响应模式&#xff08;有请求就有响应&#xff09; 那么Controller程序呢&#xff0c;除了接收请求外&#xff0c;还可以进行响应。 ResponseBody 在我们前面所编写的controller方法中&#xff0c;都已经设置了响应数据。 c…

windows下使用agentscope

1. 使用virtualenv创建虚拟环境 创建某个项目文件夹&#xff0c;在该目录下打开命令行。 pip install virtualenv virtualenv env .\env\Scripts\activate # For centralized multi-agent applications pip install agentscope # For distributed multi-agent applications pi…

一个实时波形图的封装demo(QT)(qcustomplot)

前言&#xff1a; 封装的一个实时波形图的类&#xff0c;可以直接提升使用。 提供了接口&#xff0c;可以更改颜色&#xff0c;样式&#xff0c;等等 参考&#xff1a; Qt Plotting Widget QCustomPlot - Introduction 另外参考了一个大神的作品&#xff0c;链接没找到。 项目…

智能手表的革命性突破:TRIZ理论引领未来穿戴技术!

在科技日新月异的今天&#xff0c;智能手表已经从单纯的计时工具转变为集健康监测、信息通讯、娱乐休闲等多功能于一体的智能穿戴设备。而基于TRIZ理论的智能手表更是在这一变革中扮演着引领者的角色。TRIZ&#xff0c;即发明问题解决理论&#xff0c;是一套系统的创新方法学&a…

WordPress通过宝塔面板的入门安装教程【保姆级】

WordPress安装教程【保姆级】【宝塔面板】 前言一&#xff1a;安装环境二&#xff1a;提前准备三&#xff1a;域名解析四&#xff1a;开始安装五&#xff1a;安装成功 前言 此教程适合新手&#xff0c;即使不懂代码&#xff0c;也可轻松安装wordpress 一&#xff1a;安装环…

Mybatis简述

MyBatis是持久层框架&#xff0c;用于简化JDBC开发&#xff0c;负责将数据保存到数据库&#xff0c;支持自定义SQL&#xff0c;免除了JDBC代码以及设计参数和获取结果集的工作&#xff0c;通过简单的xml文件和注解来配置sql&#xff0c;映射类型&#xff0c;接口&#xff0c;PO…

springboot2入门到实战 - JWT

JWT是什么&#xff1f; JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object。 This information can be verified and trusted because it is digi…

如何做代币分析:以 USDT 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;cicifootprint.network 数据源&#xff1a;USDT Token Dashboard &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关…

CSS:弹性盒子Flexible Box布局

CSS:Flexible Box弹性盒子布局 一、flex布局原理 ​ flex是flexible Box的缩写,意为 ”弹性布局“&#xff0c;用来为盒状模型提供最大的灵活性&#xff0c;任何一个容器都可以指定为flex布局。 当我们的父盒子设置为flex布局之后&#xff0c;子元素的 float 、clear 和 vert…

用友 NC 23处接口XML实体注入漏洞复现

0x01 产品简介 用友 NC 是用友网络科技股份有限公司开发的一款大型企业数字化平台。 0x02 漏洞概述 用友 NC 多处接口存在XML实体注入漏洞,未经身份验证攻击者可通过该漏洞读取系统重要文件(如数据库配置文件、系统配置文件)、数据库配置文件等等,导致网站处于极度不安全…