复制 NetBufferListInfo 数组而不是调用 NdisCopySendNetBufferListInfo?

Posted

技术标签:

【中文标题】复制 NetBufferListInfo 数组而不是调用 NdisCopySendNetBufferListInfo?【英文标题】:Copying the NetBufferListInfo array instead of calling NdisCopySendNetBufferListInfo? 【发布时间】:2021-12-06 10:53:05 【问题描述】:

我有一个内核驱动程序,它在每个接收/发送 NBL 中分离每个网络缓冲区,并为每个包含数据包内容和其他内容的 NB 分配一个本地结构,并将其发送到用户缓冲区,并完成/返回原创 NBL。然后,用户服务将正常的数据包发回给驱动程序,然后我通过为每个数据包创建一个 NBL,然后将它们链接在一起,最终发送/指示它们。

这会导致一些关于数据包的元数据丢失,这些元数据似乎在 NetBufferListInfo 中(特别是 WFP 元数据)。

我的问题是,我是否可以将 NetBufferListInfo 的内容保存在相应 NB 的原始 NBL 中,并将其保存到代表 NB 的本地结构中,并在我创建包含该 NB 的 NBL 时重新复制它?

我认为我应该使用 NdisAllocateCloneNetBufferList + NetBufferListInfo 并将指向克隆的 NBL 的指针作为新成员复制到我的本地结构中,但是这样做的问题是使用 NdisFreeCloneNetBufferList 释放这些缓冲区将变得非常复杂,因为我创建了一个本地每个网络缓冲区的结构并将它们插入到发送给用户服务的列表中,它们中的每一个都可以指向任意 NBL(并且其中许多可能指向同一个 NBL,因为我为多个 NB 克隆一次 NBL在 NBL 中),并且当用户发送那些对我来说可以的内容时,我需要注意不要在我指示/发送 NBL 后两次释放克隆的 NBL(我认为它会导致双重免费 BSOD)。因此,我需要为每个克隆的 NBL 保留一个引用计数,并确保在它达到 0 时将其释放,以及其他一些并发症..

那么对我来说最简单的解决方案是什么?我可以将相应 NBL 的 NetBufferListInfo 数组的内容保存在我的本地结构中,并在创建与 NB 对应的最终 NBL 时重新复制它吗?

【问题讨论】:

【参考方案1】:

您可以复制完整记录且您在语义上理解的 NetBufferListInfo 字段。例如,您可以复制TcpIpChecksumNetBufferListInfo,因为它有完整的文档记录,并且从语义上讲,将其传播到具有相同有效负载的另一个 NBL 是有意义的。

但是有些字段是操作系统私有的,其中至少有一个是 refcounted 指针。因此,如果您要复制该字段,然后返回原始 NBL,则指针将悬空。影响引用计数的唯一方法是调用NdisCopySendNetBufferListInfoNdisCopyReceiveNetBufferListInfo,它们会为您处理。

TL;DR:你可以这样写代码:

new_nbl->NetBufferListInfo[TcpIpChecksumNetBufferListInfo] = old_nbl->NetBufferListInfo[TcpIpChecksumNetBufferListInfo];
new_nbl->NetBufferListInfo[NetBufferListHashValue] = old_nbl->NetBufferListInfo[NetBufferListHashValue];
. . .

但你不能写这样的代码:

RtlCopyMemory(
    new_nbl->NetBufferListInfo,
    old_nbl->NetBufferListInfo,
    sizeof(old_nbl->NetBufferListInfo));

因为并非所有的插槽都是 blittable。

【讨论】:

那么我需要复制哪一部分来保留应用程序的 WFP 跟踪信息,任务管理器使用它来显示网络使用情况?我尝试了两件事:1.分配一个空的NBL并调用NdisCopySendNetBufferListInfo,src为原始NBL,2.将原始NBL复制到新的NBL缓冲区,然后调用NdisCopySendNetBufferListInfo。两者都导致BSOD。我尝试这样做是因为我不能使用 NdisAllocateCloneNetBufferList 因为在这种情况下开销太大,考虑到我需要保留的只是 WFP 驱动程序所需的跟踪信息。 NdisCopySendNetBufferListInfo 是使 taskmgr 满意所必需的。 所以只有当我给 NdisCopySendNetBufferListInfo 一个使用 NdisAllocateCloneNetBufferList 分配的 NBL 时才有可能,对吧?没有其他办法,例如给它一个假的NBL只是为了填写其中的信息?因为当我使用 NdisAllocateCloneNetBufferList 时,整体网络带宽减少了大约 50%。 没关系,我解决了如下问题:我为多个 NB 克隆了一个 NBL,并将其指针存储在我的内部结构中并返回/完成原始 NBL,然后我使用克隆的 NBL 中的 ChildRefCount存储对 NBL 的引用数量(使用 ChildRefCount 作为存储我的引用计数变量的地方,因为它已经没用了),当我最终发送它们时,我将其递减并仅将克隆的 NBL 用于 NdisCopyNetBufferListInfo 到我的新创建的 NBL,当引用计数为零时,我释放克隆的 NBL。

以上是关于复制 NetBufferListInfo 数组而不是调用 NdisCopySendNetBufferListInfo?的主要内容,如果未能解决你的问题,请参考以下文章

连接 Numpy 数组而不复制

将numpy结构化数组子集转换为numpy数组而不复制

复制数组而不链接到它[重复]

将相同numpy数组的两个视图组合成单个视图而不复制数组?

如何从 PHP 扩展返回数组,而不将其复制到内存中?

在 C++ std::vector 和 C 数组之间转换而不复制