rozkładanie ruchu, część pierwsza

jeśli zdarzy wam się sytuacja, w której posiadacie więcej niż jedno łącze do internetu i mają one inne użyteczne przepustowości - co dzisiaj przestało być rzadkością - pojawia się ciekawy element związany z projektowaniem sieci. jak wykorzystać te łącza optymalnie?

muszę przyznać, że do napisania tego cyklu postów sprowokował mnie Marcin Ślęczek, prezes firmy networkers.pl swoim postem na forum ccie.pl. miałem co prawda już w głowie coś na kształt rozwiązania problemu z którym sam borykałem się w swojej sieci domowej, ale niemożność rozwiązania problemu Marcina od ręki sprowokowała mnie do opisania problemu i potencjalnych rozwiązań od podszewki.

oczywiście, żyjemy w czasach eksplozji SDNu, a zatem wszystkiego software-defined. marketingowa odpowiedź na tak postawione pytanie będzie zwykle “kup pan SDWAN”, ale nie o marketingu dzisiaj, tylko o starej dobrej warstwie trzeciej (no i troszkę o czwartej ;) ).

To mógłby być osobny temat na wiele dygresji - większość tzw. “rozwiązań SDWAN" dzisiaj na rynku to dystrybucja linuxa połatana skryptami. W ogromnej większości rozwiązania te nie skalują się w praktyce (na slajdach skaluje się wszystko), nie mają jednolitego API a sposób monitoringu kluczowych parametrów do podjęcia decyzji o zmianie aktywnego łącza jest najogólniej rzecz mówiąc, bardzo umowny. co więcej, nie działają w oderwaniu od innych takich samych maszkarad po drugiej stronie połączenia, więc w ogólności na potrzeby tego artykułu są po prostu bezużyteczne. Pomijam je zatem wymownym mileczniem jako niegodne rozważań inżyniera sieciowego, ale być może jeszcze do ich tematu wrócimy.

popatrzmy zatem na zagadnienie od podstaw, opierając się na razie tylko o mechanizmy dostępne na każdym normalnym routerze, bez zbędnych “przeszkadzajek programowych”.

zanim pójdziemy dalej - będę używał w tej serii postów przestrzeni adresowej pochodzącej z dwóch RFC rezerwujących wg. IANA przestrzeń adresową do dokumentacji i testów - RFC2544 oraz RFC5737:

  • 192.0.2.0/24
  • 198.18.0.0/15
  • 198.51.100.0/24
  • 203.0.113.0/24

będziemy ich używać jako potencjalnie “publicznych” IP

dawno, dawno temu

na routerach Cisco “od zawsze” można było rozkładać ruch wskazując wiele równoległych tras. mając taką topologię:

dwa routery i dwa łącza

wystarczy wskazać dwie trasy domyślne, posługując się unikalnymi interfejsami (dla interfejsów punkt-punkt) lub adresami next-hop:

ip route 0.0.0.0 0.0.0.0 Serial0/0/0.99
ip route 0.0.0.0 0.0.0.0 Serial0/0/1.99

mając trzy równoległe połączenia - zdefiniować trzy trasy:

ip route 0.0.0.0 0.0.0.0 Serial0/0/0.99
ip route 0.0.0.0 0.0.0.0 Serial0/0/1.99
ip route 0.0.0.0 0.0.0.0 198.51.100.37

dwa routery i trzy łącza

jak widzisz, jako interfejsy/trasy next-hop podaje zamiennie nazwy interfejsów i adresy IP. na interfejsach pracujących jako punkt-punkt można wskazać bez problemu samą nazwę interfejsu, ponieważ wiadomo że z definicji adresatem pakietu jest druga strona, jest też znany i jednolity nagłówek L2. w przypadku interfejsów rozgłoszeniowych, taka definicja spowodowałaby każdorazowo (dla każdego nowego docelowego IP) zapytanie ARP o adres bramki. nie muszę chyba mówić, jak to wpływa na wydajność - jest to jeden z najczęściej popełnianych błędów przez początkujących inżynierów sieciowych.

…i tak dalej do 32 lub 64 równoległych tras. na potrzeby domowe powinno wystarczyć :)

Cisco Express Forwarding, czyli CEF, unikalne do dzisiaj rozwiązanie pozwalające budować wysokowydajne struktury do przekazywania ruchu zarówno dla rozwiązań czysto programowych (dawne routery, począwszy od AGSów aż po serię Cisco ISR 1900/2900/3900, a obecnie Cisco CSR 1000v/8000v czy IOS-XRv9000), mieszanych (dawne routery Cisco 7200 z procesorem NSE-1, 7300 z kartami NSE-1 i NSE-100, routery GSR 12000, routery 7600) jak i dedykowanych sprzętowych (Cisco ASR 9000, CRS-1/3 czy w końcu Cisco 8000, kolejny najszybszy i najbardziej skalowalny router na świecie), używa wyrafinowanego procesu stworzenia zoptymalizowanej tablicy na potrzeby FIB.

zupełnie innym zagadnieniem, w którym jako Cisco też możemy się pochwalić, jest stos pozwalający wykonać fizyczny switching lub routing ruchu - Vector Packet Processing. przekazaliśmy kod do Linux Foundation i jest on obecnie wykorzystywany m.in. w projekcie OpenStack oraz innych rozwiązaniach. bije na głowę inne podobne stosy i był opracowywany od wczesnych lat 2000’ych. dzisiaj napędza zarówno obsługę ruchu w routerach Cisco CSR 1000v/8000v jak i XRv9000

aby jak najszybciej i możliwie z takim samym (przewidywalnym) opóźnieniem dla każdego pakietu wybrać interfejs wyjściowy (oraz wykonać dodatkowe operacje, typu np. nałożyć na pakiet nowe informacje L2 - odsyłam do powyższego opisu CEF), CEF używa tabeli skrótów (ang. hash table). pozwala ona wygenerować unikalne wartości, dzięki czemu przeszukiwanie (w tym przypadku wskaźników na interfejs wyjściowy) można wykonać bardzo szybko i bez kolizji (kolizja oznacza, że więcej niż jeden wpis znajduje się pod jedną referencją w pamięci i obsługa ruchu będzie opóźniona o dodatkowy cykl lub cykle sprawdzenia wielu pozycji - a to już oznacza zmienne opóźnienie). CEF od początku projektowany był do obsługi wielu tysięcy (1984!) interfejsów wyjściowych (i prefiksów), natomiast dzisiaj pozwala skalować się do milionów interfejsów wyjściowych oraz setek milionów prefiksów.

to nie oznacza, że w każdym routerze tyle się ich zmieści - interfejsów i prefiksów. to tylko oznacza, że możemy taki zbudować :)

od ilości interfejsów głowa nie boli

na tej samej zasadzie, dla wielu równoległych interfejsów wyjściowych, CEF wykorzystuje rzeczone skróty, a tak naprawdę całe tablice skrótów (w skrócie, hasze). są one budowane z zawartości pakietów (a tak naprawdę z ich nagłówków) aby wybrać w przewidywalny sposób interfejs wyjściowy per-sesja. dzieje się tak dlatego, ponieważ np. sesje TCP nie lubią rozrzucania po łączach o różnym opóźnieniu.

rozkładanie ruchu pojedynczej sesji TCP na wiele łącz w modelu “per pakiet” może wydawać się wspaniałym pomysłem, dopóki nie spróbujesz tego zrobić. więcej o przykładowych problemach można przeczytać we wpisie Ivana tutaj

z ciekawostek, próba budowy silników przekazujących ruch bez uwzględnienia konieczności utrzymania pakietów jednej sesji w kolejności skończyła się fatalnie w praktyce - i to w paru przypadkach. jedną z ofiar był Juniper - w swoim routerze M160 zastosował cztery układy realizujące routing co doprowadziło do wielu nieciekawych problemów ze zmianą kolejności pakietów w sesji i problemami wydajnościowymi na hostach. podobne problemy miały też pierwsze karty do PeCetów realizujące routing w układach FPGA, czy też pierwsze karty z wieloma rdzeniami ARM, prowadzące routing niezależnie. krótką pracę na ten temat napisali nawet nasi rodacy z Poznańskiego Centrum Superkomputerowo-Sieciowego, które swoją drogą budowało swoje rozwiązania właśnie o sprzęt Junipera.

czym jest ta ‘per sesja’? to już zaczyna być bardziej skomplikowane, ponieważ w ostatnich latach możliwości znacząco się rozszerzały:

  • pierwsze implementacje rozkładania ruchu na wiele interfejsów pozwalały robić to w ogóle per-pakiet; szybko tego zaniechano, choć dla wolnych ale zwielokrotnionych łącz w latach ‘80-tych takie rozwiązanie można było dla części rozwiązań uznać za akceptowalne i dające realne korzyści (prościej i taniej było zestawić kolejne łącze 64kbps niż poprosić o jedno większe typu 1Mbps); nawiasem mówiąc, CEF nie wspierał na początku tego trybu rozkładania ruchu - wsparcie pojawiło się trochę później, na krótko przed wycofaniem w ogóle tego trybu pracy; brak wsparcia oznaczał, że każdy pakiet który należało “zbalansować” na jedno z łącz, wymagał wyjścia z optymalnej ścieżki przetwarzania ruchu co oczywiście wpływało na maksymalną wydajność routera
  • prosty round-robin - hash składa się z danych zawartych w adresie źródłowym i docelowym dla IPv4 i IPv6 (najprostszy model pozwalający dosyć dobrze rozłożyć ruch pomiędzy bramki biorąc pod uwagę wiele docelowych odbiorców)
  • domyślny tryb CEF - wykorzystujący do wyliczenia hasha nie tylko same adresy z nagłówka, ale również porty; dzisiaj można dodatkowo wybierać czy mają to być porty źródłowe, docelowe czy jednocześnie źródłowe i docelowe (ponownie, można tu nieco namieszać - jeśli kombinujesz w tą stronę, sprawdź czy wszystkie aplikacje będą zachowywały się prawidłowo z taką konfiguracją)
  • tryb CEF z zabezpieczeniem przed polaryzacją - obecnie jest ono włączone dla każdego trybu pracy, natomiast kiedyś (w latach ‘90-tych) było osobnym trybem pracy; czym jest rzeczona ‘polaryzacja’? w większych sieciach, w których istnieje wiele równoległych interfejsów pomiędzy routerami, każdy z nich wyliczy hash dla tego samego pakietu w ten sposób; może to spowodować dociążenie ruchem części interfejsów mimo tego, że pozostałe łącza będą wolne; modyfikacja polega na tym, że CEF przy każdym starcie routera (można to też zrobić ręcznie) generuje dodatkową wartość (ang. salt), która dodatkowo nakładana jest na wynik pierwotnego wyliczonego skrótu hash;
  • tryb CEF z badaniem ruchu tunelowanego - kolejnej modyfikacji, pozwalającej uniknąć polaryzacji ruchu dla ruchu poddanego hermetyzacji - np. GRE czy IPinIP; ruchu tunelowany może zawierać np. wiele tysięcy unikalnych sesji, a mimo to zewnętrzne adresy w nagłówkach będą te same; w zależności od architektury i możliwości sprzętowych danego routera, opcja ta może być niedostępna
  • tryb CEF z funkcją DPI - czyli Deep Packet Inspection - część brzegowych platform Cisco posiada możliwość wykorzystania dodatkowej funkcji “znajomości” przez router specyfiki nagłówków różnych protokołów tunelujących - takich jak GRE, L2TP, IPsec, IPinIP, VXLAN czy L2VPN - to pozwala jeszcze dokładniej zadbać o dobre rozłożenie ruchu
  • tryb CEF z wykorzystaniem informacji z nagłówka GTP - to specjalny tryb dla sieci komórkowych 3G/4G, gdzie protokół GTP (nagłówek UDP) jest wykorzystywany do tunelowania informacji; jeśli pracujesz z takimi sieciami, wiesz o co chodzi - jeśli nie, powinno Ci wystarczyć, że zaglądamy trochę na zasadzie DPI właśnie do tego dodatkowego nagłówka UDP i tam inteligentnie wybieramy dane to poprawnego rozkładania ruchu;

