【C语言】ipoib模块 - ipoib_send_rss函数

一、ipoib_send_rss函数定义

int ipoib_send_rss(struct net_device *dev, struct sk_buff *skb,struct ib_ah *address, u32 dqpn)
{struct ipoib_dev_priv *priv = ipoib_priv(dev);struct ipoib_tx_buf *tx_req;struct ipoib_send_ring *send_ring;u16 queue_index;int hlen, rc;void *phead;int req_index;unsigned usable_sge = priv->max_send_sge - !!skb_headlen(skb);/* Find the correct QP to submit the IO to */queue_index = skb_get_queue_mapping(skb);send_ring = priv->send_ring + queue_index;if (skb_is_gso(skb)) {hlen = skb_transport_offset(skb) + tcp_hdrlen(skb);phead = skb->data;if (unlikely(!skb_pull(skb, hlen))) {ipoib_warn(priv, "linear data too small\n");++send_ring->stats.tx_dropped;++send_ring->stats.tx_errors;dev_kfree_skb_any(skb);return -1;}} else {if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN);++send_ring->stats.tx_dropped;++send_ring->stats.tx_errors;ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);return -1;}phead = NULL;hlen  = 0;}if (skb_shinfo(skb)->nr_frags > usable_sge) {if (skb_linearize(skb) < 0) {ipoib_warn(priv, "skb could not be linearized\n");++send_ring->stats.tx_dropped;++send_ring->stats.tx_errors;dev_kfree_skb_any(skb);return -1;}/* Does skb_linearize return ok without reducing nr_frags? */if (skb_shinfo(skb)->nr_frags > usable_sge) {ipoib_warn(priv, "too many frags after skb linearize\n");++send_ring->stats.tx_dropped;++send_ring->stats.tx_errors;dev_kfree_skb_any(skb);return -1;}}ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n",skb->len, address, dqpn);/** We put the skb into the tx_ring _before_ we call post_send_rss()* because it's entirely possible that the completion handler will* run before we execute anything after the post_send_rss().  That* means we have to make sure everything is properly recorded and* our state is consistent before we call post_send_rss().*/req_index = send_ring->tx_head & (priv->sendq_size - 1);tx_req = &send_ring->tx_ring[req_index];tx_req->skb = skb;if (skb->len < ipoib_inline_thold &&!skb_shinfo(skb)->nr_frags) {tx_req->is_inline = 1;send_ring->tx_wr.wr.send_flags |= IB_SEND_INLINE;} else {if (unlikely(ipoib_dma_map_tx(priv->ca, tx_req))) {++send_ring->stats.tx_errors;dev_kfree_skb_any(skb);return -1;}tx_req->is_inline = 0;send_ring->tx_wr.wr.send_flags &= ~IB_SEND_INLINE;}if (skb->ip_summed == CHECKSUM_PARTIAL)send_ring->tx_wr.wr.send_flags |= IB_SEND_IP_CSUM;elsesend_ring->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;/* increase the tx_head after send success, but use it for queue state */if (atomic_read(&send_ring->tx_outstanding) == priv->sendq_size - 1) {ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");netif_stop_subqueue(dev, queue_index);}skb_orphan(skb);skb_dst_drop(skb);if (__netif_subqueue_stopped(dev, queue_index))if (ib_req_notify_cq(send_ring->send_cq, IB_CQ_NEXT_COMP |IB_CQ_REPORT_MISSED_EVENTS))ipoib_warn(priv, "request notify on send CQ failed\n");rc = post_send_rss(send_ring, req_index,address, dqpn, tx_req, phead, hlen);if (unlikely(rc)) {ipoib_warn(priv, "post_send_rss failed, error %d\n", rc);++send_ring->stats.tx_errors;if (!tx_req->is_inline)ipoib_dma_unmap_tx(priv, tx_req);dev_kfree_skb_any(skb);if (__netif_subqueue_stopped(dev, queue_index))netif_wake_subqueue(dev, queue_index);rc = 0;} else {netdev_get_tx_queue(dev, queue_index)->trans_start = jiffies;rc = send_ring->tx_head;++send_ring->tx_head;atomic_inc(&send_ring->tx_outstanding);}return rc;
}

