Source-Changes-HG archive

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

[src/trunk]: src/sys/net bridge(4): support VLAN frames stripped by hardware ...



details:   https://anonhg.NetBSD.org/src/rev/22f8295bfced
branches:  trunk
changeset: 367259:22f8295bfced
user:      yamaguchi <yamaguchi%NetBSD.org@localhost>
date:      Mon Jun 20 08:14:48 2022 +0000

description:
bridge(4): support VLAN frames stripped by hardware tagging

diffstat:

 sys/net/if_bridge.c    |   18 ++++-
 sys/net/if_ether.h     |   28 ++++++--
 sys/net/if_ethersubr.c |  135 ++++++++++++++++++++++++++++++++++++-----
 sys/net/if_vlan.c      |  159 ++++--------------------------------------------
 4 files changed, 168 insertions(+), 172 deletions(-)

diffs (truncated from 484 to 300 lines):

diff -r f49f6d25ad73 -r 22f8295bfced sys/net/if_bridge.c
--- a/sys/net/if_bridge.c       Mon Jun 20 08:09:13 2022 +0000
+++ b/sys/net/if_bridge.c       Mon Jun 20 08:14:48 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_bridge.c,v 1.186 2021/12/31 14:25:24 riastradh Exp $        */
+/*     $NetBSD: if_bridge.c,v 1.187 2022/06/20 08:14:48 yamaguchi Exp $        */
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.186 2021/12/31 14:25:24 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.187 2022/06/20 08:14:48 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1502,6 +1502,16 @@
        KERNEL_UNLOCK_ONE(NULL);
 #endif /* ALTQ */
 
+       if (vlan_has_tag(m) &&
+           !vlan_is_hwtag_enabled(dst_ifp)) {
+               (void)ether_inject_vlantag(&m, ETHERTYPE_VLAN,
+                   vlan_get_tag(m));
+               if (m == NULL) {
+                       if_statinc(&sc->sc_if, if_oerrors);
+                       return;
+               }
+       }
+
        len = m->m_pkthdr.len;
        mflags = m->m_flags;
 
@@ -2704,6 +2714,10 @@
                }
        }
 
+       /* drop VLAN traffic untagged by hardware offloading */
+       if (vlan_has_tag(*mp))
+               goto bad;
+
        /*
         * If we're trying to filter bridge traffic, don't look at anything
         * other than IP and ARP traffic.  If the filter doesn't understand
diff -r f49f6d25ad73 -r 22f8295bfced sys/net/if_ether.h
--- a/sys/net/if_ether.h        Mon Jun 20 08:09:13 2022 +0000
+++ b/sys/net/if_ether.h        Mon Jun 20 08:14:48 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ether.h,v 1.88 2021/11/15 07:07:05 yamaguchi Exp $  */
+/*     $NetBSD: if_ether.h,v 1.89 2022/06/20 08:14:48 yamaguchi Exp $  */
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -364,12 +364,6 @@
        return;
 }
 
-static __inline bool
-vlan_has_tag(struct mbuf *m)
-{
-       return (m->m_flags & M_VLANTAG) != 0;
-}
-
 /* extract VLAN ID value from a VLAN tag */
 static __inline uint16_t
 vlan_get_tag(struct mbuf *m)
@@ -379,6 +373,23 @@
        return m->m_pkthdr.ether_vtag;
 }
 
+static __inline bool
+vlan_has_tag(struct mbuf *m)
+{
+       return (m->m_flags & M_VLANTAG) != 0;
+}
+
+static __inline bool
+vlan_is_hwtag_enabled(struct ifnet *_ifp)
+{
+       struct ethercom *ec = (void *)_ifp;
+
+       if (ec->ec_capenable & ETHERCAP_VLAN_HWTAGGING)
+               return true;
+
+       return false;
+}
+
 /* test if any VLAN is configured for this interface */
 #define VLAN_ATTACHED(ec)      ((ec)->ec_nvlans > 0)
 
@@ -403,6 +414,9 @@
 int    ether_disable_vlan_mtu(struct ifnet *);
 int    ether_add_vlantag(struct ifnet *, uint16_t, bool *);
 int    ether_del_vlantag(struct ifnet *, uint16_t);
+int    ether_inject_vlantag(struct mbuf **, uint16_t, uint16_t);
+struct mbuf *
+       ether_strip_vlantag(struct mbuf *);
 #else
 /*
  * Prototype ethers(3) functions.
diff -r f49f6d25ad73 -r 22f8295bfced sys/net/if_ethersubr.c
--- a/sys/net/if_ethersubr.c    Mon Jun 20 08:09:13 2022 +0000
+++ b/sys/net/if_ethersubr.c    Mon Jun 20 08:14:48 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_ethersubr.c,v 1.312 2022/06/20 08:02:25 yamaguchi Exp $     */
+/*     $NetBSD: if_ethersubr.c,v 1.313 2022/06/20 08:14:48 yamaguchi Exp $     */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.312 2022/06/20 08:02:25 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.313 2022/06/20 08:14:48 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -725,6 +725,18 @@
 
        if_statadd(ifp, if_ibytes, m->m_pkthdr.len);
 
