Estou usando uma instalação mínima nova do Ubuntu server 24.04.1 LTS. Eu executo esses comandos como root para configurar a rede e fazer alguns experimentos:
apt install -y netcat-traditional tcpdump inetutils-ping
ip netns add ns1
ip netns add ns2
ip link add my_veth1 type veth peer name my_veth2
ip link set my_veth1 up netns ns1
ip link set my_veth2 up netns ns2
ip -n ns1 address add 1.2.3.4 dev my_veth1
ip -n ns1 route add 2.3.4.0/24 dev my_veth1
ip -n ns2 address add 2.3.4.5 dev my_veth2
Então executo esses comandos em diferentes terminais:
# Terminal 1
ip netns exec ns1 tcpdump -l -i my_veth1
# Terminal 2
ip netns exec ns2 tcpdump -l -i my_veth2
# Terminal 3
ip netns exec ns1 ping 2.3.4.5
Recebo a mesma saída nos terminais 1 e 2:
02:40:27.511438 ARP, Request who-has 2.3.4.5 tell 1.2.3.4, length 28
02:40:27.511438 ARP, Request who-has 2.3.4.5 tell 1.2.3.4, length 28
02:40:27.511438 ARP, Request who-has 2.3.4.5 tell 1.2.3.4, length 28
...
veth2
tem o endereço IP 2.3.4.5 e está recebendo a requisição ARP. Por que ele não envia uma resposta? Ele só responde quando eu configuro uma entrada na tabela de roteamento:
ip -n ns2 route add 1.2.3.0/24 dev my_veth2
Mas isso não deveria ser necessário, pois o endereço MAC da interface de rede que veth2
deve responder já está codificado na solicitação à qual ela está respondendo.
ARP é um protocolo de camada IP; o kernel assume, por padrão, que não faz sentido responder a solicitações ARP de endereços que não podem ser alcançados por nenhuma rota.
Se você estiver curioso sobre a lógica específica do kernel, ela começa
net/ipv4/arp.c
naarp_rcv
função, que se organiza para chamararp_process
, que chamaip_route_input_noref
, que é o que, em última análise, faz com que o pacote seja descartado porque o endereço está inacessível.Você pode alterar um pouco o comportamento desabilitando o
rp_filter
sysctl, que pode assumir os seguintes valores:0
- Nenhuma validação de fonte.1
- Modo estrito conforme definido em RFC3704.Caminho Reverso Estrito: Cada pacote de entrada é testado contra o FIB e se a interface não for o melhor caminho reverso, a verificação do pacote falhará. Por padrão, os pacotes com falha são descartados.
2
- Modo solto conforme definido no RFC3704.Caminho reverso frouxo: o endereço de origem de cada pacote recebido também é testado em relação ao FIB e, se o endereço de origem não puder ser acessado por nenhuma interface, a verificação do pacote falhará.
Se você desabilitar a validação da fonte configurando
rp_filter
para0
:O valor usado é o maior de
my_veth2
e,all
portanto, precisamos desabilitá-loall
também (no meu sistema, oall
valor já era0
, mas nem sempre será esse o caso, então é melhor defini-lo explicitamente).Então você verá que o kernel realmente responde à solicitação ARP. Se eu executar run
ip netns exec ns1 ping 2.3.4.5
, vejo o seguinte emns1
:E em
ns2
:Com a validação de origem desabilitada, o kernel responde à solicitação ARP, mas os dois namespaces não conseguem se comunicar porque ainda não há rota de ns2 para ns1, então não há como ns2 responder à
ping
solicitação.Você pode ter o
arp_ignore
sysctl definido como 2.Tradicionalmente, o Linux responde ARP para endereços locais pertencentes a todas as interfaces (ou seja, como se os endereços pertencessem ao host como um todo), por exemplo, eth0 responderá com seu próprio endereço MAC em nome de endereços locais atribuídos a eth2. Frequentemente isso é inesperado (e não consigo pensar em muitas situações em que seria de alguma utilidade) e muitos administradores desabilitam esse comportamento configurando
arp_ignore=1
o que faz o Linux responder ARP apenas para endereços atribuídos à mesma interface. (É assim que o IPv6 NDP sempre se comporta no Linux, e também o mesmo que o IPv4 ARP se comporta em vários outros sistemas operacionais, entãoarp_ignore=1
geralmente é uma boa escolha.)Mas alguns sistemas vão além e usam
arp_ignore=2
o que adicionalmente suprime respostas ARP se o endereço IP do remetente (que também é codificado em consultas ARP) não for "parte da mesma sub-rede", o que em termos Linux é determinado pela verificação se há uma rota de link para ela. Tal restrição pode fazer sentido em algumas situações em que múltiplas sub-redes IP compartilham o mesmo domínio de transmissão Ethernet... embora geralmente tais solicitações ARP (como a sua) não ocorram em uso normal.Há outro sysctl semelhante,
arp_filter
, onde a condição é "...se o kernel rotearia ou não um pacote do IP ARP para fora dessa interface (portanto, você deve usar o roteamento baseado na origem para que isso funcione)."