mam cztery interfejsy, ale różne…

no właśnie. zaczęliśmy rozważania od sytuacji, w której mamy nie tylko wiele interfejsów, ale mają one różne przepustowości. dla mojego, lekko tylko wydumanego przykładu, załóżmy że posiadam:

  • łącze “biznesowe”, 1Gbps “down” i 1Gbps “up” (operator “A”)
  • łącze “domowe”, w technologii GPON, 1Gbps “down” i 300Mbps “up” (operator “B”)
  • łącze “od lokalnego dostawcy”, również w technologii GPON, 150Mbps “down” i 60Mbps “up” (operator “C”)
  • w końcu łącze LTE, które na potrzeby pierwszej części (wrócimy jeszcze do łącz dynamicznie zmieniających swoje parametry przepustowości) określimy jako posiadające przepustowość 50Mbps “down” i 40Mbps “up” (operator “D”)

czterej operatorzy

nie ma nic prostszego, prawda? na routerze z czterema interfejsami definiujemy po prostu cztery trasy domyślne:

ip route 0.0.0.0 0.0.0.0 GigabitEthernet 0/0/0 198.51.100.37 ! ISP A
ip route 0.0.0.0 0.0.0.0 GigabitEthernet 0/0/1 203.0.113.22 ! ISP B
ip route 0.0.0.0 0.0.0.0 GigabitEthernet 0/0/2 198.18.0.6 ! ISP C
ip route 0.0.0.0 0.0.0.0 Dialer1 ! ISP D

oczywiście jeśli operatorzy Ci zapewniają dostęp z IPv6, zasada pozostaje ta sama. jeśli natomiast musisz posiłkować się tunelami IPv6inIP… zasada również pozostaje ta sama:

ipv6 route ::/0 Tunnel101 ! tunel via operator A, z adresem destination ipv4 osiągalnym
                          ! przez łącze operatora A
ipv6 route ::/0 Tunnel102 ! tunel via operator B, z adresem destination ipv4 osiągalnym
                          ! przez łącze operatora B

taka konfiguracja będzie działać poprawnie, ale każdy geek zauważy, że rozkładamy ruch po równo, mimo że każde z tych łącz może przyjąć inną ilość ruchu wychodzącego:

rtr-edge#sh ip route
[...]

S*    0.0.0.0/0 [1/0] via 198.51.100.37, GigabitEthernet0/0/0 ! tędy 1000Mbps
                [1/0] via 203.0.113.22, GigabitEthernet0/0/1  ! tędy 300Mbps
                [1/0] via 198.18.0.6, GigabitEthernet0/0/2    ! tędy 60Mbps
                is directly connected, Dialer1                ! tędy 40Mbps

najprostsza sztuczka z routingiem (nie)rekursywnym

pierwszą sztuczką, którą można było kiedyś wykonać, było wprowadzenie wielu tras prowadzących przez każdy z interfejsów. jak wielu? tak wielu ile potrzeba, żeby oddać wzajemne zależności między przepustowościami:

1000 : 300 : 60 : 40

jeśli podzielimy te wartości przez najniższą - czyli 40, otrzymamy (nieco tylko zaokrąglając):

25 : 8 : 2 : 1

czy musimy definiować 36 tras? nie, nie ma to sensu. możemy spokojnie założyć, że gigabitowe łącze “biznesowe” powinno otrzymywać lwią część ruchu wychodzącego, łącze 300Mbps mniej więcej 1/3 pierwszego, łącze 60Mbps już tylko 1/5 łącza 300Mbps a 40Mbps po prostu połowę tego 300Mbps.

