요약

  • RFC 3542는 소켓 전체에 지속되는 IPv6 옵션과 UDP 또는 raw 데이터그램 하나에만 적용되는 보조 제어 데이터를 분리했다. 메시지별 항목은 동일한 이름의 고정(sticky) 옵션만 덮어쓰며, 관련 없는 기본값은 그대로 유지된다.
  • 이 범위에는 명확한 경계가 있다. 길이 0의 항목은 하나의 패킷에 대해 하나의 옵션만 비활성화할 수 있고, 이미 큐에 들어간 수신 패킷에는 새로 요청한 메타데이터가 없을 수 있으며, TCP는 send 호출이 전송 세그먼트와 일대일로 대응하지 않기 때문에 같은 모델을 상속할 수 없다.

제어 트래픽을 실어 나르는 오래 살아있는 UDP 소켓을 상상해 보라. 애플리케이션은 인터페이스, 트래픽 클래스, 그리고 모든 데이터그램에 적용될 확장 헤더 동작을 이미 선택해 둔 상태다. 그런데 단 하나의 예외적인 메시지가 다른 라우팅 헤더를 필요로 한다. 가장 쉬운 구현은 곧 가장 위험한 구현이기도 하다. 예외를 기본값 묶음 전체의 대체물로 취급하는 것이다. 패킷은 특별한 경로를 얻지만, 호출자가 전혀 건드릴 의도가 없던 정책을 조용히 잃어버린다.

2003년 5월에 발표된 RFC 3542, 즉Advanced Sockets Application Program Interface (API) for IPv6는 그 범위를 명시적으로 만들었다. 이 문서는 전송 규격이 아니라 Informational 문서였다. 주제는 애플리케이션과 커널 사이의 경계였다. 즉, 소프트웨어가 IPv6 바이트를 일일이 만들지 않고도 패킷 정보, 확장 헤더, 홉 한계, 다음 홉, 트래픽 클래스, Path MTU 동작을 어떻게 요청하는가에 관한 것이었다.

이 규격은 두 가지 송신 표면을 기술했다.setsockopt()는 소켓에 "고정(sticky)" 옵션을 설정해, 애플리케이션이 바꾸기 전까지 전송되는 패킷에 계속 적용되도록 한다. 반면sendmsg()와 함께 전달되는 보조 데이터(ancillary data)는 UDP 또는 raw 소켓에서 하나의 데이터그램에 대한 제어 정보를 지정할 수 있다. 이 구분은 시간적이면서도 구조적이다. 한쪽 표면은 상시 기본값을 정하고, 다른 쪽은 단일 메시지 예외를 선언한다.

결정적인 규칙은 4.2절에 나온다. 보조 항목이 고정 옵션을 덮어쓰는 경우는 두 항목이 동일한 옵션 이름을 가질 때뿐이다. 데이터그램별IPV6_RTHDR은 그 데이터그램에 한해 고정된 라우팅 헤더를 대체한다. 고정된 목적지 옵션이나 패킷 정보 선택, 그 외 독립적으로 구성된 상태는 건드리지 않는다. 예외는 자신이 이름을 지정한 셀에 대한 권한만 얻는 것이지, 소켓 전체에 대한 권한이 아니다.

이 규칙은 RFC 2292에 대한 의도적 변경이었다. 이전 API에서는 고정 옵션들을 하나의 소켓 옵션으로 함께 지정할 수 있었기 때문에, 보조 데이터를 제공하면 그 세트 전체가 대체되었다. RFC 3542는 더 큰 규모의 고정 및 보조 제어 모음을 개별 옵션으로 분리했다. 상태가 개별적으로 주소 지정 가능해지자 덮어쓰기 규칙도 개별적으로 범위가 한정되었다. 이 역사는 API의 데이터 모델이 갱신의 부수적 효과를 결정한다는 사실을 일깨워 준다.

같은 설계는 명시적인 부재도 허용한다. 소켓에 고정된IPV6_HOPOPTS값이 있을 때, 해당 유형의 길이 0 보조 항목은 하나의 송신 패킷에 대해 Hop-by-Hop 옵션 헤더를 생략할 수 있다. 이 0은 "모든 기본값을 잊어라"는 뜻이 아니다. 이는 유형이 지정된 지시문으로, 이 한 메시지에서 이 한 기능만 생략하라는 의미다. 다음 데이터그램은 소켓 정책의 나머지를 다시 만들지 않고도 고정 값으로 돌아갈 수 있다.

수신에는 다른 타이밍 문제가 있다. 애플리케이션이 먼저 관련IPV6_RECVxxx옵션을 활성화하면, 이후recvmsg()가 사용 가능한 정보를 보조 객체 형태로 반환한다. 패킷에 라우팅 헤더가 없다면 대응하는 객체도 없다. 그러나 RFC 3542는 수신 옵션이 활성화된 시점에 이미 큐에 들어 있던 패킷에는 새로 요청한 보조 정보가 없을 수 있다고도 경고한다. 따라서 메타데이터의 부재에는 적어도 두 가지 가능한 이력이 있다. 회선상 그 기능이 실제로 없었거나, 관측이 너무 늦게 활성화되었거나 둘 중 하나다.

TCP는 또 하나의 경계를 그린다. 이 문서는 애플리케이션의 send 연산과 전송 세그먼트 사이에 일대일 대응이 없기 때문에 TCP에 대한 send별 보조 전송을 정의하지 않는다. 고정 옵션은 사용할 수 있지만, 재전송된 세그먼트가 원래 전송 이후에 설정된 정보를 사용할지는 보장되지 않는다. 수신되는 선택적 정보 역시 TCP에 대해 정의되지 않았으며, RFC는 그것이 UDP나 raw 소켓에서 애플리케이션이 상상할 수 있는 방식으로 접근 제어 목적에 사용될 수 없다고 명시한다. 패킷 범위의 의도에는 실제 패킷 범위가 필요하다.

체크섬 처리조차 하나의 검증된 속성과 전체 판정 사이의 구분을 지킨다. 커널은 필수적인 ICMPv6 체크섬을 검증하고 실패한 패킷을 폐기한다. 추가 검사를 수행할 수도 있지만, 이식성 있는 애플리케이션은 그런 명시되지 않은 검사가 수행되었다고 가정해서는 안 된다. "체크섬 통과"는 그 계산에 대한 영수증일 뿐, 모든 필드가 의미 있고 허가되었다는 증명서가 아니다.

버퍼 구성도 더 작은 규모에서 같은 교훈을 준다.CMSG_SPACE는 정렬과 할당에 필요한 공간까지 포함하고,CMSG_LEN은 보조 헤더에 저장되는 길이, 즉 끝의 패딩을 제외한 길이를 제공한다. 예약된 양과 논리적 객체 길이는 관련이 있지만 서로 바꿔 쓸 수는 없다. 이를 혼동하면 올바른 페이로드가 잘못 기술된 봉투에 담길 수 있다.

역사적 예제에는 현재의 레이블이 필요하다. RFC 3542는 RFC 2460 시대의 IPv6 라우팅 헤더 Type 0 예제를 그대로 물려받았다. 지금은 RFC 8200이 IPv6 기본 규격이며, Type 0을 현재 지침으로 유지하지 않는다. 그 예제는 해당 API 함수와 그 시기에 관한 증거로 남아 있을 뿐, 폐기된 라우팅 메커니즘을 배포하라는 권고가 아니다.

따라서 이번 작업의 범위는 일반적인 IPv6 확장 헤더 정책, Path MTU 알고리즘, 포워딩 동작 앞에서 멈춘다. 다루는 것은 제어 범위의 전환이다. RFC 2292의 세트 전체 대체가 RFC 3542의 동일 이름 덮어쓰기가 되었고, 유형이 지정된 단일 패킷 비활성화와, 관측이나 세그먼테이션이 그 유비머적인 구조를 깨뜨리는 지점의 명시적 한계가 함께 정해졌다.

지속 가능한 운영 규칙은 네 층을 따로 기록하는 것이다. 호출 전의 소켓 기본값, 데이터그램을 위해 제공된 보조 예외, 커널이 실제로 내보낸 패킷, 그리고 다운스트림에서 관측된 결과. 성공한sendmsg()는 인터페이스가 요청을 받아들였다는 증거일 뿐이다. 어떤 패킷이 나갔고 그것에게 무슨 일이 일어났는지는 실행 중인 증거만이 보여 준다. 좁은 덮어쓰기는 기본값을 보호하고, 출처 추적은 진실을 보호한다.

출처