Unify vlan_input() and vlan_input_tag():
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 16 May 2008 13:19:12 +0000 (13:19 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 16 May 2008 13:19:12 +0000 (13:19 +0000)
- For device drivers that support hardware vlan tag extraction, mbuf's
  M_VLANTAG is turned on and vlan tag is saved in mbuf.m_pkthdr.ether_vlantag
- At the very beginning of ether_input_chain(), if the packet's ether type is
  vlan and hardware does not extract vlan tag, vlan_ether_decap() is called to
  do software vlan tag extraction.
- Instead of BPF_MTAP(), ETHER_BPF_MTAP() is used in ether_input_chain() to
  deliver possible vlan tagging information to the bpf listeners.
- Ether header is restored before calling vlan_input(), so under most cases,
  extra ether header copy is avoided.  vlan_input() does nothing more than
  finding vlan interface and looping back the packet to ether_input_chain()
  with vlan interface as input interface.

Ideas-from: FreeBSD

14 files changed:
sys/dev/netif/bce/if_bce.c
sys/dev/netif/bge/if_bge.c
sys/dev/netif/em/if_em.c
sys/dev/netif/nge/if_nge.c
sys/dev/netif/re/if_re.c
sys/dev/netif/stge/if_stge.c
sys/dev/netif/ti/if_ti.c
sys/dev/netif/txp/if_txp.c
sys/dev/netif/vge/if_vge.c
sys/net/ethernet.h
sys/net/if_ethersubr.c
sys/net/vlan/if_vlan.c
sys/net/vlan/if_vlan_ether.c
sys/net/vlan/if_vlan_ether.h

index 81f3453..f0560c1 100644 (file)
@@ -28,7 +28,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/bce/if_bce.c,v 1.31 2007/05/16 23:34:11 davidch Exp $
- * $DragonFly: src/sys/dev/netif/bce/if_bce.c,v 1.4 2008/05/14 11:59:18 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/bce/if_bce.c,v 1.5 2008/05/16 13:19:11 sephe Exp $
  */
 
 /*
@@ -3925,10 +3925,12 @@ bce_rx_int_next_rx:
                        DBPRINT(sc, BCE_VERBOSE_RECV,
                                "%s(): Passing received frame up.\n", __func__);
 
-                       if (status & L2_FHDR_STATUS_L2_VLAN_TAG)
-                               VLAN_INPUT_TAG(m, l2fhdr->l2_fhdr_vlan_tag);
-                       else
-                               ifp->if_input(ifp, m);
+                       if (status & L2_FHDR_STATUS_L2_VLAN_TAG) {
+                               m->m_flags |= M_VLANTAG;
+                               m->m_pkthdr.ether_vlantag =
+                                       l2fhdr->l2_fhdr_vlan_tag;
+                       }
+                       ifp->if_input(ifp, m);
 
                        DBRUNIF(1, sc->rx_mbuf_alloc--);
                }
index a577138..a6da7d2 100644 (file)
@@ -31,7 +31,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/bge/if_bge.c,v 1.3.2.39 2005/07/03 03:41:18 silby Exp $
- * $DragonFly: src/sys/dev/netif/bge/if_bge.c,v 1.91 2008/05/14 11:59:18 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/bge/if_bge.c,v 1.92 2008/05/16 13:19:11 sephe Exp $
  *
  */
 
@@ -2303,11 +2303,11 @@ bge_rxeof(struct bge_softc *sc)
                 * to vlan_input() instead of ether_input().
                 */
                if (have_tag) {
-                       VLAN_INPUT_TAG(m, vlan_tag);
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag = vlan_tag;
                        have_tag = vlan_tag = 0;
-               } else {
-                       ifp->if_input(ifp, m);
                }
+               ifp->if_input(ifp, m);
        }
 
        if (stdcnt > 0) {
index 9aebb86..e1a4c2e 100644 (file)
@@ -64,7 +64,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/dev/netif/em/if_em.c,v 1.71 2008/05/14 11:59:19 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/em/if_em.c,v 1.72 2008/05/16 13:19:11 sephe Exp $
  * $FreeBSD$
  */
 /*
@@ -3114,17 +3114,16 @@ em_rxeof(struct adapter *adapter, int count)
                                em_receive_checksum(adapter, current_desc,
                                                    adapter->fmp);
                                if (current_desc->status & E1000_RXD_STAT_VP) {
-                                       VLAN_INPUT_TAG(adapter->fmp,
-                                                      (current_desc->special & 
-                                                       E1000_RXD_SPC_VLAN_MASK));
-                               } else {
+                                       adapter->fmp->m_flags |= M_VLANTAG;
+                                       adapter->fmp->m_pkthdr.ether_vlantag =
+                                               (current_desc->special &
+                                                E1000_RXD_SPC_VLAN_MASK);
+                               }
 #ifdef ETHER_INPUT_CHAIN
-                                       ether_input_chain(ifp, adapter->fmp,
-                                                         chain);
+                               ether_input_chain(ifp, adapter->fmp, chain);
 #else
-                                       ifp->if_input(ifp, adapter->fmp);
+                               ifp->if_input(ifp, adapter->fmp);
 #endif
-                               }
                                adapter->fmp = NULL;
                                adapter->lmp = NULL;
                        }
index df0f62e..4ba86bc 100644 (file)
@@ -31,7 +31,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/nge/if_nge.c,v 1.13.2.13 2003/02/05 22:03:57 mbr Exp $
- * $DragonFly: src/sys/dev/netif/nge/if_nge.c,v 1.47 2008/05/14 11:59:21 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/nge/if_nge.c,v 1.48 2008/05/16 13:19:12 sephe Exp $
  */
 
 /*
@@ -1287,10 +1287,12 @@ nge_rxeof(struct nge_softc *sc)
                 * If we received a packet with a vlan tag, pass it
                 * to vlan_input() instead of ether_input().
                 */
-               if (extsts & NGE_RXEXTSTS_VLANPKT)
-                       VLAN_INPUT_TAG(m, extsts & NGE_RXEXTSTS_VTCI);
-               else
-                       ifp->if_input(ifp, m);
+               if (extsts & NGE_RXEXTSTS_VLANPKT) {
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag =
+                               (extsts & NGE_RXEXTSTS_VTCI);
+               }
+               ifp->if_input(ifp, m);
        }
 
        sc->nge_cdata.nge_rx_prod = i;