sztuczka polega na tym, żeby wskazać CEFowi wirtualne trasy, które wskazują na wyjściowy interfejs nie bezpośrednio (wtedy router zastąpi po prostu poprzednią trasę), a przez adres pośredni. dla interfejsów punkt-punkt można wskazać bezpośrednio interfejs (ale tylko dla pierwszej dodatkowej trasy, kolejne też trzeba wskazywać pośrednio).

załóżmy, że chcemy zdefiniować 10 tras przez interfejs gigabitowy, który dla przypomnienia wyglądał tak:

ip route 0.0.0.0 0.0.0.0 GigabitEthernet 0/0/0 198.51.100.37

definiujemy zatem dodatkowe 9 tras “pośrednich” (jedną, “główną” mamy już powyżej):

ip route 192.0.2.10 255.255.255.255 198.51.100.37
ip route 192.0.2.11 255.255.255.255 198.51.100.37
ip route 192.0.2.12 255.255.255.255 198.51.100.37
ip route 192.0.2.13 255.255.255.255 198.51.100.37
ip route 192.0.2.14 255.255.255.255 198.51.100.37
ip route 192.0.2.15 255.255.255.255 198.51.100.37
ip route 192.0.2.16 255.255.255.255 198.51.100.37
ip route 192.0.2.17 255.255.255.255 198.51.100.37
ip route 192.0.2.18 255.255.255.255 198.51.100.37

a teraz dodajmy je jako wskazujące dodatkowe opcje dla trasy domyślnej (0/0):

ip route 0.0.0.0 0.0.0.0 192.0.2.10
ip route 0.0.0.0 0.0.0.0 192.0.2.11
ip route 0.0.0.0 0.0.0.0 192.0.2.12
ip route 0.0.0.0 0.0.0.0 192.0.2.13
ip route 0.0.0.0 0.0.0.0 192.0.2.14
ip route 0.0.0.0 0.0.0.0 192.0.2.15
ip route 0.0.0.0 0.0.0.0 192.0.2.16
ip route 0.0.0.0 0.0.0.0 192.0.2.17
ip route 0.0.0.0 0.0.0.0 192.0.2.18

choć na pierwszy rzut oka taki zapis wydaje się pozbawiony sensu, CEF do wersji 12.1 włącznie (część równoległych linii oprogramowania też nie miała jeszcze tej modyfikacji, możesz zatem spotkać tą funkcję w teoretycznie nowszych wersjach typu 12.2S/12.3T) nie rozwiązywał adresów next-hop rekursywnie do końca przed zbudowaniem tablicy FIB, co miało ten miły efekt uboczny, że pozwalało zrealizować UCMP - Unequal Cost Multi Path.

teraz dodajmy dodatkowe trzy trasy (ponownie - jedną już mamy zdefiniowaną) przez drugi interfejs a dwa ostatnie łącza zostawimy na razie jako pojedyncze wpisy w tablicy:

rtr-edge#sh ip route
[...]

S*    0.0.0.0/0 [1/0] via 198.51.100.2, GigabitEthernet0/0/0 ! tędy 1000Mbps
                [1/0] via 203.0.113.22, GigabitEthernet0/0/1 ! tędy 300Mbps
                [1/0] via 198.18.0.6, GigabitEthernet0/0/2   ! tędy 60Mbps
                is directly connected, Dialer1               ! tędy 40Mbps
ip route 192.0.2.20 255.255.255.255 203.0.113.22
ip route 192.0.2.21 255.255.255.255 203.0.113.22
ip route 192.0.2.22 255.255.255.255 203.0.113.22
ip route 0.0.0.0 0.0.0.0 192.0.2.20
ip route 0.0.0.0 0.0.0.0 192.0.2.21
ip route 0.0.0.0 0.0.0.0 192.0.2.22

CEF podzieli nam teraz wpisy na 16 “wiaderek” (lub 32 lub 64, w zależności od możliwości platformy na której pracujesz). pierwsze 10 wskazywać będzie na łącze gigabitowe, kolejne 4 na łącze 300Mbps, a ostatnie 2 odpowiednio na drugie łącze GPON 60Mbps oraz łącze LTE 40Mbps:

