OSPF reaguje okamžitě v případě, že samotnému routeru padne link na fyzickém portu. V tom případě je OSPF naprosto skvělé.
Pokud jsou ale mezi dvěma routery např. dva switche, a padne spoj mezi těmi switchi, tak oběma těm routerům fyzický link zůstane nahoře. A OSPF dlouho dál tvrdošíjně routuje pakety tou mrtvou cestou.
Třeba "bonding driver" v linuxu má option zvanou "miimon", pomocí které ho lze nakonfigurovat, aby si hlídal link state a pro své potřeby se jím řídil - což může dělat pomocí MII ioctl(), ethtool ioctl(), nebo voláním netif_carrier_ok() což je default. (Funkce netif_carrier_ok() žije v kernelu, což není problém, protože bonding driver žije tamtéž.) Ale bonding driver si podle toho řídí jenom svoje vlastní failovery, routovací tabulku/rozhodování to podle všeho neovlivňuje.
Zkusil jsem se zběžně podívat pod kapotu, která oblast ve zdrojácích kernelu se routingu konkrétně týká. Teda spíš jsem se rozhlédl po webu, jestli o tom někdo nesepsal hezké povídání pro lenocha jako jsem já :-)
Tady je docela dobrý začátek, je tam zmíněno pár relevantních funkcí, zejm. fib_lookup() resp. fib_table_lookup().
Odtud vede odkaz na
moc pěkný webík, kde jsou hezky v kostce popsány stromové struktury, ve kterých je v kernelu udržována routovací tabulka (FIB, Forwarding Information Base).
Na tomto webíku je zmínka o objektu
struct fib_info což vypadá jako jeden záznam v routovací tabulce.
Ten se dále odkazuje na
struct fib_nh (= Next Hop) a jeho prostřednictvím na
struct fib_nh_common - který už obsahuje pointer na struct net_device, kde by se asi dalo doptat na okamžitý stav rozhraní (zda je "running").
Zarazil jsem se zhruba ve chvíli, kdy bych měl začít zkoumat vnitřnosti funkce fib_table_lookup(). To by bylo vážně na delší ponor. Dovolím si shrnout dojmy:
Routovací tabulka je v kernelu uskladněna v pokročilé stromové struktuře, která je vtipně interně komprimována dvěma způsoby: "path-compressed" a "level-compressed". Zmíněná datová struktura a vyhledávací funkce jsou optimalizovány na rychlost vyhledávání (procházení stromem). Zmíněný webík z roku 2017 tvrdí, že tehdejší plná routovací tabulka vytvoří strom o maximální hloubce 6 nebo 7 uzlů a (maximální? mediánová?) latence procházení je asi 50 ns, na vcelku běžném Haswell CPU.
V datových strukturách jsem si při letmém čenichání nevšiml nějaké informace o "stavu next-hopu", podle které by bylo možno "routovací záznamy náležející zhaslému rozhraní" při prohledávání ignorovat / přeskakovat nebo tak něco. Teoreticky by se dalo, doskákat několik dalších pointer indirections a zkontrolovat to přímo na síťovém rozhraní (struct net_device). Nebo by "něco" muselo cyklicky procházet FIB strom a cinkat jednotlivé záznamy (fib_info), které mají zrovna down příslušný next_hop interface. Není mi bez dalšího dumání jasné, nakolik by zaplevelení FIB takovými "potlačenými" záznamy zkomplikovalo vyhledávání živého next_hopu (procházení stromem). Ale v zásadě: vzhledem k důrazu na co nejefektivnější vyhledávání v tabulce (stromě) mi dává smysl, že se toto prostě nedělá. Ne per packet. Beru to jako zralé návrhové rozhodnutí. Znamenalo by to latenci navíc, a zátěž CPU.
Ještě by se dalo uvažovat, že v kernelu bude FIB "dvouúrovňová": horní "managementová" úroveň by držela všechny záznamy, a byla by nějak cyklicky "zrcadlena" do spodní "provozní" FIB tabulky, ze které by byly vyplety "potlačené" routovací záznamy. Hm. I tady zcela chápu, že se správcům nechtělo udržovat takovou složitost přímo v kernelu, když totéž a mnoho dalšího snadno zařídí dedicated routing daemon žijící v user space. Prostě "keep it simple". Čím víc o tom přemejšlím, tím víc maintainery chápu.
OT: Cestou jsem narazil na zajímavou stránku
Interactive Linux Kernel Map - která mi připadá zábavná, přestože konkrétně výše zmíněnou oblast cudně zamlčuje :-) Tzn. ten hezký barevný pavouk nebude zdaleka úplný...