CGNAT Bulk Port Allocation com DPDK

De Wiki BPF
Revisão de 22h54min de 9 de novembro de 2020 por Gondim (discussão | contribs)
Ir para navegação Ir para pesquisar

Objetivo:

Mostrar a configuração do projeto DANOS para funcionar como um CGNAT Bulk Port Allocation utilizando um hardware de baixo custo e proporcionando uma enorme economia de IPv4 público, pois trabalha com alocação de portas TCP/UDP dinamicamente e não da forma Determinística onde pré-fixamos uma quantidade de portas por assinante. Temos que ter sempre em mente que a implantação e o uso do IPv6 é importantíssimo, porque o CGNAT não irá resolver todos os problemas da Internet. O CGNAT ajudará à manter a rede funcionando enquanto o IPv6 não for 100% utilizado no Mundo. O fato do projeto DANOS utilizar o DPDK, permite que consigamos usar um equipamento mais simples para gerenciar tráfegos bem maiores em Gbps/PPS.

Diagrama:

Diagrama.png

O BNG é o responsável por gerenciar as conexões PPPoE/IPoE e no nosso artigo fará o encaminhamento de todos os pacotes do pool CGNAT 100.64.0.0/10 via PBR (Policy Based Routing) para a caixa DANOS CGNAT. O DANOS CGNAT estará conectado via iBGP com o Router Borda e fará a tradução e alocação dinâmica das portas TCP/UDP usando como exemplo de saída o prefixo 198.51.100.0/24.Clientes conectados no BNG com IPv4 público e IPv6 não devem ser encaminhados para a caixa CGNAT.

Teremos uma rede lógica 192.168.254.0/24 entre os BNGs e o DANOS CGNAT e outra rede lógica 10.69.0.8/30 entre o DANOS CGNAT e o Router Borda. Usaremos os IPs das loopbacks para fecharmos o iBGP. O iBGP está sendo fechado somente de um lado para facilitar o artigo, mas cabe à você decidir a melhor forma de implementar em seu cenário.

Também usaremos nessa configuração um bonding (LACP) de duas portas de 10GbE para entrada de dados provenientes do Router Borda e outro bonding também com duas portas de 10GbE para a saída do tráfego em direção aos BNGs.

Embora esteja no diagrama, não falaremos sobre BNG e nem o Router Borda nesse artigo e por isso deve-se estudar como fazer o PBR em seu equipamento concentrador e também a configuração do iBGP no seu router pois será muito importante para o funcionamento da nossa caixa CGNAT.

Você pode adicionar outras caixas CGNAT basta seguir a mesma lógica apresentada aqui nesse artigo.

Descritivo sobre o DANOS:

É um projeto desenvolvido pelo pessoal da AT&T, que está atualmente na versão 2009, que utiliza o Vyatta como interface de configuração. A syntax me lembra bastante a configuração de um JunOS, possui diversos recursos semelhantes como commit, commit-confirm, rollback, validate para validar uma alteração dentre outras características. Por baixo do capô temos um sistema GNU/Linux Debian 10, Linux Kernel 5.4, FRR 7.3.1 e DPDK 19.11. O projeto possui utilidade inclusive para roteamento mas nesse artigo falaremos sobre CGNAT. Embora o sistema seja um Debian, não é disponibilizado uma atualização via apt, pois poderia quebrá-lo já que este possui partes não Debian incluídas no sistema como o DPDK. A atualização pode ser feita sempre que sai uma nova ISO do DANOS, através de comandos simples e salvando sua configuração atual.

Equipamento utilizado no artigo e em produção atualmente:

- Dell PowerEdge R230 - Quad Core Intel(R) Xeon(R) CPU E3-1240 v6 @ 3.70GHz.

- 16G ram.

- 2x Intel X520-SR2.

- SSD 120Gb.

Dados estatísticos desse equipamento em produção:

Atualmente passando 24Gbps agregado com mais de 1.5Mpps. Esse sistema tem 382 IPv4 públicos, 9980 clientes utilizando e mais de 50% dos IPs públicos ainda livres no CGNAT. Como o sistema utiliza DPDK, não temos como acompanhar visualmente a utilização dos processadores pois o dataplane ocupa todos eles ou quase todos durante seu uso mas essa é uma característica dele. Por isso temos que observar o comportamento do tráfego e erros que possam aparecer nas portas da switch e perdas de pacotes. Dessa forma estamos documentando o hardware utilizado em produção e quanto está suportando para usarmos de referência futura:

