Me rënien e adresave IPv4, shumë operatorë të telekomunikacionit u përballën me nevojën për të organizuar qasjen e klientëve të tyre në rrjet nëpërmjet përkthimit të adresave. Në këtë artikull, do të flas për mënyrat se si mund të arrijmë performancën e nivelit Carrier Grade NAT në serverë të zakonshëm.
Pak histori
Tema e përfundimit të hapësirës adresuese IPv4 nuk është e re. Në një moment të caktuar në RIPE u shfaqën listarë pritjeje, pastaj tregje ku tregoheshin blloqet e adresave dhe u lidhën marrëveshje për qiramarrjen e tyre. Gradualisht, operatorët e telekomunikacionit filluan të ofrojnë shërbime qasje në internet duke përdorur përkthimin e adresave dhe porteve. Disa nuk arritën të merrnin mjaft adresash për t'iu ofruar çdo abonenti një adresë 'të bardhë', ndërsa disa filluan të kursejnë, duke refuzuar të blenin adresa në tregun e dytë. Prodhuesit e pajisjeve rrjetike mbështetën këtë ide, pasi ky funksionalitet zakonisht kërkon modulet e zgjerimit ose licensat shtesë. Për shembull, në linjën e routerëve MX të Juniper (përveç versioneve të fundit MX104 dhe MX204), për të realizuar NAPT kërkohet një kartë shërbimi e veçantë MS-MIC, ndërsa për Cisco ASR1k kërkohet një licensë SGN, dhe për Cisco ASR9k - një moduli i veçantë A9K-ISM-100 dhe licensë A9K-CGN-LIC për të. Në përgjithësi, këto shërbime kërkojnë një investim të konsiderueshëm.
IPTables
Detyra e realizimit të NAT-it nuk kërkon burime të specializuara të llogaritjes; kjo mund të zgjidhet nga procesorët e zakonshëm, të cilët janë të instaluar, për shembull, në çdo router shtëpiak. Në shkallën e një operatori telekomunikacioni, kjo detyrë mund të zgjidhet duke përdorur serverët e zakonshëm nën menaxhimin e FreeBSD (ipfw/pf) ose GNU/Linux (iptables). Nuk do ta shqyrtojmë FreeBSD-në, pasi unë kam hequr dorë nga përdorimi i këtij sistemi operativ mjaft kohë më parë, kështu që do të ndalemi në GNU/Linux.
Aktivizimi i përkthimit të adresave nuk është aspak i komplikuar. Së pari, është e nevojshme të shkruani një rregull në iptables në tabelën nat:
iptables -t nat -A POSTROUTING -s 100.64.0.0/10 -j SNAT --to - --persistent
Sistemi operativ do të ngarkojë modulin nf_conntrack, i cili do të monitorojë të gjitha lidhjet aktive dhe do të bëjë transformimet e nevojshme. Ka disa nuanca. Së pari, duke qenë se bëhet fjalë për NAT në shkallë operatori të komunikimit, nevojitet të rregullohen timeout-et, pasi me vlerat e paracaktuar, madhësia e tabelës së translacioneve do të rritet mjaft shpejt në përmasa katastrofike. Më poshtë është një shembull i cilësimeve që kam përdorur në serverët e mi:
net.ipv4.ip_forward = 1
net.ipv4.ip_local_port_range = 8192 65535
net.netfilter.nf_conntrack_generic_timeout = 300
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_established = 600
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 45
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 60
net.netfilter.nf_conntrack_icmpv6_timeout = 30
net.netfilter.nf_conntrack_icmp_timeout = 30
net.netfilter.nf_conntrack_events_retry_timeout = 15
net.netfilter.nf_conntrack_checksum=0
Dhe së dyti, duke qenë se madhësia e tabelës së përkthimeve nuk është e optimizuar për punë në kushtet e një operatori të komunikimit, është e nevojshme ta shtojmë atë:
net.netfilter.nf_conntrack_max = 3145728
Gjithashtu, është e nevojshme të rritet numri i buckets për tabelën e hash-it që mban të gjitha përkthimet (kjo është një opsion i modulit nf_conntrack):
options nf_conntrack hashsize=1572864
Pas këtyre manovrave të thjeshta, rezulton një strukturë mjaft funksionale, e cila mund të përkthejë një numër të madh adresash klienti në një grup të jashtëm. Megjithatë, performanca e këtij zgjidhjeje është e kënaqshme. Në përpjekjet e mia të para për të përdorur GNU/Linux për NAT (rreth vitit 2013), arrita një performancë prej rreth 7Gbit/s me 0.8Mpps në një server (Xeon E5-1650v2). Që atëherë, në stack-un rrjetor të kernelit GNU/Linux janë bërë shumë optimizime të ndryshme, dhe performanca e një serveri me të njëjtin hardware është rritur në pothuajse 18-19 Gbit/s me 1.8-1.9 Mpps (këto ishin nivele maksimale), por kërkesa për sasinë e trafik po përpunuar nga një server po rritej shumë më shpejt. Në fund, janë zhvilluar skema balancimi ngarkese në serverë të ndryshëm, por të gjitha këto e rritën kompleksitetin e konfigurimit, mirëmbajtjes dhe mbajtjes së cilësisë së shërbimeve të ofruara.
NFTables
Një trend aktual në programimin e "transferit të paketave" është përdorimi i DPDK dhe XDP. Në këtë temë janë shkruar shumë artikuj, janë mbajtur shumë prezantime dhe kanë dalë produkte komerciale (për shembull, SKAT nga VasExperts). Por në kushte të burimeve të kufizuara të programuesve tek operatorët e komunikimit, të zhvillosh ndonjë "zgjidhje" të tillë në bazë të këtyre kuadrove është mjaft problematike. Shfrytëzimi i një zgjidhjeje të tillë më vonë do të jetë shumë më i komplikuar, veçanërisht do të duhet të zhvillohen mjete diagnostikimi. Për shembull, tcpdump-i standard me DPDK nuk do të funksionojë thjesht, as paketat që dërgohen përsëri në tela me ndihmën e XDP nuk do të "shihen". Në sfondin e të gjitha bisedave për teknologjitë e reja të përmirësimit të paketave në hapësirën e përdoruesit, janë mbetur të paivë në mes dhe Pablo Neira Ayuso, mirëmbajtësi i iptables, për zhvillimin e shkarkimit të rrjedhës në nftables. Le ta shqyrtojmë këtë mekanizëm më hollësisht.
Ideja kryesore është që, nëse router-i ka kaluar paketat e një seance në të dy anët e rrjedhës (seanca TCP ka kaluar në gjendjen ESTABLISHED), nuk ka nevojë të kalojnë paketat e mëtejshme të kësaj seance përmes të gjitha rregullave të firewall-it, sepse të gjitha këto kontrole do të përfundojnë në dërgimin e paketës më tej në routing. Po ashtu, nuk është e nevojshme të ndërtohet në rrugën - ne tashmë e dimë se në cilin ndërfaqe dhe cilit host duhet t'u dërgohen paketat brenda kësaj seance. Mbete vetëm të ruhet kjo informacion dhe ta përdorim për routing në një fazë të hershme të përpunimit të paketës. Në realizimin e NAT-it është e nevojshme gjithashtu të ruhet informacioni mbi ndryshimet e adresave dhe porteve, të transformuara nga moduli nf_conntrack. Po, sigurisht, në këtë rast ndalen të funksionojnë politikat e ndryshme dhe rregullat e tjera informacion-statistike në iptables, por në kuadër të detyrës së një NAT-i të veçantë ose, për shembull, një kufi - kjo nuk është aq e rëndësishme, sepse shërbimet janë të shpërndara në pajisje.
Konfigurimi
Për të përdorur këtë funksionalitet, na nevojitet:
- Të përdorim një bërthamë të re. Përkundër faktit se funksionaliteti vetë u shfaq që në bërthamën 4.16, ai ishte shumë "i papjekur" për një kohë të gjatë dhe shpesh shkaktonte panic të kernel-it. Gjithçka u stabilizua rreth dhjetorit 2019, kur dolën bërthamat LTS 4.19.90 dhe 5.4.5.
- Rite rregullat e iptables në formatin nftables, duke përdorur një version mjaft të ri të nftables. Funksionon saktësisht në versionin 0.9.0
Nëse pika e parë është e qartë, gjëja më e rëndësishme është të mos harrosh të aktivizosh modulit në konfigurim gjatë ndërtimit (CONFIG_NFT_FLOW_OFFLOAD=m), pika e dytë kërkon sqarime. Rregullat e nftables përshkruhen ndryshe nga ato të iptables. shpreh pothuajse të gjitha aspektet, gjithashtu ka konvertues rregullave nga iptables në nftables. Prandaj, do të jap vetëm një shembull të konfigurimit NAT dhe flow offload. Një legjendë e vogël për shembullin: , - këto janë ndërfaqet rrjetërore përmes të cilave kalon trafiku, realisht mund të kenë më shumë se dy. , - adresa fillestare dhe përfundimtare e diapazonit të adresave "të bardha".
Konfigurimi i NAT është shumë i thjeshtë:
#! /usr/sbin/nft -f
table nat {
chain postrouting {
type nat hook postrouting priority 100;
oif <o_if> snat to <pool_addr_start>-<pool_addr_end> persistent
}
}
Me flow offload është pak më e komplikuar, por e qartë:
#! /usr/sbin/nft -f
table inet filter {
flowtable fastnat {
hook ingress priority 0
devices = { <i_if>, <o_if> }
}
chain forward {
type filter hook forward priority 0; policy accept;
ip protocol { tcp , udp } flow offload @fastnat;
}
}
Ja, kjo është e gjithë konfigurimi. Tani gjithë trafiku TCP/UDP do të kalojë në tabelën fastnat dhe do të përpunohen shumë më shpejt.
Rezultatet
Për t'u kuptuar sa 'shumë më shpejt', do të bashkangjitja një screenshot të ngarkesës në dy servera aktualë, me të njëjtën përbërje (Xeon E5-1650v2), të konfiguruar njëlloj, duke përdorur të njëjtin bërthamë Linux, por që kryejnë NAT në iptables (NAT4) dhe në nftables (NAT5).

Në screenshot nuk ka grafik të pakove për sekondë, por në profilin e ngarkesës së këtyre serverave, madhësia mesatare e paketës është rreth 800 byte, kështu që vlerat arrijnë deri në 1.5Mpps. Siç duket, kapaciteti i performancës së serverit me nftables është i madh. Në këtë moment, ky server përpunon deri në 30Gbit/s me 3Mpps dhe është padyshim i aftë të arrijë kufirin fizik të rrjetit 40Gbps, duke pasur në të njëjtën kohë burime të lira CPU.
Shpresoj që ky material do të jetë i dobishëm për inxhinierët e rrjetit që përpiqen të përmirësojnë performancën e serverëve të tyre.
Burimi: habr.com
