홉 바이 홉의 진실
당신의 경로 도구는 통로를 그립니다. 라우터는 홉 단위로 포워딩합니다. 그 간극을 4,032쌍으로 측정했습니다.
Michel Wijnberg
제가 써 본 거의 모든 네트워크 경로 도구는(얼마 전까지는 제 것도 포함해서) 이렇게 동작합니다.
- 출발 라우터를 잡는다.
- 토폴로지 위에서 Dijkstra를 돌린다.
- 그렇게 나온 최단 경로를 그린다.
그것은 출발지를 뿌리로 하는 통로이고, IP 포워딩의 모델로서는 미묘하게 틀렸습니다. 실제 포워딩에는 통로가 없습니다. 모든 라우터가 독립적으로 목적지 주소를 자기 자신의 라우팅 테이블과 맞춰 보고 넥스트 홉을 고릅니다. 두 답이 일치하는 것은 중간 라우터 하나하나의 판단 규칙과 입력 집합이 출발지의 그것과 같은 동안뿐입니다.
OSPF에서는 흔히 같지 않습니다.
결코 도착하지 않는 패킷 하나
제 랩에서 나온 사례입니다. 관련된 모든 라우터에서 show ip route로 직접 측정했고, 모델링한
값이 아니라 장비에서 읽어 낸 값입니다.
| 라우터 | 목적지에 대해 하는 말 | 포워딩 대상 |
|---|---|---|
dfw1-gw2 | metric 20031, type inter area | dfw1-cr1 |
dfw1-cr1 | metric 30001, type intra area | ord1-cr1 ← dfw2-cr1이 아님 |
ord1-cr1 | metric 20001, type intra area | jfk1-cr1 |
jfk1-cr1 | metric 10001, type intra area | lhr1-cr1 |
lhr1-cr1 | metric 1, connected | 전달 완료 |
출발지를 뿌리로 한 통로는 이렇게 그렸습니다.
dfw1-gw2 → dfw1-cr1 → dfw2-cr1 → iad2-cr1 → ams1-cr1 → lhr1-cr1
패킷은 dfw2-cr1에 결코 도달하지 않습니다. 통로가 더 싼 경로인 것은 맞습니다. 다만 어떤
라우터도 만들어 내지 않을 경로일 뿐입니다. 서로 무관한 RFC 2328의 두 규칙이 dfw1-cr1로
하여금 그것을 거부하게 만듭니다.
§16 단계 (3) / §16.2 첫 문단: 백본 게이트. 여러 영역에 붙어 있는 라우터는 백본
summary-LSA 만 검사합니다. dfw2-cr1의 코스트 20011짜리 더 싼 summary는 실제로
dfw1-cr1의 영역 4.6.23.0 데이터베이스 안에 있습니다(show ip ospf database summary로
확인했습니다). 그러나 그것은 후보가 아닙니다. dfw1-cr1이 ABR이고 그 summary가 영역 0을
통해 들어온 것이 아니기 때문입니다. RFC 3509 §2.1/§2.2(이 장비들에서 실제로 돌아가는 Cisco
ABR 동작)는 이 조건을 활성 백본 연결이 있는지에 걸어 두는데, dfw1-cr1은 그것을 가지고
있습니다.
§16.2 단계 (6): 영역 내가 영역 간을 이깁니다, 끝. “If the paths present in the table are
intra-area paths, do nothing with the LSA (intra-area paths are always preferred).”
dfw1-cr1은 이미 메트릭 30001짜리 영역 내 경로를 쥐고 있습니다. 20011짜리 summary는 그것에
집니다. 메트릭은 아무 상관이 없습니다. 이것은 경로 유형에 관한 규칙이고, 코스트 비교는
아예 일어나지 않습니다.
두 규칙 중 어느 하나만으로도 그 통로는 죽습니다. 출발지에서 SPF를 한 번 돌리는 도구는 둘 다
볼 수 없습니다. dfw1-cr1에게 dfw1-cr1의 생각을 한 번도 묻지 않기 때문입니다.
이게 실제로 얼마나 자주 문제가 될까
제가 신경 쓰는 대목이 여기입니다. “당신 모델은 이론적으로 부정확합니다”는 숫자보다 훨씬 약한 주장이기 때문입니다.
그래서 AS 200의 라우터 64대 전부에서 OSPF 라우팅 테이블을 통째로 읽어 내고, 4,032개의 순서 있는 출발지/목적지 쌍을 하나도 빠짐없이 비교했습니다.
| 측정 | 결과 |
|---|---|
| 어떤 라우터도 택하지 않을 홉을 통로가 1개 이상 그린 영역 간 쌍 | 2,839개 중 360개(12.68%) |
| 같은 결함이 있는 영역 내 쌍 | 1,193개 중 0개 |
| 전체 | 4,032개 중 360개(8.93%) |
영역 내가 0인 것이 바로 온전성 검사입니다. 한 영역 안에서는 모든 라우터가 동일한 LSDB 위에서 SPF를 돌리고, 최단 경로는 그 경로 위 어느 지점에서 보아도 여전히 최단이므로 두 모델이 일치할 이유는 충분합니다. 핵심은 그 일치를 가정한 것이 아니라 측정했다는 점입니다. 1,193쌍, 불일치 없음. 그런데 ABR과 summary-LSA가 등장하는 순간, 여덟 경로 중 하나가 허구가 됩니다.
“약간 최적이 아니다”가 아닙니다. 허구입니다. 패킷이 결코 들르지 않는다고 증명할 수 있는 라우터가 그 안에 들어 있습니다. 그 경로를 근거로 정비 시간을 잡거나 장애를 설명하고 있다면, 존재하지 않는 경로를 두고 추론하고 있는 것입니다.
해법: 모든 라우터에게 물어보기
이제 Osprey는 체인을 따라갑니다. 각 홉에서 그 라우터 자신의 LSDB, 자신의 영역 소속, 자신의 ABR 여부, 자신의 어드미니스트레이티브 디스턴스 조합을 써서 그 라우터가 목적지 주소를 향해 설치해 둔 자기 경로를 평가하고, 그 라우터가 실제로 고른 넥스트 홉을 따라간 뒤 이를 반복합니다.
같은 4,032쌍으로 검증했습니다.
| 검사 | 결과 |
|---|---|
| 라우터 자신의 메트릭을 정확히 재현 | 4,032 / 4,032 |
| 경로 유형(영역 내 / 영역 간 / 외부) 정확히 일치 | 4,032 / 4,032 |
| 설치된 전체 ECMP 넥스트 홉 집합이 동일 | 4,032 / 4,032 |
요청한 목적지에서 체인이 delivered로 종료 | 4,032 / 4,032 |
“비슷하다”가 아닙니다. 모든 쌍에서 동일하며, 임의로 고른 한 멤버가 아니라 등가 코스트 넥스트 홉 집합 전체까지 동일합니다.
캔버스에서는 이렇게 보입니다. 정방향 경로는 주황색, 역방향은 파란색, 경로에 없는 것은 모두 어둡게 낮춰 통로를 만듭니다.
4 equal-cost paths 선택기와 per-flow hash 라벨을 눈여겨보십시오. Osprey는 한 멤버를 골라
그 경로라고 제시하는 대신 ECMP 집합 전체를 열거합니다. 트래픽은 네 경로 전체에 해시로
분산되고, 그중 하나만 들여다보는 트러블슈팅은 네 번 중 세 번은 아무 이상도 찾지 못하기
때문입니다.
같은 경로를 펼치면 이렇습니다.
모든 홉에는 그 결정을 내린 라우터, 결정이 내려진 영역, 인그레스와 이그레스 물리 인터페이스와
그 주소, 그리고 코스트가 함께 실립니다. ABR 배지는 호스트명이 아니라 LSDB에서 끌어냈습니다.
아래쪽 영역 리본은 경로가 12.1.24.0 → 0.0.0.0 → 6.18.1.0을 지나감을 보여 주는데, 이는
영역 간 트래픽에 대해 RFC 2328이 요구하는 백본 경유입니다.
그리고 표시된 총 코스트 30061은 출발지 자신이 설치한 메트릭입니다. 말 그대로 lax1-gw1
에서 show ip route가 찍어 내는 숫자이고 스텁 코스트까지 포함되어 있으며, Osprey가 마음에 든
링크들을 더해 만든 합계가 아닙니다.
설명은 생성된 것이지 장식이 아닙니다.
- Route type: O IA (inter-area): Source 172.16.2.33 and destination 172.16.5.23 have no shared area, routing via backbone (area 0.0.0.0)
- Path traverses: area 12.1.24.0 (cost 10) → area 0.0.0.0 (cost 30040) → area 6.18.1.0 (cost 10)
- Total cost: 30061 via 10 hops
- ECMP: 4 equal-cost paths available
AS 경계를 넘어서
하나의 IGP 안에서는 LSDB가 완전하기 때문에 체인을 계산할 수 있습니다. AS 경계를 넘으면 완전한 것이 아무것도 없습니다. 공유 데이터베이스도, 공유 메트릭 공간도, 공유 어드미니스트레이티브 디스턴스 정책도 없습니다.
정직한 답은 포기하는 것이 아니고, 메트릭이 합성된다고 시늉하는 것은 더더욱 아닙니다. 근거를 이어 붙이는 것입니다.
AS 200(테넌트 Harrier-Broadband, OSPF)의 lax1-gw1에서 AS 300(테넌트 Merlin-Carrier, IS-IS)의
i-sin1-gw1까지 열다섯 홉입니다. 무엇을 하는지 읽어 보십시오.
- 홉 8
jfk1-gw1에는BGP배지가 붙습니다. 여기서 IGP가 멈추고 BGP의 결정이 넘겨받습니다. - 홉 9
i-jfk1-gw1에는IS-IS배지가 붙습니다. 완전히 다른 프로토콜, 다른 주소 설계, 다른 테넌트입니다. - 푸터에는 **“Per-segment costs (never summed) | 15 hops”**라고 적혀 있습니다. OSPF 코스트
20051과 IS-IS 코스트 1320은 서로 무관한 메트릭 공간의 숫자입니다. 더하면
21371이 나오지만 그것은 존재하지 않는 양입니다. Osprey는 그것을 찍기를 거부합니다.
생성된 설명은 단계마다 자기 근거를 이름으로 밝힙니다.
- BGP border selection:
jfk1-gw1holds 10.66.0.0/15 for 10.66.15.3 (AS path: 300)- AS 200: IGP segment:
lax1-gw1→jfk1-gw1, cost 20051- eBGP transition 200 → 300:
jfk1-gw1 Et1/1 → i-jfk1-gw1 Et1/2(bmp-peer+l2; ip-bound)- AS 300: IGP segment:
i-jfk1-gw1→i-sin1-gw1, cost 1320
3번 단계는 제품을 통틀어 제가 가장 좋아하는 줄입니다. “이 두 라우터는 아마 어떤 식으로든 연결되어 있을 것”이라고 말하지 않습니다. 양쪽 끝의 물리 포트를 이름으로 밝히고, 그다음 괄호 안에서 풀이 과정을 보여 줍니다.
bmp-peer: 둘 사이에 확립된 eBGP 세션이 있고, BMP를 통해 관측됨+l2: 반대편은 두 경계 장비의 LLDP/CDP 인접을 통해 맞춰짐ip-bound: 두 세션 주소가 장비의 IP-MIB 바인딩을 통해 그 특정 포트로 해석됨
서로 독립적인 근거 세 가지가 일치합니다. 일치하지 않을 때는 제품이 그렇다고 말하며, 그것이 다음 글 전체의 주제입니다.
제가 기능보다 이것을 더 신경 쓰는 이유
경로 그림은 당신의 네트워크가 패킷을 어떻게 다룰지에 대한 주장입니다. 그 주장이 여덟 번에 한 번 틀리는데 화면 위에서 틀린 것과 맞는 것을 구분해 주는 게 아무것도 없다면, 그 그림은 쓸모없는 것보다 나쁩니다. 자신만만하게 쓸모없고, 하필 틀리는 것이 비싸게 먹히는 바로 그 순간에 사람들의 믿음을 삽니다.
“그럴듯하다”에서 “64개 라우팅 테이블 전부를 정확히 재현, 4,032 중 4,032”까지 가는 데에는 검증 하네스와, 기준 진실을 읽어 낼 수 있는 랩과, 내 도구가 360번이나 허구를 그려 왔다는 사실을 받아들일 각오가 필요했습니다.
랩은 그러라고 있는 것입니다.
다음은 같은 동전의 반대면입니다. Osprey가 답을 계산할 수 없고, 그렇다고 말하는 자리들: Osprey가 추측하기를 거부하는 것.