index 78c8979..510193f 100644 (file)
@@ -33,7 +33,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/re/if_re.c,v 1.25 2004/06/09 14:34:01 naddy Exp $
- * $DragonFly: src/sys/dev/netif/re/if_re.c,v 1.42 2008/05/14 11:59:21 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/re/if_re.c,v 1.43 2008/05/16 13:19:12 sephe Exp $
  */
 
 /*
@@ -1612,11 +1612,11 @@ re_rxeof(struct re_softc *sc)
                }
 
                if (rxvlan & RE_RDESC_VLANCTL_TAG) {
-                       VLAN_INPUT_TAG(m,
-                          be16toh((rxvlan & RE_RDESC_VLANCTL_DATA)));
-               } else {
-                       ifp->if_input(ifp, m);
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag =
+                               be16toh((rxvlan & RE_RDESC_VLANCTL_DATA));
                }
+               ifp->if_input(ifp, m);
        }
 
        /* Flush the RX DMA ring */
index e788306..bc9509e 100644 (file)
@@ -1,6 +1,6 @@
 /*     $NetBSD: if_stge.c,v 1.32 2005/12/11 12:22:49 christos Exp $    */
 /*     $FreeBSD: src/sys/dev/stge/if_stge.c,v 1.2 2006/08/12 01:21:36 yongari Exp $    */
