Та же сеть на другом интерфейсе

Та же сеть на другом интерфейсе

Мы работаем с устройствами, прошитыми (на заводе) с помощью 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

решение1

Во-первых, если вы еще не пробовали proxy arp отдельно, вам следует попробовать proxy arp.

echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp

Вариант 1: некоторое искажение маршрута connmark/policy

Если 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: контейнер kvm на сетевое устройство usb

Вариант 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 вам может понадобиться репозиторий для каждого образа VM (если только вы не передаете каталог только для чтения каждой VM, что выполнимо). Маршрут connmark/policy немного более привередлив, но он также требует только одного сервера tftp, хотя, если ваши порты недостаточно случайны, conntrack может запутаться и перезаписать, если есть перекрытие портов (или может и не быть). С другой стороны, мостовое соединение с kvms требует гораздо больше памяти; целая VM на подключенное USB-устройство, но гораздо более вероятно, что оно будет работать каждый раз, потому что у VM есть целый изолированный сетевой стек для работы, в то время как ядру хоста нужно просто передавать пакеты туда и обратно через мост, особенно если фильтрация моста отключена.

Надеюсь, один из этих двух вариантов вам подойдет.

Связанный контент