Vinnige roetering en NAT in Linux

Soos IPv4-adresse uitgeput raak, word baie telekommunikasie-operateurs gekonfronteer met die behoefte om hul kliënte van netwerktoegang te voorsien met behulp van adresvertaling. In hierdie artikel sal ek jou vertel hoe jy Carrier Grade NAT-prestasie op kommoditeitsbedieners kan kry.

'N bietjie geskiedenis

Die onderwerp van uitputting van IPv4-adresruimte is nie meer nuut nie. Op 'n stadium het waglyste in RIPE verskyn, toe het uitruilings ontstaan ​​waarop blokke adresse verhandel en transaksies aangegaan is om dit te huur. Geleidelik het telekommunikasie-operateurs internettoegangsdienste begin verskaf deur adres- en poortvertaling te gebruik. Sommige het nie daarin geslaag om genoeg adresse te kry om 'n "wit" adres aan elke intekenaar uit te reik nie, terwyl ander geld begin spaar het deur te weier om adresse op die sekondêre mark te koop. Vervaardigers van netwerktoerusting het hierdie idee ondersteun, want hierdie funksionaliteit vereis gewoonlik bykomende uitbreidingsmodules of lisensies. Byvoorbeeld, in Juniper se reeks MX-roeteerders (behalwe vir die nuutste MX104 en MX204), kan jy NAPT op 'n aparte MS-MIC-dienskaart uitvoer, Cisco ASR1k vereis 'n CGN-lisensie, Cisco ASR9k vereis 'n aparte A9K-ISM-100-module en 'n A9K-CGN lisensie -LIC aan hom. Oor die algemeen kos die plesier baie geld.

iptables

Die taak om NAT uit te voer vereis nie gespesialiseerde rekenaarhulpbronne nie; dit kan opgelos word deur algemene doelverwerkers, wat byvoorbeeld in enige tuisroeteerder geïnstalleer is. Op die skaal van 'n telekommunikasie-operateur kan hierdie probleem opgelos word deur gebruik te maak van kommoditeitsbedieners wat FreeBSD (ipfw/pf) of GNU/Linux (iptables) gebruik. Ons sal nie FreeBSD oorweeg nie, want... Ek het lankal opgehou om hierdie bedryfstelsel te gebruik, so ons sal by GNU/Linux bly.

Dit is glad nie moeilik om adresvertaling te aktiveer nie. Eerstens moet jy 'n reël in iptables in die nat tabel registreer:

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

Die bedryfstelsel sal die nf_conntrack-module laai, wat alle aktiewe verbindings sal monitor en die nodige omskakelings sal uitvoer. Hier is verskeie subtiliteite. Eerstens, aangesien ons praat oor NAT op die skaal van 'n telekommunikasie-operateur, is dit nodig om die time-outs aan te pas, want met verstekwaardes sal die grootte van die vertaaltabel vinnig groei tot katastrofiese waardes. Hieronder is 'n voorbeeld van die instellings wat ek op my bedieners gebruik het:

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 tweedens, aangesien die verstekgrootte van die vertaaltabel nie ontwerp is om onder die toestande van 'n telekommunikasie-operateur te werk nie, moet dit verhoog word:

net.netfilter.nf_conntrack_max = 3145728