-/*     $DragonFly: src/sys/dev/netif/stge/if_stge.c,v 1.5 2008/05/14 11:59:22 sephe Exp $      */
+/*     $DragonFly: src/sys/dev/netif/stge/if_stge.c,v 1.6 2008/05/16 13:19:12 sephe Exp $      */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -1801,11 +1801,11 @@ stge_rxeof(struct stge_softc *sc, int count)
                        /* Check for VLAN tagged packets. */
                        if ((status & RFD_VLANDetected) != 0 &&
                            (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
-                               VLAN_INPUT_TAG(m, RFD_TCI(status64));
-                       } else {
-                               /* Pass it on. */
-                               ifp->if_input(ifp, m);
+                               m->m_flags |= M_VLANTAG;
+                               m->m_pkthdr.ether_vlantag = RFD_TCI(status64);
                        }
+                       /* Pass it on. */
+                       ifp->if_input(ifp, m);
 
                        STGE_RXCHAIN_RESET(sc);
                }
index 5d46cc8..35a3b8b 100644 (file)
@@ -30,7 +30,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/pci/if_ti.c,v 1.25.2.14 2002/02/15 04:20:20 silby Exp $
- * $DragonFly: src/sys/dev/netif/ti/if_ti.c,v 1.51 2008/05/14 11:59:22 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/ti/if_ti.c,v 1.52 2008/05/16 13:19:12 sephe Exp $
  */
 
 /*
@@ -1702,14 +1702,11 @@ ti_rxeof(struct ti_softc *sc)
                        m->m_pkthdr.csum_data = cur_rx->ti_tcp_udp_cksum;
                }
 
-               /*
-                * If we received a packet with a vlan tag, pass it
-                * to vlan_input() instead of ether_input().
-                */
-               if (have_tag)
-                       VLAN_INPUT_TAG(m, vlan_tag);
-               else
-                       ifp->if_input(ifp, m);
+               if (have_tag) {
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag = vlan_tag;
+               }
+               ifp->if_input(ifp, m);
        }
 
        /* Only necessary on the Tigon 1. */
index edb5073..2629317 100644 (file)
@@ -1,6 +1,6 @@
 /*     $OpenBSD: if_txp.c,v 1.48 2001/06/27 06:34:50 kjc Exp $ */
 /*     $FreeBSD: src/sys/dev/txp/if_txp.c,v 1.4.2.4 2001/12/14 19:50:43 jlemon Exp $ */
-/*     $DragonFly: src/sys/dev/netif/txp/if_txp.c,v 1.48 2008/05/14 11:59:22 sephe Exp $ */
+/*     $DragonFly: src/sys/dev/netif/txp/if_txp.c,v 1.49 2008/05/16 13:19:12 sephe Exp $ */
 
 /*
  * Copyright (c) 2001
@@ -724,10 +724,11 @@ txp_rx_reclaim(struct txp_softc *sc, struct txp_rx_ring *r)
                        m->m_pkthdr.csum_data = 0xffff;
                }
 
-               if (rxd->rx_stat & RX_STAT_VLAN)
-                       VLAN_INPUT_TAG(m, htons(rxd->rx_vlan >> 16));
-               else
-                       ifp->if_input(ifp, m);
+               if (rxd->rx_stat & RX_STAT_VLAN) {
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag = htons(rxd->rx_vlan >> 16);
+               }
+               ifp->if_input(ifp, m);
 
 next:
 
index 8662788..53d2173 100644 (file)
@@ -30,7 +30,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/dev/vge/if_vge.c,v 1.24 2006/02/14 12:44:56 glebius Exp $
- * $DragonFly: src/sys/dev/netif/vge/if_vge.c,v 1.8 2008/05/14 11:59:22 sephe Exp $
+ * $DragonFly: src/sys/dev/netif/vge/if_vge.c,v 1.9 2008/05/16 13:19:12 sephe Exp $
  */
 
 /*
@@ -1386,10 +1386,12 @@ vge_rxeof(struct vge_softc *sc, int count)
                        }
                }
 
-               if (rxstat & VGE_RDSTS_VTAG)
-                       VLAN_INPUT_TAG(m, ntohs((rxctl & VGE_RDCTL_VLANID)));
-               else
-                       ifp->if_input(ifp, m);
+               if (rxstat & VGE_RDSTS_VTAG) {
+                       m->m_flags |= M_VLANTAG;
+                       m->m_pkthdr.ether_vlantag =
+                               ntohs((rxctl & VGE_RDCTL_VLANID));
+               }
+               ifp->if_input(ifp, m);
 
                lim++;
                if (lim == VGE_RX_DESC_CNT)
index ac5f341..529cfee 100644 (file)
@@ -2,7 +2,7 @@
  * Fundamental constants relating to ethernet.
  *
  * $FreeBSD: src/sys/net/ethernet.h,v 1.12.2.8 2002/12/01 14:03:09 sobomax Exp $
- * $DragonFly: src/sys/net/ethernet.h,v 1.17 2008/03/19 14:46:03 sephe Exp $
+ * $DragonFly: src/sys/net/ethernet.h,v 1.18 2008/05/16 13:19:12 sephe Exp $
  *
  */
 
