Diff below moves bridge_output() to if_output(). It fixes the case I already described some weeks ago where you have a physical interface in a bridge and a vlan on top of it which is not in the bridge.
It also change the loop prevention code to use M_PROTO1 like in the input path. Tests, comments and oks welcome. Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.338 diff -u -p -r1.338 if.c --- net/if.c 7 Jun 2015 12:02:28 -0000 1.338 +++ net/if.c 8 Jun 2015 13:46:19 -0000 @@ -449,6 +449,19 @@ if_output(struct ifnet *ifp, struct mbuf int s, length, error = 0; unsigned short mflags; +#ifdef DIAGNOSTIC + if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { + printf("%s: trying to send packet on wrong domain. " + "if %d vs. mbuf %d\n", ifp->if_xname, ifp->if_rdomain, + rtable_l2(m->m_pkthdr.ph_rtableid)); + } +#endif + +#if NBRIDGE > 0 + if (ifp->if_bridgeport && (m->m_flags & M_PROTO1) == 0) + return (bridge_output(ifp, m, NULL, NULL)); +#endif + length = m->m_pkthdr.len; mflags = m->m_flags; Index: net/if_bridge.c =================================================================== RCS file: /cvs/src/sys/net/if_bridge.c,v retrieving revision 1.241 diff -u -p -r1.241 if_bridge.c --- net/if_bridge.c 8 Jun 2015 13:44:08 -0000 1.241 +++ net/if_bridge.c 8 Jun 2015 13:46:19 -0000 @@ -2665,10 +2665,12 @@ bridge_ifenqueue(struct bridge_softc *sc { int error, len; + /* Loop prevention. */ + m->m_flags |= M_PROTO1; + #if NGIF > 0 /* Packet needs etherip encapsulation. */ if (ifp->if_type == IFT_GIF) { - m->m_flags |= M_PROTO1; /* Count packets input into the gif from outside */ ifp->if_ipackets++; Index: net/if_ethersubr.c =================================================================== RCS file: /cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.204 diff -u -p -r1.204 if_ethersubr.c --- net/if_ethersubr.c 8 Jun 2015 13:44:08 -0000 1.204 +++ net/if_ethersubr.c 8 Jun 2015 13:46:20 -0000 @@ -181,15 +181,6 @@ ether_output(struct ifnet *ifp, struct m struct arpcom *ac = (struct arpcom *)ifp; int error = 0; -#ifdef DIAGNOSTIC - if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { - printf("%s: trying to send packet on wrong domain. " - "if %d vs. mbuf %d, AF %d\n", ifp->if_xname, - ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid), - dst->sa_family); - } -#endif - esrc = ac->ac_enaddr; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) @@ -276,47 +267,6 @@ ether_output(struct ifnet *ifp, struct m eh->ether_type = etype; memcpy(eh->ether_dhost, edst, sizeof(eh->ether_dhost)); memcpy(eh->ether_shost, esrc, sizeof(eh->ether_shost)); - -#if NBRIDGE > 0 - /* - * Interfaces that are bridgeports need special handling for output. - */ - if (ifp->if_bridgeport) { - struct m_tag *mtag; - - /* - * Check if this packet has already been sent out through - * this bridgeport, in which case we simply send it out - * without further bridge processing. - */ - for (mtag = m_tag_find(m, PACKET_TAG_BRIDGE, NULL); mtag; - mtag = m_tag_find(m, PACKET_TAG_BRIDGE, mtag)) { -#ifdef DEBUG - /* Check that the information is there */ - if (mtag->m_tag_len != sizeof(caddr_t)) { - error = EINVAL; - goto bad; - } -#endif - if (!memcmp(&ifp->if_bridgeport, mtag + 1, - sizeof(caddr_t))) - break; - } - if (mtag == NULL) { - /* Attach a tag so we can detect loops */ - mtag = m_tag_get(PACKET_TAG_BRIDGE, sizeof(caddr_t), - M_NOWAIT); - if (mtag == NULL) { - error = ENOBUFS; - goto bad; - } - memcpy(mtag + 1, &ifp->if_bridgeport, sizeof(caddr_t)); - m_tag_prepend(m, mtag); - error = bridge_output(ifp, m, NULL, NULL); - return (error); - } - } -#endif return (if_output(ifp, m)); bad: Index: sys/mbuf.h =================================================================== RCS file: /cvs/src/sys/sys/mbuf.h,v retrieving revision 1.191 diff -u -p -r1.191 mbuf.h --- sys/mbuf.h 23 May 2015 12:52:59 -0000 1.191 +++ sys/mbuf.h 8 Jun 2015 13:46:20 -0000 @@ -454,7 +454,6 @@ struct m_tag *m_tag_next(struct mbuf *, /* Packet tag types */ #define PACKET_TAG_IPSEC_IN_DONE 0x0001 /* IPsec applied, in */ #define PACKET_TAG_IPSEC_OUT_DONE 0x0002 /* IPsec applied, out */ -#define PACKET_TAG_BRIDGE 0x0020 /* Bridge processing done */ #define PACKET_TAG_GIF 0x0040 /* GIF processing done */ #define PACKET_TAG_GRE 0x0080 /* GRE processing done */ #define PACKET_TAG_DLT 0x0100 /* data link layer type */