+       if (!vlan_has_tag(m) && etype == ETHERTYPE_VLAN) {
+               m = ether_strip_vlantag(m);
+               if (m == NULL) {
+                       if_statinc(ifp, if_ierrors);
+                       return;
+               }
+
+               eh = mtod(m, struct ether_header *);
+               etype = ntohs(eh->ether_type);
+               ehlen = sizeof(*eh);
+       }
+
        if ((m->m_flags & (M_BCAST | M_MCAST | M_PROMISC)) == 0 &&
            (ifp->if_flags & IFF_PROMISC) != 0 &&
            memcmp(CLLADDR(ifp->if_sadl), eh->ether_dhost,
@@ -763,22 +775,9 @@
         * does not exist to take those frames, they're returned
         * to ether_input().
         */
-       if (vlan_has_tag(m) || etype == ETHERTYPE_VLAN) {
-               struct ether_vlan_header *evl = (void *)eh;
-               uint16_t vlan_id;
 
-               if (vlan_has_tag(m)) {
-                       vlan_id = EVL_VLANOFTAG(vlan_get_tag(m));
-               } else {
-                       if (m->m_len < sizeof(*evl))
-                               goto error;
-
-                       vlan_id = EVL_VLANOFTAG(ntohs(evl->evl_tag));
-                       etype = ntohs(evl->evl_proto);
-                       ehlen = sizeof(*evl);
-               }
-
-               if (vlan_id == 0) {
+       if (vlan_has_tag(m)) {
+               if (EVL_VLANOFTAG(vlan_get_tag(m)) == 0) {
                        if (etype == ETHERTYPE_VLAN ||
                             etype == ETHERTYPE_QINQ)
                                goto drop;
@@ -1747,6 +1746,108 @@
        return 0;
 }
 
+int
+ether_inject_vlantag(struct mbuf **mp, uint16_t etype, uint16_t tag)
+{
+       static const size_t min_data_len =
+           ETHER_MIN_LEN - ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN;
+       /* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
+       static const char vlan_zero_pad_buff[ETHER_MIN_LEN] = { 0 };
+
+       struct ether_vlan_header *evl;
+       struct mbuf *m = *mp;
+       int error;
+
+       error = 0;
+
+       M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
+       if (m == NULL) {
+               error = ENOBUFS;
+               goto out;
+       }
+
+       if (m->m_len < sizeof(*evl)) {
+               m = m_pullup(m, sizeof(*evl));
+               if (m == NULL) {
+                       error = ENOBUFS;
+                       goto out;
+               }
+       }
+
+       /*
+        * Transform the Ethernet header into an
+        * Ethernet header with 802.1Q encapsulation.
+        */
+       memmove(mtod(m, void *),
+           mtod(m, char *) + ETHER_VLAN_ENCAP_LEN,
+           sizeof(struct ether_header));
+       evl = mtod(m, struct ether_vlan_header *);
+       evl->evl_proto = evl->evl_encap_proto;
+       evl->evl_encap_proto = htons(etype);
+       evl->evl_tag = htons(tag);
+
+       /*
+        * To cater for VLAN-aware layer 2 ethernet
+        * switches which may need to strip the tag
+        * before forwarding the packet, make sure
+        * the packet+tag is at least 68 bytes long.
+        * This is necessary because our parent will
+        * only pad to 64 bytes (ETHER_MIN_LEN) and
+        * some switches will not pad by themselves
+        * after deleting a tag.
+        */
+       if (m->m_pkthdr.len < min_data_len) {
+               m_copyback(m, m->m_pkthdr.len,
+                   min_data_len - m->m_pkthdr.len,
+                   vlan_zero_pad_buff);
+       }
+
+       m->m_flags &= ~M_VLANTAG;
+
+out:
+       *mp = m;
+       return error;
+}
+
+struct mbuf *
+ether_strip_vlantag(struct mbuf *m)
+{
+       struct ether_vlan_header *evl;
+
+       if (m->m_len < sizeof(*evl) &&
+           (m = m_pullup(m, sizeof(*evl))) == NULL) {
+               return NULL;
+       }
+
+       if (m_makewritable(&m, 0, sizeof(*evl), M_DONTWAIT)) {
+               m_freem(m);
+               return NULL;
+       }
+
+       evl = mtod(m, struct ether_vlan_header *);
+       KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
+
+       vlan_set_tag(m, 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;
+
+       /*
+        * Remove the encapsulation header and append tag.
+        * The original header has already been fixed up above.
+        */
+       vlan_set_tag(m, ntohs(evl->evl_tag));
+       memmove((char *)evl + ETHER_VLAN_ENCAP_LEN, evl,
+           offsetof(struct ether_vlan_header, evl_encap_proto));
+       m_adj(m, ETHER_VLAN_ENCAP_LEN);
+
+       return m;
+}
+
 static int
 ether_multicast_sysctl(SYSCTLFN_ARGS)
 {
diff -r f49f6d25ad73 -r 22f8295bfced sys/net/if_vlan.c
--- a/sys/net/if_vlan.c Mon Jun 20 08:09:13 2022 +0000
+++ b/sys/net/if_vlan.c Mon Jun 20 08:14:48 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_vlan.c,v 1.169 2022/06/20 08:09:13 yamaguchi Exp $  */
+/*     $NetBSD: if_vlan.c,v 1.170 2022/06/20 08:14:48 yamaguchi Exp $  */
 
 /*
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.169 2022/06/20 08:09:13 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.170 2022/06/20 08:14:48 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -228,9 +228,6 @@
 struct if_clone vlan_cloner =
     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
 
-/* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
-static char vlan_zero_pad_buff[ETHER_MIN_LEN];
-
 static uint32_t nvlanifs;
 



Home | Main Index | Thread Index | Old Index