Lloyd Parkes
2013-08-05 00:32:41 UTC
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
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