Назад | Перейти на главную страницу

Почему arp_ignore = 1 нарушает ARP на интерфейсах POINTOPOINT? (kvm гость)

Если я добавлю следующие настройки в гостевой kvm:

net.ipv4.conf.all.arp_ignore=1

Сеть гостя останавливается (очень прерывистая).

Хост kvm использует мостовую сеть:

auto lo
iface lo inet loopback
iface lo inet6 loopback

auto {{ vbox_interface }}
iface {{ vbox_interface }} inet static
  address {{ vbox_main_ipv4 }}
  netmask {{ vbox_ipv4_netmask }}
  gateway {{ vbox_ipv4_gw }}
  pointopoint {{ vbox_ipv4_gw }}

iface {{ vbox_interface }} inet6 static
  address {{ vbox_main_ipv6 }}
  netmask 128
  gateway {{ vbox_ipv6_gw }}

auto  br0
iface br0 inet static
 address   {{ vbox_main_ipv4 }}
 netmask   255.255.255.255
 bridge_ports none
 bridge_stp off
 bridge_fd 0
 bridge_maxwait 0
{% for ip in vbox_addtl_ipv4 %}
 up route add -host {{ ip }} dev br0
{% endfor %}

iface br0 inet6 static
  address {{ vbox_main_ipv6 }}
  netmask 64

Это почему?

Как указывает Майкл в комментариях, некоторый контекст:

Итак, я полагаю, что мой вопрос:

Почему arp_ignore=1 разорвать сеть kvm-guest <> kvm-host, когда kvm-guest использует pointopoint / 255.255.255.255?

Редактировать 23/10/2018: конфигурация гостевых интерфейсов

# The loopback network interface
auto lo
iface lo inet loopback

auto ens7
iface ens7 inet static
  address IP from the pool {{ vbox_addtl_ipv4 }}
  netmask 255.255.255.255
  gateway {{ vbox_main_ipv4 }}
  pointopoint {{ vbox_main_ipv4 }}

iface ens7 inet6 static
  address xxx::xxx
  netmask 64
  gateway {{ vbox_main_ipv6 }}

Я проверил это поведение на Ubuntu 18.04 без каких-либо мостов, KVM или Hetzner вообще, и я думаю, что на самом деле это ошибка ядра в отношении обработки arp_ignore на двухточечных интерфейсах Ethernet. Шаги для проверки:

  1. Удостовериться netplan не будет мешать, отключив его совсем.
  2. Настройте две системы с подключенными друг к другу интерфейсами Ethernet и назначенными IP-адресами следующим образом:

    Север А:

    ip addr add 192.168.100.1/32 peer 192.168.100.2 dev ens33

    ip link set ens33 up

    Сервер B:

    ip addr add 192.168.100.2/32 peer 192.168.100.1 dev ens33

    ip link set ens33 up

  3. Наблюдайте нормальный пинг от сервера A к серверу B и ip addr show вывод, содержащий эту строку:

    inet 192.168.100.1 peer 192.168.100.2/32 scope global ens33

  4. включить arp_ignore=1 с участием sysctl net.ipv4.conf.all.arp_ignore=1 на сервере A и увидите, что эхо-запросы останавливаются по истечении времени ожидания записи ARP. Через некоторое короткое время пингует возобновится на какое-то время, а затем снова закончится. Таким образом, этот процесс будет продолжаться бесконечно.

  5. Запустить tcpdump на сервере B и наблюдайте входящие пинги и исходящие бесконечные who-has запросы для IP-адреса Сервера A, поступающие от Сервера B, без ответа. Иногда сервер A выдает who-has запрос IP-адреса Сервера B получит ответ, и Сервер B временно кэширует исходный MAC-адрес, полученный из этого запроса ARP, и тогда пинги возобновятся.

Вот что происходит. Внутри ядра разница между двухточечными и стандартными широковещательными интерфейсами заключается в том, как iproute2 (и аналогичные инструменты) заполнить in_ifaddr структура, определенная в include/linux/inetdevice.h.

Для обычных интерфейсов это ifa_address поле заполняется адрес локального интерфейса; для двухточечных интерфейсов ifa_address заселяется адрес удаленного узла и ifa_local заселяется адрес локального интерфейса.

Это нормальное и ожидаемое поведение, поскольку в старые времена любой интерфейс точка-точка сам считался подключенным удаленным устройством; соответствующий ему адрес локальной конечной точки может даже не существовать. Так что здесь ничего не сломано.

Что действительно сломано, так это то, что arp_ignore() обработчик, определенный в net/ipv4/arp.c косвенно использует confirm_addr_indev() функция, определенная в net/ipv4/devinet.c который итеративно пытается сопоставить целевой IP-адрес запроса ARP (то есть адрес локального интерфейса) с ifa_address поле всех настроенных записей IP-адресов на интерфейсе.

Это хорошо работает на стандартных интерфейсах, поскольку их локальный IP-адрес записан в ifa_address поле, однако с интерфейсами точка-точка он не работает, потому что вместо этого в этом поле записан IP-адрес однорангового узла.

Теперь настоящий вопрос заключается в том, действительно ли эта проблема нуждается в исправлении, поскольку уже было указано, что нет смысла использовать arp_ignore по p2p ссылкам. Я думаю, что это так, поскольку может существовать ситуация, когда рассматриваемый хост имеет более одного интерфейса (и эти интерфейсы не являются p2p), и кто-то может включить этот материал с помощью conf.all префикс только для того, чтобы увидеть, как его p2p-ссылки отключаются без видимой причины.

Ответ в определении: arp_ignore - 0 - (default): reply for any local target IP address, configured on any interface 1 - reply only if the target IP address is local address configured on the incoming interface 2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface 3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied 4-7 - reserved 8 - do not reply for all local addresses

По сути, поскольку сами двухточечные интерфейсы не имеют назначенных IP-адресов, нет «целевого IP-адреса на входящем интерфейсе». IP назначается интерфейсу моста ... не фактическому интерфейсу связи. Таким образом, ARP обрабатываться не будет.