Routage rapide et NAT sous Linux

Les adresses IPv4 étant épuisées, de nombreux opérateurs de télécommunications sont confrontés à la nécessité d'organiser l'accès de leurs clients au réseau à l'aide de la traduction d'adresses. Dans cet article, je vais vous expliquer comment obtenir des performances de niveau NAT de niveau opérateur sur les serveurs de base.

Un peu d'histoire


Le sujet de manquer d'espace d'adressage IPv4 n'est plus nouveau. À un moment donné, des listes d'attente sont apparues dans RIPE, puis il y a eu des échanges sur lesquels ils ont échangé des blocs d'adresses et conclu des transactions pour leur loyer. Progressivement, les opérateurs télécoms ont commencé à fournir des services d'accès à Internet par la traduction d'adresses et de ports. Quelqu'un n'a pas réussi à obtenir suffisamment d'adresses pour donner une adresse «blanche» à chaque abonné, tandis que quelqu'un a commencé à économiser de l'argent en refusant d'acheter des adresses sur le marché secondaire. Les fabricants d’équipements de réseau ont soutenu cette idée, cette fonctionnalité nécessite généralement des modules d'extension ou des licences supplémentaires. Par exemple, avec Juniper dans la gamme de routeurs MX (à l'exception des derniers MX104 et MX204), NAPT peut être exécuté sur une carte de service MS-MIC distincte, Cisco ASR1k nécessite une licence GN,sur Cisco ASR9k, un module A9K-ISM-100 distinct et une licence A9K-CGN-LIC. En général, le plaisir coûte cher.

Iptables


La tâche d'effectuer NAT ne nécessite pas de ressources informatiques spécialisées; les processeurs à usage général installés, par exemple, dans n'importe quel routeur domestique, peuvent le résoudre. À l'échelle du transporteur, ce problème peut être résolu en utilisant des serveurs de base exécutant FreeBSD (ipfw / pf) ou GNU / Linux (iptables). Nous ne considérerons pas FreeBSD, car J'ai refusé d'utiliser ce système d'exploitation pendant longtemps, alors concentrons-nous sur GNU / Linux.

Activer la traduction d'adresse n'est pas du tout difficile. Vous devez d'abord écrire la règle dans iptables dans la table nat:

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

Le système d'exploitation chargera le module nf_conntrack, qui surveillera toutes les connexions actives et effectuera les conversions nécessaires. Il existe plusieurs subtilités. Tout d'abord, étant donné que nous parlons de NAT à l'échelle du transporteur, il est nécessaire de resserrer les délais d'attente, car avec les valeurs par défaut, la taille de la table de traduction passera rapidement à des valeurs catastrophiques. Voici un exemple des paramètres que j'ai utilisés sur mes serveurs:

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

Et d'autre part, comme la taille par défaut de la table de traduction n'est pas conçue pour fonctionner dans les conditions d'un opérateur télécom, elle doit être augmentée:

net.netfilter.nf_conntrack_max = 3145728

Il est également nécessaire d'augmenter le nombre de compartiments pour une table de hachage qui stocke toutes les traductions (c'est une option du module nf_conntrack):

options nf_conntrack hashsize=1572864

Après ces manipulations simples, une construction entièrement fonctionnelle est obtenue, qui peut traduire un grand nombre d'adresses client en un pool externe. Cependant, les performances de cette solution sont médiocres. Lors de mes premières tentatives d'utilisation de GNU / Linux pour NAT (vers 2013), j'ai pu obtenir des performances d'environ 7 Gbit / s à 0,8 Mpps par serveur (Xeon E5-1650v2). Depuis ce temps, de nombreuses optimisations différentes ont été faites dans la pile réseau du noyau GNU / Linux, les performances d'un serveur sur le même matériel ont augmenté de près de 18 à 19 Gbit / s à 1,8-1,9 Mpps (ce sont les valeurs limites), mais le besoin de volume de trafic, traité par un seul serveur, a augmenté beaucoup plus rapidement. En conséquence, des schémas d'équilibrage de charge pour différents serveurs ont été développés, mais tout cela a accru la complexité de la configuration,entretenir et maintenir la qualité des services fournis.

Nftables


