큰 TCP 패킷의 분할 오프로드

NDIS 미니포트 드라이버는 네트워크 매체의 최대 전송 단위(MTU)보다 큰 대형 TCP 패킷의 분할을 오프로드할 수 있습니다. 큰 TCP 패킷의 구분을 지원하는 NIC도 다음을 수행할 수 있어야 합니다.

  • IP 옵션이 포함된 송신 패킷에 대한 IP 체크섬을 계산합니다.

  • TCP 옵션을 포함하는 송신 패킷에 대한 TCP 체크섬을 계산합니다.

NDIS 버전 6.0 이상은 NDIS 5의 LSO(대규모 송신 오프로드)와 유사한 LSOv1(대규모 송신 오프로드 버전 1)을 지원합니다. x. NDIS 버전 6.0 이상에서는 IPv6 지원을 포함하여 향상된 대규모 패킷 구분 서비스를 제공하는 LSOv2(대규모 송신 오프로드 버전 2)도 지원합니다.

LSOv2 및 LSOv1을 지원하는 미니포트 드라이버는 NET_BUFFER_LIST 구조 OOB 정보에서 오프로드 유형을 결정해야 합니다. 드라이버는 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 데이터(NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO) 를 포함하는 모든NET_BUFFER_LIST 삭제해야 합니다.

TCP/IP 전송은 다음 조건을 충족하는 큰 TCP 패킷만 오프로드합니다.

분할을 위해 큰 TCP 패킷을 오프로드하기 전에 TCP/IP 전송은 다음과 같습니다.

  • LSOv1의 경우 큰 TCP 패킷의 총 길이를 패킷 IP 헤더의 총 길이 필드에 씁니다. 총 길이에는 IP 헤더의 길이, 있는 경우 IP 옵션의 길이, TCP 헤더의 길이, TCP 옵션의 길이(있는 경우) 및 TCP 페이로드의 길이가 포함됩니다. LSOv2의 경우 패킷 IP 헤더의 총 길이 필드를 0으로 설정합니다. 미니포트 드라이버는 NET_BUFFER_LIST 구조체의 첫 번째 NET_BUFFER 구조체 길이에서 패킷의 길이를 결정해야 합니다.

  • TCP 의사 헤더에 대한 보수 합계를 계산하고 이 합계를 TCP 헤더의 체크섬 필드에 씁니다. TCP/IP 전송은 의사 헤더의 소스 IP 주소, 대상 IP 주소 및 프로토콜의 다음 필드에 대한 보완 합계를 계산합니다. TCP/IP 전송에서 제공하는 의사 헤더에 대한 보완 합계는 NIC가 IP 헤더를 검사하지 않고도 큰 TCP 패킷에서 파생되는 각 패킷에 대한 실제 TCP 체크섬을 계산하는 초기 시작을 NIC에 제공합니다. RFC 793은 의사 헤더 체크섬이 원본 IP 주소, 대상 IP 주소, 프로토콜 및 TCP 길이를 통해 계산되도록 규정합니다. (TCP 길이는 TCP 헤더의 길이와 TCP 페이로드의 길이입니다. TCP 길이에는 의사 헤더의 길이가 포함되지 않습니다.) 그러나 기본 미니포트 드라이버와 NIC는 TCP/IP 전송에 의해 전달되는 큰 패킷에서 TCP 세그먼트를 생성하므로 전송은 각 TCP 세그먼트에 대한 TCP 페이로드의 크기를 알지 못하므로 의사 헤더에 TCP 길이를 포함할 수 없습니다. 대신, 아래에 설명된 대로 NIC는 TCP/IP 전송에서 제공한 의사 헤더 체크섬을 확장하여 생성된 각 TCP 세그먼트의 TCP 길이를 포함합니다.

  • TCP 헤더의 시퀀스 번호 필드에 올바른 시퀀스 번호를 씁니다. 시퀀스 번호는 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 전송에서 계산한 의사 헤더에 대한 보완 합계에 추가한 다음 체크섬에 대한 16비트 보수를 계산합니다. 이러한 체크섬 계산에 대한 자세한 내용은 RFC 793 및 RFC 1122를 참조하세요.

