Trabalhamos com dispositivos que são flasheados (de fábrica) usando TFTP em uma conexão de rede USB.
O servidor possui um endereço fixo 192.168.2.100 e o dispositivo um endereço fixo 192.168.2.101. Ao iniciar, ele se conecta para baixar o firmware.
Na configuração atual, apenas um dispositivo pode funcionar ao mesmo tempo. Mas eu gostaria de tornar possível atualizar tantos dispositivos quanto pudermos conectar (porque podemos ter alguns requisitos enormes de flash).
Para contornar o problema de roteamento, criei uma versão xinetd que define setsockopt como SO_BIND_DEVICE.
Mas o que não fiz foi que o Linux não consiga lidar com as solicitações ARP em ambas as interfaces ao mesmo tempo.
se eu fizer um "ping 192.168.2.101 -I usb0" e "ping 192.168.2.101 -I usb1" ao mesmo tempo, ele funcionará em uma interface:
ARP, Request who-has sk tell 192.168.2.100, length 28
ARP, Reply 192.168.2.101 is-at 7a:0f:66:7c:fc:2c (oui Unknown), length 28
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 21807, seq 1, length 64
IP 192.168.2.101 > 192.168.2.100: ICMP echo reply, id 21807, seq 1, length 64
Mas por outro lado não vai:
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31071, seq 1, length 64
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31071, seq 2, length 64
IP 192.168.2.100 > 192.168.2.101: ICMP echo request, id 31077, seq 1, length 64
ARP, Request who-has 192.168.2.100 tell 192.168.2.101, length 28
O servidor parece não responder à solicitação ARP.
É assim que a conexão do dispositivo é tratada no servidor com um script /etc/network/if-up.d/000-first:
ifconfig $IFACE up
ifconfig $IFACE 192.168.2.100
PID=/var/run/xinetd-$IFACE.pid
# this is the modified xinetd version to bind on one address
kill -9 `cat $PID`
xinetd -pidfile $PID -interface $IFACE
# I tried this to force the handling of ARP table per interface, but it doesn't change anything:
# /usr/sbin/arpd -b /tmp/$IFACE.db -a 3 -k $IFACE
Aqui está a versão modificada do xinetd: https://github.com/fclairamb/xinetd/commit/1f5c1e8f9944e372b137e6aa46247f8de807bece#L8R253
Responder1
Primeiro, se você ainda não experimentou o proxy arp sozinho, você deve tentar o proxy arp.
echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
Opção 1: alguma confusão de rota de conexão/política
Se o proxy arp sozinho não funcionou, não posso garantir que funcionará, mas acho que vale a pena tentar. O que estou prestes a descrever é como configurar o roteamento de política para vincular respostas com base na interface de entrada usando conntrack. Descreverei como configurá-lo para duas interfaces e deve ser fácil de expandir para qualquer número. Por outro lado, em vez de funcionar, ele pode simplesmente ficar muito confuso e não fazer nada (provavelmente porque a tabela arp do kernel não sabe que deve armazenar em cache pares ip/mac por dispositivo). Se isso acontecer, tente o segundo método, mais feio.
Primeiro, configure algumas regras do connmark mangle:
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j ACCEPT
Em /etc/iproute2/rt_tables adicione duas tabelas, 100 e 101, rotule-as como usb0 e usb1
100 usb0
101 usb1
Para cada uma dessas tabelas adicione o seguinte (substitua <N> pelo número apropriado):
ip route add 192.168.2.0/24 dev usb<N> table usb<N>
ip rule add fw <N> table usb<N>
iptables -t mangle -A PREROUTING -i usb<N> -j MARK --set-mark <N>
Não tenho certeza, mas talvez seja necessário configurar uma interface fictícia como esta para o seu daemon tftp ouvir:
modprobe dummy
ifconfig dummy0 192.168.2.100/32 up
echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
sysctl net.ipv4.ip_forward=1
iptables -I FORWARD -s 192.168.2.100 -j ACCEPT
iptables -I FORWARD -d 192.168.2.100 -j ACCEPT
Agora teste com dois dispositivos. Se funcionar, excelente, caso contrário, tente o próximo método:
Opção 2: contêiner kvm por dispositivo de rede USB
A opção 2 é mais feia, envolvendo algumas pontes e qemu/kvm. virt-manager
é provavelmente a maneira mais fácil de criar essas coisas.
Crie dispositivos de toque e pontes, um por interface USB.
tunctl -t tap<N>
brctl addbr usb<N>br
brctl addif usb<N>br tap<N>
brctl addif usb<N>br usb<N> # this may need to be done each time the usb device is connected/disconnected.
Crie um arquivo de imagem kvm ou CD de inicialização projetado para ser somente leitura e hospede seu servidor tftp e imagem ... ou omita somente leitura e crie um arquivo de imagem por VM (usar snapshots para isso seria melhor, mas isso é mais fora de escopo do que esta resposta está obtendo).
Execute um kvm usando a interface tap e seu arquivo de imagem e teste a conectividade da rede USB.
Comparação
Se a rota connmark/policy funcionou, é muito mais fácil manter de forma síncrona o repositório tftp. Com o KVM, pode ser necessário ter um repositório por imagem de VM (a menos que você passe um diretório somente leitura para cada VM, o que é possível). A rota Connmark/política é um pouco mais complicada, mas também requer apenas um servidor tftp, embora se suas portas não forem aleatórias o suficiente, o conntrack pode ficar confuso e sobrescrever se houver uma sobreposição de portas (ou não). Por outro lado, a ponte para o kvms requer muito mais memória; uma VM inteira por dispositivo USB conectado, mas é muito mais provável que funcione sempre porque a VM tem uma pilha de rede isolada inteira para trabalhar, enquanto o kernel do host só precisa passar pacotes de um lado para outro por uma ponte, especialmente verdadeiro se a filtragem de ponte está fora.
Esperamos que um desses dois funcione para você.