Zabbix 12G.png
Htop 12G.png

Instalação do DANOS:

Não vou falar sobre a instalação do sistema porque é extremamente simples. Não tem muitas opções durante a instalação, é feita através de um simples boot com um pendrive já com a ISO nele.

O passo à passo da instalação pode ser vista aqui. Basicamente é iniciar o boot e ao final dele executar: install image e responder as perguntas. Depois disso vamos para o nosso "mão na massa".

Começando a configuração:

Bem a primeira coisa é colocarmos os IPs nas interfaces para inclusive podermos acessar remotamente via ssh e também habilitar o serviço ssh. Vou utilizar uma configuração com IPv6 para fazer meu acesso remoto à esse sistema. Se você tiver outra interface reconhecida pelo sistema, você pode configurar um IP de gerência nela também e acessar por ali. No DANOS nem todas as interfaces de rede são reconhecidas e por isso você precisa consultar essa página e checar as suportadas. Também vamos configurar o bonding antes de configurarmos os IPs:

Após se logar com o usuário e senha que escolheu na instalação, basta executar o comando abaixo e passar os sets. Lembrando que os IPs que estou utilizando você deve alterar para o seu ambiente.:

$ configure

# set interfaces bonding dp0bond0 address '2804:XXXX:XXXX:faca:192:168:255:2/64'

# set interfaces bonding dp0bond0 address 10.69.0.10/30

# set interfaces bonding dp0bond0 mode lacp

# set interfaces bonding dp0bond1 address 192.168.254.1/24

# set interfaces bonding dp0bond1 mode lacp

# set interfaces dataplane dp0p1s0f0 bond-group dp0bond0

# set interfaces dataplane dp0p1s0f1 bond-group dp0bond0

# set interfaces dataplane dp0p2s0f0 bond-group dp0bond1

# set interfaces dataplane dp0p2s0f1 bond-group dp0bond1

# set protocols static route6 '::/0' next-hop '2804:XXXX:XXXX:faca::3'

Estamos definindo 2 bondings, sendo 1 pra cada interface de rede. Não faça bonding entre portas de interfaces de rede diferentes, isso prejudica o cpu affinity. Os nomes utilizados também possuem uma certa regra de criação e que pode ser vista digitando um "?" por exemplo:

# set interfaces bonding ?

Possible Completions:

> <dpFbondN> Bonding interface name

As 5 primeiras linhas criamos os bondings, definimos o mode lacp e colocamos os IPs. As 4 últimas linhas dizemos quais interfaces de rede fazem parte desse bonding e a última linha definindo o gateway default para o meu acesso IPv6 ao sistema.

Configuração do iBGP:

Vamos definir nosso endereço de loopback para usar no nosso iBGP com o Router Borda e setar uma rota apontando pro IP da loopback do Router Borda:

# set interfaces loopback lo address 186.xxx.xxx.163/32

# set protocols static route 186.xxx.xxx.160/32 next-hop 10.69.0.9

Agora vamos definir uma policy prefix-list para o prefixo que vamos anunciar no iBGP e outra prefix-list de rota default que só aceitaremos vindo do Router Borda:

# set policy route prefix-list bloco-publico rule 5 action permit

# set policy route prefix-list bloco-publico rule 5 prefix 198.51.100.0/24

# set policy route prefix-list rota-default rule 5 action permit

# set policy route prefix-list rota-default rule 5 prefix 0.0.0.0/0

Definição do policy route-map que usaremos:

# set policy route route-map router-IN rule 5 action permit

# set policy route route-map router-IN rule 5 match ip address prefix-list rota-default

# set policy route route-map router-IN rule 10 action deny

# set policy route route-map router-OUT rule 5 action permit

# set policy route route-map router-OUT rule 5 match ip address prefix-list bloco-publico

# set policy route route-map router-OUT rule 10 action deny

O que queremos é anunciar o prefixo público 198.51.100.0/24 para o Router e só aceitar receber dele o prefixo 0.0.0.0/0 assim:

# set protocols bgp 53XXX address-family ipv4-unicast network 198.51.100.0/24

# set protocols bgp 53XXX neighbor 186.xxx.xxx.160 address-family ipv4-unicast route-map export router-OUT

# set protocols bgp 53XXX neighbor 186.xxx.xxx.160 address-family ipv4-unicast route-map import router-IN

# set protocols bgp 53XXX neighbor 186.xxx.xxx.160 remote-as 53XXX

# set protocols bgp 53XXX neighbor 186.xxx.xxx.160 update-source lo

# set protocols bgp 53XXX parameters router-id 186.xxx.xxx.163

Roteamento estático para o BNG:

Aqui definimos as rotas estáticas para o BNG no IP 192.168.254.98, conforme nosso diagrama do artigo. Também pode ser feito por exemplo com iBGP mas para simplificar o artigo, coloquei como sendo rotas estáticas.

# set protocols static route 100.64.0.0/22 next-hop 192.168.254.98

# set protocols static route 100.64.8.0/22 next-hop 192.168.254.98

# set protocols static route 100.64.12.0/22 next-hop 192.168.254.98

# set protocols static route 100.64.16.0/22 next-hop 192.168.254.98

Definindo blackholes para evitar ataques de static loop:

Fazemos isso para evitar os ataques à IPs que não estão conectados mas que existem rotas para eles. Nesse caso definimos um blackhole para cada prefixo de IPv4 público que usaremos no nosso CGNAT.

# set protocols static route 198.51.100.0/24 blackhole

Entrando na configuração do CGNAT:

Agora começaremos a configuração do nosso CGNAT. Basicamente vamos definir quem são os pools de IPs privados usados no CGNAT (100.64.0.0/10), os pools de IPv4 públicos que serão usados no NAT e a configuração propriamente dita do cgnat dentro do DANOS. Vamos começar então:

Os pools CGNAT:

# set resources group address-group AG_MATCH address 100.64.0.0/22

# set resources group address-group AG_MATCH address 100.64.8.0/22

# set resources group address-group AG_MATCH address 100.64.12.0/22

# set resources group address-group AG_MATCH address 100.64.16.0/22

O pool IPv4 público que será feito NAT de saída. Nessa parte da configuração abaixo além da definição do prefixo público que usaremos, utilizei a configuração de até 8 blocos de 512 portas tcp/udp por assinante. Fiz isso porque em meus testes muitos assinantes estouravam a configuração de até 8 blocos de 256 portas tcp/udp e quando isso ocorre o cliente tem problemas de acesso. Mesmo utilizando esse perfil de até 4096 portas tcp/udp por assinante, a economia de IPv4 público ainda assim é muito grande porque a maioria dos clientes utilizam muito menos que 1024 portas tcp/udp durante o uso da Internet. Também por boa prática setamos o início das portas em 1024 e finalizando em 65535. Essa parte precisa ser bem definida porque mudanças no dynamic-block-allocation block-size e dynamic-block-allocation max-blocks-per-subscriber requerem uma mudança grande de estratégia e por isso um reboot no sistema será necessário para efetivar essas alterações devido as sessões anteriores ainda estarem em uso.

# set service nat pool NAT_POOL1 address-allocation round-robin

# set service nat pool NAT_POOL1 address-pooling paired

# set service nat pool NAT_POOL1 entry RANGE1 ip-address prefix 198.51.100.0/24

# set service nat pool NAT_POOL1 port allocation sequential

# set service nat pool NAT_POOL1 port dynamic-block-allocation block-size 512

# set service nat pool NAT_POOL1 port dynamic-block-allocation max-blocks-per-subscriber 8

# set service nat pool NAT_POOL1 port range end 65535

# set service nat pool NAT_POOL1 port range start 1024

# set service nat pool NAT_POOL1 select event port-block-allocation

# set service nat pool NAT_POOL1 type CGNAT

Veremos agora a definição restante do nosso CGNAT. Abaixo habilitamos o log que precisaremos gerar e armazenar para futuras requisições jurídicas, criaremos uma policy para dizermos qual grupo de IPs privados usaremos no source do NAT (nesse caso AG_MATCH) e qual o pool de IPs públicos usaremos na saída (nesse caso NAT_POOL1). Também são definidos alguns timeouts:

# set service nat cgnat log event port-block-allocation

# set service nat cgnat policy POLICY match source address-group AG_MATCH

# set service nat cgnat policy POLICY priority 10

# set service nat cgnat policy POLICY translation pool NAT_POOL1

# set service nat cgnat session-timeout other established 30

# set service nat cgnat session-timeout other partially-open 20

# set service nat cgnat session-timeout tcp established 1800

# set service nat cgnat session-timeout tcp partially-open 240

# set service nat cgnat session-timeout tcp port 53 established 10

# set service nat cgnat session-timeout udp established 1800

# set service nat cgnat session-timeout udp partially-open 240

Vamos habilitar também os ALGs:

# set system alg ftp

# set system alg pptp

# set system alg rpc

# set system alg sip

# set system alg tftp

Até então só criamos as configurações do CGNAT mas ainda não dizemos em qual interface devemos aplicá-las. Devemos aplicá-las na interface de saída que liga com o Router Borda:

# set service nat cgnat interface dp0bond0 policy POLICY

Para checar se a configuração não possui erros fazemos ainda na configuração:

# validate

Se nenhum erro for exibido, podemos fazer um commit ou commit-confirm. A diferença é que o commit-confirm você passa como parâmetro um valor em minutos que o sistema esperará antes de fazer um rollback automático. Para confirmar e evitar o rollback só fazer o comando "confirm". No nosso caso aqui vamos apenas fazer o commit e um exit para sair do modo configuração:

# commit

# exit

Alguns comandos para administração do DANOS:

$ show configuration => lista a configuração do sistema em produção.

$ show configuration commands => lista a configuração do sistema em produção em formato de sets de comandos. Igual como fizemos acima. Muito bom para guardarmos também como backup.

$ show cgnat subscriber => mostra IP de CGNAT, IP público pareado, número de sessões, quantidade de blocos e portas alocadas, se houve falha pra alguém por ter estourado a quantidade máxima de blocos.Você também pode fazer um: show cgnat subscriber 100.64.0.2 e nesse caso vai mostrar apenas as informações referente à esse cliente que está usando esse IP.

Cgnat subscriber.png

$ show cgnat public => mostra informações referente aos IPs públicos usados. O mesmo ocorre se fizermos: show cgnat public 170.xxx.xxx.208, nesse caso irá mostrar apenas esse IP. Na imagem abaixo podemos observar que esse mesmo IP tem limite de 126 blocos de portas tcp/udp mas só está usando 55.

Cgnat public.png

$ show cgnat summary => mostra um sumário de valores do CGNAT. Os campos importantes são "Table full" não pode dar Yes, caso contrário precisará aumentar o "Maximum table size". "Public address mapping table" indica quantos IPs públicos temos disponíveis para o nosso CGNAT. É o somatório de todos os IPs dos prefixos que disponibilizamos, nesse meu caso abaixo são 382. "Subscriber address table" temos quantos assinantes estão usando o CGNAT. Nesse caso temos 10025.

Cgnat summary.png

$ show cgnat errors => mostra algumas estatísticas e erros.

Cgnat errors.png

Para mais comandos de administração consulte aqui.

Mais algumas configurações complementares:

Bem de nada adianta configurar este CGNAT se você não enviar esses logs para algum servidor de logs seu e/ou para alguma base de dados, onde será mais fácil fazer consultas. Nesse artigo não cobriremos o servidor de logs mas vou indicar o que usamos aqui, o Graylog. Existe uma versão free e que tem nos atendido muito bem, mas deixamos em aberto para sua escolha. Então vamos adicionar algumas coisas na nossa configuração. Entre em modo configuração e vamos aos próximos comandos:

set system host-name danos-cgnat

set system name-server 'fc00::10:20:20:20'

set system ntp server a.ntp.br

set system syslog host '[2804:XXXX:XXXX:XXXX:191:XXXX:XXXX:215]:1514' facility all level info

set system time-zone America/Sao_Paulo

Acima estamos dando nome ao host, setando um servidor de DNS, sim no meu caso aqui é esse mesmo fc00::10:20:20:20, um ntp server, estamos apontando para um servidor syslog que no nosso caso é um graylog e dele jogamos para uma base de dados MySQL. Também setamos o time-zone.