router#sh ip cef 0.0.0.0 0.0.0.0 internal
0.0.0.0/0, version 24, epoch 0, per-destination sharing
[...]
  tmstats: external 0 packets, 0 bytes
           internal 0 packets, 0 bytes
  Load distribution: 0 0 0 0 0 0 0 0 0 0 1 1 1 1 2 3

o ile nie da to dokładnie zamierzonego efektu, jest znacznie lepiej - ruch będzie rozkładał się w proporcji 10:4:1:1.

takie podejście może jednak męczyć, a co więcej, CEF został szybko zmodyfikowany.

ponieważ trudno zaakceptować takie zaniedbanie jak nie rozwiązywanie next-hopów “do upadłego” przed zbudowaniem optymalnej tablicy FIB, w nowszych wersjach IOS (w tym IOS-XE, NX-OS nie mówiąc już o IOS XR) mechanizm został udoskonalony i dzisiaj taka sztuczka już się nie uda. niezależnie od tego ile takich przekierowań pośrednich zdefiniujemy, CEF zawsze najpierw rozwiąże prawdziwy next-hop a dopiero potem zainstaluje go jako najlepsza trasa. ta sztuczka w sprzęcie z obecnie wspieranym oprogramowaniem już nam nie pomoże. przykład poniżej dla trasy pośredniej składającej się z pięciu zagnieżdżeń:

 path list 7EFF6F9FA7E8, 3 locks, per-destination,
   path 7EFF6FA7FFA8, share 1/1, type recursive, for IPv4
     recursive via 192.0.2.1[IPv4:Default](), fib 7EFF779F6F88, 1 terminal fib, v4:Default:192.0.41.1/32
     path list 7EFF6F9FA888, 3 locks, per-destination, flags 0x69 [shble, rif, rcrsv, hwcn]()
         path 7EFF6FA80528, share 1/1, type recursive, for IPv4
           recursive via 192.0.21.1[IPv4:Default](), fib 7EFF779F7088, 1 terminal fib, v4:Default:192.0.41.1/32
           path list 7EFF6F9FAB08, 3 locks, per-destination, flags 0x69 [shble, rif, rcrsv, hwcn]()
               path 7EFF6FA80268, share 1/1, type recursive, for IPv4
                 recursive via 192.0.31.1[IPv4:Default](), fib 7EFF779F7188, 1 terminal fib, v4:Default:192.0.41.1/32
                 path list 7EFF6F9FA9C8, 3 locks, per-destination, flags 0x69 [shble, rif, rcrsv, hwcn]()
                     path 7EFF6FA807E8, share 1/1, type recursive, for IPv4
                       recursive via 192.0.41.1[IPv4:Default](), fib 7EFF6F9F8E20, 1 terminal fib, v4:Default:192.0.41.1/32
                       path list 7EFF6F9FAD88, 9 locks, per-destination, flags 0x69 [shble, rif, rcrsv, hwcn]()
                           path 7EFF0C6D9620, share 1/1, type recursive, for IPv4
                             recursive via 10.0.2.254[IPv4:Default](), fib 7EFF0C6D8838, 1 terminal fib, v4:Default:10.0.2.254/32
                             path list 7EFF09E95768, 2 locks, per-destination, flags 0x49 [shble, rif, hwcn]()
                                 path 7EFF09E95FB8, share 1/1, type adjacency prefix, for IPv4
                                   attached to GigabitEthernet2, IP adj out of GigabitEthernet2, addr 10.0.2.254 7EFF740B1110

część innych producentów sieciowych nadal nie opanowało tej optymalizacji i nie potrafią rozwiązać w ten sposób interfejsów ani pól next-hop; nie oznacza to automatycznie, że rozwiązania te są o klasę gorsze, ale istotnie w kontekście efektywności wykorzystania miejsca w pamięciach używanych jako FIB oraz czasu do budowy tablicy FIB, CEF generalnie deklasuje inne rozwiązania dostępne na rynku

