If I add the following settings on a kvm guest:
net.ipv4.conf.all.arp_ignore=1
Networking of the guest stops (highly intermittent).
The kvm host uses bridge-networking:
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
Why is that?
As Michael is pointing out in the comments, some context:
- I do understand the basic gist of
arp_ignore
(http://kb.linuxvirtualserver.org/wiki/Using_arp_announce/arp_ignore_to_disable_ARP) – I mainly want to keep that setting as I am in a untrusted network - I do understand that the setup of network is maybe not standard, this is due to me following this: https://wiki.hetzner.de/index.php/KVM_mit_Nutzung_aller_IPs_-_the_easy_way/en – which allows me to make usage of all IPs of my given subnet
- I do understand that setting
arp_ignore=0
on the guest VM will solve the issue. However I would like to know why (because I do not need to do that on the host itself) and I can not accept that as answer because I do not believe setting it should cause the network to go offline (e.g. I want to solve the issue without making that setting a dependency) - I am assuming (thanks Peter Zhabin) that with netmask 255.255.255.255 it is safe enough that nobody within the untrusted network can take advantage of arp?
So my question I suppose is:
Why does arp_ignore=1
break the kvm-guest <> kvm-host networking when the kvm-guest uses pointopoint/255.255.255.255 ?
Edit 23/10/2018: guest interfaces config
# 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 }}
Best Answer
I have verified this behavior on Ubuntu 18.04 without any bridges, KVMs or Hetzner whatsoever and I think this is actually a kernel bug with regard to handling of
arp_ignore
on point-to-point Ethernet interfaces. Steps to verify:netplan
won't interfere by disabling it altogether.Set up two systems with Ethernet interfaces connected to each other and IP addresses assigned like this:
Sever A:
ip addr add 192.168.100.1/32 peer 192.168.100.2 dev ens33
ip link set ens33 up
Server B:
ip addr add 192.168.100.2/32 peer 192.168.100.1 dev ens33
ip link set ens33 up
Observe a normal ping from Server A to Server B and
ip addr show
output that contains this line:inet 192.168.100.1 peer 192.168.100.2/32 scope global ens33
Enable
arp_ignore=1
withsysctl net.ipv4.conf.all.arp_ignore=1
on Server A and see pings stopping as soon as ARP entry times out. After certain short amount of time pings will resume for a while and then end again. This process will continue indefinitely in this manner.Run a
tcpdump
on Server B and observe inbound pings and outbound endlesswho-has
requests for the Server A IP address coming from Server B with no response. Occasionally, Server A will issuewho-has
request for the Server B IP, will get a reply, and Server B will temporarily cache source MAC-address obtained from this ARP request and this is when pings resume.Now, here's what's going on. There's an in-kernel difference between point-to-point and standard broadcast interfaces in terms of how
iproute2
(and similar tools) populatein_ifaddr
structure defined ininclude/linux/inetdevice.h
.For normal interfaces it's
ifa_address
field gets populated with local interface address; for point-to-point interfacesifa_address
gets populated with remote peer address andifa_local
gets populated with local interface address.This is normal and expected behavior, as in old-school days any point-to-point interface was considered an attached remote device itself; a local endpoint address corresponding to it may not even exist. So nothing is broken here.
What's really broken is that
arp_ignore()
handler defined innet/ipv4/arp.c
indirectly usesconfirm_addr_indev()
function defined innet/ipv4/devinet.c
that iteratively tries to match target IP address of the ARP request (that is, local interface address) withifa_address
field of all configured IP address records on an interface.This works well on standard interfaces as they do have their local IP address recorded in
ifa_address
field, however with point-to-point interfaces it fails, 'cause they have peer IP address recorded in this field instead.Now, the real question is does this issue really need a fix, as it has been pointed out already that there's no sense in using
arp_ignore
on p2p links. I think it does, as there might exist a situation where the host in question has more than one interface (and these interfaces are not p2p ones) and someone might enable this stuff withconf.all
prefix only to see his p2p links going down for no apparent reason.