I have one setup with multiple interfaces in a bridge and on some of
these interfaces some vlan(4)s.  But there's currently a bug that
prevent us to send (receive is fine) VLAN packets in such config.
Diff below fixes that.

The problem is that vlan_output() does not pass its parent interface
to ether_output().  That's a mis-design that should be fixed later.
The reason for not passing the parent interface is that we want to
tcpdump(8) packets on vlan interfaces and the easiest hack^Wsolution
was to add a bpf handler in vlan_start()*.

Since my vlans are not part of the bridge, the check below is never
true and my packets never go through the bridge.  By moving this
check to if_output() we kill two birds with one diff.  First of
all we fix this vlan bug and secondly we simplify ether_output()
which in turn will allow us to fix all pseudo-interface *output()
functions.

One of the goals of if_output() is to move all bpf handlers instead
of having them in multiple if_start().  Of course, this will also
help us removing the various "#if PSEUDODRIVER" from our stack...

Ok?

*: Note that for the exact same reason we cannot tcpdump output
packets on a carp(4) interface, this will be fixed at the same
time in upcoming diffs.


Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.198
diff -u -p -r1.198 if_ethersubr.c
--- net/if_ethersubr.c  15 May 2015 10:15:13 -0000      1.198
+++ net/if_ethersubr.c  15 May 2015 10:58:37 -0000
@@ -363,47 +363,6 @@ ether_output(struct ifnet *ifp0, struct 
        if (ether_addheader(&m, ifp, etype, esrc, edst) == -1)
                senderr(ENOBUFS);
 
-#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
-
        len = m->m_pkthdr.len;
 
        error = if_output(ifp, m);
Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.331
diff -u -p -r1.331 if.c
--- net/if.c    15 May 2015 10:15:13 -0000      1.331
+++ net/if.c    15 May 2015 10:58:37 -0000
@@ -450,6 +450,40 @@ if_output(struct ifnet *ifp, struct mbuf
        length = m->m_pkthdr.len;
        mflags = m->m_flags;
 
+#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)) {
+                       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) {
+                               m_freem(m);
+                               return (ENOBUFS);
+                       }
+                       memcpy(mtag + 1, &ifp->if_bridgeport, sizeof(caddr_t));
+                       m_tag_prepend(m, mtag);
+                       error = bridge_output(ifp, m, NULL, NULL);
+                       return (error);
+               }
+       }
+#endif
+
        s = splnet();
 
        /*

Reply via email to