@@ -358,6 +358,7 @@ extern const uint8_t        etherbroadcastaddr[ETHER_ADDR_LEN];
 
 struct ifnet;
 struct mbuf;
+struct mbuf_chain;
 
 extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
 extern void (*ng_ether_input_orphan_p)(struct ifnet *ifp,
@@ -366,19 +367,7 @@ extern     int  (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
 extern void (*ng_ether_attach_p)(struct ifnet *ifp);
 extern void (*ng_ether_detach_p)(struct ifnet *ifp);
 
-extern int (*vlan_input_p)(const struct ether_header *eh, struct mbuf *m);
-extern int (*vlan_input_tag_p)(struct mbuf *m, uint16_t t);
-
-#define VLAN_INPUT_TAG(m, t) do {                      \
-       /* XXX: lock */                                 \
-       if (vlan_input_tag_p != NULL)                   \
-               (*vlan_input_tag_p)(m, t);              \
-       else {                                          \
-               (m)->m_pkthdr.rcvif->if_noproto++;      \
-               m_freem(m);                             \
-        }                                              \
-       /* XXX: unlock */                               \
-} while (0)
+extern int (*vlan_input_p)(struct mbuf *m, struct mbuf_chain *chain);
 
 /*
  * The ETHER_BPF_MTAP macro should be used by drivers which support hardware
index 0a9dd5a..9443f6f 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)if_ethersubr.c      8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/if_ethersubr.c,v 1.70.2.33 2003/04/28 15:45:53 archie Exp $
- * $DragonFly: src/sys/net/if_ethersubr.c,v 1.59 2008/05/14 11:59:23 sephe Exp $
+ * $DragonFly: src/sys/net/if_ethersubr.c,v 1.60 2008/05/16 13:19:12 sephe Exp $
  */
 
 #include "opt_atalk.h"
@@ -65,6 +65,7 @@
 #include <net/ifq_var.h>
 #include <net/bpf.h>
 #include <net/ethernet.h>
+#include <net/vlan/if_vlan_ether.h>
 
 #if defined(INET) || defined(INET6)
 #include <netinet/in.h>
@@ -117,8 +118,7 @@ int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
 void   (*ng_ether_attach_p)(struct ifnet *ifp);
 void   (*ng_ether_detach_p)(struct ifnet *ifp);
 
-int    (*vlan_input_p)(const struct ether_header *eh, struct mbuf *m);
-int    (*vlan_input_tag_p)(struct mbuf *m, uint16_t t);
+int    (*vlan_input_p)(struct mbuf *, struct mbuf_chain *);
 
 static int ether_output(struct ifnet *, struct mbuf *, struct sockaddr *,
                        struct rtentry *);
@@ -555,6 +555,17 @@ ether_input_chain(struct ifnet *ifp, struct mbuf *m, struct mbuf_chain *chain)
        }
        eh = mtod(m, struct ether_header *);
 
