Schnelles Routing und NAT unter Linux

Da die IPv4-Adressen erschöpft sind, müssen viele Telekommunikationsbetreiber den Zugriff ihrer Kunden auf das Netzwerk mithilfe der Adressübersetzung organisieren. In diesem Artikel werde ich Ihnen erklären, wie Sie die Leistung auf Carrier Grade NAT-Ebene auf Commodity-Servern erzielen.

Ein bisschen Geschichte


Das Thema, dass der IPv4-Adressraum knapp wird, ist nicht mehr neu. Irgendwann erschienen Wartelisten in RIPE, dann gab es Börsen, an denen sie Adressblöcke tauschten und Transaktionen für ihre Miete abschlossen. Allmählich begannen Telekommunikationsbetreiber, Internetzugangsdienste durch die Übersetzung von Adressen und Ports bereitzustellen. Jemand hat es nicht geschafft, genügend Adressen zu erhalten, um jedem Abonnenten eine „weiße“ Adresse zu geben, während jemand Geld gespart hat, indem er sich geweigert hat, Adressen auf dem Sekundärmarkt zu kaufen. Hersteller von Netzwerkgeräten unterstützten diese Idee als Diese Funktionalität erfordert normalerweise zusätzliche Erweiterungsmodule oder Lizenzen. Mit Juniper in der MX-Router-Reihe (mit Ausnahme der neuesten MX104 und MX204) kann NAPT beispielsweise auf einer separaten MS-MIC-Servicekarte ausgeführt werden. Cisco ASR1k benötigt eine NGN-Lizenz.auf Cisco ASR9k ein separates A9K-ISM-100-Modul und eine A9K-CGN-LIC-Lizenz dafür. Vergnügen kostet im Allgemeinen viel Geld.

Iptables


Für die Ausführung von NAT sind keine speziellen Computerressourcen erforderlich. Allzweckprozessoren, die beispielsweise in einem Heimrouter installiert sind, können dieses Problem lösen. Auf Carrier-Ebene kann dieses Problem mit Commodity-Servern gelöst werden, auf denen FreeBSD (ipfw / pf) oder GNU / Linux (iptables) ausgeführt werden. Wir werden FreeBSD nicht berücksichtigen, weil Ich habe mich lange geweigert, dieses Betriebssystem zu verwenden, also konzentrieren wir uns auf GNU / Linux.

Das Einschalten der Adressübersetzung ist überhaupt nicht schwierig. Zuerst müssen Sie die Regel in iptables in die nat-Tabelle schreiben:

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

Das Betriebssystem lädt das Modul nf_conntrack, das alle aktiven Verbindungen überwacht und die erforderlichen Konvertierungen durchführt. Es gibt mehrere Feinheiten. Erstens, da es sich um NAT auf der Skala des Trägers handelt, müssen die Zeitüberschreitungen verschärft werden, da mit den Standardwerten die Größe der Übersetzungstabelle schnell auf katastrophale Werte anwächst. Unten finden Sie ein Beispiel für die Einstellungen, die ich auf meinen Servern verwendet habe:

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

Und zweitens muss die Standardgröße der Übersetzungstabelle erhöht werden, da sie nicht für die Bedingungen eines Telekommunikationsbetreibers ausgelegt ist:

net.netfilter.nf_conntrack_max = 3145728

Es ist auch erforderlich, die Anzahl der Buckets für eine Hash-Tabelle zu erhöhen, in der alle Übersetzungen gespeichert sind (dies ist eine Option des Moduls nf_conntrack):

options nf_conntrack hashsize=1572864

Nach diesen einfachen Manipulationen wird eine vollständig funktionierende Konstruktion erhalten, die eine große Anzahl von Clientadressen in einen externen Pool übersetzen kann. Die Leistung dieser Lösung ist jedoch schlecht. Bei meinen ersten Versuchen, GNU / Linux für NAT zu verwenden (um 2013), konnte ich eine Leistung von etwa 7 Gbit / s bei 0,8 Mpps pro Server (Xeon E5-1650v2) erzielen. Seitdem wurden viele verschiedene Optimierungen im GNU / Linux-Kernel-Netzwerkstapel vorgenommen. Die Leistung eines Servers auf derselben Hardware ist mit 1,8 bis 1,9 Mpps (dies waren die Grenzwerte) auf 18 bis 19 Gbit / s gestiegen. von einem einzigen Server verarbeitet, wuchs viel schneller. Infolgedessen wurden Lastausgleichsschemata für verschiedene Server entwickelt, was jedoch die Komplexität des Setups erhöhte.Wartung und Aufrechterhaltung der Qualität der erbrachten Dienstleistungen.

Nftables


Heutzutage ist die Verwendung von DPDK und XDP eine modische Richtung bei der "Paketübertragung" von Software. Es wurden viele Artikel zu diesem Thema geschrieben, viele verschiedene Präsentationen wurden gemacht, kommerzielle Produkte erscheinen (zum Beispiel SKAT von VasExperts). Unter den Bedingungen begrenzter Ressourcen von Programmierern von Telekommunikationsbetreibern ist es jedoch ziemlich problematisch, auf der Grundlage dieser Rahmenbedingungen eine Art „Anteil“ zu kürzen. Eine solche Lösung in Zukunft zu betreiben, wird viel schwieriger sein, insbesondere wird es notwendig sein, Diagnosewerkzeuge zu entwickeln. Beispielsweise funktioniert ein normaler tcpdump mit DPDK einfach nicht und sieht keine Pakete, die mit XDP an die Kabel zurückgesendet werden. Bei all dem Gerede über neue Technologien für die Ausgabe der Paketweiterleitung an den Benutzerraum blieben Berichte und Artikel unbemerktPablo Neira Ayuso, Iptables-Betreuer, über die Entwicklung von Flow-Offloading in NFTables. Schauen wir uns diesen Mechanismus genauer an.

Die Hauptidee ist, dass, wenn der Router Pakete einer Sitzung auf beiden Seiten des Streams übergeben hat (die TCP-Sitzung wurde in den Status ESTABLISHED geschaltet), nachfolgende Pakete dieser Sitzung nicht durch alle Firewall-Regeln geleitet werden müssen, weil Alle diese Überprüfungen enden alle gleich, indem das Paket weiter zum Routing übertragen wird. Ja, und tatsächlich muss die Auswahl der Route nicht durchgeführt werden. Wir wissen bereits, welche Schnittstelle und welcher Host die Pakete innerhalb dieser Sitzung weiterleiten soll. Es bleibt nur, diese Informationen zu speichern und für das Routing in einem frühen Stadium der Paketverarbeitung zu verwenden. Bei der Ausführung von NAT müssen zusätzlich Informationen zu Änderungen an Adressen und Ports gespeichert werden, die vom Modul nf_conntrack konvertiert wurden. Ja, in diesem Fall funktionieren natürlich verschiedene Polyser und andere informationsstatistische Regeln in iptables nicht mehr.Im Rahmen der Aufgabe eines separaten stehenden NAT oder beispielsweise einer Grenze ist dies jedoch nicht so wichtig, da die Dienste auf mehrere Geräte verteilt sind.

Aufbau


Um diese Funktion nutzen zu können, benötigen wir:

  • Verwenden Sie einen frischen Kernel. Trotz der Tatsache, dass die Funktionalität selbst im 4.16-Kernel erschien, war sie eine ganze Weile sehr "roh" und wurde regelmäßig als Kernel-Panik bezeichnet. Alles stabilisierte sich um Dezember 2019, als die LTS-Kernel 4.19.90 und 5.4.5 veröffentlicht wurden.
  • Schreiben Sie iptables-Regeln im nftables-Format neu, indem Sie eine relativ neue Version von nftables verwenden. Funktioniert gut in Version 0.9.0

Wenn mit dem ersten Absatz im Prinzip alles klar ist, ist es wichtig, das Modul während der Montage nicht in die Konfiguration einzubeziehen (CONFIG_NFT_FLOW_OFFLOAD = m), dann muss der zweite Absatz erläutert werden. Die nftables-Regeln werden ganz anders beschrieben als in iptables. Die Dokumentation zeigt fast alle Punkte, gibt es auch spezielle Regel Konvertern von iptables zu nftables. Daher werde ich nur ein Beispiel für die Einrichtung von NAT und Flow Offload geben. Eine kleine Legende für ein Beispiel: <i_if>, <o_if> sind die Netzwerkschnittstellen, über die der Datenverkehr geleitet wird. In Wirklichkeit kann es mehr als zwei geben. <pool_addr_start>, <pool_addr_end> - die Start- und Endadresse des Bereichs "weißer" Adressen.

Die NAT-Konfiguration ist sehr einfach:

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

Flow Offload ist etwas komplizierter, aber verständlich:
#! /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;
        }
}

Das ist in der Tat das ganze Setup. Jetzt wird der gesamte TCP / UDP-Verkehr in die Fastnat-Tabelle verschoben und viel schneller verarbeitet.

Ergebnisse


Um zu verdeutlichen, wie „viel schneller“ dies ist, werde ich einen Screenshot der Last auf zwei realen Servern mit derselben Hardware (Xeon E5-1650v2) anhängen, die gleichermaßen konfiguriert sind, denselben Linux-Kernel verwenden, aber NAT in iptables (NAT4) und in ausführen nftables (NAT5).



Der Screenshot enthält kein Paketdiagramm pro Sekunde, aber im Lastprofil dieser Server beträgt die durchschnittliche Paketgröße etwa 800 Byte, sodass die Werte bis zu 1,5 Mpps betragen. Wie Sie sehen können, ist die Leistungsspanne des Servers mit nftables enorm. Derzeit verarbeitet dieser Server bis zu 30 Gbit / s bei 3 Mpps und ist eindeutig in der Lage, auf die physische Einschränkung des 40 Gbit / s-Netzwerks zu stoßen, während er über freie CPU-Ressourcen verfügt.

Ich hoffe, dass dieses Material für Netzwerktechniker nützlich ist, die versuchen, die Leistung ihrer Server zu verbessern.

All Articles