二、函数解读

函数`ipoib_send_rss` 是一个用于IPoIB(IP over InfiniBand)的Linux内核网络模块中针对发送数据包的函数。该函数使用Receive-Side Scaling(RSS)技术来支持多核处理,意味着它可以将数据包的发送操作分配给不同的CPU核心。以下是对该函数的逐行解读:
1. 函数接收四个参数:
   - *dev:指向`net_device`结构的指针,表示关联的InfiniBand网络设备。
   - *skb:指向`sk_buff`结构的指针,表示要发送的数据包。
   - *address:指向`ib_ah`结构的指针,表示Address Handle,用于标识目的地的地址信息。
   - dqpn:一个无符号32位整数,表示目的地的队列对编号(Destination Queue Pair Number)。
2. 函数首先通过`ipoib_priv(dev)`获取到设备的私有结构体指针`ipoib_dev_priv`。
3. 接着定义了一些本地变量,包括发送缓冲区请求指针`tx_req`、发送环指针 send_ring、队列索引`queue_index`和其他与发送操作相关的辅助变量。
4. 函数中首先计算出要使用的发送环的索引,通过调用`skb_get_queue_mapping(skb)`获取`skb`数据包的队列映射并存储于`queue_index`中。然后使用该索引从设备的私有结构体中获得对应的发送环 send_ring。
5. 对于分段的传输(skb_is_gso),函数将执行必要的操作来调整skb的头部指向传输数据,并更新数据包头长度。如果skb的头部数据太小无法进行这个操作,打印警告信息,丢弃skb,并返回错误代码。
6. 如果数据包长度超过了多播的最大传输单元加上IPoIB的封装长度,也会打印警告信息,递增丢包统计,并调用`ipoib_cm_skb_too_long`处理过长的数据包,然后返回错误代码。
7. 如果数据包包含的片段数(nr_frags)超出了最大支持的Scatter/Gather条目数量(usable_sge),函数尝试通过调用`skb_linearize`将数据包线性化。如果线性化失败或者仍然有太多片段,打印警告信息,丢弃skb,并返回错误代码。
8. 准备发送的数据包。如果skb的长度少于内联阈值并且没有片段,将数据包标记为内联发送;否则,将数据通过DMA映射到设备,并根据校验和需求设置IB的发送标志。
9. 在尝试发送数据包前,需要确保如果发送完成处理程序先于`post_send_rss`调用完成执行,所有的状态记录都已更新。
10. 如果发送队列满了,会停止网络队列来防止更多的发送操作。数据包被孤立(断开与套接字的联系),并且其路由缓存项被删除。
11. 如果子网络队列被停止了,请求发送完成队列的通知。如果请求通知失败,打印警告信息。
12. 通过调用`post_send_rss`函数发送数据包。如果发送失败,打印警告信息,解除DMA映射(如果使用的是DMA),释放skb,并唤醒网络子队列(如果它被停止了)。如果发送成功,更新发送环的状态记录,递增发送缓冲区标头索引,增加未完成的发送操作的计数,并返回成功。
综上所述,这个函数的作用是对于使用RSS的IPoIB进行数据包的准备和发送工作,涉及到网络队列的管理、数据包的内存管理和DMA,还包括对InfiniBand传输和其完成事件的处理。

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

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

相关文章

使用chromium代码函数入参和出参传入同一个变量踩到的坑

背景&#xff1a; 开发一个需求的时候需要用到chromium中的加解密功能&#xff0c;但是发现加密之后解密失败了。 伪代码&#xff1a; std::string text "encryped-text"; bool b Encryptor::Crypt(false, text, &text); 发现b的值为false。 备注&#x…

[ELK] ELK企业级日志分析系统

一、ELK 概述 1.1 ELK 简介与组件 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 ●ElasticSearch&#xff1a;是基于Lucene&#xff08;一个…

