UDP получает сегмент объединения разгрузки (URO)
Начиная с версии Windows 11 24H2, разгрузка объединения UDP-сегментов (URO) позволяет сетевым интерфейсным картам (NIC) совмещать принимаемые сегменты UDP. Сетевые адаптеры могут объединять датаграммы UDP из одного потока, соответствующего набору правил, в логически смежный буфер. Затем эти объединенные диаграммы данных указываются в сетевом стеке Windows в виде одного большого пакета.
Объединение диаграмм данных UDP снижает затраты ЦП на обработку пакетов в потоках высокой пропускной способности, что приводит к повышению пропускной способности и меньшему объему циклов на байт.
В следующих разделах описаны правила объединения пакетов UDP и создание минипорт-драйвера URO.
- правила объединения пакетов UDP
- написать драйвер мини-порта URO
- Рекомендации по программированию драйверов URO
Правила объединения пакетов UDP
Объединение URI может выполняться только на пакетах, которые соответствуют всем следующим критериям:
-
IpHeader.Version
идентичен для всех пакетов. -
IpHeader.SourceAddress
иIpHeader.DestinationAddress
идентичны для всех пакетов. -
UdpHeader.SourcePort
иUdpHeader.DestinationPort
идентичны для всех пакетов. -
UdpHeader.Length
идентичен для всех пакетов, кроме последнего, который может быть меньше. -
UdpHeader.Length
должен быть ненулевой. -
UdpHeader.Checksum
, если ненулевая, должна быть правильной для всех пакетов. Это означает, что разгрузка контрольной суммы должна проверить пакет. -
Layer 2 headers
должен быть идентичен для всех пакетов.
Если пакеты являются IPv4, они также должны соответствовать следующим критериям:
-
IPv4Header.Protocol
== 17 (UDP) для всех пакетов. -
EthernetHeader.EtherType
== 0x0800 для всех пакетов. -
IPv4Header.HeaderChecksum
на полученных пакетах должно быть правильным. Это означает, что прием разгрузки контрольной суммы должен удостовериться в правильности заголовка. -
IPv4Header.HeaderLength
== 5 (без заголовков параметров IPv4) для всех пакетов. -
IPv4Header.ToS
идентичен для всех пакетов. -
IPv4Header.ECN
идентичен для всех пакетов. -
IPv4Header.DontFragment
идентичен для всех пакетов. -
IPv4Header.TTL
идентичен для всех пакетов. -
IPv4Header.TotalLength
==UdpHeader.Length
* + длина (IPv4Header
) для всех пакетов.
Если пакеты являются IPv6, они также должны соответствовать следующим критериям:
-
IPv6Header.NextHeader
== 17 (UDP) для всех пакетов (без заголовков расширений). -
EthernetHeader.EtherType
== 0x86dd (IPv6) для всех пакетов. -
IPv6Header.TrafficClass
иIPv6Header.ECN
идентичны для всех пакетов. -
IPv6Header.FlowLabel
идентичны для всех пакетов. -
IPv6Header.HopLimit
идентичен для всех пакетов. -
IPv6Header.PayloadLength
==UdpHeader.Length
для всех пакетов.
Структура пакетов URI
Результирующая единая объединенная единица (SCU) должна иметь один IP-заголовок и заголовок UDP, за которыми следуют полезные данные UDP для всех объединенных датаграмм, соединённых вместе.
Для индикаторов URO необходимо задать поле IPv4Header.TotalLength
на общую длину SCU, поле IPv6Header.PayloadLength
на длину полезных данных UDP и поле UdpHeader.Length
на длину объединенных полезных данных.
Если заголовки уровня 2 (L2) присутствуют в объединенных диаграммах данных, SCU должен содержать допустимый заголовок L2. Заголовок L2 в SCU должен напоминать заголовок L2 объединенных диаграмм данных.
Проверка и указание контрольной суммы
Указания URO должны задать для полей IPv4Header.HeaderChecksum
и UdpHeader.Checksum
значение нуль и заполнить сведения об обоченном вычислении контрольной суммы через SCU, указывающем на успешность проверки контрольных сумм IPv4 и UDP.
Пакет, соответствующий всем условиям объединения, но проверка контрольной суммы завершается сбоем, должна быть указана отдельно. Пакеты, полученные после него, не должны быть объединены с пакетами, полученными до него.
Например, предположим, что пакеты 1, 2, 3, 4 и 5 получены из одного потока, но пакет 3 не проходит проверку контрольной суммы. Пакеты 1 и 2 можно объединить вместе, а пакеты 4 и 5 можно объединить вместе, но пакет 3 не должен быть объединен с помощью SCU. Пакеты 1 и 2 не должны объединяться вместе с пакетами 4 и 5. Пакет 2 — это последний пакет в SCU, а пакет 4 запускает новый SCU. Кроме того, необходимо указать SCU, содержащий пакеты 1 и 2, прежде чем указан пакет 3, и перед SCU, содержащим пакеты 4 и 5, необходимо указать пакет 3.
Объединение пакетов и разделение потоков
Пакеты из нескольких потоков могут быть объединены параллельно, если это позволяет аппаратное обеспечение и память. Пакеты из разных потоков не должны объединяться друг с другом.
Пакеты, полученные из нескольких чередующихся приемов, могут быть разделены и объединены с их соответствующими потоками. Например, для потоков A, B и C, если пакеты прибывают в порядке A, A, B, C, B, A, пакеты из потока A можно объединить в AAA, а пакеты из потока B объединить в BB, в то время как пакет из потока C может быть отмечен как обычно или объединён с ожидающей SCU из потока C.
Пакеты в заданном потоке не должны быть переупорядочены относительно друг друга. Например, пакеты из потока A должны быть объединены в порядке их получения, даже если пакеты из потоков B и C поступают между ними.
Ключевое слово INF для управления URO
Для включения и отключения URO с настройкой ключа реестра можно использовать следующее ключевое слово:
*UdpRsc
Ключевые слова INF, стандартизированные для перечисления, имеют следующие атрибуты:
subkeyName: имя ключевого слова, которое необходимо указать в INF-файле и которое отображается в реестре.
ParamDesc: отображаемый текст, связанный с SubkeyName.
Значение: Целочисленное значение перечисления, которое связано с каждым параметром в списке. Это значение хранится в NDI\params\SubkeyName\Value.
EnumDesc: отображаемый текст, связанный с каждым значением, отображаемым в меню.
по умолчанию: значение по умолчанию для меню.
SubkeyName | ParamDesc | Ценность | EnumDesc |
---|---|---|---|
*UdpRsc |
УРО | 0 | Нетрудоспособный |
1 (по умолчанию) | Включен |
Дополнительные сведения об использовании ключевых слов перечисления см. в разделе о ключевых словах перечисления.
Написать минипорт-драйвер URO
Начиная с версии NDIS 6.89 интерфейс NDIS для URO упрощает обмен данными между TCP/IP и мини-драйвером NDIS.
Возможности URO отчета
Минипорт-драйвер объявляет поддержку URI в элементе UdpRsc
структуры NDIS_OFFLOAD, которая передается в функцию NdisMSetMiniportAttributes.
Возможность запроса URO
Чтобы проверить, поддерживает ли минипорт драйвер URO, драйверы NDIS и другие приложения могут запрашивать OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES OID, который возвращает структуру NDIS_OFFLOAD
.
Состояние URI запроса
Чтобы определить текущее состояние URO, драйверы NDIS и другие приложения могут выполнить запрос OID_TCP_OFFLOAD_CURRENT_CONFIG OID. NDIS обрабатывает этот OID и не передает его в мини-порт.
Изменение состояния URO
URO можно включить или отключить путём отправки запроса OID_TCP_OFFLOAD_PARAMETERS OID. Этот OID использует структуру NDIS_OFFLOAD_PARAMETERS. В этой структуре элемент UdpRsc.Enabled
может иметь следующие значения:
Ценность | Значение |
---|---|
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_NO_CHANGE 0 |
Драйвер минипорта не должен изменять текущий параметр. |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED 1 |
URO отключен. |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_ENABLED 2 |
URO включен. |
Когда драйвер обрабатывает запрос OID_TCP_OFFLOAD_PARAMETERS OID с установленным флагом NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED
, сетевому адаптеру необходимо дождаться завершения обработки запроса, пока не будут обработаны все существующие агрегированные сегменты и активные индикации URO. Это обеспечивает синхронизацию событий включения и отключения URO между компонентами NDIS.
После того как драйвер минипорта обработает запрос OID_TCP_OFFLOAD_PARAMETERS OID, он должен выдать указание статуса NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG с обновленным состоянием разгрузки.
Флаг NDIS_OFFLOAD_PARAMETERS_SKIP_REGISTRY_UPDATE
в NDIS_OFFLOAD_PARAMETERS позволяет отключить URO только во время выполнения. Изменения, внесенные с этим флагом, не сохраняются в реестре.
Отказ от URO в NDIS 6.89 и более поздних версиях
Драйверы, предназначенные для NDIS 6.89 и более поздних версий, должны понимать пакеты URO и корректно обрабатывать их. Чтобы отказаться от URO, выполните приведенные действия.
- Драйверы упрощенного фильтра (LWF) задают флаг
NDIS_FILTER_DRIVER_UDP_RSC_NOT_SUPPORTED
в структуре NDIS_FILTER_DRIVER_CHARACTERISTICS. - Драйверы протокола задают флаг
NDIS_PROTOCOL_DRIVER_UDP_RSC_NOT_SUPPORTED
в структуре NDIS_PROTOCOL_DRIVER_CHARACTERISTICS.
Этот подход гарантирует, что компоненты, не знакомые с URO, не получают NBL URO. NDIS отключает URI в мини-порте во время привязки, если присутствует драйвер LWF или протокол, не поддерживающий URI.
Соображения по программированию драйверов URO
При реализации минипорта, поддерживающего URO, примите во внимание следующие проблемы.
Winsock URO API
Дополнительные сведения об API URI Winsock см. в IPPROTO_UDP параметрах сокета. См. сведения о UDP_RECV_MAX_COALESCED_SIZE
и UDP_COALESCED_INFO
.
Обновления стека TCP/IP Для Windows
Транспорт Microsoft TCP/IP включает URO на этапе привязки с NDIS, если только конфигурация не препятствует этому.
Выделения WFP могут использовать FWP_CALLOUT_FLAG_ALLOW_URO
в FWPS_CALLOUT2, чтобы объявить о своей поддержке URO. Если несовместимая вызываемая функция WFP зарегистрирована на уровне, чувствительном к УРО, то ОС отключает УРО, пока функция зарегистрирована.
Если сокет выбирает URO с максимальным размером объединения больше или равным размеру аппаратной разгрузки, стек будет доставлять NBL-ы от оборудования в сокет без изменений. Если сокет выбирает меньший максимальный размер объединенного пакета, стек разбивает объединенный прием на меньшие части для сокета.
Если сокет не принимает участие в URI, стек перерегистрирует получение для этого сокета. При отсутствии аппаратного УРО существующая программная функция УРО остаётся доступной.