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

news2024/11/18 5:53:01

一、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;
    else
        send_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.coloradmin.cn/o/1395815.html

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

相关文章

SQL Povit函数使用及实例

PIVOT函数常用于数据的行转列&#xff0c;同时也可以用此函数实现类似于Excel中的数据透视表的效果。 PIVOT函数 PIVOT 函数的基本语法如下&#xff1a; -- PIVOT 语法 SELECT <非透视的列>,[第一个透视的列] AS <列名称>,[第二个透视的列] AS <列名称>,.…

Oracle 数据库备份与恢复的重要性与最佳实践

文章目录 一、备份的重要性二、备份工具-RMAN四、比较备份策略五、实例恢复六、完全恢复与不完全恢复七、备份与恢复脚本 引言&#xff1a; 在现代信息时代&#xff0c;数据已成为组织和企业最重要的资产之一。保护和恢复数据的能力对于确保业务连续性和减少潜在风险至关重要。…

探索 2024 年新副业:无人饮品机的新风向

随着科技的迅猛发展&#xff0c;无人饮品机作为一种全新的商业模式&#xff0c;正逐渐成为 2024 年副业的新风向。如果你还没有了解过这种全新的副业&#xff0c;那么现在是时候深入了解一下了。 D咖无人饮品机的优势在于其 24 小时不间断的营业模式&#xff0c;它可以在你睡觉…

【成功案例】首日ROI超70%!ROI目标超150%!看 NetMarvel如何助力棋牌游戏出海?

今天无论是线上线下&#xff0c;中国游戏广告在海外市场上屡见不鲜&#xff0c;甚至还会出现包场式营销&#xff0c;“中国人敢花钱”的印象已经深入人心&#xff0c;特别是休闲游戏的爆发给众多众多厂商带来新的增长机遇&#xff0c;大家花钱的态势更猛了。 棋牌类属于休闲体…

以后要做GIS开发的话是学GIS专业还是学计算机专业好一些?

GIS开发其实严格来说分为前后端以及底层开发。不同的方向&#xff0c;代表了不同的开发语言。 所以大家首先要了解自己具体要做的岗位类型是什么&#xff0c;其次才是选择专业侧重点。 但是严格来说&#xff0c;选择某个专业&#xff0c;到就业方向这个过程&#xff0c;并不是…

大疆笔试题目(2023-08-13)

1. 输出无重复3位数 时间限制&#xff1a; 3000MS 内存限制&#xff1a; 65536KB 题目描述&#xff1a; 从{1,2,3,4,5,6,7,8,9}中随机挑选不重复的5个数字作为输入数组’selectedDigits’&#xff0c;能组成多少个互不相同且无重复数字的3位数&#xff1f;请编写程序&#xff…

大创项目推荐 深度学习的水果识别 opencv python

文章目录 0 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习…

基于小波多普勒变换的回波信号检测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1小波变换基础 4.2 多普勒效应与多普勒变换 4.3 小波多普勒变换 4.4 回波信号检测 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 %回波…

QT自定义控件0-360°刻度尺

支持0到360&#xff0c;360到0的过度。 直接上代码&#xff0c;可以直接用&#xff0c;使用的paintevent事件实现的&#xff0c;没啥好讲的。 .cpp void Widget::drawCourse(QPainter& p,QPen pen,QFont font) {double currentNumber m_ang;p.setBrush(Qt::black);p.dra…

Docker-02-镜像项目部署

Docker-02-镜像&项目部署 文章目录 Docker-02-镜像&项目部署一、镜像①&#xff1a;镜像结构②&#xff1a;Dockerfile③&#xff1a;构建镜像01&#xff1a;构建02&#xff1a;查看镜像列表03&#xff1a;运行镜像 二、网络①&#xff1a;容器的网络IP地址②&#xff…

【动态规划】【二分查找】【C++算法】730. 统计不同回文子序列

作者推荐 【动态规划】【数学】【C算法】18赛车 涉及知识点 动态规划 二分查找 LeetCode730. 统计不同回文子序列 给你一个字符串 s &#xff0c;返回 s 中不同的非空回文子序列个数 。由于答案可能很大&#xff0c;请返回对 109 7 取余 的结果。 字符串的子序列可以经由…

PGSQL主键序列

PostgreSQL和 MySQL数据库还是有一定的区别。 下面了解一下 PGSQL的主键序列。 一、主键 1、系统自带主键序列 在 PostgreSQL 中&#xff0c;GENERATED BY DEFAULT 和 GENERATED ALWAYS 是用于定义自动生成的列&#xff08;Generated Column&#xff09;的选项。一般可作用…

可达性分析

可达性分析 这个算法的基本思路就是通过 一系列称为“GC Roots”的根对象作为起始节点集&#xff0c;从这些节点开始&#xff0c;根据引用关系向下搜索&#xff0c;搜索过 程所走过的路径称为“引用链”&#xff08;Reference Chain&#xff09;&#xff0c;如果某个对象到GC …

数学建模--比赛

内容来自数学建模BOOM&#xff1a;【快速入门】北海&#xff1a;数模建模基础MATLAB入门论文写作数学模型与算法(推荐数模美赛国赛小白零基础必看教程)_哔哩哔哩_bilibili 目录 1.学习内容 2.参赛须知 1&#xff09;参赛作品的组成 2)参赛作品的提交 3.软件安装 4.注意…

Electron中苹果支付 Apple Pay inAppPurchase 内购支付

正在开发中&#xff0c;开发好了&#xff0c;写一个完整详细的过程&#xff0c;保证无脑集成即可 一、先创建一个App 一般情况下&#xff0c;在你看这篇文章的时候&#xff0c;说明你已经开发的app差不多了。 但是要上架app到Mac App Store&#xff0c;则要在appstoreconnect…

pyspark 笔记:窗口函数window

窗口函数相关的概念和基本规范可以见&#xff1a;pyspark笔记&#xff1a;over-CSDN博客 1 创建Pyspark dataFrame from pyspark.sql.window import Window import pyspark.sql.functions as F employee_salary [("Ali", "Sales", 8000),("Bob&qu…

UI自动化Selenium 无头模式运行

1、导入浏览器参数设置 from selenium.webdriver.chrome.options import Options 2、创建参数&#xff0c;并使用无厘头模式创建driver对象 opt Options() # 新建参数对象 opt.add_argument("--headless") # 无头 self.driver webdriver.Chrome(optionsopt) …

【数据结构】哈希表详解,举例说明 java中的 HashMap、HashTable及其区别

一、哈希表&#xff08;Hash Table&#xff09;简介&#xff1a; 哈希表是一种数据结构&#xff0c;用于实现字典或映射等抽象数据类型。它通过把关键字映射到表中的一个位置来实现快速的数据检索。哈希表的基本思想是利用哈希函数将关键字映射到数组的索引位置上&#xff0c;…

四款免费、易用的Docker漏洞扫描工具

本文向您介绍四种既可以扫描Docker镜像中的漏洞&#xff0c;又能够被轻松地集成到CI/CD中的四种免费实用工具。 基本原理 所有这些工具的工作原理都比较类似。它们使用的是如下两步流程&#xff1a; 生成软件物料清单(Software Bill of Materials&#xff0c;SBOM)。将SBOM与…

USB PHY for FPGA layout

https://blog.csdn.net/qq_41904778/article/details/123967670 ZYNQ7000内部没有USB PYH&#xff0c;我们通过USB 3320 PHY 芯片来连接FPGA 和外部的USB端口&#xff08;DP & DP-&#xff09;。USB 3320 PHY跟FPGA内部是t通过ULPI接口试下的&#xff0c;然后把数据转化为…