Sentinel 轨道数据及下载

Sentinel卫星轨道文件在处理Sentinel卫星数据时发挥着关键作用。这些轨道文件包含了有关卫星在轨道上的运动、位置、姿态等信息&#xff0c;对于地理校正、成像几何校正以及多时相分析等方面具有重要作用。以下是Sentinel卫星轨道文件的主要作用&#xff1a; 地理校正&#xff…

File 类的用法和 InputStream, OutputStream 的用法

1.File类的用法 下面就用几个简单的代码案例来熟悉File类里面函数的用法&#xff1a; public class IODemo1 {public static void main(String[] args) throws IOException {File f new File("./test2.txt");//File f new File("C:/User/1/test.txt");S…

1月下半笔记(个人向)

最近才开始看d2l&#xff08;这种东西早该在两年前看的&#xff0c;拖到现在了&#xff09; 为了做项目还得学一手OpenGL&#xff08;被windows安装GLFW逼疯了&#xff09; 1.15 打完ICPC EC final回来&#xff0c;也许可以出一篇博客写下简单的题解。 对蛋白质相似空间子结…

23款奔驰C260L升级香氛负离子 车载香薰

奔驰原厂香氛系统激活原车自带系统&#xff0c;将香气加藏储物盒中&#xff0c;通过系统调节与出风口相结合&#xff0c;再将香味传达至整个车厢&#xff0c;达到净化车厢空气的效果&#xff0c;让整个车厢更加绿色健康&#xff0c;清新淡雅。 星骏汇小许Xjh15863 产品功能&a…

爱普生L3150新更换废墨垫还是不能使用,如何对它进行废墨清零操作

环境&#xff1a; 爱普生L3150 Win10 专业版 废墨清零软件Resetter 问题描述&#xff1a; 爱普生L3150新更换废墨垫还是不能使用&#xff0c;如何对它进行废墨清零操作 打印机右后方更换了全新的废墨垫&#xff0c;还是告警闪灯用不了&#xff0c;需要进行废墨清零操作 解…

【数据结构二】链表和LinkedList详解

目录 链表和LinkedList 1.链表的实现 2.LinkedList的使用 3.ArrayList和LinkedList的区别 4.链表OJ题训练 链表和LinkedList 当 在 ArrayList 任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后 搬移&#xff0c;时间复杂度为 O(n) &#xff0c;效率…

软件测试|sqlalchemy一对一关系详解

简介 SQLAlchemy 是一个强大的 Python ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它允许我们将数据库表映射到 Python 对象&#xff0c;并提供了丰富的关系模型来处理不同类型的关系&#xff0c;包括一对一关系。在本文中&#xff0c;我们将深入探讨 SQLAlchemy …

【Linux 命令】tree 对目录进行树形展示

目录 1、tree 命令功能展示 2、tree 命令安装 3、tree 命令语法及其参数功能 4、终止 tree 展开树命令 1、tree 命令功能展示 在 Linux 中&#xff0c;我们使用 ll 命令对目录的展示并不太方便我们查看&#xff0c;不太清晰明了&#xff0c;所以我们可以使用 tree 命令以…

JavaScript的代码执行顺序

&#xff08;1&#xff09;. js的执行顺序&#xff0c;先同步后异步 &#xff08;2&#xff09;. 异步中任务队列的执行顺序&#xff1a; 先微任务microtask队列&#xff0c;再宏任务macrotask队列 注意&#xff0c;按顺序从上到下时&#xff0c;没有轮到执行的任务会进入相应…

Spring Boot Aop 执行顺序

Spring Boot Aop 执行顺序 1. 概述 在 spring boot 项目中&#xff0c;使用 aop 增强&#xff0c;不仅可以很优雅地扩展功能&#xff0c;还可以让一写多用&#xff0c;避免写重复代码&#xff0c;例如&#xff1a;记录接口耗时&#xff0c;记录接口日志&#xff0c;接口权限&…