Enrutamento rápido e NAT en Linux

A medida que se esgotan os enderezos IPv4, moitos operadores de telecomunicacións enfróntanse á necesidade de proporcionar aos seus clientes acceso á rede mediante a tradución de enderezos. Neste artigo vouche dicir como podes obter o rendemento de Carrier Grade NAT nos servidores de produtos básicos.

Un pouco de historia

O tema do esgotamento do espazo de enderezos IPv4 xa non é novo. Nalgún momento, apareceron listas de espera en RIPE, despois xurdiron intercambios nos que se negociaban bloques de enderezos e concluíronse acordos para arrendalos. Aos poucos, os operadores de telecomunicacións comezaron a ofrecer servizos de acceso a Internet mediante a tradución de enderezos e portos. Algúns non lograron obter enderezos suficientes para emitir un enderezo "branco" a cada abonado, mentres que outros comezaron a aforrar diñeiro ao negarse a comprar enderezos no mercado secundario. Os fabricantes de equipos de rede apoiaron esta idea, porque esta funcionalidade require normalmente módulos de extensión ou licenzas adicionais. Por exemplo, na liña de enrutadores MX de Juniper (excepto os últimos MX104 e MX204), pode realizar NAPT nunha tarxeta de servizo MS-MIC separada, Cisco ASR1k require unha licenza CGN, Cisco ASR9k require un módulo A9K-ISM-100 separado. e unha licenza A9K-CGN -LIC para el. En xeral, o pracer custa moito diñeiro.

Táboas IP

A tarefa de realizar NAT non require recursos informáticos especializados; pódese resolver mediante procesadores de propósito xeral, que se instalan, por exemplo, en calquera router doméstico. A escala dun operador de telecomunicacións, este problema pódese resolver utilizando servidores de mercadorías que executan FreeBSD (ipfw/pf) ou GNU/Linux (iptables). Non imos considerar FreeBSD, porque... Deixei de usar este sistema operativo hai moito tempo, así que seguiremos GNU/Linux.

Activar a tradución de enderezos non é nada difícil. Primeiro cómpre rexistrar unha regra en iptables na táboa nat:

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

O sistema operativo cargará o módulo nf_conntrack, que supervisará todas as conexións activas e realizará as conversións necesarias. Aquí hai varias sutilezas. En primeiro lugar, xa que estamos a falar de NAT a escala dun operador de telecomunicacións, é necesario axustar os tempos de espera, porque cos valores predeterminados o tamaño da táboa de tradución crecerá rapidamente ata alcanzar valores catastróficos. A continuación móstrase un exemplo da configuración que usei nos meus servidores:

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

E en segundo lugar, dado que o tamaño predeterminado da táboa de tradución non está deseñado para funcionar nas condicións dun operador de telecomunicacións, cómpre aumentar:

net.netfilter.nf_conntrack_max = 3145728

Tamén é necesario aumentar o número de depósitos para a táboa hash que almacena todas as emisións (esta é unha opción no módulo nf_conntrack):

options nf_conntrack hashsize=1572864

Despois destas sinxelas manipulacións, obtense un deseño completamente funcional que pode traducir un gran número de enderezos de clientes nun conxunto de externos. Non obstante, o rendemento desta solución deixa moito que desexar. Nos meus primeiros intentos de usar GNU/Linux para NAT (alredor de 2013), puiden obter un rendemento duns 7 Gbit/s a 0.8 Mpps por servidor (Xeon E5-1650v2). Desde ese momento, fixéronse moitas optimizacións diferentes na pila de rede do núcleo GNU/Linux, o rendemento dun servidor no mesmo hardware aumentou ata case 18-19 Gbit/s a 1.8-1.9 Mpps (estes eran os valores máximos) , pero a demanda de volume de tráfico procesado por un servidor creceu moito máis rápido. Como resultado, desenvolvéronse esquemas para equilibrar a carga en diferentes servidores, pero todo iso aumentou a complexidade de configurar, manter e manter a calidade dos servizos prestados.

NTFables

