[Bug 296652] ARP replies from bridge are lost (?runt packet)

[email protected] Fri, 10 Jul 2026 03:10:10 +0000
Newsgroups gmane.os.freebsd.devel.net
Message-ID <[email protected]/bugzilla/>
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=296652

David Horn <[email protected]> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |[email protected]

--- Comment #1 from David Horn <[email protected]> ---
Created attachment 272682
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=272682&action=edit
Test fix to 15.1 sys/netinet/if_ether.c

Please try attached patch against stable/15 (or 15.1)  If it works, we can
hopefully have ivy@ take a look and see if there are any other scenarios it
does not cover.

I tested with a vm and igb0 with and without bridge0 against 15.1

If the patch does not work, try building the kernel with INVARIANTS in the
kernel config so we can see if the KASSERT(9) triggers from the patch (or other
oddities)

More background:

arp: do not leave trailing mbufs attached to the ARP reply

in_arpinput() turns the received request into a reply in place and shrinks it
by assigning m_len and m_pkthdr.len.  That fixes up the first mbuf and the
packet header, but leaves any trailing mbufs of the chain attached, so the
chain ends up longer than m_pkthdr.len claims.

The if_bridge(4) input path is what produces such a chain.  Before reinjecting
a broadcast frame into the bridge ifnet, bridge_input() realigns it with

        m_copyup(mc2, min(mc2->m_pkthdr.len, max_protohdr), ETHER_ALIGN)

and m_copyup() attaches whatever does not fit into the new head mbuf as
m_next.  max_protohdr is 60, so any ARP request longer than 60 bytes leaves a
tail; requests are padded to the minimum Ethernet frame size and some senders
pad further.

The reply is then transmitted with m_pkthdr.len = 42 while the chain really
holds 46 bytes.  Drivers are entitled to trust m_pkthdr.len: iflib derives the
transmit descriptor length from it, so the i210 is handed a length that
disagrees with its DMA segment list and the frame never reaches the peer.
re(4) instead pads short frames by 60 - m_pkthdr.len = 18 bytes and appends
that to the real chain, yielding a 64-byte frame; this is why the failure is
visible only with some NICs.

Trim the surplus with m_adj() rather than merely assigning the lengths.  A
negative length truncates the chain to the requested size, frees the trailing
mbufs and updates m_pkthdr.len, restoring the invariant
m_pkthdr.len == sum(m_len).

-- 
You are receiving this mail because:
You are the assignee for the bug.