Linux mini-howto? Krátce o nástrojích ze života sysadmina.
Simulace zpoždění a ztrátovosti paketů
V předchozím Linux-mini howto (Je tunelování TCP skrz TCP dobrý nápad ?) jsme na konci článku zmínili formou odkazů informace k této problematice i přes tento fakt a existenci Google přišlo pár dotazů jak na to, pojďme to v rychlosti proběhnout.
Diagnostika sítí je komplexní, rozsáhlá a složitá disciplína plná záludností, složitých software nástrojů a sofistikovaných drahých měřících přístrojů, přesto se hodí umět si vyrobit kontrolovaně svůj vlastní problém na stole (nemluvíme teď o “muchlání” a kroucení kabelů či nucení kolegů na chodbě běhat skrze bezdrátový spoj ) a to zcela zdarma díky Linux jádru.
Základní kvalitativní parametry sítě
Zpoždění (latency)
https://cs.wikipedia.org/wiki/Latence#V_informatice
Ztrátovost paketů (packet loss)
https://cs.wikipedia.org/wiki/Ztráta_paketů
Linux kernel, IP stack, fronty, netem NIC
Linux jádro má již od verze 2.6 (dobře, vlastně od 2.4.37) implementovanou funkcionalitu pro network emulaci (netem), pokud máte kernel 2.6 a novější, zakompilovanou podporu Network emulatoru do jádra či jako modul a k tomu nainstalovaný obslužný nástroj tc (traffic control) z balíku iproute2 máte vše potřebné.
Networking --> Networking Options --> QoS and/or fair queuing --> Network emulator CONFIG_NET_SCH_NETEM=m
Jak funguje netem (linux network emulator) ?
Popišme si alespoň základní koncept síťování v Linux, jednoduchá ilustrace nám dobře pomůže k pochopení, na jedné straně máme aplikace komunikující prostřednictvím systémových volání jádra (syscall) s IP stackem, chtějí komunikovat s hostem a.b.c.d, navazovat spojení, posílat data a o moc více se nestarat.
IP stack předává pakety do qdisc (Queueing discipline), což není nic jiného než scheduler (plánovač, kód v jádře systému) fronty, který rozhoduje o tom v jakém pořadí zpracovat pakety, každé výstupní rozhraní má alespoň jeden qdisc (scheduler, frontu), po průchodu frontou přes ovladač síťové karty putují data ven.
Výchozí fronta v Linuxu je většinou FIFO (First-in, First-Out).
root@netem-machine:~# tc -s qdisc qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap Sent 14757932 bytes 163954 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 root@netem-machine:~# tc qdisc show qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap
Výpisem pomocí nástroje tc jsme si ověřili aktuálně nastavený qdisc na zařízení eth0 (ethernet), je patrné, že máme nastavenou frontu typu pfifo (packet FIFO) z následující obrázku je vidět, že pfifo interně implementuje i jednoduchý priority mapping a obsahuje uvnitř tři různé fronty pro přednostní zpracování.
Pokud je fronta plná (linka je zatížená) a nemůže být přijmut další paket ke zpracování, dojde k jeho zahození, frontu lze pro tento účel zvětšit, následkem je většinou zvýšení latence, ale můžeme pozorovat i lepší využití linky.
Pro doplnění představ, v Linux jádře je dnes přes 20 různých schedulerů paketů (red, qfq, prio, mq, cbq, htb, sfq ,…) a nic Vám nebrání napsat si svůj vlastní unikátní pro Vaše potřeby. (http://lxr.free-electrons.com/source/net/sched/ )
Netem, skrze dlouhou okliku a vysvětlení qdisc se vraťme zpět k našemu emulátoru, z předchozích informací je zřejmé, že netem je implementován jako další plánovač paketů se schopností přidávat ke zpracování latence včetně náhodné distribuce, generovat ztrátovost, duplikovat i měnit pořadí paketů(reordering).
Použití je opravdu triviální, ukážeme si, nahrajeme modul netem do jádra, nastavíme na rozhraní eth0 qdisc netem, nastavíme parametry zpoždění, náhodného rozptylu, ztrátovosti a otestujeme.
root@netem-machine:~# modprobe sch_netem root@netem-machine:~# tc qdisc show qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap root@netem-machine:~# root@netem-machine:~# tc qdisc add dev eth0 root netem root@netem-machine:~# tc qdisc show qdisc netem 8004: dev eth0 root refcnt 2 limit 1000
Zpoždění 200ms , host 10.0.200.1 je součástí directly connected sítě, okamžitě lze vidět nárůst latence zde pomocí ping nástroje.
root@netem-machine:~# tc qdisc change dev eth0 root netem delay 200ms root@test-machine:~$ ping 10.0.200.1 PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data. 64 bytes from 10.0.200.1: icmp_seq=1 ttl=64 time=0.295 ms 64 bytes from 10.0.200.1: icmp_seq=2 ttl=64 time=0.268 ms 64 bytes from 10.0.200.1: icmp_seq=9 ttl=64 time=0.230 ms 64 bytes from 10.0.200.1: icmp_seq=10 ttl=64 time=200 ms 64 bytes from 10.0.200.1: icmp_seq=11 ttl=64 time=200 ms 64 bytes from 10.0.200.1: icmp_seq=12 ttl=64 time=200 ms
Zpoždění 500ms ± 100ms, je vidět zpoždění ± s velkým rozptylem (ne realtime jádro s tím asi dost bojuje).
root@test-machine:~# tc qdisc change dev eth0 root netem delay 500ms 100ms root@test-machine:~$ ping 10.0.200.1 PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data. 64 bytes from 10.0.200.1: icmp_seq=24 ttl=64 time=0.242 ms 64 bytes from 10.0.200.1: icmp_seq=25 ttl=64 time=0.272 ms --- aplikace netem --- root@test-machine:~$ ping 10.0.200.1 PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data. 64 bytes from 10.0.200.1: icmp_seq=1 ttl=64 time=453 ms 64 bytes from 10.0.200.1: icmp_seq=2 ttl=64 time=479 ms 64 bytes from 10.0.200.1: icmp_seq=3 ttl=64 time=502 ms 64 bytes from 10.0.200.1: icmp_seq=4 ttl=64 time=491 ms 64 bytes from 10.0.200.1: icmp_seq=5 ttl=64 time=553 ms 64 bytes from 10.0.200.1: icmp_seq=6 ttl=64 time=532 ms 64 bytes from 10.0.200.1: icmp_seq=7 ttl=64 time=534 ms 64 bytes from 10.0.200.1: icmp_seq=8 ttl=64 time=490 ms 64 bytes from 10.0.200.1: icmp_seq=9 ttl=64 time=450 ms
Ztrátovost 10% (10% paketů bude náhodně zahazováno) + latence 100ms, náhodu lze ještě ovlivňovat korelací kdy je závislá na předchozím výsledku v %, je to trochu chaotické, ale vlastně méně chaotické, protože zmenšujeme náhodnost generátoru).
root@test-machine:~# tc qdisc change dev eth0 root netem delay 100ms loss 10% root@test-machine:~$ ping -q -c 10 10.0.200.1 PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data. --- 10.0.200.1 ping statistics --- 10 packets transmitted, 9 received, 10% packet loss, time 9026ms rtt min/avg/max/mdev = 100.222/100.298/100.371/0.163 ms root@test-machine:~$ ping -q -c 10 10.0.200.1 PING 10.0.200.1 (10.0.200.1) 56(84) bytes of data. --- 10.0.200.1 ping statistics --- 10 packets transmitted, 6 received, 40% packet loss, time 9013ms rtt min/avg/max/mdev = 100.197/100.239/100.295/0.185 ms
Základní představu o konceptu netem a jeho využití jsme snad představili, studujte dokumentaci, další pěknou věcí, která stojí za vyzkoušení je poškozování paketů (netestovali jsme bohužel), není špatné si pro přehled projít i zdrojový kód netem, pěkné je nasazení netem i na příchozí provoz pomocí modulu IFB (pouze otočí in přes pseudo device na out a na něm udělat netem) v ukázkách dokumentace nejdete jak netem protáhnout i jen specifický traffic přes tc filter, omezit rychlost apod … prostě studujte.
V našem případě při testování a hledání problémů s TCP over TCP jsem si postavili script který měnil hodnoty zpoždení a ztrátovosti od malých až po extrémní, tak aby jsme donutili TCP prodlužovat adaptivní timeout a sledovat pomocí tcpdump/wireshark co se děje uvnitř spojení.
Děkuji za pozornost.
František Havel, MOJEservery.cz
Zdroje:
http://man7.org/linux/man-pages/man8/tc-netem.8.html
http://lxr.free-electrons.com/source/net/sched/sch_netem.c
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem
http://info.iet.unipi.it/~luigi/dummynet/