TL;DR

  • Quinn의 손실 프로브에서 경로 MTU에는 맞지만 1,200바이트 프로브에는 들어가지 않는 DATAGRAM이 대기 중이면 대체 PING이 누락될 수 있으며, 프로브의 실제 프레임 공간을 확인하도록 수정함.
  • 손실 프로브 크기는 현재 세그먼트 크기와 INITIAL_MTU(1,200바이트) 중 작은 값으로 제한되며, 경로 MTU는 회귀 사례에서 1,452바이트임.
  • 수정 사항은 프로브 패킷 예산에서 예측한 1-RTT 오버헤드를 빼고 남은 공간을 can_send_1rtt()에 전달해 데이터 전송 가능 여부를 판단함.
  • 피어가 ACK Frequency를 지원하지 않을 때 데이터그램이 프로브에 들어가지 않으면 대체 PING을 유지하고, 들어가면 추가 PING을 생략함.
  • 회귀 테스트 두 건이 통과했으며, 변경 사항은 quinn-rs/quinn#2794, 커밋 6469478로 병합됨.

문제 상황

  • quinn-rs/quinn#2173을 다루는 과정에서 Quinn의 손실 프로브 처리에 경계 사례가 있음을 확인함. 대기 중인 DATAGRAM이 프로브에 들어가지 않는데도 Quinn이 대체 PING을 생략할 수 있었고, 그 결과 프로브가 대체 PING이 보장하려던 ACK 유발 프레임 없이 전송될 수 있었음.
  • Quinn은 전송 대기 중인 ACK 유발 1-RTT 데이터가 있으면 대체 PING을 추가하지 않음. DATAGRAM 프레임은 ACK 유발 프레임이므로, 대기 중인 DATAGRAM은 보통 이 조건을 충족함.
  • 문제는 대기 중인 DATAGRAM이 반드시 프로브에 포함될 것처럼 취급된 데 있음. 실제로는 항상 포함되는 것이 아님.

원인

  • 손실 프로브의 크기는 현재 세그먼트 크기와 INITIAL_MTU 중 작은 값으로 제한됨. Quinn에서 INITIAL_MTU는 1,200바이트임.
  • 연결이 성립된 경로의 MTU는 이보다 클 수 있음. 회귀 사례의 경로 MTU는 1,452바이트임. 따라서 DATAGRAM이 경로에는 유효하면서도 프로브에는 너무 클 수 있음.
  • 이 사례에서 Quinn의 상태는 다음과 같음.
  • ACK 유발 DATAGRAM이 전송 대기 중임.
  • DATAGRAM이 현재 경로에는 들어감.
  • DATAGRAM이 1,200바이트 프로브에는 들어가지 않음.
  • 대기 중인 DATAGRAM 때문에 Quinn이 대체 PING을 생략함.
  • 큐는 보낼 데이터가 있음을 알려주지만, 해당 데이터가 현재 패킷에 들어가는지는 알려주지 않음.
  • 피어가 ACK Frequency를 지원하지 않는 경우 프로브에는 여전히 PING이 필요함.

수정 사항

  • 이제 대체 PING 여부를 결정할 때 프로브에서 사용할 수 있는 공간을 계산함. Quinn은 패킷 예산에서 예측한 1-RTT 오버헤드를 빼고, 남은 프레임 공간을 can_send_1rtt()에 전달함.
  • 실제 전송 경로에는 패킷 공간, 손실 상태, 프레임 스케줄링 처리도 포함됨. 핵심 동작은 프로브 크기를 현재 세그먼트 크기와 INITIAL_MTU 중 작은 값으로 정하고, 다음 패킷 번호에 따른 1-RTT 오버헤드를 제외해 데이터가 들어갈 공간이 있는지 확인하는 방식임.
  • 남은 프레임 공간에 ACK 유발 데이터가 들어가면 대체 PING을 생략할 수 있음. 대기 중인 DATAGRAM이 너무 크면 PING을 유지함.
  • can_send_1rtt()를 사용해 프로브 코드에 별도의 DATAGRAM 크기 계산을 추가하지 않음. 이 판단은 이후 패킷 조립에서 사용하는 전송 경로 규칙과 동일한 규칙을 따름.

회귀 테스트

  • 새 테스트 이름은 tail_loss_probe_keeps_ping_when_datagram_does_not_fit임.
  • 테스트는 경로 MTU를 1,452바이트로 설정하고 피어의 ACK Frequency 지원을 비활성화함. 미확인 상태의 ACK 유발 패킷을 생성한 뒤 폐기하고, 연결을 프로브 타임아웃 시점까지 진행함.
  • 이후 경로에서 허용되는 최대 크기의 DATAGRAM을 큐에 넣음. 이 DATAGRAM은 일반 패킷에는 들어가지만 INITIAL_MTU로 제한된 프로브에는 들어가지 않음.
  • 테스트는 대체 PING이 전송되는지 확인함. 또한 Quinn이 DATAGRAM을 담을 만큼 큰 패킷을 구성할 때 DATAGRAM이 나중에 전달되는지도 확인함.
  • 기존 테스트 tail_loss_small_segment_size도 갱신함. 이 테스트에서는 DATAGRAM이 프로브 안에 들어가므로 추가 PING이 전송되지 않아야 함.
  • 두 테스트 모두 필요함. PING을 항상 추가하면 새 회귀 테스트는 통과하지만, 기존 코드가 보존하려던 최적화가 사라짐.
  • 정확히 병합된 커밋을 대상으로 두 테스트를 실행한 결과임.
  • tail_loss_probe_keeps_ping_when_datagram_does_not_fit: 통과, 실패 0건, 무시 0건, 필터링된 테스트 299건.
  • tail_loss_small_segment_size: 통과, 실패 0건, 무시 0건, 필터링된 테스트 299건.

병합된 변경 사항

  • 패치가 quinn-rs/quinn#2794를 통해 커밋 6469478로 병합됨.
  • 변경 파일은 다음 세 개임.
  • quinn-proto/src/connection/mod.rs
  • quinn-proto/src/connection/spaces.rs
  • quinn-proto/src/tests/mod.rs
  • 최종 diff는 88개 삽입, 3개 삭제로 구성되며, 추가 코드 대부분은 테스트에 포함됨.
  • 문제의 핵심은 데이터가 대기 중인지를 확인했지만, 실제로 필요한 판단은 해당 데이터가 현재 패킷에 들어갈 수 있는지 여부였음. 프로브의 실제 바이트 예산을 기준으로 판단하면서 대체 동작이 명확해짐.

참고 자료

  • Pull request #2794
  • 병합 커밋 6469478
  • 이슈 #2173
  • RFC 9221: QUIC용 비신뢰 데이터그램 확장