On Fri, 22 Aug 2008 02:34:12 +0700, Reyk Floeter <[EMAIL PROTECTED]> wrote:

On Thu, Aug 21, 2008 at 04:05:50PM +0200, Claudio Jeker wrote:
> no point in just doing that.
>
> a button to change the ether type would make sense.
>


this is not trivial because it would require a change in the Rx path
where it is currently matching the ethertype in ether_input() before
calling vlan_input().  do you want to call vlan_input() for every
other packet or do a configured type lookup all the time?  and what if
the user specifies an ethernet type that is conflicting with something
else?  i think it should really only be 0x8100 or 0x88a8.

If we stack vlan interfaces I don't see a real need for such a button.
This could be figured out either at configuration time or on runtime.
E.g. just check if the ethertype is 0x8100 and add the next vlan tag as
0x88a8. This would also allow to use a bridge for qinq setups. Because of
this I think doing it on runtime is the best.


here is another approach defining QinQ-compliant interfaces as a new
cloner type; so you can stack 0x88a8 devices as you wish and it
doesn't need a new button in ifconfig.  it also uses a dedicated vlan
tag hash for "Service VLANs" to avoid tag/Id conflicts.

# ifconfig em0 up
# ifconfig svlan100 vlandev em0
# ifconfig vlan200 vlandev svlan100 192.168.2.100

reyk

Index: share/man/man4/vlan.4
===================================================================
RCS file: /cvs/src/share/man/man4/vlan.4,v
retrieving revision 1.31
diff -u -p -r1.31 vlan.4
--- share/man/man4/vlan.4       26 Jun 2008 05:42:07 -0000      1.31
+++ share/man/man4/vlan.4       21 Aug 2008 19:18:42 -0000
@@ -31,8 +31,9 @@
 .Dt VLAN 4
 .Os
 .Sh NAME
-.Nm vlan
-.Nd "IEEE 802.1Q encapsulation/decapsulation pseudo-device"
+.Nm vlan ,
+.Nm svlan
+.Nd "IEEE 802.1Q/1AD encapsulation/decapsulation pseudo-devices"
 .Sh SYNOPSIS
 .Cd "pseudo-device vlan"
 .Sh DESCRIPTION
@@ -40,6 +41,10 @@ The
 .Nm
 Ethernet interface allows construction of virtual LANs when used in
 conjunction with IEEE 802.1Q-compliant Ethernet devices.
+The
+.Ic svlan
+Ethernet interface allows contruction of IEEE 802.1AD-compliant
+provider bridges.
 .Pp
 A
 .Nm
@@ -83,6 +88,24 @@ option for more information.
Following the vlan header is the actual ether type for the frame and length
 information.
 .Pp
+An
+.Ic svlan
+interface is normally used for QinQ in 802.1AD-compliant provider bridges to
+stack other
+.Nm
+interfaces on top of it.
+It can be created using the
+.Ic ifconfig svlan Ns Ar N Ic create
+command or by setting up a
+.Xr hostname.if 5
+configuration file for
+.Xr netstart 8 .
+The configuration is identical to the
+.Nm
+interface, the only differences are that it uses a different Ethernet
+type (0x88a8) and an independent VLAN Id space on the parent
+interface.
+.Pp
 .Nm
 interfaces support the following unique
 .Xr ioctl 2 Ns s :
@@ -104,7 +127,10 @@ interfaces use the following interface c
 The parent interface can handle full sized frames, plus the size
 of the vlan tag.
 .It IFCAP_VLAN_HWTAGGING
-The parent interface will participate in the tagging of frames.
+The parent interface will participate in the tagging of frames
+(This is not supported by
+.Ic svlan
+interfaces).
 .El
 .Sh DIAGNOSTICS
 .Bl -diag
@@ -150,6 +176,10 @@ and
 .Rs
 .%T IEEE 802.1Q standard
 .%O http://standards.ieee.org/getieee802/802.1.html
+.Re
+.Rs
+.%T IEEE 802.1AD standard
+.%O Provider Bridges, QinQ
 .Re
 .Sh AUTHORS
 Originally [EMAIL PROTECTED]
