我已经阅读了所有可能的文档,例如 ( 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
流程似乎是:
- 数据包通过 TP_STATUS_USER 从内核到达 RX 缓冲区
- 我处理数据包,然后设置 TP_STATUS_SEND_REQUEST
- 内核设置TP_STATUS_SENDING,同时发送
- 发送完成后内核设置 TP_STATUS_AVAILABLE
- 我设置 TP_STATUS_KERNEL 告诉内核我已经处理完这些数据包,它们可能会被覆盖
但是,由于 TP_STATUS_AVAILABLE 与 TP_STATUS_KERNEL 具有相同的值,如果此流程正确,内核将在完成 TX 操作后立即清除数据包。在我看来,可能需要复制到单独的 TX 缓冲区。关于使用 packet_mmap 和 packet_tx_ring 的信息有限。我发现的例子主要是针对 RX(我有工作的 atm)。我喜欢 RX/TX 场景的示例(例如桥接原始数据包)。
有没有人对此有更好的理解?示例桥接也将是最有帮助的!
最佳答案
之前注意:我仍在阅读和学习PACKET_MMAP
和af_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 路径时发现的内容 here和 here .我现在要开始通过 Rx 路径进行跟踪。这些链接中有关 Tx 路径的信息摘要是,在用应用程序数据(帧)填充 Tx 环并调用 sendto()
后,内核将每个数据包/帧复制到 sk_buff
和 NIC 将数据复制到它的硬件队列(通过 DMA)以在线路上发送数据包/帧。所以这是两个拷贝(尽管 DMA 拷贝是必需的!),再加上您必须将应用程序数据复制到 Tx 环中,以便制作三个拷贝。这与没有 PACKET_MMAP
和 AF_PACKET
的情况相同,除了我们针对成批的帧而不是针对每个单独的帧启动流程(因此我们保存了一些上下文切换和系统调用)。
一旦我跟踪了 Rx 路径,我列表中的下一个是使用 sendmmsg()
和 recvmmsg()
再次比较 Tx 和 Rx。
关于c++ - 使用 packet_mmap 的 RX/TX 是否需要拷贝?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43688308/