【问题标题】:How to avoid data copy in NDIS filter driver如何避免 NDIS 过滤器驱动程序中的数据复制
【发布时间】:2017-12-02 02:03:55
【问题描述】:

我正在开发一个 NDIS 过滤器驱动程序,它实际上将数据从 NET_BUFFER 复制到发送路径中驱动程序分配的缓冲区,并将这些驱动程序分配的缓冲区推入内部队列。稍后,数据再次从队列中这些驱动程序分配的缓冲区复制到 IRP 缓冲区。我想避免这个数据副本。

在 Linux 中,我们可以创建一个 skbuff 的克隆,并且克隆的 skbuff 可以排队供以后使用。 Windows 中是否也有类似的选项?如果有办法克隆 NET_BUFFER,我们可以简单地避免从 NET_BUFFER 到驱动程序分配的内存缓冲区的第一次复制。

如果有一种方法可以实现从 NetBufferLists 到 IRP 缓冲区的零复制,那么它确实是一个理想的解决方案。如果有人可以提出更好的解决方案来避免发送路径中的副本,那将非常有帮助。

【问题讨论】:

    标签: ndis


    【解决方案1】:

    我不清楚为什么你需要复制 NB (NET_BUFFER)。如果您打算将 NB 加入队列以在不同线程上进行处理,则可以使用原始 NB 执行此操作 - 无需复制任何内容。

    您需要复制有效负载的唯一原因是您计划在缓冲区上挂起一段时间(例如,超过 1000 毫秒)。在高层次上,与 NB 相关联的有效负载属于应用程序。 NDIS 允许您对 NB 进行排队、进行一些处理、删除它、修改它等。但是(取决于套接字选项)应用程序可能会被卡住,直到它的缓冲区完成返回给它为止。因此,您不能无限期地挂在原始 NB 或其有效负载上。如果您要做一些需要很长时间的事情,那么您应该分配您需要的所有数据结构(NBL、NB、MDL 和有效负载缓冲区)的深层副本,并将原件返回给应用程序。

    如果您将数据包负载填充到 IRP 中以便用户模式进程可以考虑负载,那么您确实需要 1 个副本。原因是内核不能信任任何用户模式进程在特定的时间预算内做任何事情。例如,想象一下系统将要休眠。内核适当地挂起所有用户模式进程,然后等待每个设备进入低功耗状态。但是网卡不能低功耗,因为数据路径不会暂停,因为某些数据包卡在您的过滤器驱动程序中,等待(现在暂停的)用户模式进程回复。因此,您可以通过网络设备上的 IO 将 IO 分离到用户模式来保护自己:制作副本。

    但是,如果您所做的只是将数据包发送到另一个进行(例如)加密的内核设备,那么您可以假设加密设备确保了合理的时间预算,因此提供原始数据包可能是安全的有效载荷。

    【讨论】:

    • 感谢您的回复!我真的需要在 NB 中复制有效负载并将其传递给调用 read 的用户模式进程。现在,在 SendNetBufferLists() 中,NB 中的有效负载被复制到驱动程序分配的中间缓冲区,并将该中间缓冲区添加到队列中。在调度(读取)例程中,中间缓冲区从队列中移除并复制到 IRP 缓冲区。我想将有效负载直接从 NB 复制到 IRP 缓冲区,如果我们可以将 NB 放入队列中,这应该是可能的。它会保存一份副本。如果您能提出一种方法来做到这一点,那将非常有帮助。
    猜你喜欢
    • 2012-02-02
    • 2020-03-19
    • 2020-11-16
    • 1970-01-01
    • 2020-11-12
    • 2012-05-05
    • 2016-03-10
    • 2021-01-27
    • 2013-08-20
    相关资源
    最近更新 更多