Как избежать копирования данных в драйвере фильтра NDIS

Я работаю над драйвером фильтра NDIS, который фактически копирует данные из NET_BUFFER в выделенные драйвером буферы в пути отправки и помещает эти выделенные драйвером буферы во внутреннюю очередь. Позже данные снова копируются из этих выделенных драйвером буферов в очереди в буферы IRP. Я хочу избежать этой копии данных.

В Linux мы можем создать клон skbuff, и клонированный skbuff может быть поставлен в очередь для последующего использования. Есть ли аналогичная опция в Windows? Если есть способ клонировать NET_BUFFER, мы можем просто избежать первой копии, которая происходит из NET_BUFFER в буферы памяти, выделенные драйвером.

Если бы существовал способ добиться нулевого копирования из NetBufferLists в буферы IRP, то это действительно было бы идеальным решением. Было бы очень полезно, если бы кто-нибудь мог предложить лучшее решение, чтобы избежать копий в пути отправки.


person Arun Kaushal    schedule 28.06.2017    source источник


Ответы (1)


Мне непонятно, зачем вообще нужно копировать NB (NET_BUFFER). Если вы планируете поставить NB в очередь для обработки в другом потоке, вы можете сделать это с исходным NB, и вам не нужно ничего копировать.

Единственная причина, по которой вам нужно скопировать полезную нагрузку, — это если вы планируете некоторое время зависать в буфере (скажем, более 1000 мс). На высоком уровне полезная нагрузка, связанная с NB, принадлежит приложению. NDIS позволяет вам поставить NB в очередь, выполнить некоторую обработку, удалить его, изменить и т. д. Но (в зависимости от параметров сокета) приложение может зависнуть до тех пор, пока его буфер не будет возвращен обратно к нему. Таким образом, вы не можете цепляться за исходный NB или его полезную нагрузку бесконечно. Если вы собираетесь делать что-то, что занимает много времени, вам следует выделить глубокую копию всех необходимых вам структур данных (NBL, NB, MDL и буфер полезной нагрузки) и вернуть оригиналы обратно в приложение.

Если вы загружаете полезную нагрузку пакета в IRP, чтобы процесс пользовательского режима мог обдумать полезную нагрузку, вам действительно нужна 1 копия. Причина в том, что ядро ​​не может доверять какому-либо процессу пользовательского режима выполнение каких-либо действий в рамках определенного бюджета времени. Представьте, например, что система переходит в спящий режим. Ядро должным образом приостанавливает все процессы пользовательского режима, а затем ждет, пока каждое устройство перейдет в состояние пониженного энергопотребления. Но сетевая карта не может перейти в режим пониженного энергопотребления, потому что путь данных не будет приостановлен, потому что какой-то пакет застрял в вашем драйвере фильтра, ожидая ответа (теперь приостановленного) процесса пользовательского режима. Таким образом, вы защищаете себя, отвязывая IO в usermode с IO по сетевому устройству: сделайте копию.

Но если все, что вы делаете, это отправляете пакет на другое устройство ядра, которое выполняет (скажем) шифрование, тогда вы можете предположить, что устройство шифрования обеспечивает разумный бюджет времени, поэтому может быть безопасно передать ему исходную полезную нагрузку пакета. .

person Jeffrey Tippet    schedule 30.06.2017
comment
Спасибо за ответ! Мне действительно нужно скопировать полезную нагрузку в NB и передать ее процессу пользовательского режима, вызывающему чтение. Прямо сейчас в SendNetBufferLists() полезная нагрузка в NB копируется в промежуточный буфер, выделенный драйвером, и этот промежуточный буфер добавляется в очередь. В процедуре отправки (чтения) промежуточный буфер удаляется из очереди и копируется в буфер IRP. Я хочу скопировать полезную нагрузку непосредственно из NB в буфер IRP, что должно быть возможно, если мы сможем поставить NB в очередь. Это сэкономит одну копию. Было бы очень полезно, если бы вы могли предложить способ сделать это. - person Arun Kaushal; 30.06.2017