内核驱动场景下:复制NetBufferListInfo数组替代调用NdisCopySendNetBufferListInfo是否可行?
你的问题正好戳中了内核驱动处理NBL时的一个常见痛点——拆分NB后重建NBL,很容易丢失绑定在原始NBL上的WFP这类关键元数据。先直接给你答案:完全可以通过保存并重新复制NetBufferListInfo数组内容来解决这个问题,而且这大概率是比克隆NBL更简单的方案。
为什么直接复制NetBufferListInfo更合适?
你之前考虑的NdisAllocateCloneNetBufferList+引用计数的思路虽然可行,但复杂度太高了:
- 同一个原始NBL拆分出的多个NB会共享同一个克隆NBL,你必须给克隆NBL维护严格的引用计数——每个本地结构关联克隆NBL时计数+1,所有关联的本地结构都处理完成后计数减到0才能释放,稍有不慎就会触发双重释放导致BSOD。
- 还要额外处理同步(比如自旋锁)来保证引用计数的线程安全,很容易引入隐蔽的bug,而且克隆NBL本身也会占用更多内核内存。
相比之下,直接复制NetBufferListInfo数组是轻量得多的选择,步骤也清晰:
具体实现步骤
保存原始NBL的NetBufferListInfo
遍历原始NBL的NetBufferListInfo数组,把每个条目的InfoType和对应的InfoData完整复制到你的本地结构中。这里要注意区分两种类型的元数据:- 值类型(比如
ULONG、固定大小的结构体):直接 memcpy 复制即可。 - 指针类型(比如WFP的某些动态分配的元数据):不能只复制指针,要把指针指向的实际内存内容也拷贝到你自己分配的内核内存里,和本地结构绑定在一起。
- 特别针对WFP元数据:比如
NET_BUFFER_LIST_INFO_WFP_METADATA,里面的FWPS_STREAM_METADATA可能包含动态数据,建议用WFP提供的专用函数来完成安全拷贝,避免手动拷贝出错。
- 值类型(比如
重建NBL时恢复元数据
当用户服务确认数据包正常并返回后,你创建新的NBL时,调用NdisSetNetBufferListInfo,把之前保存的每个InfoType和对应的数据逐一设置到新NBL中。如果是之前拷贝的动态内存,设置完成后记得在合适的时机释放这些内存(比如新NBL被NDIS处理完成后)。
额外优化点
如果某些元数据是NBL级别的(所有NB共享同一份),你不用给每个本地结构都存一份——可以在本地结构里记录一个指向共享元数据的指针,或者用一个单独的结构保存NBL级元数据,让同一个原始NBL拆分出的所有本地结构共享它,这样能节省内核内存。
总的来说,直接保存并复制NetBufferListInfo是最简洁、低风险的解决方案,只要处理好元数据的内存拷贝和释放,就能完美保留WFP等关键元数据。
内容的提问来源于stack exchange,提问作者OneAndOnly

