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();
/*