Мы работаем с устройствами, прошитыми (заводскими) по TFTP через сетевое соединение usb.
Сервер имеет фиксированный адрес 192.168.2.100, а устройство - фиксированный адрес 192.168.2.101. При запуске подключается для загрузки прошивки.
В текущей настройке одновременно может работать только одно устройство. Но я бы хотел, чтобы можно было прошивать столько устройств, сколько мы можем подключить (потому что у нас могут быть огромные требования к прошивке).
Чтобы обойти проблему маршрутизации, я сделал версию xinetd, которая устанавливает для setsockopt значение SO_BIND_DEVICE.
Но чего я не сделал, кроме того, что Linux не может обрабатывать ARP-запросы на обоих интерфейсах одновременно.
если я сделаю «ping 192.168.2.101 -I usb0» и «ping 192.168.2.101 -I usb1» одновременно, он будет работать на одном интерфейсе:
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
Но с другой - не будет:
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
Сервер не отвечает на запрос ARP.
Вот как соединение с устройства обрабатывается на сервере с помощью сценария /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
Вот модифицированная версия xinetd: https://github.com/fclairamb/xinetd/commit/1f5c1e8f9944e372b137e6aa46247f8de807bece#L8R253
Во-первых, если вы не пробовали использовать proxy arp отдельно, вам следует попробовать proxy arp.
echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
Если только proxy arp не работал, я не могу гарантировать, что это сработает, но я думаю, что попробовать стоит. Я собираюсь описать, как настроить маршрутизацию политики для привязки ответов на основе интерфейса ввода с помощью conntrack. Я опишу, как настроить его для двух интерфейсов, и его должно быть достаточно легко расширить до любого числа. С другой стороны, вместо того, чтобы работать, он может просто сильно запутаться и ни черта не сделать (вероятно, потому, что таблица arp ядра не знает, что она должна кэшировать пары ip / mac для каждого устройства). Если это произойдет, попробуйте второй, более уродливый метод.
Сначала установите несколько правил 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
В / etc / iproute2 / rt_tables добавьте две таблицы, 100 и 101, пометьте их usb0 и usb1
100 usb0
101 usb1
Для каждой из этих таблиц добавьте следующее (замените <N> на соответствующий номер):
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>
Я не уверен, но вам может потребоваться настроить фиктивный интерфейс, например, для вашего демона tftp, чтобы он слушал:
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
Теперь протестируйте с двумя устройствами. Если работает - отлично, в противном случае попробуйте следующий метод:
Вариант 2 уродливее, включает в себя мост и qemu / kvm. virt-manager
наверное, самый простой способ создать эти вещи.
Создавайте устройства разветвления и мосты, по одному на интерфейс 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.
Создайте файл образа kvm или загрузочный компакт-диск, который предназначен только для чтения и содержит ваш tftp-сервер и образ ... или опустите только для чтения и создайте один файл образа для каждой виртуальной машины (использование снимков для этого было бы лучше, но это больше объема, чем этот ответ).
Запустите kvm, используя интерфейс Tap и файл изображения, и проверьте подключение к сети USB.
Если маршрут connmark / policy сработал, намного проще синхронно поддерживать репозиторий tftp. С KVM вам может потребоваться репозиторий для каждого образа виртуальной машины (если только вы не передадите каталог только для чтения каждой виртуальной машине, что возможно). Маршрут Connmark / policy немного сложнее, но он также требует только одного tftp-сервера, хотя, если ваши порты недостаточно случайны, conntrack может запутаться и перезаписать, если есть перекрытие портов (а может и нет). С другой стороны, мост к kvms требует гораздо больше памяти; целая виртуальная машина на подключенное USB-устройство, но гораздо более вероятно, что она будет работать каждый раз, потому что виртуальная машина имеет весь изолированный сетевой стек для работы, в то время как ядро хоста просто должно передавать пакеты назад и вперед через мост, особенно если фильтрация моста выключен.
Надеюсь, один из этих двух сработает для вас.