Index: sys/net/ethertypes.h
===================================================================
RCS file: /cvs/src/sys/net/ethertypes.h,v
retrieving revision 1.9
diff -u -p -r1.9 ethertypes.h
--- sys/net/ethertypes.h        5 May 2008 13:40:17 -0000       1.9
+++ sys/net/ethertypes.h        21 Aug 2008 19:18:42 -0000
@@ -300,6 +300,7 @@
 #define        ETHERTYPE_LANPROBE      0x8888  /* HP LanProbe test? */
 #define        ETHERTYPE_PAE           0x888E  /* 802.1X Port Access Entity */
 #define        ETHERTYPE_AOE           0x88A2  /* ATA over Ethernet */
+#define        ETHERTYPE_QINQ          0x88A8  /* 802.1ad VLAN stacking */
 #define        ETHERTYPE_LLDP          0x88CC  /* Link Layer Discovery 
Protocol */
 #define        ETHERTYPE_LOOPBACK      0x9000  /* Loopback */
 #define        ETHERTYPE_LBACK         ETHERTYPE_LOOPBACK      /* DEC MOP 
loopback */
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.170
diff -u -p -r1.170 if_bridge.c
--- sys/net/if_bridge.c 14 Jun 2008 21:46:22 -0000      1.170
+++ sys/net/if_bridge.c 21 Aug 2008 19:18:42 -0000
@@ -2601,7 +2601,7 @@ bridge_fragment(struct bridge_softc *sc,
        goto dropit;
 #else
        etype = ntohs(eh->ether_type);
-       if (etype == ETHERTYPE_VLAN &&
+       if ((etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) &&
            (ifp->if_capabilities & IFCAP_VLAN_MTU) &&
            ((m->m_pkthdr.len - sizeof(struct ether_vlan_header)) <=
            ifp->if_mtu)) {
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.123
diff -u -p -r1.123 if_ethersubr.c
--- sys/net/if_ethersubr.c      4 Aug 2008 18:55:08 -0000       1.123
+++ sys/net/if_ethersubr.c      21 Aug 2008 19:18:42 -0000
@@ -573,7 +573,8 @@ ether_input(ifp0, eh, m)
        }
#if NVLAN > 0
-       if (etype == ETHERTYPE_VLAN && (vlan_input(eh, m) == 0))
+       if ((etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) &&
+           (vlan_input(eh, m, etype) == 0))
                return;
 #endif
@@ -598,7 +599,7 @@ ether_input(ifp0, eh, m)
 #endif
#if NVLAN > 0
-       if (etype == ETHERTYPE_VLAN) {
+       if (etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
                /* The bridge did not want the vlan frame either, drop it. */
                ifp->if_noproto++;
                m_freem(m);
Index: sys/net/if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.73
diff -u -p -r1.73 if_vlan.c
--- sys/net/if_vlan.c   7 May 2008 13:45:35 -0000       1.73
+++ sys/net/if_vlan.c   21 Aug 2008 19:18:42 -0000
@@ -78,16 +78,16 @@
 #include <net/if_vlan_var.h>
extern struct   ifaddr  **ifnet_addrs;
-u_long vlan_tagmask;
+u_long vlan_tagmask, svlan_tagmask;
-#define TAG_HASH_SIZE  32
-#define TAG_HASH(tag)  (tag & vlan_tagmask)
-LIST_HEAD(, ifvlan)    *vlan_tagh;
+#define TAG_HASH_SIZE          32
+#define TAG_HASH(tag)          (tag & vlan_tagmask)
+LIST_HEAD(vlan_taghash, ifvlan)        *vlan_tagh, *svlan_tagh;
void    vlan_start (struct ifnet *ifp);
 int    vlan_ioctl (struct ifnet *ifp, u_long cmd, caddr_t addr);
 int    vlan_unconfig (struct ifnet *ifp);
-int    vlan_config (struct ifvlan *, struct ifnet *, u_int16_t);
+int    vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
 void   vlan_vlandev_state(void *);
 void   vlanattach (int count);
 int    vlan_set_promisc (struct ifnet *ifp);
@@ -100,16 +100,26 @@ void      vlan_ifdetach(void *);
struct if_clone vlan_cloner =
     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
+struct if_clone svlan_cloner =
+ IF_CLONE_INITIALIZER("svlan", vlan_clone_create, vlan_clone_destroy);
/* ARGSUSED */
 void
 vlanattach(int count)
 {
-       vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, &vlan_tagmask);
+       /* Normal VLAN */
+       vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
+           &vlan_tagmask);
        if (vlan_tagh == NULL)
                panic("vlanattach: hashinit");
-
        if_clone_attach(&vlan_cloner);
+
+       /* Service-VLAN for QinQ/802.1ad provider bridges */
+       svlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
+           &svlan_tagmask);
+       if (svlan_tagh == NULL)
+               panic("vlanattach: hashinit");
+       if_clone_attach(&svlan_cloner);
 }
int
@@ -130,6 +140,12 @@ vlan_clone_create(struct if_clone *ifc,
        /* NB: flags are not set here */
        /* NB: mtu is not set here */
+       /* Special handling for the IEEE 802.1ad QinQ variant */
+       if (strcmp("svlan", ifc->ifc_name) == 0)
+               ifv->ifv_type = ETHERTYPE_QINQ;
+       else
+               ifv->ifv_type = ETHERTYPE_VLAN;
+
        ifp->if_start = vlan_start;
        ifp->if_ioctl = vlan_ioctl;
        ifp->if_output = ether_output;
@@ -220,7 +236,8 @@ vlan_start(struct ifnet *ifp)
                 * following potentially bogus rcvif pointers off into
                 * never-never land.
                 */
-               if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
+               if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
+                   (ifv->ifv_type == ETHERTYPE_VLAN)) {
                        m->m_pkthdr.rcvif = ifp;
                        m->m_flags |= M_PROTO1;
                } else {
@@ -228,7 +245,7 @@ vlan_start(struct ifnet *ifp)
                        m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
                        evh.evl_proto = evh.evl_encap_proto;
-                       evh.evl_encap_proto = htons(ETHERTYPE_VLAN);
+                       evh.evl_encap_proto = htons(ifv->ifv_type);
                        evh.evl_tag = htons(ifv->ifv_tag +
                            (ifv->ifv_prio << EVL_PRIO_BITS));
@@ -268,13 +285,12 @@ vlan_start(struct ifnet *ifp)
  * vlan_input() returns 0 if it has consumed the packet, 1 otherwise.
  */
 int
-vlan_input(eh, m)
-       struct ether_header *eh;
-       struct mbuf *m;
+vlan_input(struct ether_header *eh, struct mbuf *m, u_int16_t etype)
 {
        struct ifvlan *ifv;
        u_int tag;
        struct ifnet *ifp = m->m_pkthdr.rcvif;
+       struct vlan_taghash *tagh;
        if (m->m_len < EVL_ENCAPLEN &&
            (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
@@ -282,10 +298,12 @@ vlan_input(eh, m)
                return (0);
        }
+       tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
        tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)));
-       LIST_FOREACH(ifv, &vlan_tagh[TAG_HASH(tag)], ifv_list) {
-               if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag)
+       LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) {
+               if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag &&
+                   etype == ifv->ifv_type)
                        break;
        }
        if (ifv == NULL)