+       if (ntohs(eh->ether_type) == ETHERTYPE_VLAN &&
+           (m->m_flags & M_VLANTAG) == 0) {
+               /*
+                * Extract vlan tag if hardware does not do it for us
+                */
+               vlan_ether_decap(&m);
+               if (m == NULL)
+                       return;
+               eh = mtod(m, struct ether_header *);
+       }
+
        m->m_pkthdr.rcvif = ifp;
 
        if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
@@ -566,7 +577,7 @@ ether_input_chain(struct ifnet *ifp, struct mbuf *m, struct mbuf_chain *chain)
                ifp->if_imcasts++;
        }
 
-       BPF_MTAP(ifp, m);
+       ETHER_BPF_MTAP(ifp, m);
 
        ifp->if_ibytes += m->m_pkthdr.len;
 
@@ -700,10 +711,31 @@ post_stats:
                        return;
                }
        }
-       eh = NULL; /* catch any further usage */
 
        ether_type = ntohs(save_eh.ether_type);
 
+       if (m->m_flags & M_VLANTAG) {
+               if (ether_type == ETHERTYPE_VLAN) {
+                       /*
+                        * To prevent possible dangerous recursion,
+                        * we don't do vlan-in-vlan
+                        */
+                       m->m_pkthdr.rcvif->if_noproto++;
+                       m_freem(m);
+               }
+
+               if (vlan_input_p != NULL) {
+                       ether_restore_header(&m, eh, &save_eh);
+                       if (m != NULL)
+                               vlan_input_p(m, chain);
+               } else {
+                       m->m_pkthdr.rcvif->if_noproto++;
+                       m_freem(m);
+               }
+               return;
+       }
+       KKASSERT(ether_type != ETHERTYPE_VLAN);
+
        switch (ether_type) {
 #ifdef INET
        case ETHERTYPE_IP:
@@ -752,15 +784,6 @@ post_stats:
                break;
 #endif
 
-       case ETHERTYPE_VLAN:
-               if (vlan_input_p != NULL) {
-                       (*vlan_input_p)(&save_eh, m);
-               } else {
-                       m->m_pkthdr.rcvif->if_noproto++;
-                       m_freem(m);
-               }
-               return;
-
        default:
 #ifdef IPX
                if (ef_inputp && ef_inputp(ifp, &save_eh, m) == 0)
index 8a4d050..1371d35 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/net/if_vlan.c,v 1.15.2.13 2003/02/14 22:25:58 fenner Exp $
- * $DragonFly: src/sys/net/vlan/if_vlan.c,v 1.31 2008/03/18 14:12:45 sephe Exp $
+ * $DragonFly: src/sys/net/vlan/if_vlan.c,v 1.32 2008/05/16 13:19:12 sephe Exp $
  */
 
 /*
  * ether_output() left on our output queue queue when it calls
  * if_start(), rewrite them for use by the real outgoing interface,
  * and ask it to send them.
- *
- *
- * XXX It's incorrect to assume that we must always kludge up
- * headers on the physical device's behalf: some devices support
- * VLAN tag insertion and extraction in firmware. For these cases,
- * one can change the behavior of the vlan interface by setting
- * the LINK0 flag on it (that is setting the vlan interface's LINK0
- * flag, _not_ the parent's LINK0 flag; we try to leave the parent
- * alone). If the interface has the LINK0 flag set, then it will
- * not modify the ethernet header on output, because the parent
- * can do that for itself. On input, the parent can call vlan_input_tag()
- * directly in order to supply us with an incoming mbuf and the vlan
- * tag value that goes with it.
  */
 
 #ifndef NVLAN
@@ -147,8 +134,7 @@ static void vlan_init(void *);
 static void    vlan_start(struct ifnet *);
 static int     vlan_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
 
-static int     vlan_input(const struct ether_header *eh, struct mbuf *m);
-static int     vlan_input_tag(struct mbuf *m, uint16_t t);
+static int     vlan_input(struct mbuf *m, struct mbuf_chain *);
 
 static void    vlan_clrmulti(struct ifvlan *, struct ifnet *);
 static int     vlan_setmulti(struct ifvlan *, struct ifnet *);
@@ -265,7 +251,6 @@ vlan_modevent(module_t mod, int type, void *data)
        case MOD_LOAD:
                LIST_INIT(&ifv_list);
                vlan_input_p = vlan_input;
-               vlan_input_tag_p = vlan_input_tag;
                vlan_ifdetach_cookie =
                EVENTHANDLER_REGISTER(ifnet_detach_event,
                                      vlan_ifdetach, NULL,
@@ -276,7 +261,6 @@ vlan_modevent(module_t mod, int type, void *data)
        case MOD_UNLOAD:
                if_clone_detach(&vlan_cloner);
                vlan_input_p = NULL;
-               vlan_input_tag_p = NULL;
                EVENTHANDLER_DEREGISTER(ifnet_detach_event,
                                        vlan_ifdetach_cookie);
                while (!LIST_EMPTY(&ifv_list))
@@ -457,93 +441,58 @@ vlan_start(struct ifnet *ifp)
 }
 
 static int
-vlan_input_tag(struct mbuf *m, uint16_t t)
+vlan_input(struct mbuf *m, struct mbuf_chain *chain)
 {
-       struct bpf_if *bif;
-       struct ifvlan *ifv;
+       struct ifvlan *ifv = NULL;
        struct ifnet *rcvif;
+       struct vlan_trunk *vlantrunks;
+       struct vlan_entry *entry;
 
        rcvif = m->m_pkthdr.rcvif;
-
        ASSERT_SERIALIZED(rcvif->if_serializer);
+       KKASSERT(m->m_flags & M_VLANTAG);
 
-       /*
-        * Fake up a header and send the packet to the physical interface's
-        * bpf tap if active.
-        */
-       if ((bif = rcvif->if_bpf) != NULL)
-               vlan_ether_ptap(bif, m, t);
-
-       for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
-           ifv = LIST_NEXT(ifv, ifv_list)) {
-               if (rcvif == ifv->ifv_p && ifv->ifv_tag == t)
-                       break;
-       }
-
-       if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
+       vlantrunks = rcvif->if_vlantrunks;
+       if (vlantrunks == NULL) {
+               rcvif->if_noproto++;
                m_freem(m);
-               return -1;      /* So the parent can take note */
+               return -1;
        }
 
-       /*
-        * Having found a valid vlan interface corresponding to
-        * the given source interface and vlan tag, run the
-        * the real packet through ether_input().
-        */
-       m->m_pkthdr.rcvif = &ifv->ifv_if;
-
-       ifv->ifv_if.if_ipackets++;
-       lwkt_serialize_exit(rcvif->if_serializer);
-       lwkt_serialize_enter(ifv->ifv_if.if_serializer);
-       ether_input(&ifv->ifv_if, m);
-       lwkt_serialize_exit(ifv->ifv_if.if_serializer);
-       lwkt_serialize_enter(rcvif->if_serializer);
-       return 0;
-}
-
-static int
-vlan_input(const struct ether_header *eh, struct mbuf *m)
-{
-       struct ifvlan *ifv;
-       struct ifnet *rcvif;
-       struct ether_header eh_copy;
-
-       rcvif = m->m_pkthdr.rcvif;
-       ASSERT_SERIALIZED(rcvif->if_serializer);
-
-       for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
-           ifv = LIST_NEXT(ifv, ifv_list)) {
-               if (rcvif == ifv->ifv_p
-                   && (EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)))
-                       == ifv->ifv_tag))
+       crit_enter();
+       LIST_FOREACH(entry, &vlantrunks[mycpuid].vlan_list, ifv_link) {
+               if (entry->ifv->ifv_tag ==
+                   EVL_VLANOFTAG(m->m_pkthdr.ether_vlantag)) {
+                       ifv = entry->ifv;
                        break;
+               }
        }
