L4 - TCP, UDP a přehled dalších L4 protokolů

Protokoly vyšších vrstev teď nebudeme dopodrobna rozebírat. Spíš stojí za to říct, co všechno se dá přenášet protokolem IP. Tento přehled bychom mohli snadno odbýt radou: cat /etc/protocols. Tento soubor obsahuje převodní tabulku čísel protokolů, jak se vyskytují v poli Protocol v IPv4 hlavičce resp. poli Next Header u IPv6.

V této tabulce jsou přirozeně dva nejdůležitější zástupci L4 - protkoly TCP (6) a UDP (17). Vedle toho tam ale vidíme i několik typů rozšiřujících hlaviček pro IPv6, protože IPv6 vskutku vrství rozšiřující hlavičky pomocí Next Header pole. A pak také samotné IPv4 (0 a 94) a IPv6 (41). Takto se totiž dělají statické nešifrované tunely - zkrátka se protokolem IP přenáší další hlavička IP a následující payload, ať je to cokoli. IP ve vnitřní i vnější hlavičce může být jak IPv4, tak IPv6, čímž nám vznikají 4 možnosti tunelů - a Linux podporuje všechny 4.

IP in IP tunnel

K čemu vlastně tunely jsou? Když zůstaneme u tunelů, které tunelovaný provoz nešifrují, ani nezajištují jeho neměnnost a autenticitu (jako to dělá například IPsec pomocí ESP a AH headerů), tak je smysl tunelů především v oddělení provozu a oddělení adresních prostorů. Typický příklad je, že vnitřní IP header používá adresy, které nelze přenášet přes Internet - například privátní adresy (RFC1918).

IP Tunnel

Dále možná poznáváte z tabulky v /etc/protocols podle jména GRE - Generic Routing Encapsulation, což je další možnost, jak tunelovat libovolný protokol přes IP - tentokrát se však mezi vnější IP hlavičku a vnitřní (tunelovanou) L3 hlavičku vkládá ještě GRE header. Ten umožňuje mít více tunelů stejného typu mezi jednou dvojicí IP adres identifikující koncové body tunelu. A také umožňuje v jednom tunelu přenášet různé protokoly, zatímco v případě prostého IP-in-IP se musí IPv4-in-IPv4 a IPv6-in-IPv4 (SIT) konfigurovat jako dva zvláštní tunely. Naopak cenou za flexibilitu je vyšší overhead - GRE header má 8 bytů, což nevypadá jako mnoho, ale přidává se to ke každému datagramu, který přes tunel prochází, bez ohledu na jeho velikost. Takže těchto 8 bytů může být pro malý datagram, který přenáší pár bytů užitečného payloadu docela velké procento celkové velikosti.

Další zajímavé protokoly, které lze přenášet přes IP, jsou OSPF - to je link-state směrovací protokol, který impmenetuje například BIRD nebo Quagga. Nebo VRRP - protokol pro volbu mastera ze dvou (nebo více) kandidátů pro zajištění redundance služeb, které daná adresa poskytuje. VRRP je implementován například programem keepalived.

Z hlediska Linuxu je TCP a UDP často poslední protokol TCP/IP stacku, který je implementován v jádře. Vyšší vrstvy, například SSL, jsou pak už implementované jako knihovny v userspace.

Nicméně z hlediska objemu provozu jsou nejdůležitější protokoly, přenášené v IP TCP a UDP. K TCP a UDP přistupují aplikace a knihovny přes tradiční API, známé jako BSD sockets nebo Berkeley sockets. Rozhraní BSD socketů stojí za to aspoň v hrubých obrysech znát - vizte odkazy na Wikipedii níže.

TCP má poměrně velké množství parametrů - doby timeoutů, parametry „pomalého startu“, velikosti bufferů atd., UDP má sice parametrů méně, protože je jednodušší, ale přesto jich pár je. Jak už to v Linuxovém jádře s různými parametry bývá, mají své výchozí (default) hodnoty, které jsou nastaveny pomocí konstant v kódu jádra. Mnohé se však dají za běhu změnit pro celý systém resp. pro daný síťový namespace přes sysctl parametry (a nebo přes odpovídající virtuální soubor v procfs (/proc/sys/net/...). Příklad:

root@osboxes:~# sysctl net.ipv4 | grep tcp_
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_adv_win_scale = 1
net.ipv4.tcp_allowed_congestion_control = reno cubic
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_autocorking = 1
...
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_rmem = 4096    131072  6291456
net.ipv4.tcp_rx_skb_cache = 0
net.ipv4.tcp_sack = 1
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_syn_retries = 6
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_thin_linear_timeouts = 0
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_tw_reuse = 2
net.ipv4.tcp_tx_skb_cache = 0
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_wmem = 4096    16384   4194304
net.ipv4.tcp_workaround_signed_windows = 0

A některé parametry lze měnit přes BSD sockets API pro každé spojení. Nebudeme teď opět zabíhat do detailů, nicméně je dobré podotknout, že parametry TCP a UDP protokolu mají význam pro výkon. Výchozí hodnoty většinou fungují docela dobře pro běžné nasazení jako pracovní stanice a nebo server. Přesto dřív či později každý admin linuxových serverů dojde k tomu, že bude potřebovat něco změnit či vylepšit kvůli zvláštním aplikacím a nebo výkonu celého systému. K tomu se ale dostaneme dále.

Odkazy: