두 업링크가 fe80::1을 공유할 때의 IPv6 정책 라우팅
두 업링크가 서로 다른 링크에서 같은 fe80::1 다음 홉을 제시할 수 있습니다. 정책마다 표를 하나씩 고르고 수명을 직접 관리하며, 경로 조회로 검증하십시오.
업링크가 두 개 있는데, ip -6 route show 는 두 링크 모두에서 같은 다음 홉을 출력합니다: default via fe80::1 dev uplink0 그리고 default via fe80::1 dev uplink1. 이것은 주소 중복 충돌이 아니며, 껍데기 다음 홉 fe80::1 을 정책 표에 복사한다고 해서 커널이 어느 링크를 뜻하는지 알 수 있는 것도 아닙니다. 진짜 질문은 증상이 시사하는 것보다 좁습니다. 두 번째 표에 링크가 하나 필요한지 둘 필요한지, 그리고 재부팅 후에 무엇이 그 경로들을 살려 두는지, 세 가지 조건을 차례로 점검하면 대부분 정리됩니다.
같은 fe80::1은 서로 다른 두 이웃입니다
링크 로컬 주소는 단일 링크로 범위가 한정됩니다, 따라서 fe80::1 은 한 주소가 두 번 출력된 것이 아니라 접미사만 우연히 공유하는 두 이웃입니다. 영역 인덱스는 호스트가 어느 쪽을 뜻하는지 말하는 방식이므로, fe80::1%uplink0 과 fe80::1%uplink1 는 커널에게 서로 다른 목적지이며, 그 접미사는 원격 라우터로 전달되지 않습니다. RFC 4007 은 그 뒤에 있는 영역 모델을 설명하며, 정책 표의 모든 링크 로컬 다음 홉에 장치를 함께 실어야 하는 이유가 여기에 있습니다.
한 호스트의 숫자 영역 ID를 템플릿에 복사하는 VPN 구성 생성기는 로컬 컨텍스트를 주소의 일부인 양 취급하는 것이며, 그렇게 만든 파일은 인터페이스 이름이나 인덱스가 다른 모든 머신에서 틀립니다. 정책 표가 두 링크를 하나로 합쳐 주는 것도 아니며, 라우팅 VPN은 네트워크 사이로 패킷을 전달하지만 원격 이더넷 이웃의 링크 로컬 신원을 터널 너머로 가져가지 않으므로 링크 로컬 트래픽은 자기 링크에 남습니다.
장치를 빼면 그 경로는 기록할 수 없게 됩니다. ip -6 route add default via fe80::1 table 200 은 게이트웨이를 해석하지 못하며, iproute2는 Error: Nexthop has invalid gateway. 오류로 거부합니다. dev uplink0 를 붙이면 명령이 성공합니다. 장치가 바로 다음 홉을 그 두 이웃 중 하나에 고정하기 때문이며, 장치가 말해 주지 못하는 것은 uplink0이 이 표에 맞는 링크인지 여부이고, 다른 호스트에서 복사한 경로는 그 호스트의 인터페이스 이름을 함께 데려오는데, 진짜 실수는 대개 여기서 나옵니다.
조건 하나: 표에 링크를 하나 둘 것인가 둘 둘 것인가
두 번째 업링크가 무엇을 위한 것인지부터 시작하십시오. 두 링크가 같은 트래픽을 나르고 하나가 대기용이라면, 대체 표에는 두 게이트웨이를 서로 다른 메트릭으로 넣어야 합니다. 같은 목적지, 하나의 우선 경로, 하나의 분명한 차선책입니다. 서로 다른 트래픽이 서로 다른 사업자를 통해 나가야 해서, 또는 일부 트래픽은 VPN을 우회하고 나머지는 안에 남는 분할 터널이라서 업링크가 존재한다면 그 두 링크는 애초에 한 표에 속하지 않으며, 두 표에 속해 규칙이 표를 고르고, 규칙은 터널이 아니라 표를 고르며, 우회 트래픽은 라우팅 전에 표시되고 그 표시가 그것을 두 번째 표로 보냅니다.
그 두 번째 경우에 규칙은 표를 언제 참조할지 정하고, 경로는 패킷이 참조된 뒤 어디로 갈지 정합니다:
ip -6 rule add fwmark 0x2 table 201
ip -6 route add default via fe80::1 dev uplink1 metric 100 table 201
ip -6 route add 2001:db8:100::/48 dev uplink1 metric 100 table 201
ip -6 route show table 201두 객체는 서로를 대체하지 못하며, 기본 경로만 담은 표도 여전히 게이트웨이를 해석하지 못할 수 있습니다. 추가가 거부되거나 경로가 있지만 쓸 수 없다면, 그 인터페이스의 연결된 프리픽스를 같은 표에 넣거나, 다음 홉을 onlink 로 표시하십시오(그 프리픽스가 다른 곳에서 라우팅될 때). 위 블록에서 2001:db8:100::/48 은 임의의 목적지가 아니라 uplink1의 그 연결된 프리픽스를 가리키며, fwmark 규칙은 다른 무언가가 설정해야 하는 표시만 소비합니다. 포워딩 경로의 nftables나 iptables 규칙에서, 또는 SO_MARK 소켓에서 온 표시이며, 따라서 표시 출처 없이 복사한 블록은 아무것도 일치시키지 못합니다.
조건 둘: 메트릭은 죽은 사업자를 감지하지 못합니다
메트릭은 존재하는 경로들 사이의 선호일 뿐, 상태 점검이 아닙니다. 통신사가 끊기면 커널은 그 장치의 경로를 제거하고 두 번째 기본 경로가 이어받습니다. 케이블은 살아 있는데 그 뒤의 사업자가 죽으면 표에서는 아무것도 바뀌지 않으며, 우선 경로는 설치되어 있고 이웃은 2계층에서 도달 가능한 채 패킷은 블랙홀로 빠져나갑니다. 이 차이가 환경에 중요하다면 장애 조치는 경로를 탐지하고 경로를 제거하는 무언가에서 와야 하며, 그것이 라우팅 데몬이든 항목을 지우고 다시 설치하는 작은 스크립트든 마찬가지입니다.
표를 만든 뒤 선택을 검증하고, 커널이 보는 방식으로 검증하십시오. ip -6 route get 2001:db8:100::1 은 사용될 경로를 출력하며, 장치와 선택된 소스 주소를 포함하고, 정책 규칙을 존중합니다. 잘못된 업링크에 속한 소스 주소는 보통 규칙이 예상보다 일찍 일치했다는 신호입니다.
조건 셋: 지속성의 주인을 정하십시오
경로를 ip -6 route add 명령으로 추가하면 재부팅까지, 또는 무언가가 그것을 비울 때까지 살아남습니다. 라우터 광고에서 학습한 기본 경로는 수명을 지니고 라우터가 철회할 수 있지만, 수동으로 추가한 기본 경로는 스스로 만료되지 않습니다. 둘을 한 표에 섞으면, 묘사하던 업링크가 사라진 지 한참 뒤에도 낡은 영구 경로가 새로 광고된 경로를 앞지르게 됩니다.
표마다 주인을 하나 정하고, 네트워크 관리자나 라우팅 데몬이 이미 인터페이스를 관리한다면 정책 경로를 거기서 기술하고 커널은 건드리지 마십시오. 스크립트로 한다면 스크립트를 멱등하게 만들고 해체 절차를 같은 시점에 작성하십시오. 처음 잘못 바꿀 때 바로 필요해집니다:
ip -6 route flush table 201
ip -6 rule del fwmark 0x2 table 201다른 호스트를 위해 포워딩하는 라우터에서는 표를 탓하기 전에 net.ipv6.conf.all.forwarding 을 확인하십시오. 포워딩이 꺼져 있으면 다른 네트워크로 향한 패킷은 표 201이 아무리 정확해도 버려집니다.
다음 사람이 감사할 수 있도록 설계를 기록하십시오
오직 fe80::1 만 저장하는 인벤토리는 중요한 필드를 버리므로, 목적지, 다음 홉, 장치, 표, 메트릭을 함께 기록하고 각 경로가 어디서 왔는지도 적으십시오. 광고된 것인지, 관리자가 생성한 것인지, 정적인지 말입니다. 나중에 누군가 두 번째 업링크가 실제로 트래픽을 나르는지 묻는다면, 그 기록이 추측 없이 답합니다.
표가 끝났다고 하기 전에, 이웃을 ip -6 neigh show dev uplink0 로 확인하고, ip -6 rule show 를 다시 읽어 순서 사고가 없는지 보고, 기본 경로를 타는 ping 대신 규칙에 맞는 트래픽으로 시험하십시오. 그런 다음 업링크 하나를 일부러 내리고 커널이 어느 경로로 물러나는지 보며, 답이 적어 둔 것과 같은지 확인하십시오.