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 */