Разгрузка сегментации больших TCP-пакетов
Минипорт-драйверы NDIS могут разгрузить сегментацию крупных TCP-пакетов, превышающих MTU сетевого носителя. Сетевой адаптер, поддерживающий сегментацию больших TCP-пакетов, также должен иметь возможность:
Вычислите контрольные суммы IP для исходящих пакетов, содержащих IP-опции.
Вычислите контрольные суммы TCP для отправляемых пакетов, содержащих параметры TCP.
NDIS версии 6.0 и выше поддерживают разгрузку отправки большого объема версии 1 (LSOv1), которая аналогична разгрузке отправки большого объема (LSO) в NDIS 5.x. NDIS версии 6.0 и более поздних версий также поддерживают разгрузку отправки крупных пакетов версии 2 (LSOv2), которая предоставляет улучшенные функции сегментации крупных пакетов, включая поддержку IPv6.
Минипорт-драйвер, поддерживающий LSOv2 и LSOv1, должен определить тип разгрузки, используя информацию вне диапазона (OOB) о структуре NET_BUFFER_LIST. Драйвер может использовать элемент типа
Однако в случае, когда минипорт получил OID_TCP_OFFLOAD_PARAMETERS, чтобы отключить функцию LSO и после успешного выполнения OID, минипорт должен отбросить все NET_BUFFER_LIST, содержащие любые ненулевые данные LSOv1 или LSOv2 OOB (NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO).
Транспорт TCP/IP выгружает только те большие TCP-пакеты, которые соответствуют следующим критериям:
Пакет представляет собой TCP-пакет. Транспорт TCP/IP не выгружает большие пакеты UDP для сегментации.
Пакет должен быть разделен по крайней мере минимальным количеством сегментов, указанных драйвером мини-порта. Дополнительные сведения см. в статье Отчеты о возможностя х TCP-Packet-Segmentation сетевого адаптераPacket-Segmentation и отчетов о возможностях TCP-Packet-Segmentation сетевого адаптера.
Пакет не является пакетом обратного цикла.
Пакет не будет отправлен через туннель.
Перед разгрузкой большого TCP-пакета для сегментации транспорт TCP/IP:
- Обновляет сведения о сегментации больших пакетов, связанные со структурой NET_BUFFER_LIST. Эта информация соответствует структуре NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO, которая является частью информации NET_BUFFER_LIST, ассоциированной со структурой NET_BUFFER_LIST. Дополнительные сведения о NET_BUFFER_LIST см. в доступ к информации о NET_BUFFER_LIST для TCP/IP Offload. Транспорт TCP/IP задает значение MSS максимальному размеру сегмента.
Для LSOv1 записывает общую длину большого TCP-пакета в поле
Total Length
заголовка IP-адреса пакета. Общая длина включает длину заголовка IP, длину параметров IP, если они присутствуют, длину заголовка TCP, длину параметров TCP, если они присутствуют, и длину полезных данных TCP. Для LSOv2 задает полеTotal Length
ip-заголовка пакета значение 0. Драйверы минипорта должны определить длину пакета на основе длины первой структуры NET_BUFFER в структуре NET_BUFFER_LIST.Вычисляет суммы единичного дополнения для псевдозаголовка TCP и записывает эту сумму в поле
Checksum
TCP-заголовка. Транспорт TCP/IP вычисляет сумму дополнения одного из следующих полей в псевдогоголовоке:Source IP Address
,Destination IP Address
иProtocol
. Сумма дополнения для псевдозаголовка, предоставленного транспортом TCP/IP, предоставляет сетевому адаптеру возможность заранее вычислить реальную контрольную сумму TCP для каждого пакета, который сетевой адаптер получает из большого TCP-пакета, без необходимости проверки заголовка IP. Обратите внимание, что RFC 793 предусматривает, что контрольная сумма псевдозаголовка вычисляется на основеSource IP Address
,Destination IP Address
,Protocol
иTCP Length
. (Длина TCP — это длина заголовка TCP, а также длина полезных данных TCP. Длина TCP не включает длину псевдо-заголовка.) Однако, поскольку базовый мини-драйвер и сетевой адаптер создают сегменты TCP из большого пакета, передаваемого транспортом TCP/IP, транспорт не знает размер полезных данных TCP для каждого сегмента TCP и поэтому не может включать длину TCP в псевдозаголовок. Вместо этого, как описано ниже, сетевой адаптер расширяет контрольную сумму псевдозаголовка, предоставленную транспортом TCP/IP, для охвата длины каждого сегмента TCP.Записывает правильный порядковый номер в поле
Sequence Number
заголовка TCP. Номер последовательности определяет первый байт полезных данных TCP.
После получения структуры NET_BUFFER_LIST в функции MiniportSendNetBufferLists или MiniportCoSendNetBufferLists можно вызвать макрос NET_BUFFER_LIST_INFO с указанием _Id
TcpLargeSendNetBufferListInfo
, чтобы получить значение MSS, записанное транспортом TCP/IP.
Мини-драйвер получает общую длину большого пакета из IP-заголовка пакета и использует значение MSS для разделения большого TCP-пакета на меньшие пакеты. Каждый из небольших пакетов содержит MSS или меньше байт данных пользователя. Только последний пакет, созданный из сегментированного большого пакета, должен содержать меньше байтов пользовательских данных MSS. Все остальные пакеты, созданные из сегментированного пакета, должны содержать байты данных пользователя MSS. Если вы не следуйте этому правилу, создание и передача ненужных дополнительных пакетов может снизить производительность.
Минипорт-драйвер прикрепляет заголовки MAC, IP и TCP к каждому сегменту, производным от большого пакета. Минипорт-драйвер должен вычислить контрольные суммы IP и TCP для этих производных пакетов. Чтобы вычислить контрольную сумму TCP для каждого пакета, полученного из большого TCP-пакета, сетевой адаптер вычисляет переменную часть контрольной суммы TCP (для заголовка TCP и полезных данных TCP), добавляет эту контрольную сумму к сумме дополнения до единицы для псевдоголовика, вычисленного транспортом TCP/IP, а затем вычисляет 16-разрядное дополнение для этой контрольной суммы. Дополнительные сведения о вычислении таких контрольных сумм см. в rfC 793 и RFC 1122.
На следующем рисунке показана сегментация большого пакета.
Длина данных пользователя TCP в большом пакете TCP должна быть равна или меньше значения, которое драйвер минипорта назначает значению MaxOffLoadSize
. Дополнительные сведения о значении MaxOffLoadSize
см. в статье отчетов о возможностях TCP-Packet-Segmentation сетевого адаптера и отчетов о возможностях TCP-Packet-Segmentation сетевого адаптера.
После того как драйвер выдает указание состояния об изменении значения на MaxOffLoadSize
, он не должен завершаться сбоем, если получает запрос на отправку LSO, использующий предыдущее значение MaxOffLoadSize
. Вместо этого драйвер может отклонить запрос на отправку.
Промежуточный драйвер, который независимо выдает признаки состояния, сообщающие об изменении значения MaxOffLoadSize
, должен убедиться, что базовый минипорт-адаптер, не выдавший указания состояния, не получает пакеты, размеры которых превышают значение MaxOffLoadSize
, которое сообщил минипорт-адаптер.
Промежуточный минипорт-драйвер, реагирующий на OID_TCP_OFFLOAD_PARAMETERS для отключения служб LSO, должен быть готов к короткому периоду времени, когда запросы на отправку LSO по-прежнему могут достичь мини-драйвера.
Длина данных пользователя TCP в пакете сегмента должна быть меньше или равна MSS. MSS — это значение ULONG, которое транспорт TCP передает, используя информацию LSO NET_BUFFER_LIST, связанную с структурой NET_BUFFER_LIST. Только последний пакет, созданный из сегментированного большого пакета, должен содержать меньше байтов пользовательских данных MSS. Все остальные пакеты, созданные из сегментированного пакета, должны содержать байты данных пользователя MSS. Если вы не следуйте этому правилу, создание и передача ненужных дополнительных пакетов может снизить производительность.
Число пакетов сегментов, производных от большого TCP-пакета, должно быть равно или больше, чем значение MinSegmentCount
, указанное драйвером мини-порта. Дополнительные сведения о значении MinSegmentCount
см. в разделах отчет о возможностях TCP-Packet-Segmentation сетевого адаптера и отчет о возможностях TCP-Packet-Segmentation сетевого адаптера.
Следующие предположения и ограничения применяются к обработке заголовков IP и TCP для любого мини-порта, поддерживающего LSO, независимо от версии:
Бит MF в заголовке IP большого TCP-пакета, от которого транспорт TCP/IP разгружен, не будет установлен, и смещение фрагмента в заголовке IP будет равно нулю.
Флаги URG, RSTи SYN в заголовке TCP большого TCP-пакета не будут установлены, а срочное смещение (указатель) в заголовке TCP будет равно нулю.
Если бит FIN установлен в заголовке TCP большого пакета, минипорт-драйвер должен установить этот бит в заголовке TCP последнего пакета, который он формирует из большого TCP-пакета.
Если в заголовке TCP для большого TCP-пакета установлен бит PSH, мини-драйвер должен установить этот бит в заголовке TCP последнего пакета, который он создаёт из большого TCP-пакета.
Если бит CWR в заголовке TCP большого TCP-пакета установлен, драйвер минипорта должен установить этот бит в заголовке TCP первого пакета, который он создает из большого TCP-пакета. Минипорт-драйвер может задать этот бит в заголовке TCP последнего пакета, который он создает из большого TCP-пакета, хотя это менее желательно.
Если большой TCP-пакет содержит параметры IP или параметры TCP (или оба), драйвер минипорта копирует эти параметры без изменений в каждый пакет, производный от большого TCP-пакета. В частности, сетевой адаптер не будет увеличивать опцию метки времени .
Все заголовки пакетов (ethernet, IP, TCP) будут находиться в первом MDL пакета. Заголовки не будут разделены между несколькими MDL.
Совет
Это предположение допустимо при включении LSO. В противном случае, если LSO не включен, драйверы минипорта не могут предположить, что заголовки IP-адресов находятся в том же MDL, что и заголовки Ethernet.
Минипорт-драйвер должен отправлять пакеты в NET_BUFFER_LIST структурах в том порядке, в котором он получает NET_BUFFER_LIST структуры от транспорта TCP/IP.
При обработке большого TCP-пакета мини-адаптер отвечает только за сегментирование пакета и аффиксирование заголовков MAC, IP и TCP на пакеты, производные от большого TCP-пакета. Транспорт TCP/IP выполняет все остальные задачи (например, изменение размера окна отправки на основе размера окна получения удаленного узла).
Перед выполнением операции отправки для большого пакета (например, с NdisMSendNetBufferListsComplete или NdisMCoSendNetBufferListsComplete), минипорт-драйвер записывает значение NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO (NET_BUFFER_LIST сведения для разгрузки при больших отправках) с общим числом TCP байтов пользовательских данных, которые успешно отправляются во всех пакетов, созданных из большого TCP-пакета.
Помимо предыдущих требований LSO, драйверы мини-порта, поддерживаемые LSOv2, также должны:
Поддержка IPv4 или IPv6 или IPv4 и IPv6.
Поддерживать репликацию параметров IPv4 из большого пакета в каждом сегментном пакете, который генерирует сетевая карта.
Обеспечение репликации заголовка расширения IPv6 из крупного TCP-пакета в каждом пакете TCP-сегмента.
Поддержка репликации параметров TCP в каждом пакете сегмента TCP, который создает драйвер мини-порта.
Используйте заголовок IP и TCP в структуре NET_BUFFER_LIST в качестве шаблона для создания заголовков TCP/IP для каждого пакета сегмента.
Используйте значения идентификатора IP в диапазоне от 0x0000 до 0x7FFF. (Диапазон от 0x8000 до 0xFFFF зарезервирован для устройств с поддержкой разгрузки TCP.) Например, если IP-заголовок шаблона начинается со значения поля идентификации 0x7FFE, первый пакет сегмента TCP должен иметь значение IP-идентификатора 0x7FFE, а затем 0x7FFF, 0x0000, 0x0001 и т. д.
Используйте смещение байтов в члене TcpHeaderOffset структуры NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO, чтобы определить расположение заголовка TCP, начиная с первого байта пакета.
Ограничить число структур NET_BUFFER, связанных с каждой структурой NET_BUFFER_LIST LSOv2, до одной.
Заметка
Это новое требование для минипорт-драйверов с поддержкой LSOv2. Это правило не применяется для драйверов мини-порта LSOv1 явно, хотя рекомендуется.
Определите общую длину пакета, исходя из длины первой структуры
NET_BUFFER
в структуреNET_BUFFER_LIST
. Это отличается от драйверов методов для LSOv1.Поддержка параметров TCP, параметров IP и заголовков расширений IP.
После завершения операции отправки драйвер минипорта должен установить член
LsoV2TransmitComplete.Reserved
структуры NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO в ноль, а членLsoV2TransmitComplete.Type
— вNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE
.