有没有办法一次读取NET_BUFFER



我制作了NDIS 6网络过滤器驱动程序,正在读取数据包。当我使用Intel I350 NIC时,"MmGetMdlByteCount"返回"9014"字节。这个值与MTU大小相同,所以我可以一次读取数据。但是,当使用x540 NIC时,"MmGetMdlByteCount"将返回到"2048"字节。所以我不得不一遍又一遍地阅读MDL。为什么会发生这种情况?有没有办法在X540 NIC上一次读取数据?我想减少重复,因为我认为如果我把数据带几次,消耗时间会更长。

您看到的是NIC硬件物理工作方式的结果。不同的硬件将使用不同的缓冲区布局策略。NDIS并不试图强制每个NIC使用相同的策略,因为这会降低某些NIC的性能。不幸的是,这意味着处理不同缓冲区的复杂性会被推到NDIS过滤器中;协议驱动程序。

您可以使用NdisGetDataBuffer为您做一些这方面的工作。在内部,NdisGetDataBuffer的工作方式如下:

if MmGetSystemAddressForMdl fails:
return NULL;
else if the payload is already contiguous in memory:
return a pointer to that directly;
else if you provided your own buffer:
copy the payload into your buffer
return a pointer to your buffer;
else:
return NULL;

因此,您可以使用NdisGetDataBuffer来获得有效负载的连续视图。最简单的使用方法是:

UCHAR ScratchBuffer[MAX_MTU_SIZE];
UCHAR *Payload = NdisGetDataBuffer(NetBuffer, NetBuffer->DataLength, ScratchBuffer, 1, 0);
if (!Payload) {
return NDIS_STATUS_RESOURCES; // very unlikely: MmGetSystemAddressForMdl failed
}
memcpy(baImage, Payload, NetBuffer->DataLength);

但在某些情况下,这可能有双重副本。(练习测试你的理解:什么时候会有双重复制?(为了获得更好的性能,你可以用这个技巧避免双重复制:

UCHAR *Payload = NdisGetDataBuffer(NetBuffer, NetBuffer->DataLength, baImage, 1, 0);
if (!Payload) {
return NDIS_STATUS_RESOURCES; // very unlikely: MmGetSystemAddressForMdl failed
}
// Did NdisGetDataBuffer already copy the payload into my flat buffer?
if (Payload != baImage) {
// If not, copy from the MDL to my flat buffer now.
memcpy(baImage, Payload, NetBuffer->DataLength);
}

您还没有包含完整的代码示例,但我怀疑您的代码中可能存在一些错误。我没有看到任何处理NetBuffer的尝试->CurrentMdlOffset。虽然这通常是零,但它并不总是零,因此您的代码并不总是正确的。

类似地,副本似乎没有受到ulDataLength的正确约束。你需要一个ulDataLength -= ulBytesToCopy在那里的某个地方来解决这个问题。

我非常同情导航NBL、NB和MDL是多么棘手——我的第一个NIC驱动程序在计算MDL偏移量时包含了一个严重的错误。我在内部有一些MDL处理代码——我会尝试清理一下,并在https://github.com/microsoft/ndis-driver-library/在接下来的几天里。如果我发布了这篇文章,我会更新它。我认为显然需要一些好的、可重复使用的、文档充分的示例代码,以便将MDL链(的子集(复制到平面缓冲区中,反之亦然。

更新:参考mdl.h 中的MdlCopyMdlChainAtOffsetToFlatBuffer

最新更新