I've stumbled upon a problem in the neighbor adj code that handles incomplete entries. These entries are pre-created under some circumstances such as creation of a VXLAN tunnel and used to make Ethernet headers for outbound ARP requests. Problem is, when the MAC address of the interface changes, these entries are never updated.
It is possible to reproduce the problem with 2 VPP instances connected together using memif. Let's start 2 VPP instances and configure them.
On VPP 1:
DBGvpp# ip table add 500
DBGvpp# create memif socket id 1 filename /run/vpp/memif.sock
DBGvpp# create interface memif id 0 socket-id 1 master
DBGvpp# set interface state memif1/0 up
DBGvpp# set interface ip table memif1/0 500
DBGvpp# set interface ip address memif1/0 10.0.0.1/24
DBGvpp# create vxlan tunnel src 10.0.0.1 dst 10.0.0.2 vni 1 encap-vrf-id 500
vxlan_tunnel0
DBGvpp# sh adj
[@0] ipv4-glean: [src:0.0.0.0/0] memif1/0: mtu:9000 next:1 flags:[] ffffffffffff02abcd0102030806
[@1] ipv4-glean: [src:10.0.0.0/24] memif1/0: mtu:9000 next:1 flags:[] ffffffffffff02abcd0102030806
[@2] arp-ipv4: via 10.0.0.2 memif1/0
Note arp-ipv4
entry. It's there even before any ARP requests are
sent due to create vxlan tunnel
which causes it to be created by
invoking fib_entry_track()
for the other tunnel endpoint IP. It also
has rewrite_header
which is not shown by sh adj
, yet which is used
to generate the ARP packets.
Now let's change the MAC address of the memif:
DBGvpp# set interface mac address memif1/0 02:ab:cd:01:02:03
At this point, the arp-ipv4
entry is NOT updated and it contains the old
mac address which is wrong.
Let's configure VPP 2 now and enable packet tracing:
DBGvpp# create memif socket id 1 filename /run/vpp/memif.sock
DBGvpp# create interface memif id 0 socket-id 1 slave
DBGvpp# set interface state memif1/0 up
DBGvpp# set interface ip address memif1/0 10.0.0.2/24
DBGvpp# trace add memif-input 10
And now let's try to run ping on VPP1:
DBGvpp# ping 10.0.0.2 source memif1/0
Statistics: 5 sent, 0 received, 100% packet loss
As we can see, the packets don't pass. sh error
on VPP 1 shows ARP requests being sent:
DBGvpp# sh error
Count Node Reason Severity
5 ip4-arp ARP requests sent error
1 memif1/0-output interface is down error
On VPP 2:
DBGvpp# sh error
Count Node Reason Severity
5 arp-reply ARP hw addr does not match L2 frame error
DBGvpp# sh trace
------------------- Start of thread 0 vpp_main -------------------
Packet 1
00:00:50:293029: memif-input
memif: hw_if_index 1 next-index 4
slot: ring 0
00:00:50:293061: ethernet-input
ARP: 02:fe:cd:1e:1f:4b -> ff:ff:ff:ff:ff:ff
00:00:50:293087: arp-input
request, type ethernet/IP4, address size 6/4
02:ab:cd:01:02:03/10.0.0.1 -> 00:00:00:00:00:00/10.0.0.2
00:00:50:293098: arp-reply
request, type ethernet/IP4, address size 6/4
02:ab:cd:01:02:03/10.0.0.1 -> 00:00:00:00:00:00/10.0.0.2
00:00:50:293121: error-drop
rx:memif1/0
00:00:50:293130: drop
arp-reply: ARP hw addr does not match L2 frame src addr
Here we can see that while the ARP packet has the correct MAC address
inside it (02:ab:cd:01:02:03
), the Ethernet header contains the
wrong old one for memif1/0
on VPP 1 (02:fe:cd:1e:1f:4b
). This
problem is apparently ignored by the Linux kernel, so I was not able
to reproduce the lack of connectivity using tap interface, but when
the peer is another VPP the problem is there.
With the patch applied, the rewrite data are visible for the incomplete entries (before ping) on VPP 1:
DBGvpp# sh adj
[@0] ipv4-glean: [src:0.0.0.0/0] memif1/0: mtu:9000 next:1 flags:[] ffffffffffff02abcd0102030806
[@1] ipv4-glean: [src:10.0.0.0/24] memif1/0: mtu:9000 next:1 flags:[] ffffffffffff02abcd0102030806
[@2] arp-ipv4: via 10.0.0.2 memif1/0 memif1/0: mtu:9000 next:1 flags:[] ffffffffffff02abcd0102030806
An ping works too (1st packet gone due to glean):
DBGvpp# ping 10.0.0.2 source memif1/0
116 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=32.0279 ms
116 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=20.0323 ms
116 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=28.0757 ms
116 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=32.0262 ms
Statistics: 5 sent, 4 received, 20% packet loss