De nos jours, l'utilisation de DPDK et XDP est une direction à la mode dans le «transfert de paquets» logiciel. De nombreux articles ont été écrits sur ce sujet, de nombreuses présentations ont été faites, des produits commerciaux apparaissent (par exemple, SKAT de VasExperts). Mais dans les conditions de ressources limitées des programmeurs des opérateurs de télécommunications, il est assez problématique de couper une sorte de «part» sur la base de ces cadres. Faire fonctionner une telle solution à l'avenir sera beaucoup plus difficile, en particulier, il sera nécessaire de développer des outils de diagnostic. Par exemple, un tcpdump standard avec DPDK ne fonctionne tout simplement pas, et il ne "verra" pas les paquets renvoyés aux câbles à l'aide de XDP. Au milieu de toutes les discussions sur les nouvelles technologies de sortie du transfert de paquets vers l'espace utilisateur, les rapports et les articles sont passés inaperçusPablo Neira Ayuso, mainteneur iptables, sur le développement du délestage de flux dans nftables. Examinons ce mécanisme plus en détail.

L'idée principale est que si le routeur a transmis les paquets d'une session des deux côtés du flux (la session TCP est passée à l'état ESTABLISHED), il n'est pas nécessaire de passer les paquets suivants de cette session à travers toutes les règles de pare-feu, car toutes ces vérifications aboutiront toutes à la même fin en transférant le paquet vers le routage. Oui, et en fait, le choix de la route n'a pas besoin d'être effectué - nous savons déjà quelle interface et quel hôte doivent transmettre les paquets au cours de cette session. Il ne reste plus qu'à sauvegarder ces informations et à les utiliser pour le routage à un stade précoce du traitement des paquets. Lors de l'exécution du NAT, il est également nécessaire d'enregistrer des informations sur les changements d'adresses et de ports convertis par le module nf_conntrack. Oui, bien sûr, dans ce cas, divers polysers et autres règles d'information-statistique dans iptables cessent de fonctionner,mais dans le cadre de la tâche d'un NAT permanent séparé ou, par exemple, d'une frontière, ce n'est pas si important, car les services sont répartis sur plusieurs appareils.

Configuration


Pour utiliser cette fonction, nous avons besoin de:

  • Utilisez un noyau frais. Malgré le fait que la fonctionnalité elle-même soit apparue dans le noyau 4.16, pendant un certain temps, elle était très "brute" et régulièrement appelée panique du noyau. Tout s'est stabilisé vers décembre 2019, lorsque les noyaux LTS 4.19.90 et 5.4.5 ont été publiés.
  • Réécrivez les règles iptables au format nftables en utilisant une version assez récente de nftables. Fonctionne bien dans la version 0.9.0

Si tout est clair en principe avec le premier paragraphe, l'essentiel est de ne pas oublier d'inclure le module dans la configuration lors du montage (CONFIG_NFT_FLOW_OFFLOAD = m), alors le deuxième paragraphe nécessite une explication. Les règles de nftables sont décrites différemment de celles d'iptables. La documentation révèle presque tous les points, il existe également des convertisseurs de règles spéciaux d'iptables en nftables. Par conséquent, je ne donnerai qu'un exemple de configuration de NAT et de déchargement de flux. Une petite légende pour un exemple: <i_if>, <o_if> sont les interfaces réseau à travers lesquelles le trafic passe, en réalité il peut y en avoir plus de deux. <pool_addr_start>, <pool_addr_end> - l'adresse de début et de fin de la plage d'adresses "blanches".

La configuration NAT est très simple:

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

Le déchargement de flux est un peu plus compliqué, mais compréhensible:
#! /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;
        }
}

En fait, c'est toute la configuration. Maintenant, tout le trafic TCP / UDP ira à la table fastnat et sera traité beaucoup plus rapidement.

résultats


Pour préciser à quel point cela est «beaucoup plus rapide», je vais joindre une capture d'écran de la charge sur deux serveurs réels avec le même matériel (Xeon E5-1650v2), également configurés, utilisant le même noyau Linux, mais exécutant NAT dans iptables (NAT4) et dans nftables (NAT5).



Il n'y a pas de graphique de paquets par seconde dans la capture d'écran, mais dans le profil de charge de ces serveurs, la taille moyenne des paquets est d'environ 800 octets, donc les valeurs vont jusqu'à 1,5 Mpps. Comme vous pouvez le voir, la marge de performance du serveur avec nftables est énorme. Actuellement, ce serveur traite jusqu'à 30 Gbit / s à 3 Mpps et est clairement capable de fonctionner dans la limitation physique du réseau à 40 Gbit / s, tout en disposant de ressources CPU gratuites.

J'espère que ce matériel sera utile aux ingénieurs réseau qui tentent d'améliorer les performances de leurs serveurs.

All Articles