Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Supports hardware 802.1q VLAN tagging, per discussio...



details:   https://anonhg.NetBSD.org/src/rev/6285fccbcc51
branches:  trunk
changeset: 499344:6285fccbcc51
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Fri Nov 17 19:21:53 2000 +0000

description:
Supports hardware 802.1q VLAN tagging, per discussion on tech-net. The tag is
stored in a m_aux mbuf defined by AF_LINK, ETHERTYPE_VLAN.
Thanks to Jason & Itojun for the feedback.

diffstat:

 sys/net/if_ether.h     |    4 +-
 sys/net/if_ethersubr.c |   19 ++++-
 sys/net/if_vlan.c      |  180 ++++++++++++++++++++++++++++--------------------
 3 files changed, 125 insertions(+), 78 deletions(-)

diffs (292 lines):

diff -r eb3582a8e9cf -r 6285fccbcc51 sys/net/if_ether.h
--- a/sys/net/if_ether.h        Fri Nov 17 19:14:41 2000 +0000
+++ b/sys/net/if_ether.h        Fri Nov 17 19:21:53 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ether.h,v 1.20 2000/10/11 16:53:41 thorpej Exp $    */
+/*     $NetBSD: if_ether.h,v 1.21 2000/11/17 19:21:53 bouyer Exp $     */
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -154,7 +154,7 @@
 };
 
 #define        ETHERCAP_VLAN_MTU       0x00000001      /* VLAN-compatible MTU */
-#define        ETHERCAP_VLAN_TAGGING   0x00000002      /* VLAN tag support */
+#define        ETHERCAP_VLAN_HWTAGGING 0x00000002      /* hardware VLAN tag support */
 
 #ifdef _KERNEL
 extern u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN];
diff -r eb3582a8e9cf -r 6285fccbcc51 sys/net/if_ethersubr.c
--- a/sys/net/if_ethersubr.c    Fri Nov 17 19:14:41 2000 +0000
+++ b/sys/net/if_ethersubr.c    Fri Nov 17 19:21:53 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ethersubr.c,v 1.69 2000/11/15 01:02:15 thorpej Exp $        */
+/*     $NetBSD: if_ethersubr.c,v 1.70 2000/11/17 19:21:53 bouyer Exp $ */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -505,6 +505,7 @@
        u_int16_t etype;
        int s;
        struct ether_header *eh;
+       struct mbuf *n;
 #if defined (ISO) || defined (LLC) || defined(NETATALK)
        struct llc *l;
 #endif
@@ -543,6 +544,22 @@
                return;
        }
 
