Snelle routing en NAT yn Linux

As IPv4-adressen leech wurde, wurde in protte telekomoperators konfrontearre mei de needsaak om har kliïnten netwurk tagong te jaan mei adresoersetting. Yn dit artikel sil ik jo fertelle hoe't jo Carrier Grade NAT-prestaasjes kinne krije op commodity-servers.

In bytsje skiednis

It ûnderwerp fan útputting fan IPv4-adresromte is net mear nij. Op in stuit ferskynden wachtlisten yn RIPE, doe ûntstiene útwikselingen wêrop blokken fan adressen waarden ferhannele en deals waarden sletten om se te leasen. Stadichoan, telecom operators begûn te leverjen ynternet tagong tsjinsten mei help fan adres en haven oersetting. Guon slaggen der net yn om genôch adressen te krijen om in "wyt" adres oan elke abonnee út te jaan, wylst oaren begûnen jild te besparjen troch te wegeren om adressen op 'e sekundêre merk te keapjen. Fabrikanten fan netwurk apparatuer stipe dit idee, omdat dizze funksjonaliteit fereasket meastentiids ekstra útwreiding modules of lisinsjes. Bygelyks, yn Juniper syn line fan MX routers (útsein foar de nijste MX104 en MX204), kinne jo útfiere NAPT op in aparte MS-MIC service card, Cisco ASR1k fereasket in CGN lisinsje, Cisco ASR9k fereasket in aparte A9K-ISM-100 module en in A9K-CGN lisinsje -LIC oan him. Oer it algemien kostet it genot in soad jild.

IPTables

De taak fan it útfieren fan NAT fereasket gjin spesjalisearre kompjûterboarnen; it kin wurde oplost troch processors foar algemiene doelen, dy't ynstalleare wurde, bygelyks yn elke thúsrouter. Op 'e skaal fan in telekomoperator kin dit probleem oplost wurde mei help fan commodity-tsjinners dy't FreeBSD (ipfw/pf) of GNU/Linux (iptables) draaie. Wy sille FreeBSD net beskôgje, om't ... Ik bin in skoft lyn stoppe mei it brûken fan dit OS, dus wy sille fêsthâlde oan GNU/Linux.

It ynskeakeljen fan adresoersetting is hielendal net dreech. Earst moatte jo in regel registrearje yn iptables yn 'e nat-tabel:

iptables -t nat -A POSTROUTING -s 100.64.0.0/10 -j SNAT --to <pool_start_addr>-<pool_end_addr> --persistent

It bestjoeringssysteem sil de nf_conntrack-module lade, dy't alle aktive ferbiningen kontrolearje sil en de nedige konversaasjes útfiere. D'r binne hjir ferskate subtiliteiten. As earste, om't wy it hawwe oer NAT op 'e skaal fan in telekomoperator, is it nedich om de timeouts oan te passen, om't mei standertwearden de grutte fan' e oersettingstabel fluch groeie nei katastrofale wearden. Hjirûnder is in foarbyld fan 'e ynstellings dy't ik brûkte op myn servers:

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

En twad, om't de standertgrutte fan 'e oersettingtabel net is ûntworpen om te wurkjen ûnder de betingsten fan in telekomoperator, moat it ferhege wurde:

net.netfilter.nf_conntrack_max = 3145728

It is ek nedich om it oantal emmers te ferheegjen foar de hash-tabel dy't alle útstjoerings opslaan (dit is in opsje yn 'e nf_conntrack-module):

options nf_conntrack hashsize=1572864

Nei dizze ienfâldige manipulaasjes wurdt in folslein wurkjend ûntwerp krigen dat in grut oantal kliïntadressen oersette kin yn in pool fan eksterne. Lykwols, de prestaasjes fan dizze oplossing lit in protte te winskjen oer. Yn myn earste besykjen om GNU / Linux te brûken foar NAT (circa 2013), koe ik prestaasjes krije fan sawat 7Gbit / s by 0.8Mpps per tsjinner (Xeon E5-1650v2). Sûnt dy tiid binne in protte ferskillende optimisaasjes makke yn 'e GNU/Linux kernel netwurk stack, de prestaasjes fan ien server op deselde hardware is ferhege nei hast 18-19 Gbit / s by 1.8-1.9 Mpps (dit wiene de maksimale wearden) , mar de fraach nei ferkear folume, ferwurke troch ien tsjinner groeide folle flugger. As resultaat waarden regelingen ûntwikkele om de lading op ferskate servers te balansearjen, mar dit alles fergrutte de kompleksiteit fan it opsetten, ûnderhâlden en behâlden fan de kwaliteit fan 'e levere tsjinsten.

NTFables

