큰 TCP 패킷의 세그먼트화 오프로드하기
NDIS(네트워크 드라이버 인터페이스 사양) 미니포트 드라이버는 네트워크 매체의 최대 전송 장치(MTU)보다 큰 대형 TCP 패킷의 분할을 오프로드할 수 있습니다. 큰 TCP 패킷의 분할을 지원하는 NIC도 다음을 수행할 수 있어야 합니다.
IP 옵션을 포함하는 송신 패킷에 대한 IP 체크섬을 계산합니다.
TCP 옵션을 포함하는 송신 패킷에 대한 TCP 체크섬을 계산합니다.
NDIS 버전 6.0 이상에서는 NDIS 5의 대규모 송신 오프로드(LSO)와 유사한 대규모 송신 오프로드 버전 1(LSOv1)을 지원합니다.x. NDIS 버전 6.0 이상에서는 IPv6 지원을 포함하여 향상된 대규모 패킷 구분 서비스를 제공하는 LSOv2(대규모 송신 오프로드 버전 2)도 지원합니다.
LSOv2 및 LSOv1을 지원하는 미니포트 드라이버는 NET_BUFFER_LIST 구조체 OOB(out-of-band) 정보에서 오프로드 유형을 결정해야 합니다. 드라이버는 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 구조체의 Type 멤버를 사용하여 드라이버 스택이 LSOv2 또는 LSOv1을 사용하는지 여부를 확인하고 적절한 오프로드 서비스를 수행할 수 있습니다. LSOv1 또는 LSOv2 OOB 데이터를 포함하는 모든 NET_BUFFER_LIST 구조체에는 단일 NET_BUFFER 구조도 포함됩니다. NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO에 대한 자세한 내용은 TCP/IP 오프로드 NET_BUFFER_LIST 정보 접근하기를 참조하세요.
그러나 미니포트가 미니포트에서 LSO 기능을 해제하라는 OID_TCP_OFFLOAD_PARAMETERS를 수신하고, 미니포트가 해당 OID를 성공적으로 완료한 후에는, 미니포트는 0이 아닌 LSOv1 또는 LSOv2 OOB 데이터를 포함하는 모든 NET_BUFFER_LIST(NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO포함)를 삭제해야 합니다.
TCP/IP 전송은 다음 조건을 충족하는 큰 TCP 패킷만 오프로드합니다.
패킷은 TCP 패킷입니다. TCP/IP 전송은 분할을 위해 큰 UDP 패킷을 오프로드하지 않습니다.
패킷은 미니포트 드라이버에서 지정한 최소 세그먼트 수만큼 나눌 수 있어야 합니다. 자세한 내용은 NIC의 LSOv1 TCPPacket-Segmentation 기능 및 NIC의 LSOv2 TCPPacket-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 정보에 대한 자세한 내용은 액세스 TCP/IP 오프로드 NET_BUFFER_LIST 정보참조하세요. TCP/IP 전송은 MSS 값을 최대 세그먼트 크기로 설정합니다.
LSOv1의 경우 큰 TCP 패킷의 총 길이를 패킷 IP 헤더의
Total Length
필드에 씁니다. 총 길이에는 IP 헤더의 길이, IP 옵션의 길이(있는 경우) , TCP 헤더의 길이, TCP 옵션의 길이(있는 경우 TCP 옵션의 길이) 및 TCP 페이로드의 길이가 포함됩니다. LSOv2의 경우 패킷 IP 헤더의Total Length
필드를 0으로 설정합니다. 미니포트 드라이버는 NET_BUFFER_LIST 구조체의 첫 번째 NET_BUFFER 구조체의 길이를 통해 패킷의 길이를 결정해야 합니다.TCP 의사 헤더에 대한 보수 합계 계산하고 이 합계를 TCP 헤더의
Checksum
필드에 씁니다. TCP/IP 전송은 의사 헤더에서Source IP Address
,Destination IP Address
및Protocol
필드에 대한 보수 합계를 계산합니다. TCP/IP 전송에서 제공하는 사전 헤더에 대한 보수 합계는 NIC가 IP 헤더를 검사하지 않고도 큰 TCP 패킷에서 파생되는 각 패킷에 대한 실제 TCP 체크섬을 더 빨리 계산할 수 있도록 돕습니다. 주목하십시오, RFC 793은 의사 헤더 체크섬이Source IP Address
,Destination IP Address
,Protocol
및TCP Length
을 기준으로 계산되는 것이라고 규정합니다. TCP 길이는 TCP 헤더와 TCP 페이로드의 길이를 합한 것으로, 의사 헤더의 길이는 포함되지 않습니다. 그러나 기본 미니포트 드라이버와 NIC는 TCP/IP 전송에서 전달된 큰 패킷을 기반으로 TCP 세그먼트를 생성하기 때문에, 전송은 각 TCP 세그먼트의 TCP 페이로드 크기를 알지 못하여 의사 헤더에 TCP 길이를 포함할 수 없습니다. 대신, 아래에 설명된 대로 NIC는 TCP/IP 전송에서 제공한 의사 헤더 체크섬을 확장하여 생성된 각 TCP 세그먼트의 TCP 길이를 포함합니다.TCP 헤더의
Sequence Number
필드에 올바른 시퀀스 번호를 씁니다. 시퀀스 번호는 TCP 페이로드의 첫 번째 바이트를 식별합니다.
미니포트 드라이버는 MiniportSendNetBufferLists 또는 MiniportCoSendNetBufferLists 함수에서 NET_BUFFER_LIST 구조를 가져온 후 TcpLargeSendNetBufferListInfo
_Id
사용하여 NET_BUFFER_LIST_INFO 매크로를 호출하여 TCP/IP 전송으로 작성된 MSS 값을 가져올 수 있습니다.
미니포트 드라이버는 패킷의 IP 헤더에서 큰 패킷의 총 길이를 가져오고 MSS 값을 사용하여 큰 TCP 패킷을 더 작은 패킷으로 나눕니다. 각 작은 패킷에는 MSS 이하의 사용자 데이터 바이트가 포함됩니다. 분할된 큰 패킷에서 만든 마지막 패킷만 MSS 사용자 데이터 바이트보다 작아야 합니다. 분할된 패킷에서 만든 다른 모든 패킷에는 MSS 사용자 데이터 바이트가 포함되어야 합니다. 이 규칙을 따르지 않으면 불필요한 추가 패킷을 만들고 전송하면 성능이 저하됩니다.
미니포트 드라이버는 MAC, IP 및 TCP 헤더를 큰 패킷에서 파생된 각 세그먼트에 연결합니다. 미니포트 드라이버는 이러한 파생 패킷에 대한 IP 및 TCP 체크섬을 계산해야 합니다. 큰 TCP 패킷에서 파생된 각 패킷의 TCP 체크섬을 계산하기 위해, NIC는 먼저 TCP 체크섬의 가변 부분(TCP 헤더 및 TCP 페이로드)을 계산합니다. 그런 다음, 그 체크섬을 TCP/IP 전송에서 계산한 의사 헤더의 1의 보수 합에 더하고, 마지막으로 체크섬에 대한 16비트 1의 보수를 계산합니다. 이러한 체크섬 계산에 대한 자세한 내용은 RFC 793 및 RFC 1122를 참조하세요.
다음 그림에서는 큰 패킷의 세분화를 보여줍니다.
큰 TCP 패킷에 있는 TCP 사용자 데이터의 길이는 미니포트 드라이버가 MaxOffLoadSize
값에 할당하는 값과 같거나 작아야 합니다.
MaxOffLoadSize
값에 대한 자세한 내용은 NIC의 LSOv1 TCP-Packet-Segmentation 기능 및 NIC의 LSOv2 TCP-Packet-Segmentation 기능보고를 참조하세요.
드라이버가 MaxOffLoadSize
값의 변경 사항을 나타내는 상태 표시를 한 후, 드라이버는 LSO 전송 요청을 이전 MaxOffLoadSize
값을 사용하여 받더라도 충돌해서는 안 됩니다. 대신 드라이버가 송신 요청에 실패할 수 있습니다.
MaxOffLoadSize
값의 변경을 보고하는 상태 표시를 독립적으로 발급하는 중간 드라이버는 상태 표시를 발급하지 않은 기본 미니포트 어댑터가 미니포트 어댑터가 보고한 MaxOffLoadSize
값보다 큰 패킷을 얻지 않도록 해야 합니다.
미니포트 중간 드라이버가 LSO 서비스를 끄기 위해 OID_TCP_OFFLOAD_PARAMETERS에 응답할 경우, 짧은 시간 후에도 LSO 전송 요청이 계속해서 미니포트 드라이버에 도달할 수 있다는 사실에 대비해야 합니다.
세그먼트 패킷의 TCP 사용자 데이터 길이는 MSS보다 작거나 같아야 합니다. MSS는 TCP 전송이 NET_BUFFER_LIST 구조와 연결된 LSO NET_BUFFER_LIST 정보를 사용하여 전달하는 ULONG 값입니다. 분할된 큰 패킷에서 만든 마지막 패킷만 MSS 사용자 데이터 바이트보다 작아야 합니다. 분할된 패킷에서 만든 다른 모든 패킷에는 MSS 사용자 데이터 바이트가 포함되어야 합니다. 이 규칙을 따르지 않으면 불필요한 추가 패킷을 만들고 전송하면 성능이 저하됩니다.
큰 TCP 패킷에서 파생된 세그먼트 패킷 수는 미니포트 드라이버에서 지정한 MinSegmentCount
값과 같거나 커야 합니다.
MinSegmentCount
값에 대한 자세한 내용은 NIC의 LSOv1 TCP-Packet-Segmentation 기능 보고 및 NIC의 LSOv2 TCP-Packet-Segmentation 기능보고를 참조하세요.
버전에 관계없이 LSO 지원 미니포트 드라이버에 대한 IP 및 TCP 헤더 처리에는 다음과 같은 가정과 제한이 적용됩니다.
오프로드된 큰 TCP 패킷의 IP 헤더에 있는 MF 비트는 설정되지 않으며, IP 헤더의 조각 오프셋은 0입니다.
URG, RST및 SYN 플래그는 큰 TCP 패킷의 TCP 헤더에 설정되지 않으며 TCP 헤더의 긴급 오프셋(포인터)은 0이 됩니다.
큰 패킷의 TCP 헤더에서 FIN 비트가 설정된 경우 미니포트 드라이버는 큰 TCP 패킷에서 만든 마지막 패킷의 TCP 헤더에서 이 비트를 설정해야 합니다.
큰 TCP 패킷의 TCP 헤더에 PSH 비트가 설정된 경우 미니포트 드라이버는 큰 TCP 패킷에서 만든 마지막 패킷의 TCP 헤더에서 이 비트를 설정해야 합니다.
큰 TCP 패킷의 TCP 헤더에서 CWR 비트가 설정된 경우 미니포트 드라이버는 큰 TCP 패킷에서 만든 첫 번째 패킷의 TCP 헤더에서 이 비트를 설정해야 합니다. 미니포트 드라이버는 큰 TCP 패킷에서 만든 마지막 패킷의 TCP 헤더에서 이 비트를 설정하도록 선택할 수 있지만 이는 바람직하지 않습니다.
큰 TCP 패킷에 IP 옵션 또는 TCP 옵션(또는 둘 다)이 포함된 경우 미니포트 드라이버는 이러한 옵션을 큰 TCP 패킷에서 파생된 각 패킷에 변경할 수 없는 상태로 복사합니다. 특히 NIC는 타임스탬프 옵션을 증가하지 않습니다.
모든 패킷 헤더(이더넷, IP, TCP)는 패킷의 첫 번째 MDL에 있습니다. 헤더는 여러 MDL 간에 분할되지 않습니다.
팁
이 가정은 LSO를 사용할 때 유효합니다. 그렇지 않으면 LSO를 사용하도록 설정하지 않으면 미니포트 드라이버는 IP 헤더가 이더넷 헤더와 동일한 MDL에 있다고 가정할 수 없습니다.
미니포트 드라이버는 TCP/IP 전송에서 NET_BUFFER_LIST 구조를 수신하는 순서대로 NET_BUFFER_LIST 구조체로 패킷을 보내야 합니다.
큰 TCP 패킷을 처리할 때 미니포트 어댑터는 패킷을 분할하고 MAC, IP 및 TCP 헤더를 큰 TCP 패킷에서 파생된 패킷에만 연결합니다. TCP/IP 전송은 다른 모든 작업(예: 원격 호스트의 수신 창 크기에 따라 송신 창 크기 조정)을 수행합니다.
큰 패킷에 대한 보내기 작업을 완료하기 전에(예: NdisMSendNetBufferListsComplete 또는 NdisMCoSendNetBufferListsComplete), 미니포트 드라이버는 큰 TCP 패킷에서 만든 모든 패킷에서 성공적으로 전송된 총 TCP 사용자 데이터 바이트 수와 함께 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 값(대용량 송신 오프로드에 대한NET_BUFFER_LIST 정보)을 씁니다.
이전 LSO 요구 사항 외에도 LSOv2 지원 미니포트 드라이버도 다음을 수행해야 합니다.
IPv4 또는 IPv6 또는 IPv4 및 IPv6을 모두 지원합니다.
네트워크 인터페이스 카드(NIC)가 생성하는 각 세그먼트 패킷에서 큰 패킷에 있는 IPv4 옵션의 복제를 지원합니다.
각 TCP 세그먼트 패킷에서 대형 TCP 패킷의 IPv6 확장 헤더 복제 기능을 지원합니다.
미니포트 드라이버가 생성하는 각 TCP 세그먼트 패킷에서 TCP 옵션의 복제를 지원합니다.
NET_BUFFER_LIST 구조의 IP 및 TCP 헤더를 템플릿으로 사용하여 각 세그먼트 패킷에 대한 TCP/IP 헤더를 생성합니다.
0x0000부터 0x7FFF까지의 범위에서 IP 식별자(IP ID) 값을 사용합니다. (0x8000 범위에서 0xFFFF 범위는 TCP 챔니 오프로드 기능이 있는 장치용으로 예약됩니다.) 예를 들어, 템플릿 IP 헤더가 0x7FFE라는 ID 필드 값으로 시작하면, 첫 번째 TCP 세그먼트 패킷의 IP ID 값은 0x7FFE로 시작하고, 이어서 0x7FFF, 0x0000, 0x0001 순서로 지정되어야 합니다.
TcpHeaderOffset 멤버의 바이트 오프셋을 사용하여, NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO의 패킷 첫 번째 바이트부터 TCP 헤더의 위치를 결정합니다.
각 LSOv2 NET_BUFFER_LIST 구조체와 연결된 NET_BUFFER 구조체의 수를 1로 제한합니다.
메모
이는 LSOv2 지원 미니포트 드라이버에 대한 새로운 요구 사항입니다. 이 규칙은 LSOv1 미니포트 드라이버에 명시적으로 적용되지 않지만 권장됩니다.
NET_BUFFER_LIST
구조체의 첫 번째NET_BUFFER
구조체 길이에서 패킷의 총 길이를 산출합니다. 이는 LSOv1대한메서드 드라이버와 다릅니다. TCP 옵션, IP 옵션 및 IP 확장 헤더를 지원합니다.
보내기 작업이 완료되면 미니포트 드라이버는 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 구조체의
LsoV2TransmitComplete.Reserved
멤버를 0으로 설정하고LsoV2TransmitComplete.Type
멤버를NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE
로 설정해야 합니다.