Policy routing IPv6 quando dois uplinks compartilham fe80::1
Dois uplinks podem apresentar o mesmo próximo salto fe80::1 em links diferentes. Escolha uma tabela por política, gerencie as validades e verifique com uma consulta de rota.
Você tem dois uplinks, e ip -6 route show imprime o mesmo próximo salto nos dois: default via fe80::1 dev uplink0 e default via fe80::1 dev uplink1. Isso não é um conflito de endereços duplicados, e copiar o próximo salto nu fe80::1 para uma tabela de política não diz ao kernel qual link você quis dizer. A pergunta real é mais estreita do que o sintoma sugere: a segunda tabela precisa de um link ou dos dois, e o que mantém essas rotas vivas depois de um reboot. Três condições, verificadas em ordem, resolvem a maior parte.
O mesmo fe80::1 são dois vizinhos diferentes
Endereços link-local são limitados a um único link, então fe80::1 não é um endereço impresso duas vezes; são dois vizinhos que por acaso compartilham um sufixo. O índice de zona é como um host diz qual deles quer dizer, então fe80::1%uplink0 e fe80::1%uplink1 são destinos diferentes para o kernel, e esse sufixo nunca viaja até um roteador remoto. RFC 4007 descreve o modelo de zonas por trás disso, e é por isso que uma tabela de política precisa carregar um dispositivo com cada próximo salto link-local.
Um gerador de configuração de VPN que copia um ID de zona numérico de um host para um modelo trata o contexto local como se fosse parte do endereço, e o arquivo que ele grava está errado em toda máquina cujos nomes ou índices de interface difiram. Nem uma tabela de política funde dois links em um: uma VPN roteada passa pacotes entre redes, mas não carrega a identidade link-local de um vizinho Ethernet remoto pelo túnel, então o tráfego link-local fica no seu próprio link.
Remova o dispositivo e a rota se torna não gravável. ip -6 route add default via fe80::1 table 200 não consegue resolver o gateway, e o iproute2 o rejeita com Error: Nexthop has invalid gateway. Adicione dev uplink0 e o comando funciona, porque é o dispositivo que fixa o próximo salto a um desses dois vizinhos. O que o dispositivo não pode lhe dizer é se uplink0 é o link certo para esta tabela, e uma rota copiada de outro host traz os nomes de interface daquele host, e é daí que vêm os erros reais.
Condição um: um link ou dois na tabela
Comece pelo que o segundo uplink serve. Se ambos os links carregam o mesmo tráfego e um é standby, a tabela alternativa deve conter ambos os gateways com métricas distintas: mesmos destinos, um caminho preferido, uma segunda escolha óbvia. Se os uplinks existem porque tráfegos diferentes precisam sair por provedores diferentes, ou porque isto é um split tunnel em que parte do tráfego contorna a VPN enquanto o resto fica dentro, os dois links não pertencem a uma única tabela de jeito nenhum. Eles pertencem a duas tabelas, escolhidas por uma regra, e a regra escolhe a tabela, não o túnel: o tráfego que contorna é marcado antes de ser roteado, e a marca é o que o envia para a segunda tabela.
Nesse segundo caso a regra decide quando uma tabela é consultada, e a rota decide para onde o pacote vai uma vez que isso acontece:
ip -6 rule add fwmark 0x2 table 201
ip -6 route add default via fe80::1 dev uplink1 metric 100 table 201
ip -6 route add 2001:db8:100::/48 dev uplink1 metric 100 table 201
ip -6 route show table 201Nenhum dos objetos substitui o outro, e uma tabela contendo apenas um default ainda pode falhar em resolver o gateway. Se um add for rejeitado, ou a rota existir mas for inutilizável, coloque o prefixo conectado daquela interface na mesma tabela, ou marque o salto onlink quando esse prefixo é roteado em outro lugar. No bloco acima, 2001:db8:100::/48 representa esse prefixo conectado em uplink1, não um destino arbitrário. A regra fwmark só consome uma marca que algo mais precisa definir, de uma regra nftables ou iptables no caminho de encaminhamento ou de SO_MARK no socket, então um bloco copiado sem uma fonte de marca não corresponde a nada.
Condição dois: métricas não detectam um provedor morto
Uma métrica é uma preferência entre rotas que existem, não uma verificação de saúde. Quando a operadora cai, o kernel remove as rotas naquele dispositivo e o segundo default assume. Quando o cabo continua ligado e o provedor por trás morre, nada muda na tabela: a rota preferida está instalada, o vizinho é alcançável na camada 2, e os pacotes saem para um buraco negro. Se essa distinção importa para a sua configuração, o failover precisa vir de algo que sonda o caminho e remove a rota, seja um daemon de roteamento ou um pequeno script que apaga e reinstala a entrada.
Verifique a escolha depois que a tabela estiver construída, e verifique-a como o kernel a verá. ip -6 route get 2001:db8:100::1 imprime a rota que seria usada, incluindo o dispositivo e o endereço de origem selecionado, e respeita as regras de política. Um endereço de origem pertencente ao uplink errado é o sinal habitual de que uma regra casou antes do que você esperava.
Condição três: decida quem é o dono da persistência
Uma rota adicionada com ip -6 route add sobrevive até um reboot ou até algo limpá-la. Um default aprendido de anúncios de roteador carrega uma validade e pode ser retirado pelo roteador, enquanto um default adicionado manualmente nunca expira sozinho. Misturar os dois numa tabela é como uma rota permanente antiga acaba superando uma recém-anunciada, muito depois de o uplink que ela descrevia ter deixado de existir.
Escolha um único dono por tabela. Se um gerenciador de rede ou daemon de roteamento já gerencia a interface, descreva a rota de política lá e deixe o kernel em paz. Se você estiver scriptando, torne o script idempotente e escreva o teardown ao mesmo tempo, porque você vai precisar dele na primeira mudança ruim:
ip -6 route flush table 201
ip -6 rule del fwmark 0x2 table 201Num roteador que encaminha por outros hosts, verifique net.ipv6.conf.all.forwarding antes de culpar a tabela. Com o encaminhamento desligado, pacotes endereçados a outra rede são descartados, por mais correta que seja a tabela 201.
Registre o projeto para que a próxima pessoa possa auditá-lo
Um inventário que armazena apenas fe80::1 joga fora os campos que importam. Registre o destino, o próximo salto, o dispositivo, a tabela e a métrica juntos, mais de onde veio cada rota, se anunciada, gerada pelo gerenciador ou estática. Quando alguém perguntar depois se o segundo uplink está de fato carregando tráfego, esse registro responde sem adivinhação.
Antes de declarar a tabela pronta, confirme o vizinho com ip -6 neigh show dev uplink0, releia ip -6 rule show para acidentes de ordenação, e teste com tráfego que corresponda à regra em vez de um ping que pega a rota padrão. Depois derrube um uplink de propósito e observe para qual rota o kernel recua; a resposta deve coincidir com a que você anotou.