Tsjintwurdich is in modieuze trend yn software "ferhúzjen tassen" it brûken fan DPDK en XDP. In protte artikels binne skreaun oer dit ûnderwerp, in protte ferskillende taspraken binne makke, en kommersjele produkten ferskine (Bygelyks SKAT út VasExperts). Mar sjoen de beheinde programmearringsboarnen fan telekomoperators, is it frij problematysk om elk "produkt" te meitsjen op basis fan dizze kaders op jo eigen. It sil folle dreger wêze om sa'n oplossing yn 'e takomst te betsjinjen; benammen diagnostyske ark moatte wurde ûntwikkele. Bygelyks, standert tcpdump mei DPDK sil net wurkje krekt sa, en it sil net "sjen" pakketten stjoerd werom nei de triedden mei help fan XDP. Te midden fan al it praat oer nije technologyen foar it útfieren fan pakketferstjoeren nei brûkersromte, giene se ûngemurken ferslaggen и artikels Pablo Neira Ayuso, ûnderhâlder fan iptables, oer de ûntwikkeling fan streamôfladen yn nftables. Litte wy in tichterby besjen op dit meganisme.

It haadgedachte is dat as de router pakketten fan ien sesje yn beide rjochtingen fan 'e stream trochjûn (TCP-sesje gie yn 'e ESTABLISHED state), dan is d'r gjin ferlet om folgjende pakketten fan dizze sesje troch alle firewall-regels troch te jaan, om't al dizze kontrôles sille noch einigje mei it pakket dat fierder wurdt oerbrocht nei de routing. En wy hoege eins net in rûte te selektearjen - wy witte al nei hokker ynterface en nei hokker host wy pakketten moatte stjoere binnen dizze sesje. Alles wat oerbliuwt is dizze ynformaasje op te slaan en te brûken foar routing yn in ier stadium fan pakketferwurking. By it útfieren fan NAT is it nedich om ekstra ynformaasje te bewarjen oer feroaringen yn adressen en havens oerset troch de nf_conntrack-module. Ja, fansels, yn dit gefal stopje ferskate plysjes en oare ynformaasje- en statistyske regels yn iptables te wurkjen, mar yn it ramt fan 'e taak fan in aparte steande NAT of, bygelyks, in grins, is dit net sa wichtich, om't de tsjinsten wurde ferdield oer apparaten.

Konfiguraasje

Om dizze funksje te brûken hawwe wy nedich:

  • Brûk in frisse kernel. Nettsjinsteande it feit dat de funksjonaliteit sels yn kernel 4.16 ferskynde, wie it in lange tiid heul "rau" en feroarsake regelmjittich kernelpanyk. Alles stabilisearre rûn desimber 2019, doe't LTS-kernels 4.19.90 en 5.4.5 waarden frijlitten.
  • Iptables-regels oerskriuwe yn nftables-formaat mei in frij resinte ferzje fan nftables. Wurket krekt yn ferzje 0.9.0

As alles yn prinsipe dúdlik is mei it earste punt, is it wichtichste ding net te ferjitten om de module yn 'e konfiguraasje op te nimmen by de gearstalling (CONFIG_NFT_FLOW_OFFLOAD=m), dan fereasket it twadde punt útlis. nftables-regels wurde folslein oars beskreaun as yn iptables. Dokumintaasje docht bliken hast alle punten, der binne ek spesjale converters regels fan iptables nei nftables. Dêrom sil ik mar in foarbyld jaan fan it opsetten fan NAT en flow-offload. In lytse leginde bygelyks: , - dit binne de netwurkynterfaces dêr't ferkear trochhinne giet; yn werklikheid kinne d'r mear dan twa wêze. , - it begjin- en einadres fan it berik fan "wite" adressen.

NAT-konfiguraasje is heul ienfâldich:

#! /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
        }
}

Mei flow offload is it in bytsje yngewikkelder, mar frij begryplik:

#! /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;
        }
}

Dat is trouwens de hiele opset. No sil alle TCP / UDP-ferkear yn 'e fastnat-tabel falle en folle flugger wurde ferwurke.

Resultaten

Om dúdlik te meitsjen hoe "folle flugger" dit is, sil ik in skermôfbylding taheakje fan 'e lading op twa echte servers, mei deselde hardware (Xeon E5-1650v2), identyk konfigureare, mei deselde Linux-kernel, mar NAT útfiere yn iptables (NAT4) en yn nftables (NAT5).

Snelle routing en NAT yn Linux

D'r is gjin grafyk fan pakketten per sekonde yn 'e skermôfbylding, mar yn it loadprofyl fan dizze servers is de gemiddelde pakketgrutte sawat 800 bytes, sadat de wearden oant 1.5Mpps berikke. Sa't jo sjen kinne, hat de server mei nftables in enoarme prestaasjesreserve. Op it stuit ferwurket dizze server oant 30Gbit / s by 3Mpps en is dúdlik yn steat om te foldwaan oan 'e fysike netwurkbeheining fan 40Gbps, wylst se fergees CPU-boarnen hawwe.

Ik hoopje dat dit materiaal nuttich sil wêze foar netwurkingenieurs dy't besykje de prestaasjes fan har servers te ferbetterjen.

Boarne: www.habr.com

Add a comment