Dit is ook nodig om die aantal emmers te verhoog vir die hash-tabel wat alle uitsendings stoor (dit is 'n opsie in die nf_conntrack-module):

options nf_conntrack hashsize=1572864

Na hierdie eenvoudige manipulasies word 'n volledig werkende ontwerp verkry wat 'n groot aantal kliëntadresse in 'n poel eksternes kan vertaal. Die prestasie van hierdie oplossing laat egter veel te wense oor. In my eerste pogings om GNU/Linux vir NAT te gebruik (ongeveer 2013), kon ek werkverrigting van ongeveer 7Gbit/s kry teen 0.8Mpps per bediener (Xeon E5-1650v2). Sedert daardie tyd is baie verskillende optimaliserings in die GNU/Linux-kernnetwerkstapel gemaak, die werkverrigting van een bediener op dieselfde hardeware het toegeneem tot byna 18-19 Gbit/s teen 1.8-1.9 Mpps (dit was die maksimum waardes) , maar die vraag na verkeersvolume, verwerk deur een bediener, het baie vinniger gegroei. Gevolglik is skemas ontwikkel om die las op verskillende bedieners te balanseer, maar dit alles het die kompleksiteit van die opstel, instandhouding en instandhouding van die kwaliteit van die dienste wat verskaf word, verhoog.

NFT-tabelle

Deesdae is die gebruik van DPDK en XDP 'n modieuse neiging in sagteware "verskuif sakke". Baie artikels is oor hierdie onderwerp geskryf, baie verskillende toesprake is gemaak, en kommersiële produkte verskyn (byvoorbeeld SKAT van VasExperts). Maar gegewe die beperkte programmeringshulpbronne van telekommunikasie-operateurs, is dit nogal problematies om enige "produk" op jou eie gebaseer op hierdie raamwerke te skep. Dit sal baie moeiliker wees om so 'n oplossing in die toekoms te bedryf; veral diagnostiese instrumente sal ontwikkel moet word. Byvoorbeeld, standaard tcpdump met DPDK sal nie net so werk nie, en dit sal nie pakkies "sien" wat teruggestuur word na die drade met XDP nie. Te midde van al die praatjies oor nuwe tegnologieë om pakkie-aanstuur na gebruikersruimte uit te voer, het hulle ongemerk gebly berigte и Artikel Pablo Neira Ayuso, iptables-onderhouer, oor die ontwikkeling van vloei-aflaai in nftables. Kom ons kyk na hierdie meganisme van naderby.

Die hoofgedagte is dat as die router pakkies van een sessie in beide rigtings van die vloei deurgegee het (TCP-sessie het in die GESTELDE toestand gegaan), dit nie nodig is om daaropvolgende pakkies van hierdie sessie deur alle firewall-reëls te stuur nie, want al hierdie tjeks sal steeds eindig met die pakkie wat verder na die roete oorgedra word. En ons hoef nie eintlik 'n roete te kies nie - ons weet reeds na watter koppelvlak en na watter gasheer ons pakkies moet stuur binne hierdie sessie. Al wat oorbly, is om hierdie inligting te stoor en dit te gebruik vir roetering in 'n vroeë stadium van pakkieverwerking. Wanneer NAT uitgevoer word, is dit nodig om addisioneel inligting te stoor oor veranderinge in adresse en poorte wat deur die nf_conntrack-module vertaal is. Ja, natuurlik, in hierdie geval hou verskeie polisiebeamptes en ander inligting en statistiese reëls in iptables op om te werk, maar binne die raamwerk van die taak van 'n aparte staande NAT of, byvoorbeeld, 'n grens, is dit nie so belangrik nie, want die dienste word oor toestelle versprei.

opset

Om hierdie funksie te gebruik, benodig ons:

  • Gebruik 'n vars pit. Ten spyte van die feit dat die funksionaliteit self in kern 4.16 verskyn het, was dit vir 'n lang tyd baie "rou" en het gereeld kernpaniek veroorsaak. Alles het rondom Desember 2019 gestabiliseer, toe LTS-pitte 4.19.90 en 5.4.5 vrygestel is.
  • Herskryf iptables-reëls in nftables-formaat met 'n redelik onlangse weergawe van nftables. Werk presies in weergawe 0.9.0

As alles in beginsel duidelik is met die eerste punt, is die belangrikste ding om nie te vergeet om die module in die konfigurasie tydens samestelling in te sluit nie (CONFIG_NFT_FLOW_OFFLOAD=m), dan vereis die tweede punt verduideliking. nftables-reëls word heeltemal anders beskryf as in iptables. Dokumentasie openbaar byna alle punte, daar is ook spesiale omsetters reëls van iptables tot nftables. Daarom sal ek slegs 'n voorbeeld gee van die opstel van NAT en vloei aflaai. 'n Klein legende byvoorbeeld: , - dit is die netwerk-koppelvlakke waardeur verkeer gaan; in werklikheid kan daar meer as twee van hulle wees. , — die begin- en eindadres van die reeks "wit" adresse.

NAT-konfigurasie is baie eenvoudig:

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

Met vloeiaflaai is dit 'n bietjie meer ingewikkeld, maar redelik verstaanbaar:

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

Dit is in werklikheid die hele opset. Nou sal alle TCP/UDP-verkeer in die fastnat-tabel val en baie vinniger verwerk word.

Bevindinge

Om dit duidelik te maak hoeveel "veel vinniger" dit is, sal ek 'n skermskoot van die lading op twee regte bedieners aanheg, met dieselfde hardeware (Xeon E5-1650v2), identies gekonfigureer, met dieselfde Linux-kern, maar NAT in iptables uitvoer (NAT4) en in nftables (NAT5).

Vinnige roetering en NAT in Linux

Daar is geen grafiek van pakkies per sekonde in die skermkiekie nie, maar in die lasprofiel van hierdie bedieners is die gemiddelde pakkiegrootte ongeveer 800 grepe, so die waardes bereik tot 1.5Mpps. Soos u kan sien, het die bediener met nftables 'n groot prestasiereserwe. Tans verwerk hierdie bediener tot 30Gbit/s teen 3Mpps en is dit duidelik in staat om aan die fisiese netwerkbeperking van 40Gbps te voldoen, terwyl dit gratis SVE-hulpbronne het.

Ek hoop dat hierdie materiaal nuttig sal wees vir netwerkingenieurs wat die werkverrigting van hul bedieners probeer verbeter.

Bron: will.com

Voeg 'n opmerking