Bug 270478 - Duplicated ARP reply sent from if_bridge member
Summary: Duplicated ARP reply sent from if_bridge member
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: Zhenlei Huang
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-03-27 10:00 UTC by Zhenlei Huang
Modified: 2023-10-20 13:31 UTC (History)
2 users (show)

See Also:
zlei: mfc-stable14?
zlei: mfc-stable13?
zlei: mfc-stable12?


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Zhenlei Huang freebsd_committer freebsd_triage 2023-03-27 10:00:05 UTC
Observed the problem while repeating https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=240106#c28

A script to repeat:

```
#!/bin/sh

kldload -nq if_bridge

epa=$( ifconfig epair create )
epb=${epa%a}b


j=$( jail -ic vnet persist )
ifconfig $epb vnet $j
b=$( jexec $j ifconfig bridge create )
jexec $j ifconfig $b addm $epb
jexec $j ifconfig $epb up
jexec $j ifconfig $b inet 192.168.2.2/24
ifconfig $epa inet 192.168.2.1/24

# pre populate arp table for jail
jexec $j ping -qc1 192.168.2.1

# print interfaces
ifconfig $epa
jexec $j ifconfig $epb
jexec $j ifconfig $b

tmp=$( mktemp )
nohup tcpdump -i $epa -Uw $tmp > /dev/null &

# clear host arp table, and trigger an arp request via ping
arp -da
sleep 1
ping -c1 192.168.2.2

# wait a little for tcpdump to write all packets
sleep 2
kill $!

# show arp table in jail
jexec $j arp -na

jail -R $j
ifconfig $epa destroy

tcpdump -ennv -r $tmp 'arp or icmp'
rm $tmp
```

The output:
=====================
PING 192.168.2.1 (192.168.2.1): 56 data bytes

--- 192.168.2.1 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.181/0.181/0.181/0.000 ms
epair0a: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:30:35:63:2b:0a
	inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
epair0b: flags=8963<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:30:35:63:2b:0b
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	ether ea:80:d1:f2:05:ae
	inet 192.168.2.2 netmask 0xffffff00 broadcast 192.168.2.255
	id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
	maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
	root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
	member: epair0b flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
	        ifmaxaddr 0 port 2 priority 128 path cost 2000
	groups: bridge
	nd6 options=9<PERFORMNUD,IFDISABLED>
192.168.2.2 (192.168.2.2) deleted
PING 192.168.2.2 (192.168.2.2): 56 data bytes
64 bytes from 192.168.2.2: icmp_seq=0 ttl=64 time=0.155 ms

--- 192.168.2.2 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.155/0.155/0.155/0.000 ms
? (192.168.2.2) at ea:80:d1:f2:05:ae on bridge0 permanent [bridge]
? (192.168.2.1) at 02:30:35:63:2b:0a on bridge0 expires in 1198 seconds [bridge]
reading from file /tmp/tmp.WKOgI9yi, link-type EN10MB (Ethernet)
01:59:02.272912 02:30:35:63:2b:0a > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.2.2 tell 192.168.2.1, length 28
01:59:02.272963 ea:80:d1:f2:05:ae > 02:30:35:63:2b:0a, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Reply 192.168.2.2 is-at ea:80:d1:f2:05:ae, length 28
01:59:02.272969 02:30:35:63:2b:0a > ea:80:d1:f2:05:ae, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 34746, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.1 > 192.168.2.2: ICMP echo request, id 27667, seq 0, length 64
01:59:02.272971 02:30:35:63:2b:0b > 02:30:35:63:2b:0a, ethertype ARP (0x0806), length 42: Ethernet (len 6), IPv4 (len 4), Reply 192.168.2.2 is-at 02:30:35:63:2b:0b, length 28
01:59:02.273013 ea:80:d1:f2:05:ae > 02:30:35:63:2b:0a, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 33683, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.2.2 > 192.168.2.1: ICMP echo reply, id 27667, seq 0, length 64
Comment 1 Mina Galić freebsd_triage 2023-03-27 10:50:44 UTC
this setup seems odd.
why is `ifconfig $epa inet 192.168.2.1/24` necessary?
only the bridge should need an IP, and i don't see that assignment
Comment 2 Zhenlei Huang freebsd_committer freebsd_triage 2023-03-27 12:51:19 UTC
(In reply to Mina Galić from comment #1)
> this setup seems odd.
A short text diagram should show that clear.

                          +-----------------------+
   +---------+            | +---------+           |
   |         |            | |         |           |
   | epair0a -------------| | epair0b |  bridge0  |
   |         |            | |         |           |
   +---------+            | +---------+           |
  192.168.2.1/24          +-----------------------+
                                192.168.2.2/24     


> why is `ifconfig $epa inet 192.168.2.1/24` necessary?

$epa is in host side, assign a ip address to trigger a ARP request.

> only the bridge should need an IP, and i don't see that assignment

The bridge and $epb is in jail side.

> jexec $j ifconfig $b addm $epb
> jexec $j ifconfig $epb up
> jexec $j ifconfig $b inet 192.168.2.2/24
Comment 3 Mina Galić freebsd_triage 2023-03-27 12:53:51 UTC
ah, thanks for elaborating.
I somehow missed the part where the bridge is in the jail
Comment 4 Zhenlei Huang freebsd_committer freebsd_triage 2023-03-27 14:23:59 UTC
Tested on stable/13 and release/12.3.

CC net@ to see if smart guys has any insights about the problem.
Comment 5 Zhenlei Huang freebsd_committer freebsd_triage 2023-03-27 14:36:56 UTC
Some digs:
https://github.com/freebsd/freebsd-src/blob/19e43c163c64636d2590dca006e22f18d22f48b2/sys/netinet/if_ether.c#L828-L870

For broadcast packets, they are processed by both bridge and its member (the interface receiving the broadcast packets).
Specifically, both bridge and its member response to ARP requests and generate ARP replies.

Should we suppress either bridge or its member so that the bridge behaves like exactly ONE logical interface?