Discussion:
SOLVED: Multicast problems with bridge(4) ports
(too old to reply)
Lloyd Parkes
2013-08-05 00:32:41 UTC
Permalink
Hi all,
I have found the bug that causes this and I've got a fix.

The problem is that bridge_broadcast() only puts broadcast packets onto the output queue of the interfaces it is broadcasting the packet to and doesn't put a copy onto their input queues. I just added a small lump of code to copy the packet appropriately and I used M_LINK2 to avoid broadcasting packets that have already been broadcast.

The NetBSD bridge(4) code for handling unicast packets has a short circuit in it that allows an input packet to be switched onto another interface as ether_input() passes it up the protocol stack, but this can't be done for broadcasts because each interface needs its own copy of the packet.

I'll raise a PR for this, and here's the code I'll be submitting with it. I'll also copy my test configuration into the PR for reference. I'm more than happy to take suggestions on better ways to fix this.

Cheers,
Lloyd

Index: sys/net/if_bridge.c
===================================================================
RCS file: /vol/src/rsync-src/src/sys/net/if_bridge.c,v
retrieving revision 1.74
diff -u -r1.74 if_bridge.c
--- sys/net/if_bridge.c 19 Nov 2011 22:51:25 -0000 1.74
+++ sys/net/if_bridge.c 5 Aug 2013 00:05:32 -0000
@@ -1633,6 +1633,13 @@
}

bridge_enqueue(sc, dst_if, mc, 1);
+ mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
+ if (mc == NULL) {
+ sc->sc_if.if_oerrors++;
+ continue;
+ }
+ mc->m_pkthdr.rcvif = dst_if;
+ (*dst_if->if_input)(dst_if, mc);
}
if (used == 0)
m_freem(m);
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /vol/src/rsync-src/src/sys/net/if_ethersubr.c,v
retrieving revision 1.188.8.3
diff -u -r1.188.8.3 if_ethersubr.c
--- sys/net/if_ethersubr.c 31 Oct 2012 16:07:46 -0000 1.188.8.3
+++ sys/net/if_ethersubr.c 4 Aug 2013 06:53:32 -0000
@@ -703,7 +703,8 @@
* will always return the original packet if we need to
* process it locally.
*/
- if (ifp->if_bridge) {
+ if (ifp->if_bridge && (m->m_flags & M_LINK2) == 0) {
+ m->m_flags |= M_LINK2;
/* clear M_PROMISC, in case the packets comes from a vlan */
m->m_flags &= ~M_PROMISC;
m = bridge_input(ifp, m);
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Greg Troxel
2013-08-20 23:09:23 UTC
Permalink
The problem is that bridge_broadcast() only puts broadcast packets
onto the output queue of the interfaces it is broadcasting the packet
to and doesn't put a copy onto their input queues. I just added a
small lump of code to copy the packet appropriately and I used M_LINK2
to avoid broadcasting packets that have already been broadcast.

The NetBSD bridge(4) code for handling unicast packets has a short
circuit in it that allows an input packet to be switched onto another
interface as ether_input() passes it up the protocol stack, but this
can't be done for broadcasts because each interface needs its own copy
of the packet.

Do you think the underlying problem affects v4/v6 equally, and it's a
simple case of missing broadcasts? Do you think multicast is handled
correctly with your fix?

There's something uncomfortable about sending the packet in as well as
out every bridged interface, but I think that's just wrong intuition on
my part - if there were an external bridge, the packet would simply
appear on every network (v6 link). So your change really does seem to
replicate the behavior of an external bridge.

Loading...