przynajmniej jeden z producentów sprzętu sieciowego eksperymentował kiedyś z kompresją gotowej tablicy FIB (zamiast optymalizować jej konstrukcję); eksperymenty te kończyły się jednak poważnymi problemami w sieciach produkcyjnych, w których nie tylko kompresja nie odpowiadała obiecywanym zyskom, ale przy rekonwergencji powodowała przepełnienie pamięci, awarie oprogramowania i co najgorsze, “ciche” odrzucanie ruchu do losowych prefiksów; oczywiście chodziło o próbę oszczędzenia na droższych, szybszych pamięciach TCAMach/SRAMach które zwykle przechowują FIB; zwracam również uwagę, że tradycyjnie te karty testowane były z setkami tysięcy prefiksów ale prefiksy te były dobierane sekwencyjnie - co oznaczało, że mechanizm kompresji mógł zadziałać całkiem efektywnie w trakcie testów, ale jednocześnie taki test był zupełnie niereprezentatywny dla warunków rzeczywistych

chciałbym jakoś prościej

prostsze i bardziej naturalne rozwiązanie dostępne jest w systemie IOS XR. XR od początku projektowany był dla operatorów internetowych, a to oznaczało, że wiele mechanizmów, w tym również CEF, od początku wzbogacono o wiele doświadczeń z 15 letniej wówczas historii rozwoju IOSa.

w IOS XR analogiczną konstrukcję można opisać dużo prościej i bez potrzeby stosowania tras pośrednich:

RP/0/0/CPU0:XR1#sh running-config router static
router static
 address-family ipv4 unicast
  0.0.0.0/0 198.51.100.37 metric 25 ! 25 : 8 : 2 : 1
  0.0.0.0/0 203.0.113.22 metric 8   ! 25 : 8 : 2 : 1
  0.0.0.0/0 198.18.0.6 metric 2     ! 25 : 8 : 2 : 1
  0.0.0.0/0 Dialer1                 ! złośliwi (i uważni!) czytelnicy mogą zwrócić
                                    ! uwagę na dziwny jak na IOS XR interfejs - pomińmy
                                    ! tę nikczemną uwagę czcionką o równej szerokości
 !
!

efektem takiej konfiguracji będzie rozłożenie ruchu idealne wg. naszej pierwotnej specyfikacji:

RP/0/0/CPU0:XR1#sh cef 0.0.0.0/0 detail         
0.0.0.0/0, version 17, proxy default, internal 0x1000011 0x0 (ptr 0xa13f307c)
[...]
    Weight distribution:
    slot 0, weight 25, normalized_weight 25, class 0
    slot 1, weight  8, normalized_weight 8, class 0
    slot 2, weight  2, normalized_weight 2, class 0
    slot 3, weight  1, normalized_weight 1, class 0

    Hash  OK  Interface                 Address
    0     Y   GigabitEthernet0/0/0/0    198.51.100.37    
    1     Y   GigabitEthernet0/0/0/0    198.51.100.37  
    [...]   
    24    Y   GigabitEthernet0/0/0/0    198.51.100.37   
    25    Y   GigabitEthernet0/0/0/1    203.0.113.22    
    26    Y   GigabitEthernet0/0/0/1    203.0.113.22
    [...]
    32    Y   GigabitEthernet0/0/0/1    203.0.113.22    
    33    Y   GigabitEthernet0/0/0/2    198.18.0.6
    34    Y   GigabitEthernet0/0/0/2    198.18.0.6
    35    Y   Dialer1

no dobrze, ale nie każdy ma w domu ASRa 9000, albo NCSa 540/560 lub NCSa 5500, lub… inną XRową platformę. można oczywiście uruchomić sobie wirtualną instancję XRv9000 ale nawet wtedy ograniczeni będziemy do interfejsów Ethernet, nie posiada ona wsparcia dla NAT i klienta PPPoA/PPPoE.

inne rozwiązania brzegowe

w następnej części cyklu wrócimy zatem do innych rozwiązań, które da się uruchomić bez potrzeby posiadania platformy wspierającej IOS XR. potem zajmiemy się bardziej eleganckim i skalowalnym podejściem do tematu, używając głowy a nie brutalnej siły zautomatyzowanego CLI :)