c++ - 使用 packet_mmap 的 RX/TX 是否需要拷贝?

标签 c++ c linux network-programming

我已经阅读了所有可能的文档,例如 ( https://www.mjmwired.net/kernel/Documentation/networking/packet_mmap.txt) 和各种其他博客等。

我仍然不清楚与内核映射的 RX 缓冲区是否也可以用于 TX 操作,或者我是否需要在设置发送状态标志和调用 sendto() 之前从 RX 缓冲区复制到 TX .

根据文档,以下是状态:

// RX statuses
#define TP_STATUS_KERNEL        0
#define TP_STATUS_USER          1

// TX statuses
#define TP_STATUS_AVAILABLE        0 // Frame is available
#define TP_STATUS_SEND_REQUEST     1 // Frame will be sent on next send()
#define TP_STATUS_SENDING          2 // Frame is currently in transmission
#define TP_STATUS_WRONG_FORMAT     4 // Frame format is not correct 

流程似乎是:

  1. 数据包通过 TP_STATUS_USER 从内核到达 RX 缓冲区
  2. 我处理数据包,然后设置 TP_STATUS_SEND_REQUEST
  3. 内核设置TP_STATUS_SENDING,同时发送
  4. 发送完成后内核设置 TP_STATUS_AVAILABLE
  5. 我设置 TP_STATUS_KERNEL 告诉内核我已经处理完这些数据包,它们可能会被覆盖

但是,由于 TP_STATUS_AVAILABLE 与 TP_STATUS_KERNEL 具有相同的值,如果此流程正确,内核将在完成 TX 操作后立即清除数据包。在我看来,可能需要复制到单独的 TX 缓冲区。关于使用 packet_mmap 和 packet_tx_ring 的信息有限。我发现的例子主要是针对 RX(我有工作的 atm)。我喜欢 RX/TX 场景的示例(例如桥接原始数据包)。

有没有人对此有更好的理解?示例桥接也将是最有帮助的!

最佳答案

之前注意:我仍在阅读和学习PACKET_MMAPaf_packet.c 中的函数,所以我可能是错的!

我不认为你想做的事情本身是可能的,我认为你必须破解功能。

在 Rx 模式下使用 TPACKET v3,每个 block 可以接收一批帧。因此,一个问题可能是对于 Rx,您需要使用 TPACKET v2 以便 Tx 和 Rx 共享同一个环(但是只支持 Rx 的 v3 应该更快!)。

I set TP_STATUS_KERNEL to tell the kernel that I'm done with these packets and they may be overwritten

在 Tx 模式下使用 TPACKET v2(Tx 不支持 v3,仅 Rx 支持)您为每个 block 写入一个帧并将 block 状态设置为 TP_STATUS_SEND_REQUEST 并调用 sendto() 。内核将 block 状态转换为 TP_STATUS_SENDING,然后在传输完成后转换为 TP_STATUS_AVAILABLE

另一个问题可能是环形指针的头部。如果您收到放置在环 block 中的 5 帧,内核将环头移动到第 6 个 block (下一个空闲空间),准备将可能到达的任何其他帧放入下一个空闲 block 。同时,在用户空间中,您通过 poll() 获取前 5 帧,例如,调用 do_stuff() 直接在环内编辑 block 中的帧,然后如果您尝试对同一个环调用 sendto(),则需要将环指针的头部向后移动 5 个位置。异步地,如果一些帧到达并且环形指针的头部已被移回,您将在发送它们之前覆盖修改的帧。

正如我所说,我相信您可以绕过这些东西,但如果您必须修改数据,您不妨设置两个环。我知道现在会在环之间引入一个拷贝,但我猜你想避免。我一直在通读 PACKET_MMAP 源代码,我的理解是它应该减少拷贝,但它似乎根本没有这样做。我们可以通过为“一堆”数据包(环)调用 sendto() 来减少系统调用的数量。

您可以阅读我在调试 Tx 路径时发现的内容 herehere .我现在要开始通过 Rx 路径进行跟踪。这些链接中有关 Tx 路径的信息摘要是,在用应用程序数据(帧)填充 Tx 环并调用 sendto() 后,内核将每个数据包/帧复制到 sk_buff 和 NIC 将数据复制到它的硬件队列(通过 DMA)以在线路上发送数据包/帧。所以这是两个拷贝(尽管 DMA 拷贝是必需的!),再加上您必须将应用程序数据复制到 Tx 环中,以便制作三个拷贝。这与没有 PACKET_MMAPAF_PACKET 的情况相同,除了我们针对成批的帧而不是针对每个单独的帧启动流程(因此我们保存了一些上下文切换和系统调用)。

一旦我跟踪了 Rx 路径,我列表中的下一个是使用 sendmmsg()recvmmsg() 再次比较 Tx 和 Rx。

关于c++ - 使用 packet_mmap 的 RX/TX 是否需要拷贝?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43688308/

相关文章:

c - bsearch 与结构指针数组

编译我自己的内核(不是来自 linux-kernel 源代码)

linux - 如何根据 awk 打印中的前缀获取字段?

c# - 快速发送进程间信号

c++ - Iconv 库多次安装导致错误

c++ - 正确初始化多维 vector

linux - 将 rsa token 复制到组内的远程主机

c++ - 无法确定为什么代码在打印后停止 113383

c - 用于从 matlab 创建可执行 .mexa64 文件的 Makefile

c - 在 C 中打印值的地址或指针