Vrstvy ISO/OSI a teorie síťování

ICMP

Path MTU discovery

ICMP hraje takto kritickou roli v mechanismu Path MTU discovery. Musíme se ještě zmínit o jedné věci, která dosud nepadla: každá L2 technologie zavádí specifické omezení na maximální délku rámce (Maximum Transmission Unit - MTU). Ta je pro Ethernet obvykle 1500B, ale na různých sítích může být vyšší i nižší. Příklad, kde je obvykle nižší, jsou VDSL linky, které jsou nad DSL vrstvou zpravidla emulovaný Ethernet a nad ním se provozuje protokol PPPoE, jehož MTU je 1500 (Ethenet) - 8 bytů na overhead PPPoE, tedy 1492 B. Další příklad je tunel IP v IP, kde je overhead 20 B na IP header, takže MTU je pak 1480.

Bez ohledu na příčinu menšího MTU, protokol IP se musí umět vyrovnat se situací, kdy klient odešle IP datagram délky rovné MTU jeho síťového rozhraní, dejme tomu 1500B a tento datagram narazí cestou na linku, která má menší MTU, než je jeho délka. Protokol IPv4 tuto situaci umí řešit dvěma způsoby:

  1. Fragmentací, tedy že router, kde dochází k redukci MTU cesty, datagram rozdělí na dva a to více-méně useknutím konce, který se už nevejde do MTU, nastavením příslušných flagů v IP hlavičce, které signalizují, že bude následovat zbytek a následně vygenerování, druhého datagramu s novou hlavičkou (docela podobné té původní, jen s nastaveným offsetem na délku prvního fragmentu). Takto rozfragmentovaný datagram dojde až na cílovou stanici, která oba fragmenty spojí a získá tak původní payload. Má to ovšem řadu nevýhod: Samotná fragmentace je docela složitá akce, která se těžko implementuje v hardwaru (a většina velkokapacitních routerů dnes dělá všechnu práci ve specializovaných chipech). Navíc k fragmentaci může cestou dojít víckrát opakovaně, pokud je cestou několik zmenšení MTU za sebou. Tím se může overhead (každý fragment přidává 20B na IP hlavičku) zvýšit do astronomických procent. Navíc jeden z fragmentů se může ztratit a pro koncového hosta je to nepříjemná situace - musí držet došlé fragmenty v paměti, dokud nedojdou ostatní a nebo dokud to nevzdá a datagram nezahodí.

  2. Druhá varianta je datagram, co se nevejde do MTU prostě zahodit. To samo o sobě není moc konstruktivní, jenže o zahození datagramu vygeneruje router, který jej zahodil, ICMP zprávu a pošle jí odesílateli zahozeného datagramu. Ten se z ní dozví, který datagram byl zahozen (do zprávy o zahození se kopíruje hlavička zahozeného datagramu) a dále se dozví, jaké MTU následuje v cestě. Je tedy na odesílateli, aby data, která chce poslat přeorganizoval a poslal náhradou za zahozený datagram nový, ale menší.

    Tento krok se může opakovat, pokud je po cestě více zmenšení MTU. Odesílatel musí v každém kroku správně rozpoznat, který datagram byl zahozen a musí si zapamatovat, jaké je pro daný cíl Path MTU. V Linuxu na to slouží route cache. Primárním předpokladem však je, že musí odesílateli zahozeného datagramu dojít ICMP zpráva o zahození - ICMP Fragmentation Needed (Type 3, Code 4).

To, jestli router použije fragmentaci a nebo zahození a vygenerování ICMP zprávy závisí u IPv4 na flagu don't fragment - DF. V současné době velké množství systémů a aplikací nastavuje DF=1, protože fragmentace se považuje za neefektivní a PMTU Discovery by mělo univerzálně fungovat.

Co se ale stane, když příliš horlivý admin někde cestou zakázal ICMP a zprávy o zahození (Fragmentation Needed) se budou zahazovat? Jedná se o naprosto typický projev, nicméně bez prozkoumání situace pomocí nástroje tcpdump se zpravidla neobejdeme. Dejme tomu, že v příkladě z minulé sekce bude klient opět navazovat TCP session na server, dejme tomu, že to bude HTTP request, kterým si vyžádá soubor velký 1MB a předpokládejme, že klient i server budou nastavovat do IP hlaviček DF=1. A představme si, že linka mezi R1 a R2 má z nějakého důvodu MTU 1480 B, a že router R2 neposílá resp. zahazuje všechny ICMP zprávy.

Broken PMTU Discovery

Na začátku každého TCP spojení probíhá 3-way handshake (https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment). Ten se skládá ze 2 TCP segmentů, které jdou ve směru od klienta na server a jednoho potvrzení ze serveru ke klientovi. To jsou všechno malé datagramy dlouhé několik desítek bytů a proto skoro zaručeně projdou (protokol IPv4 vyžaduje minimální MTU 68 B, nicméně většina běžných L2 se pohybuje nad 1000 B, IPv6 pak vyźaduje minimální MTU 1280 B). Jenže jakmile se spojení naváže a klient pošle HTTP dotaz (opět pár desítek, maximálně pár stovek bytů), server se z pohledu klienta odmlčí. Naopak z pohledu serveru server pošle první 1500 B dlouhý IP datagram s daty souboru, který byl vyžádán a nedostane od klienta potvrzení, takže několikát opakuje pokus poslání prvního segmentu, až vyprší timeout a server spojení ukončí.

Celý problém je pochopitelně v tom, že router R2 zahazuje IP datagramy dlouhé 1500 B (červená šipka ve schématu), protože překračují MTU 1480 B a nevysílá resp. zahazuje o tom hlášení protokolem ICMP (zelená šipka ve schématu), které by měl poslat odesílateli zahozených datagramů - serveru. Server tedy neví, v čem je problém a nemůže tedy přizpůsobit odesílané TCP segmenty velikosti MTU po cestě a spojení se proto po slibném začátku rozpadne, jakmile do něj začnou proudit data.

V protokolu IPv6 fragmentace vůbec není definována a proto se všechny datagramy, které překračují MTU zahazují a není tedy jiné cesty, než mít zaručeně funkční Path MTU Discovery.

Odkazy: