Schnelles Routing und NAT unter Linux

Da IPv4-Adressen immer knapper werden, sehen sich viele Telekommunikationsbetreiber mit der Notwendigkeit konfrontiert, ihren Kunden Netzwerkzugriff mithilfe von Adressübersetzung zu ermöglichen. In diesem Artikel erkläre ich Ihnen, wie Sie auf Standardservern NAT-Leistung auf Carrier-Niveau erzielen können.

Ein wenig Geschichte

Das Thema der Erschöpfung des IPv4-Adressraums ist nicht mehr neu. Irgendwann tauchten in RIPE Wartelisten auf, dann entstanden Börsen, auf denen Adressblöcke gehandelt und Verträge zu deren Vermietung abgeschlossen wurden. Nach und nach begannen Telekommunikationsbetreiber, Internetzugangsdienste mithilfe der Adress- und Portübersetzung bereitzustellen. Einige schafften es nicht, genügend Adressen zu erhalten, um jedem Abonnenten eine „weiße“ Adresse zuzuteilen, während andere begannen, Geld zu sparen, indem sie sich weigerten, Adressen auf dem Sekundärmarkt zu kaufen. Hersteller von Netzwerkgeräten unterstützten diese Idee, weil Für diese Funktionalität sind in der Regel zusätzliche Erweiterungsmodule oder Lizenzen erforderlich. Beispielsweise können Sie in der MX-Router-Reihe von Juniper (mit Ausnahme der neuesten MX104 und MX204) NAPT auf einer separaten MS-MIC-Servicekarte durchführen, Cisco ASR1k erfordert eine CGN-Lizenz, Cisco ASR9k erfordert ein separates A9K-ISM-100-Modul und eine A9K-CGN-Lizenz -LIC für ihn. Generell kostet das Vergnügen viel Geld.

IPTabellen

Für die Durchführung von NAT sind keine speziellen Rechenressourcen erforderlich; sie kann durch Allzweckprozessoren gelöst werden, die beispielsweise in jedem Heimrouter installiert sind. Auf der Ebene eines Telekommunikationsbetreibers kann dieses Problem mithilfe von Standardservern gelöst werden, auf denen FreeBSD (ipfw/pf) oder GNU/Linux (iptables) ausgeführt wird. Wir werden FreeBSD nicht in Betracht ziehen, weil... Ich habe dieses Betriebssystem schon vor langer Zeit nicht mehr verwendet, daher bleiben wir bei GNU/Linux.

Die Aktivierung der Adressübersetzung ist überhaupt nicht schwierig. Zuerst müssen Sie eine Regel in iptables in der Nat-Tabelle registrieren:

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. Hier gibt es mehrere Feinheiten. Erstens ist es notwendig, die Zeitüberschreitungen anzupassen, da es sich um NAT im Maßstab eines Telekommunikationsbetreibers handelt, da die Größe der Übersetzungstabelle bei Standardwerten schnell auf katastrophale Werte anwächst. Nachfolgend 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

Außerdem muss die Anzahl der Buckets für die Hash-Tabelle, in der alle Broadcasts gespeichert werden, erhöht werden (dies ist eine Option im Modul nf_conntrack):

options nf_conntrack hashsize=1572864

Nach diesen einfachen Manipulationen erhält man ein vollständig funktionierendes Design, das eine große Anzahl von Client-Adressen in einen Pool externer Adressen übersetzen kann. Die Leistung dieser Lösung lässt jedoch zu wünschen übrig. Bei meinen ersten Versuchen, GNU/Linux für NAT zu verwenden (ca. 2013), konnte ich eine Leistung von etwa 7 Gbit/s bei 0.8 Mpps pro Server (Xeon E5-1650v2) erreichen. Seitdem wurden viele verschiedene Optimierungen im Netzwerkstack des GNU/Linux-Kernels vorgenommen, die Leistung eines Servers auf derselben Hardware ist auf fast 18–19 Gbit/s bei 1.8–1.9 Mpps gestiegen (das waren die Maximalwerte). , aber die Nachfrage nach Verkehrsvolumen, das von einem Server verarbeitet wird, wuchs viel schneller. Infolgedessen wurden Schemata entwickelt, um die Last auf verschiedenen Servern auszugleichen. Dies alles erhöhte jedoch die Komplexität der Einrichtung, Aufrechterhaltung und Aufrechterhaltung der Qualität der bereitgestellten Dienste.

NTFables

Heutzutage ist der Einsatz von DPDK und XDP ein modischer Trend bei Software-Umzügen. Zu diesem Thema wurden viele Artikel geschrieben, viele verschiedene Reden gehalten und es erscheinen kommerzielle Produkte (z. B. SKAT von VasExperts). Angesichts der begrenzten Programmierressourcen der Telekommunikationsbetreiber ist es jedoch ziemlich problematisch, selbst ein auf diesen Frameworks basierendes „Produkt“ zu erstellen. Der Betrieb einer solchen Lösung wird in Zukunft deutlich schwieriger, insbesondere müssen Diagnosetools entwickelt werden. Beispielsweise funktioniert Standard-tcpdump mit DPDK nicht einfach so und es „sieht“ keine Pakete, die über XDP an die Leitungen zurückgesendet werden. Bei all dem Gerede über neue Technologien zur Paketweiterleitung in den User-Space blieben sie unbemerkt Berichte и Artikel Pablo Neira Ayuso, iptables-Betreuer, über die Entwicklung des Flow Offloading in nftables. Schauen wir uns diesen Mechanismus genauer an.

Die Hauptidee besteht darin, dass, wenn der Router Pakete aus einer Sitzung in beide Flussrichtungen weitergeleitet hat (die TCP-Sitzung ging in den Status ESTABLISHED), dann keine Notwendigkeit besteht, nachfolgende Pakete dieser Sitzung durch alle Firewall-Regeln zu leiten, weil Alle diese Überprüfungen enden dennoch mit der Weiterleitung des Pakets an das Routing. Und wir müssen eigentlich keine Route auswählen – wir wissen bereits, an welche Schnittstelle und an welchen Host wir Pakete innerhalb dieser Sitzung senden müssen. Es bleibt nur noch, diese Informationen zu speichern und in einem frühen Stadium der Paketverarbeitung für das Routing zu verwenden. Bei der Durchführung von NAT ist es notwendig, zusätzlich Informationen über Änderungen der vom nf_conntrack-Modul übersetzten Adressen und Ports zu speichern. Ja, natürlich funktionieren in diesem Fall verschiedene Policer und andere Informations- und Statistikregeln in iptables nicht mehr, aber im Rahmen der Aufgabe eines separaten stehenden NAT oder beispielsweise einer Grenze ist dies aufgrund der Dienste nicht so wichtig werden auf alle Geräte verteilt.

Konfiguration

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

  • Verwenden Sie einen frischen Kern. Obwohl die Funktionalität selbst in Kernel 4.16 erschien, war sie lange Zeit sehr „roh“ und verursachte regelmäßig Kernel-Panik. Alles stabilisierte sich etwa im Dezember 2019, als die LTS-Kernel 4.19.90 und 5.4.5 veröffentlicht wurden.
  • Schreiben Sie die iptables-Regeln im nftables-Format mit einer relativ aktuellen Version von nftables um. Funktioniert genau in Version 0.9.0

Wenn mit dem ersten Punkt grundsätzlich alles klar ist, es vor allem nicht zu vergessen ist, das Modul beim Zusammenbau in die Konfiguration einzubinden (CONFIG_NFT_FLOW_OFFLOAD=m), dann bedarf der zweite Punkt einer Erklärung. nftables-Regeln werden völlig anders beschrieben als in iptables. Dokumentation verrät fast alle Punkte, es gibt auch Besonderheiten Konverter Regeln von iptables bis nftables. Daher werde ich nur ein Beispiel für die Einrichtung von NAT und Flow Offload geben. Eine kleine Legende zum Beispiel: , - Dies sind die Netzwerkschnittstellen, über die der Datenverkehr läuft; in Wirklichkeit kann es mehr als zwei davon geben. , — die Start- und Endadresse des Bereichs der „weißen“ 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
        }
}

Beim Flow Offload ist es etwas komplizierter, aber durchaus 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 der gesamte Aufbau. Jetzt fällt der gesamte TCP/UDP-Verkehr in die Fastnat-Tabelle und wird viel schneller verarbeitet.

Ergebnisse

Um zu verdeutlichen, wie „viel schneller“ das ist, füge ich einen Screenshot der Auslastung auf zwei realen Servern bei, mit der gleichen Hardware (Xeon E5-1650v2), identisch konfiguriert, mit dem gleichen Linux-Kernel, aber mit NAT in iptables (NAT4) und in nftables (NAT5).

Schnelles Routing und NAT unter Linux

Im Screenshot gibt es kein Diagramm der Pakete pro Sekunde, aber im Lastprofil dieser Server liegt die durchschnittliche Paketgröße bei etwa 800 Byte, sodass die Werte bis zu 1.5 Mpps erreichen. Wie Sie sehen, verfügt der Server mit nftables über eine enorme Leistungsreserve. Derzeit verarbeitet dieser Server bis zu 30 Gbit/s bei 3 Mpps und ist eindeutig in der Lage, die physische Netzwerkbeschränkung von 40 Gbit/s zu erfüllen und gleichzeitig über freie CPU-Ressourcen zu verfügen.

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

Source: habr.com

Kommentar hinzufügen