+       crit_exit();
 
-       if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
+       /*
+        * Packet is discarded if:
+        * - no corresponding vlan(4) interface
+        * - vlan(4) interface has not been completely set up yet,
+        *   or is being destroyed (ifv->ifv_p != rcvif)
+        * - vlan(4) interface is not brought up
+        */
+       if (ifv == NULL || ifv->ifv_p != rcvif ||
+           (ifv->ifv_if.if_flags & IFF_UP) == 0) {
                rcvif->if_noproto++;
                m_freem(m);
                return -1;      /* so ether_input can take note */
        }
 
        /*
-        * Having found a valid vlan interface corresponding to
-        * the given source interface and vlan tag, remove the
-        * remaining encapsulation (ether_vlan_header minus the ether_header
-        * that had already been removed) and run the real packet
-        * through ether_input() a second time (it had better be
-        * reentrant!).
+        * Clear M_VLANTAG, before the packet is handed to
+        * vlan(4) interface
         */
-       eh_copy = *eh;
-       eh_copy.ether_type = mtod(m, u_int16_t *)[1];   /* evl_proto */
-       m->m_pkthdr.rcvif = &ifv->ifv_if;
-       m_adj(m, EVL_ENCAPLEN);
-       M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT); 
-       *(struct ether_header *)mtod(m, void *) = eh_copy;
+       m->m_flags &= ~M_VLANTAG;
 
        ifv->ifv_if.if_ipackets++;
        lwkt_serialize_exit(rcvif->if_serializer);
        lwkt_serialize_enter(ifv->ifv_if.if_serializer);
