The diff attached to this mail fixes the bridge output for VLANs noted in
this link:
http://marc.info/?l=openbsd-misc&m=141508025731320&w=2

Now when we are doing VLAN input we check whether the VLAN is a bridge port
or not, if it does then we have to do nothing and just pass the packet and
the bridge will handle it. This way we save some time by not doing VLAN
popping in the packets.

Bridge was not ready or consistent in some places to handle this, so some
checks were altered to consider tagged packets without the M_VLANTAG flag.
(this means we continue to ignore tagged packets in 'bridge_ip' and
'bridge_blocknonip')
Also, when copying packets, remember to copy the packet M_VLANTAG as well.

Altered the function vlan_input to update the ether_input ifp pointer, so
now ether_input doesn't need to be re-entered when we didn't pop the VLAN
tag.

Lightly tested with in my VPLS setup.

Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.227
diff -u -p -r1.227 if_bridge.c
--- net/if_bridge.c     8 Sep 2014 06:24:13 -0000       1.227
+++ net/if_bridge.c     12 Nov 2014 01:40:03 -0000
@@ -1373,6 +1373,9 @@ bridge_input(struct ifnet *ifp, struct e
                if (mc == NULL)
                        return (m);
                bcopy(eh, mtod(mc, caddr_t), ETHER_HDR_LEN);
+               if (m->m_flags & M_VLANTAG)
+                       mc->m_flags |= M_VLANTAG;
+
                s = splnet();
                if (IF_QFULL(&sc->sc_if.if_snd)) {
                        m_freem(mc);
@@ -2064,12 +2067,13 @@ bridge_blocknonip(struct ether_header *e
        if (m->m_pkthdr.len < ETHER_HDR_LEN)
                return (1);
 
+       etype = ntohs(eh->ether_type);
 #if NVLAN > 0
-       if (m->m_flags & M_VLANTAG)
+       if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN ||
+           etype == ETHERTYPE_QINQ)
                return (1);
 #endif
 
-       etype = ntohs(eh->ether_type);
        switch (etype) {
        case ETHERTYPE_ARP:
        case ETHERTYPE_REVARP:
@@ -2399,12 +2403,12 @@ bridge_ip(struct bridge_softc *sc, int d
        int hlen;
        u_int16_t etype;
 
+       etype = ntohs(eh->ether_type);
 #if NVLAN > 0
-       if (m->m_flags & M_VLANTAG)
+       if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN ||
+           etype == ETHERTYPE_QINQ)
                return (m);
 #endif
-
-       etype = ntohs(eh->ether_type);
 
        if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) {
                if (etype > ETHERMTU ||
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.177
diff -u -p -r1.177 if_ethersubr.c
--- net/if_ethersubr.c  6 Nov 2014 14:28:47 -0000       1.177
+++ net/if_ethersubr.c  12 Nov 2014 01:40:03 -0000
@@ -552,7 +552,7 @@ ether_input(struct ifnet *ifp0, struct e
 
 #if NVLAN > 0
        if (((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN ||
-           etype == ETHERTYPE_QINQ) && (vlan_input(eh, m) == 0))
+           etype == ETHERTYPE_QINQ) && (vlan_input(eh, m, &ifp) == 0))
                return;
 #endif
 
Index: net/if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.109
diff -u -p -r1.109 if_vlan.c
--- net/if_vlan.c       7 Oct 2014 11:16:23 -0000       1.109
+++ net/if_vlan.c       12 Nov 2014 01:40:03 -0000
@@ -47,6 +47,7 @@
  * will not modify the ethernet header.
  */
 
+#include "bridge.h"
 #include "vlan.h"
 
 #include <sys/param.h>
@@ -272,7 +273,7 @@ vlan_start(struct ifnet *ifp)
  * vlan_input() returns 0 if it has consumed the packet, 1 otherwise.
  */
 int
-vlan_input(struct ether_header *eh, struct mbuf *m)
+vlan_input(struct ether_header *eh, struct mbuf *m, struct ifnet **ifp0)
 {
        struct ifvlan           *ifv;
        struct ifnet            *ifp = m->m_pkthdr.rcvif;
@@ -320,6 +321,21 @@ vlan_input(struct ether_header *eh, stru
         * reentrant!).
         */
        m->m_pkthdr.rcvif = &ifv->ifv_if;
+
+#if NBRIDGE > 0
+       /* If we are in a bridge, let it handle it */
+       if (ifv->ifv_if.if_bridgeport != NULL) {
+               *ifp0 = &ifv->ifv_if;
+#if NBPFILTER > 0
+               if (ifv->ifv_if.if_bpf)
+                       bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh,
+                           ETHER_HDR_LEN, m, BPF_DIRECTION_IN, NULL);
+#endif
+               ifv->ifv_if.if_ipackets++;
+               return (1);
+       }
+#endif
+
        if (m->m_flags & M_VLANTAG) {
                m->m_flags &= ~M_VLANTAG;
        } else {
Index: net/if_vlan_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_vlan_var.h,v
retrieving revision 1.24
diff -u -p -r1.24 if_vlan_var.h
--- net/if_vlan_var.h   24 Oct 2013 11:14:33 -0000      1.24
+++ net/if_vlan_var.h   12 Nov 2014 01:40:03 -0000
@@ -95,7 +95,7 @@ struct        ifvlan {
 #define        ifv_type        ifv_mib.ifvm_type
 #define        IFVF_PROMISC    0x01
 
-extern int vlan_input(struct ether_header *eh, struct mbuf *m);
+int vlan_input(struct ether_header *, struct mbuf *, struct ifnet **);
 #endif /* _KERNEL */
 
 #endif /* _NET_IF_VLAN_VAR_H_ */

Reply via email to