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

一、中文注释

这个函数是用来处理 Infiniband 设备在传输完成时的回调。该回调负责释放发送队列中的缓冲区并更新网络设备统计信息。

cpp 复制代码
static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
{
    // 通过net_device结构体获取私有数据结构
    struct ipoib_dev_priv *priv = ipoib_priv(dev);

    // 获取工作请求ID,这个ID在发送时被赋予,用于标识对应的缓冲区
    unsigned int wr_id = wc->wr_id;
    struct ipoib_tx_buf *tx_req;

    // 调试信息,输出完成的工作请求的ID和状态
    ipoib_dbg_data(priv, "send completion: id %d, status: %d\n",
               wr_id, wc->status);

    // 检查wr_id是否有效
    if (unlikely(wr_id >= priv->sendq_size)) {
        // 如果不是,打印警告信息
        ipoib_warn(priv, "send completion event with wrid %d (> %d)\n",
               wr_id, priv->sendq_size);
        return;
    }
    
    // 使用工作请求ID来获取发送队列中的缓冲区
    tx_req = &priv->tx_ring[wr_id];

    // 如果不是内联传输,就需要去除DMA映射
    if (!tx_req->is_inline)
        ipoib_dma_unmap_tx(priv, tx_req);

    // 更新网络设备的发送包统计信息
    ++dev->stats.tx_packets;
    dev->stats.tx_bytes += tx_req->skb->len;

    // 释放socket缓冲区
    dev_kfree_skb_any(tx_req->skb);
    tx_req->skb = NULL;

    // 更新发送尾部指针和未完成的发送计数
    ++priv->tx_tail;
    atomic_dec(&priv->tx_outstanding);

    // 如果网络队列停止了,并且未完成的发送数少于发送队列大小的一半,同时设备标记为"管理上行"则重新唤起网络队列
    if (unlikely(netif_queue_stopped(dev) &&
             (atomic_read(&priv->tx_outstanding) <= priv->sendq_size >> 1) &&
             test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
        netif_wake_queue(dev);

    // 如果完成状态不是成功且不是"刷新错误",那么会对QP状态进行验证和修复
    if (wc->status != IB_WC_SUCCESS &&
        wc->status != IB_WC_WR_FLUSH_ERR) {
        // 打印错误警告信息
        ipoib_warn(priv,
               "failed send event (status=%d, wrid=%d vend_err %#x)\n",
               wc->status, wr_id, wc->vendor_err);
        // 为QP验证工作分配内存
        struct ipoib_qp_state_validate *qp_work;
        qp_work = kzalloc(sizeof(*qp_work), GFP_ATOMIC);
        // 如果内存分配失败就直接返回
        if (!qp_work)
            return;

        // 初始化工作队列项并将它放到工作队列中去
        INIT_WORK(&qp_work->work, ipoib_qp_state_validate_work);
        qp_work->priv = priv;
        queue_work(priv->wq, &qp_work->work);
    }
}

该函数的作用是处理InfiniBand网络设备在发送数据完成后的清理工作。它检查完成状态,释放资源并更新发送队列状态,若发送失败则可能会尝试修复QP(Queue Pair)状态。

二、中文讲解

这个函数 ipoib_ib_handle_tx_wc 是处理IP-over-Infiniband(IPoIB)传输完成工作请求(Work Completion,WC)的函数,主要用于处理在IPoIB网络设备上完成发送操作的情况。这个函数是Linux内核中IPoIB模块的一部分,用来处理InfiniBand协议栈发送操作的完成事件。

下面将逐条中文解释该函数的逻辑:

cpp 复制代码
// 函数声明,接受一个网络设备和一个工作完成结构作为参数
static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) {
    // 从网络设备结构获取IPoIB设备私有数据
    struct ipoib_dev_priv *priv = ipoib_priv(dev);
    // 获取工作请求ID
    unsigned int wr_id = wc->wr_id;
    struct ipoib_tx_buf *tx_req;

    // 输出调试信息,包括工作请求ID和状态
    ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", wr_id, wc->status);

    // 检查工作请求ID是否有效,如果不在发送队列范围内,打印警告并返回
    if (unlikely(wr_id >= priv->sendq_size)) {
        ipoib_warn(priv, "send completion event with wrid %d (> %d)\n", wr_id, priv->sendq_size);
        return;
    }

    // 获取对应工作请求ID的发送缓冲区
    tx_req = &priv->tx_ring[wr_id];

    // 如果发送请求并非内联的(数据不是和描述符一起发送的),则撤销DMA映射
    if (!tx_req->is_inline)
        ipoib_dma_unmap_tx(priv, tx_req);

    // 更新网络设备统计信息:增加发送的数据包和字节计数
    ++dev->stats.tx_packets;
    dev->stats.tx_bytes += tx_req->skb->len;

    // 释放对应的skb(socket缓冲区),并将指针置空
    dev_kfree_skb_any(tx_req->skb);
    tx_req->skb = NULL;

    // 增加发送队列尾部索引,表示处理了一个发送请求
    ++priv->tx_tail;
    // 原子减少正在处理的发送请求计数
    atomic_dec(&priv->tx_outstanding);

    // 如果网络队列停止,且未完成的发送请求数量小于发送队列大小的一半
    // 并且网络接口状态为上,那么重新启动网络队列
    if (unlikely(netif_queue_stopped(dev) &&
             (atomic_read(&priv->tx_outstanding) <= priv->sendq_size >> 1) &&
             test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
        netif_wake_queue(dev);

    // 如果工作完成状态非成功,并且不是因为刷新错误
    if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) {
        struct ipoib_qp_state_validate *qp_work;
        // 打印警告,发送请求失败
        ipoib_warn(priv, "failed send event (status=%d, wrid=%d vend_err %#x)\n",
                   wc->status, wr_id, wc->vendor_err);
        // 为验证队列对状态分配工作并初始化
        qp_work = kzalloc(sizeof(*qp_work), GFP_ATOMIC);
        if (!qp_work)
            return;

        INIT_WORK(&qp_work->work, ipoib_qp_state_validate_work);
        qp_work->priv = priv;
        // 将验证工作加入到工作队列中
        queue_work(priv->wq, &qp_work->work);
    }
}

从代码可以看出,这个函数的主要作用是处理InfiniBand设备发送缓冲区完成工作事件,释放资源,更新统计数据,以及在发送操作失败时进行错误处理。

相关推荐
小冷爱学习!9 分钟前
华为动态路由-OSPF-完全末梢区域
服务器·网络·华为
技术小齐1 小时前
网络运维学习笔记 016网工初级(HCIA-Datacom与CCNA-EI)PPP点对点协议和PPPoE以太网上的点对点协议(此处只讲华为)
运维·网络·学习
打不了嗝 ᥬ᭄1 小时前
Linux的权限
linux
落幕1 小时前
C语言-进程
linux·运维·服务器
深度Linux1 小时前
C++程序员内功修炼——Linux C/C++编程技术汇总
linux·项目实战·c/c++
shimly1234563 小时前
tcpdump 用法示例
网络·测试工具·tcpdump
风静如云3 小时前
OpenBMC:BmcWeb定义service
linux
leoufung3 小时前
VIM FZF 安裝和使用
linux·编辑器·vim
bugtraq20214 小时前
XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux
linux·运维·ubuntu
xmweisi4 小时前
【华为】报文统计的技术NetStream
运维·服务器·网络·华为认证