@@ -326,6 +344,7 @@ vlan_config(struct ifvlan *ifv, struct i
 {
        struct ifaddr *ifa1, *ifa2;
        struct sockaddr_dl *sdl1, *sdl2;
+       struct vlan_taghash *tagh;
        int s;
        if (p->if_type != IFT_ETHER)
@@ -385,6 +404,13 @@ vlan_config(struct ifvlan *ifv, struct i
                /* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */
        /*
+        * Hardware VLAN tagging only works with the default VLAN
+        * ethernet type (0x8100).
+        */
+       if (ifv->ifv_type != ETHERTYPE_VLAN)
+               ifv->ifv_if.if_capabilities &= ~IFCAP_VLAN_HWTAGGING;
+
+       /*
         * Set up our ``Ethernet address'' to reflect the underlying
         * physical interface's.
         */
@@ -399,7 +425,8 @@ vlan_config(struct ifvlan *ifv, struct i
        ifv->ifv_tag = tag;
        s = splnet();
-       LIST_INSERT_HEAD(&vlan_tagh[TAG_HASH(tag)], ifv, ifv_list);
+       tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
+       LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
        /* Register callback for physical link state changes */
        ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1,
Index: sys/net/if_vlan_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_vlan_var.h,v
retrieving revision 1.18
diff -u -p -r1.18 if_vlan_var.h
--- sys/net/if_vlan_var.h       9 Feb 2006 00:05:55 -0000       1.18
+++ sys/net/if_vlan_var.h       21 Aug 2008 19:18:42 -0000
@@ -53,6 +53,7 @@ struct        ifvlan {
                u_int16_t ifvm_proto; /* encapsulation ethertype */
                u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
                u_int16_t ifvm_prio; /* prio to apply on packet leaving if */
+               u_int16_t ifvm_type; /* non-standard ethertype or 0x8100 */
        }       ifv_mib;
        LIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead;
        LIST_ENTRY(ifvlan) ifv_list;
@@ -64,6 +65,7 @@ struct        ifvlan {
 #define        ifv_if          ifv_ac.ac_if
 #define        ifv_tag         ifv_mib.ifvm_tag
 #define        ifv_prio        ifv_mib.ifvm_prio
+#define        ifv_type        ifv_mib.ifvm_type
 #define        IFVF_PROMISC    0x01
 #endif /* _KERNEL */
@@ -97,6 +99,6 @@ struct        vlanreq {
 #define        SIOCGETVLAN     SIOCGIFGENERIC
#ifdef _KERNEL
-extern int vlan_input(struct ether_header *eh, struct mbuf *m);
+extern int vlan_input(struct ether_header *eh, struct mbuf *m, u_int16_t);
 #endif /* _KERNEL */
 #endif /* _NET_IF_VLAN_VAR_H_ */
Index: usr.sbin/tcpdump/ethertype.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/ethertype.h,v
retrieving revision 1.13
diff -u -p -r1.13 ethertype.h
--- usr.sbin/tcpdump/ethertype.h        7 Oct 2007 16:41:05 -0000       1.13
+++ usr.sbin/tcpdump/ethertype.h        21 Aug 2008 19:18:42 -0000
@@ -102,6 +102,9 @@
 #ifndef ETHERTYPE_8021Q
 #define ETHERTYPE_8021Q                0x8100
 #endif
+#ifndef ETHERTYPE_QINQ
+#define ETHERTYPE_QINQ         0x88a8
+#endif
 #ifndef ETHERTYPE_IPX
 #define ETHERTYPE_IPX          0x8137
 #endif
Index: usr.sbin/tcpdump/print-ether.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v
retrieving revision 1.23
diff -u -p -r1.23 print-ether.c
--- usr.sbin/tcpdump/print-ether.c      7 Oct 2007 16:41:05 -0000       1.23
+++ usr.sbin/tcpdump/print-ether.c      21 Aug 2008 19:18:42 -0000
@@ -204,7 +204,11 @@ recurse:
                return (1);
        case ETHERTYPE_8021Q:
-               printf("802.1Q vid %d pri %d%s",
+               printf("802.1Q ");
+       case ETHERTYPE_QINQ:
+               if (ethertype == ETHERTYPE_QINQ)
+                       printf("QinQ s");
+               printf("vid %d pri %d%s",
                       ntohs(*(unsigned short*)p)&0xFFF,
                       ntohs(*(unsigned short*)p)>>13,
                       (ntohs(*(unsigned short*)p)&0x1000) ? " cfi " : " ");


Hi Misc@ and Reyk@,
I'd been watching the src at cvs for a while, I can't see that Reyk@ patch is submitted to cvs. Is there some issues? I'd like to know if there is.
So far the our machines is not complaining or anything right now.
Thanks,


Insan

--
insandotpraja(at)gmaildotcom

Reply via email to