gpt4 book ai didi

cpu - NIC 中的描述符概念

转载 作者:行者123 更新时间:2023-12-02 02:25:25 28 4
gpt4 key购买 nike

我试图理解网络驱动程序代码中使用的 Rx 和 Tx 描述符的概念。

  • 是软件(RAM)或硬件(NIC 卡)中的描述符。
  • 他们是如何填满的。

  • 编辑:所以在 Realtek 卡驱动程序代码中。我定义了以下结构。
    struct Desc
    {
    uint32_t opts1;
    uint32_t opts2;
    uint64_t addr;
    };

    txd->addr = cpu_to_le64(mapping);
    txd->opts2 = cpu_to_le32(opts2);
    txd->opts1 = cpu_to_le32(opts1 & ~DescOwn);
    opts1 and opts2也是如此还有一些像 DescOwn具体卡?制造商会在数据表中定义它们吗?

    谢谢
    纳延

    最佳答案

    快速解答:

  • 它们是遵循 NIC 硬件定义的软件结构,因此两者都可以理解并可以相互交谈。
  • 根据供应商定义的契约(Contract),它们可以以任何一种方式填充。可能的场景可能包括但不限于:
  • 由驱动程序(例如驱动程序准备的空缓冲区由硬件 Rx 接收;由驱动程序准备的数据包缓冲区由硬件 Tx 发送)
  • 通过 NIC(例如,对于由硬件写回已完成 Rx 数据包的数据包缓冲区;对于由硬件指示已传输的已完成 Tx 数据包缓冲区)

  • 更多建筑细节:

    注意:我假设您了解环数据结构、DMA 概念。
    https://en.wikipedia.org/wiki/Circular_buffer
    https://en.wikipedia.org/wiki/Direct_memory_access

    描述符,顾名思义,描述了一个数据包。它不直接包含数据包数据(据我所知,对于 NIC),而是描述了数据包,即数据包字节存储在哪里,数据包的长度等。

    我将使用 RX 路径作为示例来说明它为什么有用。收到数据包后,NIC 将线路上的电子/光学/ radio 信号转换为二进制数据字节。然后 NIC 需要通知操作系统它收到了一些东西。在过去,这是通过中断完成的,操作系统会将字节从 NIC 上的预定义位置读取到 RAM。然而,这很慢,因为 1) CPU 需要参与从 NIC 到 RAM 的数据传输 2) 可能有很多数据包,因此有很多中断,CPU 可能无法处理太多。然后 DMA 出现并解决了第一个问题。此外,人们设计了轮询模式驱动程序(或混合模式,如在 Linux NAPI 中),因此 CPU 可以从中断处理中解放出来并一次轮询多个数据包,从而解决第二个问题。

    NIC 完成将信号转换为字节,并希望对 RAM 执行 DMA。但在此之前,NIC 需要知道 DMA 到哪里,因为它不能将数据随机放入 RAM 中,而 CPU 不知道在哪里并且不安全。

    所以在RX队列的初始化过程中,NIC驱动预先分配了一些数据包缓冲区,以及一组数据包描述符。它根据 NIC 定义初始化每个数据包描述符。

    以下是 Intel XL710 NIC 使用的约定(名称已简化以便更好地理解):

    XL710 RX read Descriptor
    XL710 Rx Writeback Descriptor
    /*
    Rx descriptor used by XL710 is filled by both driver and NIC,
    * but at different stage of operations. Thus to save space, it's
    * defined as a union of read (by NIC) and writeback (by NIC).
    *
    * It must follow the description from the data sheet table above.
    *
    * __leXX below means little endian XX bit field.
    * The endianness and length has to be explicit, the NIC can be used by different CPU with different word size and endianness.
    */

    union rx_desc {
    struct {
    __le64 pkt_addr; /* Packet buffer address, points to a free packet buffer in packet_buffer_pool */
    __le64 hdr_addr; /* Header buffer address, normally isn't used */
    } read; /* initialized by driver */

    struct {
    struct {
    struct {
    union {
    __le16 mirroring_status;
    __le16 fcoe_ctx_id;
    } mirr_fcoe;
    __le16 l2tag1;
    } lo_dword;
    union {
    __le32 rss; /* RSS Hash */
    __le32 fd_id; /* Flow director filter id */
    __le32 fcoe_param; /* FCoE DDP Context id */
    } hi_dword;
    } qword0;
    struct {
    /* ext status/error/pktype/length */
    __le64 status_error_len;
    } qword1;
    } wb; /* writeback by NIC */
    };

    /*
    * Rx Queue defines a circular ring of Rx descriptors
    */
    struct rx_queue {
    volatile rx_desc rx_ring[RING_SIZE]; /* RX ring of descriptors */
    struct packet_buffer_pool *pool; /* packet pool */
    struct packet_buffer *pkt_addr_backup; /* save a copy of packet buffer address for writeback descriptor reuse */
    ....
    }

    RX Descriptor Data Structure

    enter image description here
  • 驱动程序在 RAM 中分配一定数量的数据包缓冲区(存储在 packet_buffer_pool 数据结构中)。
    pool = alloc_packet_buffer_pool(buffer_size=2048, num_buffer=512);
  • 驱动程序将每个数据包缓冲区的地址放在描述符字段中,例如
    rx_ring[i]->read.pkt_addr = pool.get_free_buffer(); 
  • 驱动程序告诉 NIC rx_ring 的起始位置、长度和头/尾。所以 NIC 会知道哪些描述符是空闲的(因此这些描述符指向的数据包缓冲区是空闲的)。这个过程是通过驱动程序将这些信息写入 NIC 寄存器来完成的(已修复,可以在 NIC 数据表中找到)。
    rx_ring_addr_reg = &rx_ring;
    rx_ring_len_reg = sizeof(rx_ring);
    rx_ring_head = 0; /* meaning all free at start */
    /* rx_ring_tail is a register in NIC as NIC updates it */
  • 现在 NIC 知道描述符 rx_ring[{x,y,z}] 是空闲的并且 {x,y,z}.pkt_addr 可以放入新的数据包数据。它继续将新数据包 DMA 到 {x,y,z}.pkt_addr。同时,NIC 可以预处理(卸载)数据包处理(如校验和验证、提取 VLAN 标记),因此它还需要一些地方为软件保留这些信息。在这里,描述符在回写时为此目的而重用(参见描述符联合中的第二个结构)。然后 NIC 推进 rx_ring 尾指针偏移,表明 NIC 已经写回了一个新的描述符。[这里的一个问题是,由于描述符被重新用于预处理结果,驱动程序必须保存 {x,y,z}。 pkt_addr 在备份数据结构中]。
    /* below is done in hardware, shown just for illustration purpose */
    if (rx_ring_head != rx_ring_tail) { /* ring not full */
    copy(rx_ring[rx_ring_tail].read.pkt_addr, raw_packet_data);
    result = do_offload_procesing();

    if (pre_processing(raw_packet_data) & BAD_CHECKSUM))
    rx_ring[rx_ring_tail].writeback.qword1.stats_error_len |= RX_BAD_CHECKSUM_ERROR;
    rx_ring_tail++; /* actually driver sets a Descriptor done indication flag */
    /* along in writeback descriptor so driver can figure out */
    /* current HEAD, thus saving a PCIe write message */
    }
  • 驱动读取新的尾指针偏移,发现 {x,y,z} 带有新包。它会从 pkt_addr_backup[{x,y,z}] 和相关的预处理结果中读取数据包。
  • 当上层软件处理完数据包时,{x,y,z} 将被放回 rx_ring 并且环头指针将被更新以指示空闲描述符。

  • RX 路径到此结束。 TX 路径几乎是相反的:上层产生数据包,驱动程序将数据包数据复制到 packet_buffer_pool 并让 tx_ring[x].buffer_addr 指向它。驱动程序还在 TX 描述符中准备了一些 TX 卸载标志(例如硬件校验和,TSO)。 NIC 从 RAM 读取 TX 描述符和 DMA tx_ring[x].buffer_addr 到 NIC。

    此信息通常出现在 NIC 数据表中,例如 Intel XL710 xl710-10-40-controller-datasheet, Chapter 8.3 & 8.4 LAN RX/TX Data Path。

    http://www.intel.com/content/www/us/en/embedded/products/networking/xl710-10-40-controller-datasheet.html

    您还可以检查开源驱动程序代码(Linux 内核或一些用户空间库,如 DPDK PMD),其中包含描述符结构定义。

    -- 编辑 1 --

    有关 Realtek 驱动程序的其他问题:
    是的,这些位是特定于 NIC 的。一个提示是像
        desc->opts1 = cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);

    DescOwn 是一个位标志,通过设置它告诉 NIC 它现在拥有这个描述符和相关的缓冲区。它还需要从 CPU 字节序(可能是电源 CPU,即 BE)转换为 NIC 同意理解的小字节序。

    您可以在 http://realtek.info/pdf/rtl8139cp.pdf中找到相关信息(例如 DescOwn 的第 70 页),虽然它不像 XL710 那样完整,但至少包含所有寄存器/描述符信息。

    -- 编辑 2 --

    NIC 描述符是一个非常依赖于供应商的定义。如上所示,Intel 的 NIC 描述符使用相同的 RX 描述符环来提供 NIC 缓冲区进行写入,并为 NIC 写回 RX 信息。还有其他实现方式,例如拆分 RX 提交/完成队列(在 NVMe 技术中更为普遍)。例如,Broadcom 的某些 NIC 具有单个提交环(为 NIC 提供缓冲区)和多个完成环。它专为网卡决定并将数据包放入不同的环而设计,例如不同的流量等级优先级,以便驱动程序可以优先获取最重要的数据包。
    enter image description here (来自 BCM5756M 网卡程序员指南)

    --编辑3--

    英特尔通常将 NIC 数据表开放给公众下载,而其他供应商可能只向 ODM 披露。在他们的 Intel 82599 中描述了 Tx/Rx 流程的一个非常简短的摘要。系列数据表,第 1.8 节体系结构和基本操作。

    关于cpu - NIC 中的描述符概念,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36625892/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com