/dev/sre

Marcelo Andrade

Sysop 2 SRE

Calico, Linux e tabelas de rota

Features não documentadas vão te surpreender quando você menos espera

Marcelo Andrade

5 Minutos De Leitura

Escher stairs

Mudança no ambiente! Atualização de cada um dos 32 componentes do cluster Kubernetes. Tranquilo! O que pode dar errado?

Após a estabilização do ambiente, começamos a atualização dos servidores que atuam como balanceadores de carga de entrada para o cluster - aqueles que executam o Haproxy Ingress Controller do dev hero João Morais.

A métrica de erros começa a estourar do nada; e o melhor, em tese, não estamos recebendo nenhum erro - algo quebrou, e algo completamente desconhecido.

E agora?

Preâmbulo - rotas assimétricas

Uma coisa que comumente faz falta em equipes de desenvolvimento de software ou mesmo de infra-estrutura é entendimento adequado de como redes funcionam (e de seus detalhes de implementação nos sistemas operacionais).

Não é raro eu ter que explicar que o problema de conectividade em determinada situação é causado por rotas assimétricas e não bloqueio por firewall.

Neste caso em particular, temos Pods de sistemas em execução no cluster Kubernetes acessando aplicações por meio de suas URLs públicas. Portanto:

  • a comunicação chega aos balanceadores por suas interfaces públicas;
  • os balanceadores também fazem parte do cluster Kubernetes, portanto seu caminho de retorno ocorrerá pelas interfaces privadas;

Até aí tudo bem, fácil de entender.

O que só anos de experiência como sysadmin Linux traz é o conhecimento de que, por padrão, se a situação de cima ocorrer, uma máquina Linux irá necessariamente descartar o pacote sem qualquer tipo de informação. A Red Hat descreve isso aqui, mas vale a pena copiar porque isso é feito:

Current recommended practice in RFC3704 is to enable strict mode to prevent IP spoofing from DDos attacks. If using asymmetric routing or other complicated routing, then loose mode is recommended.

A solução ‘ruim’ é modificar este comportamento do kernel.

A solução ‘correta’ é interferir no roteamento, forçando a resposta a sair por onde veio.

Preâmbulo do preâmbulo - roteamento no Linux

Em uma máquina regular sem ‘efeitos especiais’, se você executar o comando abaixo, provavelmente vai receber o seguinte resultado:

# ip rule list 
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

Aqui vale uma observação interessante: por ‘default’, temos três tabelas definidas nas regras: ‘local’, ‘main’ e ‘default’.

Se alguém te perguntar em inglês ‘which is the default routing table used’, qual tabela você chutaria que é a ‘default’?

A resposta, é claro, a tabela main! Por que você escolheria ‘default’, ser ignóbil?

# ip route show table main
default via 172.31.48.1 dev eth0
172.31.48.0/20 dev eth0 proto kernel scope link src 172.31.56.202

Em algumas distribuições Linux, como o CoreOS/Flatcar, embora conste na tabela de ‘rules’, ela sequer é criada:

# sudo ip route show table default
Error: ipv4: FIB table does not exist.
Dump terminated

Uma nota relevante: esses nomes só são usados porque são especificados em algum lugar; tabelas de roteamento são representadas, no Kernel, por números. Este lugar é o arquivo /etc/iproute2/rt_tables:

# cat /etc/iproute2/rt_tables
#
# reserved values
#
255     local
254     main
253     default
0       unspec

Aqui você pode prestigiar um pouco da história viva do Linux: em algum ponto no passado distante, a última tabela suportada pelo kernel era necessariamente a 255, usada para ‘local’. Mas vivemos tempos modernos, e você pode escolher qualquer número agora que não seja maior que 2147483647 (2^31-1).

De volta às rotas assimétricas

Para permitir o reencaminhamento dos pacotes para sua interface de origem, eu devo criar uma tabela e colocar uma prioridade superior à tabela padrão do sistema (que é ‘main') para evitar o descarte.

Se o número 0, 253, 254 e 255 são reservados, e eu tenho até o número 2147483647 para minha tabela, que número eu escolheria?

Tabela 1, é claro. Quem precisa de tantos números?

# cat /etc/systemd/system/routingpolicy.service
[Unit]
Description=Configure routes
After=network-online.target
Requires=network-online.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=-/usr/bin/ip route add default via 10.0.0.1 dev ens256 tab 1
ExecStart=-/usr/bin/ip route add 10.0.0.1/8 dev ens256 tab 1
ExecStart=-/usr/bin/ip rule add from 10.0.0.69/32 tab 1 priority 100

A configuração acima resolve meu problema de rota assimétrica, alterando as regras da seguinte maneira:

# ip rule list 
0:      from all lookup local
100:    from 10.0.0.69 lookup 1
32766:  from all lookup main
32767:  from all lookup default

O que chegar pela Interface com IP 10.0.0.69, ele segue a tabela de rotas 1.

Esta é a tabela de rota 1, criada pela configuração da unit de systemd acima:

# ip route show table 1
default via 10.0.0.1 dev ens256
10.0.0.0/8 dev ens256 scope link

Diagnóstico

Não foi um ‘senhor’ processo de diagnóstico; sabia-se que algum dos componentes estava interferindo. A lógica aponta para o Calico, já que ele é responsável por amplas modificações nas configurações de rede da máquina.

A parte triste é que isso não está listado em nenhum release notes. Então não apenas é bem difícil de diagnosticar o que aconteceu, mas também em se preparar para o que iria acontecer.

A descrição do problema está na página de configuração do felix, a partir da versão 3.14:

RouteTableRange (FELIX_ROUTETABLERANGE): Calico programs additional Linux route tables for various purposes. RouteTableRange specifies the indices of the route tables that Calico should use. [Default: 1-250]

Portanto, o Calico irá limpar qualquer conteúdo associado a tabelas existentes da 1 até 250. Como usamos a tabela 1, tivemos problema.

E ele não limpa apenas uma vez as instruções das tabelas; ele constantemente ajusta, ainda que não vá fazer nada com elas.


Tá vendo? Deveríamos ter escolhido a tabela 2147483647.

comments powered by Disqus

Posts Recentes

Categorias

Sobre

SRE e Cloud Native solutions engineer.
Respirando software livre desde 1997