Works for me.

(haven't tested this very extensively yet, and only OpenBSD <->
OpenBSD ... nor did I try the tcpdump patches .. will do so later)

Thanks Reyk, cool stuff ;)

Paul 'WEiRD' de Weerd

On Thu, Aug 21, 2008 at 09:34:12PM +0200, Reyk Floeter 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 " : " ");
| 

-- 
>++++++++[<++++++++++>-]<+++++++.>+++[<------>-]<.>+++[<+
+++++++++++>-]<.>++[<------------>-]<+.--------------.[-]
                 http://www.weirdnet.nl/                 

Reply via email to