다음 그림에서는 큰 패킷의 세분화를 보여줍니다.

MAC, IP 및 TCP 헤더를 사용하여 큰 TCP 패킷을 더 작은 패킷으로 구분하는 방법을 보여 주는 다이어그램

큰 TCP 패킷에 있는 TCP 사용자 데이터의 길이는 미니포트 드라이버가 MaxOffLoadSize 값에 할당하는 값과 같거나 작아야 합니다. MaxOffLoadSize 값에 대한 자세한 내용은 NIC의 LSOv1 TCP-Packet-Segmentation 기능 보고NIC의 LSOv2 TCP-Packet-Segmentation 기능 보고를 참조하세요.

드라이버가 MaxOffLoadSize 값의 변경 사항을 나타내는 상태 표시를 발급한 후 이전 MaxOffLoadSize 값을 사용하는 LSO 보내기 요청을 받으면 드라이버가 충돌하지 않아야 합니다. 대신 드라이버가 보내기 요청에 실패할 수 있습니다.

MaxOffLoadSize 값의 변경을 보고하는 상태 표시를 독립적으로 발급하는 중간 드라이버는 상태 표시를 발급하지 않은 기본 미니포트 어댑터가 미니포트 어댑터가 보고한 MaxOffLoadSize 값보다 큰 패킷을 가져오지 않도록 해야 합니다.

LSO 서비스를 끄기 위해 OID_TCP_OFFLOAD_PARAMETERS 응답하는 미니포트 중간 드라이버는 LSO 전송 요청이 여전히 미니포트 드라이버에 도달할 수 있는 짧은 기간 동안 준비해야 합니다.

세그먼트 패킷의 TCP 사용자 데이터 길이는 MSS보다 작거나 같아야 합니다. MSS는 NET_BUFFER_LIST 구조와 연결된 LSO NET_BUFFER_LIST 정보를 사용하여 TCP 전송이 전달하는 ULONG 값입니다. 분할된 큰 패킷에서 만든 마지막 패킷만 MSS 사용자 데이터 바이트보다 작아야 합니다. 분할된 패킷에서 만든 다른 모든 패킷에는 MSS 사용자 데이터 바이트가 포함되어야 합니다. 이 규칙을 따르지 않으면 불필요한 추가 패킷을 만들고 전송하면 성능이 저하 될 수 있습니다.

큰 TCP 패킷에서 파생된 세그먼트 패킷 수는 미니포트 드라이버에서 지정한 MinSegmentCount 값보다 크거나 같아야 합니다. MinSegmentCount 값에 대한 자세한 내용은 NIC의 LSOv1 TCP-Packet-Segmentation 기능 보고NIC의 LSOv2 TCP-Packet-Segmentation 기능 보고를 참조하세요.

버전에 관계없이 LSO 지원 미니포트 드라이버의 IP 및 TCP 헤더 처리에는 다음과 같은 가정과 제한이 적용됩니다.

  • TCP/IP 전송이 오프로드된 큰 TCP 패킷의 IP 헤더에 있는 MF 비트는 설정되지 않으며 IP 헤더의 조각 오프셋은 0이 됩니다.

  • 큰 TCP 패킷의 TCP 헤더에 있는 URG, RST 및 SYN 플래그는 설정되지 않으며 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 ID(IP ID) 값을 사용합니다. (0x8000 범위에서 0xFFFF 범위는 TCP 굴뚝 오프로드 가능 디바이스용으로 예약됩니다.) 예를 들어 템플릿 IP 헤더가 0x7FFE ID 필드 값으로 시작하는 경우 첫 번째 TCP 세그먼트 패킷의 IP ID 값은 0x7FFE, 그 뒤에 0x7FFF, 0x0000, 0x0001 등이 있어야 합니다.

  • NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFOTcpHeaderOffset 멤버의 바이트 오프셋을 사용하여 패킷의 첫 번째 바이트부터 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 설정해야 합니다.