-       ether_input(&ifv->ifv_if, m);
+       ether_input_chain(&ifv->ifv_if, m, chain);
        lwkt_serialize_exit(ifv->ifv_if.if_serializer);
        lwkt_serialize_enter(rcvif->if_serializer);
        return 0;
index 1ea06b1..ba06d81 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/net/if_vlan.c,v 1.15.2.13 2003/02/14 22:25:58 fenner Exp $
- * $DragonFly: src/sys/net/vlan/if_vlan_ether.c,v 1.2 2008/03/10 11:44:57 sephe Exp $
+ * $DragonFly: src/sys/net/vlan/if_vlan_ether.c,v 1.3 2008/05/16 13:19:12 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -144,3 +144,28 @@ vlan_ether_ptap(struct bpf_if *bp, struct mbuf *m, uint16_t vlantag)
        /* XXX assumes data was left intact */
        M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT);
 }
+
+void
+vlan_ether_decap(struct mbuf **m0)
+{
+       struct mbuf *m = *m0;
+       struct ether_vlan_header *evh;
+
+       KKASSERT((m->m_flags & M_VLANTAG) == 0);
+
+       if (m->m_len < sizeof(*evh)) {
+               /* Error in the caller */
+               m_freem(m);
+               *m0 = NULL;
+               return;
+       }
+       evh = mtod(m, struct ether_vlan_header *);
+
+       m->m_pkthdr.ether_vlantag = ntohs(evh->evl_tag);
+       m->m_flags |= M_VLANTAG;
+
+       bcopy((uint8_t *)evh, (uint8_t *)evh + EVL_ENCAPLEN,
+             2 * ETHER_ADDR_LEN);
+       m_adj(m, EVL_ENCAPLEN);
+       *m0 = m;
+}
index c3d0f7f..13d1860 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/net/if_vlan_var.h,v 1.5.2.3 2001/12/04 20:01:54 brooks Exp $
- * $DragonFly: src/sys/net/vlan/if_vlan_ether.h,v 1.1 2008/03/10 11:44:57 sephe Exp $
+ * $DragonFly: src/sys/net/vlan/if_vlan_ether.h,v 1.2 2008/05/16 13:19:12 sephe Exp $
  */
 
 #ifndef _NET_IF_VLAN_ETHER_H_
@@ -41,6 +41,7 @@ struct mbuf;
 
 void   vlan_start_dispatch(struct netmsg *);
 void   vlan_ether_ptap(struct bpf_if *, struct mbuf *, uint16_t);
+void   vlan_ether_decap(struct mbuf **);
 
 #endif /* _KERNEL */