Hoxe en día, unha tendencia de moda nas "bolsas de cambio" de software é o uso de DPDK e XDP. Escribíronse moitos artigos sobre este tema, fixéronse moitos discursos diferentes e aparecen produtos comerciais (por exemplo, SKAT de VasExperts). Pero dados os limitados recursos de programación dos operadores de telecomunicacións, é bastante problemático crear calquera "produto" baseado nestes marcos por conta propia. Será moito máis difícil operar con tal solución no futuro; en particular, haberá que desenvolver ferramentas de diagnóstico. Por exemplo, tcpdump estándar con DPDK non funcionará así e non "verrá" os paquetes enviados de volta aos cables usando XDP. No medio de toda a conversación sobre novas tecnoloxías para a saída de paquetes ao espazo do usuario, pasaron desapercibidos informes и Artigo Pablo Neira Ayuso, mantedor de iptables, sobre o desenvolvemento da descarga de fluxo en nftables. Vexamos este mecanismo con máis detalle.

A idea principal é que se o enrutador pasou paquetes dunha sesión en ambas direccións do fluxo (a sesión TCP pasou ao estado ESTABLISHED), entón non hai necesidade de pasar os paquetes posteriores desta sesión a través de todas as regras do firewall, porque todas estas comprobacións aínda rematarán co paquete trasladado ao enrutamento. E en realidade non necesitamos seleccionar unha ruta: xa sabemos a que interface e a que host necesitamos enviar paquetes nesta sesión. Todo o que queda é almacenar esta información e usala para o enrutamento nunha fase inicial do procesamento de paquetes. Ao realizar NAT, é necesario almacenar adicionalmente información sobre os cambios de enderezos e portos traducidos polo módulo nf_conntrack. Si, por suposto, neste caso varios policías e outras normas de información e estatísticas en iptables deixan de funcionar, pero no marco da tarefa dunha NAT separada ou, por exemplo, dunha fronteira, isto non é tan importante, porque os servizos distribúense entre dispositivos.

Configuración

Para usar esta función necesitamos:

  • Use un núcleo novo. A pesar de que a propia funcionalidade apareceu no núcleo 4.16, durante bastante tempo foi moi "cru" e causaba pánico no núcleo. Todo se estabilizou en decembro de 2019, cando se lanzaron os núcleos LTS 4.19.90 e 5.4.5.
  • Reescriba as regras de iptables en formato nftables usando unha versión bastante recente de nftables. Funciona exactamente na versión 0.9.0

Se todo está claro en principio co primeiro punto, o principal é non esquecer incluír o módulo na configuración durante a montaxe (CONFIG_NFT_FLOW_OFFLOAD=m), entón o segundo punto require unha explicación. As regras de nftables descríbense de forma completamente diferente que en iptables. Documentación revela case todos os puntos, tamén os hai especiais conversores regras de iptables a nftables. Polo tanto, só darei un exemplo de configuración de NAT e descarga de fluxo. Unha pequena lenda, por exemplo: , - Estas son as interfaces de rede polas que pasa o tráfico; en realidade pode haber máis de dúas delas. , — o enderezo inicial e final do intervalo de enderezos "brancos".

A configuración do NAT é moi sinxela:

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

Coa descarga de fluxo é un pouco máis complicado, pero bastante comprensible:

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

Esa é, de feito, toda a configuración. Agora todo o tráfico TCP/UDP caerá na táboa fastnat e procesarase moito máis rápido.

Descubrimentos

Para que quede claro o "máis rápido" que é isto, anexarei unha captura de pantalla da carga en dous servidores reais, co mesmo hardware (Xeon E5-1650v2), configurado de forma idéntica, usando o mesmo núcleo de Linux, pero realizando NAT en iptables. (NAT4) e en nftables (NAT5).

Enrutamento rápido e NAT en Linux

Non hai un gráfico de paquetes por segundo na captura de pantalla, pero no perfil de carga destes servidores o tamaño medio do paquete rolda os 800 bytes, polo que os valores chegan a 1.5 Mpps. Como podes ver, o servidor con nftables ten unha enorme reserva de rendemento. Actualmente, este servidor procesa ata 30 Gbit/s a 3 Mpps e é claramente capaz de cumprir a limitación física da rede de 40 Gbps, ao tempo que ten recursos de CPU gratuítos.

Espero que este material sexa útil para os enxeñeiros de rede que intenten mellorar o rendemento dos seus servidores.

Fonte: www.habr.com

Engadir un comentario