+       /* Check if the mbuf has a VLAN tag */
+       n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
+       if (n) {
+#if NVLAN > 0
+               /*
+                * vlan_input() will either recursively call ether_input()
+                * or drop the packet.
+                */
+               if (((struct ethercom *)ifp)->ec_nvlans != 0)
+                       vlan_input(ifp, m);
+               else
+#endif
+                       m_freem(m);
+               return;
+       }
+
        /*
         * Handle protocols that expect to have the Ethernet header
         * (and possibly FCS) intact.
diff -r eb3582a8e9cf -r 6285fccbcc51 sys/net/if_vlan.c
--- a/sys/net/if_vlan.c Fri Nov 17 19:14:41 2000 +0000
+++ b/sys/net/if_vlan.c Fri Nov 17 19:21:53 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_vlan.c,v 1.23 2000/11/15 18:15:11 bouyer Exp $      */
+/*     $NetBSD: if_vlan.c,v 1.24 2000/11/17 19:21:53 bouyer Exp $      */
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -665,6 +665,7 @@
 {
        struct ifvlan *ifv = ifp->if_softc;
        struct ifnet *p = ifv->ifv_p;
+       struct ethercom *ec = (void *) ifv->ifv_p;
        struct mbuf *m;
 
        ifp->if_flags |= IFF_OACTIVE;
@@ -678,51 +679,66 @@
                if (ifp->if_bpf)
                        bpf_mtap(ifp->if_bpf, m);
 #endif
-
                /*
-                * XXX Should handle the case where the underlying hardware
-                * interface can do VLAN tag insertion itself.
+                * If the parent can insert the tag itself, just mark
+                * the tag in the mbuf header.
                 */
-               M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
-               if (m == NULL) {
-                       printf("%s: unable to prepend encap header",
-                           ifv->ifv_p->if_xname);
-                       ifp->if_oerrors++;
-                       continue;
-               }
-
-               switch (p->if_type) {
-               case IFT_ETHER:
-                   {
-                       struct ether_vlan_header *evl;
-
-                       if (m->m_len < sizeof(struct ether_vlan_header) &&
-                           (m = m_pullup(m,
-                            sizeof(struct ether_vlan_header))) == NULL) {
-                               printf("%s: unable to pullup encap header",
+               if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
+                       struct mbuf *n;
+                       n = m_aux_add(m, AF_LINK, ETHERTYPE_VLAN);
+                       if (n == NULL) {
+                               ifp->if_oerrors++;
+                               m_freem(m);
+                               continue;
+                       }
+                       *mtod(n, int *) = ifv->ifv_tag;
+                       n->m_len = sizeof(int);
+               } else {
+                       /*
+                        * insert the tag ourselve
+                        */
+                       M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
+                       if (m == NULL) {
+                               printf("%s: unable to prepend encap header",
                                    ifv->ifv_p->if_xname);
                                ifp->if_oerrors++;
                                continue;
                        }
 
-                       /*
-                        * Transform the Ethernet header into an Ethernet
-                        * header with 802.1Q encapsulation.
-                        */
-                       memmove(mtod(m, caddr_t),
-                           mtod(m, caddr_t) + ifv->ifv_encaplen, 
-                           sizeof(struct ether_header));
-                       evl = mtod(m, struct ether_vlan_header *);
-                       evl->evl_proto = evl->evl_encap_proto;
-                       evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
-                       evl->evl_tag = htons(ifv->ifv_tag);
-                       break;
-                   }
+                       switch (p->if_type) {
+                       case IFT_ETHER:
+                           {
+                               struct ether_vlan_header *evl;
+
+                               if (m->m_len < sizeof(struct ether_vlan_header))
+                                       m = m_pullup(m,
+                                           sizeof(struct ether_vlan_header));
+                               if (m == NULL) {
+                                       printf("%s: unable to pullup encap "
+                                           "header", ifv->ifv_p->if_xname);
+                                       ifp->if_oerrors++;
+                                       continue;
+                               }
+
+                               /*
+                                * Transform the Ethernet header into an
+                                * Ethernet header with 802.1Q encapsulation.
+                                */
+                               memmove(mtod(m, caddr_t),
+                                   mtod(m, caddr_t) + ifv->ifv_encaplen, 
+                                   sizeof(struct ether_header));
+                               evl = mtod(m, struct ether_vlan_header *);
+                               evl->evl_proto = evl->evl_encap_proto;
+                               evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
+                               evl->evl_tag = htons(ifv->ifv_tag);
+                               break;
+                           }
 
 #ifdef DIAGNOSTIC
-               default:
-                       panic("vlan_start: impossible");
+                       default:
+                               panic("vlan_start: impossible");
 #endif
+                       }
                }
 
                /*
@@ -757,45 +773,68 @@
 {
        struct ifvlan *ifv;
        u_int tag;
+       struct mbuf *n;
 
-       switch (ifp->if_type) {
-       case IFT_ETHER:
-           {
-               struct ether_vlan_header *evl;
+       n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
+       if (n) {
+               /* m contains a normal ethernet frame, the tag is in m_aux */
+               tag = *mtod(n, int *);
+               m_aux_delete(m, n);
+               for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
+                   ifv = LIST_NEXT(ifv, ifv_list))
+                       if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
+                               break;
+       } else {
+               switch (ifp->if_type) {
+               case IFT_ETHER:
+                   {
+                       struct ether_vlan_header *evl;
 
-               if (m->m_len < sizeof(struct ether_vlan_header) &&
-                   (m = m_pullup(m,
-                    sizeof(struct ether_vlan_header))) == NULL) {
-                       printf("%s: no memory for VLAN header, "
-                           "dropping packet.\n", ifp->if_xname);
-                       return;
+                       if (m->m_len < sizeof(struct ether_vlan_header) &&
+                           (m = m_pullup(m,
+                            sizeof(struct ether_vlan_header))) == NULL) {
+                               printf("%s: no memory for VLAN header, "
+                                   "dropping packet.\n", ifp->if_xname);
+                               return;
+                       }
+                       evl = mtod(m, struct ether_vlan_header *);
+                       KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
+
+                       tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+
+                       /*
+                        * Restore the original ethertype.  We'll remove
+                        * the encapsulation after we've found the vlan
+                        * interface corresponding to the tag.
+                        */
+                       evl->evl_encap_proto = evl->evl_proto;
+                       break;
+                   }
+
+               default:
+                       tag = (u_int) -1;       /* XXX GCC */
+#ifdef DIAGNOSTIC
+                       panic("vlan_input: impossible");
+#endif
                }
-               evl = mtod(m, struct ether_vlan_header *);
-               KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
 
-               tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+               for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
+                    ifv = LIST_NEXT(ifv, ifv_list))
+                       if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
+                               break;
+
 
                /*
-                * Restore the original ethertype.  We'll remove
-                * the encapsulation after we've found the vlan
-                * interface corresponding to the tag.
+                * Now, remove the encapsulation header.  The original
+                * header has already been fixed up above.
                 */
-               evl->evl_encap_proto = evl->evl_proto;
-               break;
-           }
-
-       default:
-               tag = (u_int) -1;       /* XXX GCC */
-#ifdef DIAGNOSTIC
-               panic("vlan_input: impossible");
-#endif
+               if (ifv) {
+                       memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
+                           mtod(m, caddr_t), sizeof(struct ether_header));
+                       m_adj(m, ifv->ifv_encaplen);
+               }
        }
 
-       for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
-            ifv = LIST_NEXT(ifv, ifv_list))
-               if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
-                       break;
-
        if (ifv == NULL ||
            (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
             (IFF_UP|IFF_RUNNING)) {
@@ -803,15 +842,6 @@
                ifp->if_noproto++;
                return;
        }
-
-       /*
-        * Now, remove the encapsulation header.  The original
-        * header has already been fixed up above.
-        */
-       memmove(mtod(m, caddr_t) + ifv->ifv_encaplen, mtod(m, caddr_t),
-           sizeof(struct ether_header));
-       m_adj(m, ifv->ifv_encaplen);
-
        m->m_pkthdr.rcvif = &ifv->ifv_if;
        ifv->ifv_if.if_ipackets++;
 



Home | Main Index | Thread Index | Old Index