diff options
-rw-r--r-- | share/man/man4/Makefile | 3 | ||||
-rw-r--r-- | share/man/man4/vlan.4 | 40 | ||||
-rw-r--r-- | sys/net/if_bridge.c | 5 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 9 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 75 | ||||
-rw-r--r-- | sys/net/if_vlan_var.h | 4 |
6 files changed, 101 insertions, 35 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 205e60c7078..9888f9a4d37 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.507 2010/04/02 20:07:31 deraadt Exp $ +# $OpenBSD: Makefile,v 1.508 2010/06/03 16:15:00 naddy Exp $ MAN= aac.4 ac97.4 acphy.4 \ acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \ @@ -89,6 +89,7 @@ MLINKS+=speaker.4 spkr.4 MLINKS+=tht.4 thtc.4 MLINKS+=tty.4 cua.4 MLINKS+=usb.4 uhub.4 +MLINKS+=vlan.4 svlan.4 MLINKS+=vnd.4 svnd.4 # man4.hppa64 diff --git a/share/man/man4/vlan.4 b/share/man/man4/vlan.4 index 77034b7f731..8ac6b882a1e 100644 --- a/share/man/man4/vlan.4 +++ b/share/man/man4/vlan.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: vlan.4,v 1.31 2008/06/26 05:42:07 ray Exp $ +.\" $OpenBSD: vlan.4,v 1.32 2010/06/03 16:15:00 naddy Exp $ .\" .\" Copyright (c) 2000 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,12 +27,13 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: June 26 2008 $ +.Dd $Mdocdate: June 3 2010 $ .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 capabilities: 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 @@ -151,6 +177,10 @@ and .%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 wollman@freebsd.org. .Sh BUGS diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index ae4e4b5721a..51348864aae 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.177 2010/01/13 05:25:06 claudio Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.178 2010/06/03 16:15:00 naddy Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -2704,7 +2704,8 @@ bridge_fragment(struct bridge_softc *sc, struct ifnet *ifp, #else etype = ntohs(eh->ether_type); #if NVLAN > 0 - if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN) { + if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN || + etype == ETHERTYPE_QINQ) { int len = m->m_pkthdr.len; if (m->m_flags & M_VLANTAG) diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 0c40eccc614..a82b1c0a9c3 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.143 2010/05/28 12:09:09 claudio Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.144 2010/06/03 16:15:00 naddy Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -613,8 +613,8 @@ ether_input(ifp0, eh, m) } #if NVLAN > 0 - if (((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN) - && (vlan_input(eh, m) == 0)) + if (((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN || + etype == ETHERTYPE_QINQ) && (vlan_input(eh, m) == 0)) return; #endif @@ -639,7 +639,8 @@ ether_input(ifp0, eh, m) #endif #if NVLAN > 0 - if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN) { + if ((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN || + etype == ETHERTYPE_QINQ) { /* The bridge did not want the vlan frame either, drop it. */ ifp->if_noproto++; m_freem(m); diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 8fb09cba298..ab678a65d76 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan.c,v 1.83 2010/04/20 22:05:43 tedu Exp $ */ +/* $OpenBSD: if_vlan.c,v 1.84 2010/06/03 16:15:00 naddy Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -77,19 +77,19 @@ #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); +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); void vlan_vlandev_state(void *); -void vlanattach (int count); -int vlan_set_promisc (struct ifnet *ifp); +void vlanattach(int count); +int vlan_set_promisc(struct ifnet *ifp); int vlan_ether_addmulti(struct ifvlan *, struct ifreq *); int vlan_ether_delmulti(struct ifvlan *, struct ifreq *); void vlan_ether_purgemulti(struct ifvlan *); @@ -99,16 +99,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 @@ -129,6 +139,12 @@ vlan_clone_create(struct if_clone *ifc, int unit) /* 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; IFQ_SET_MAXLEN(&ifp->if_snd, 1); @@ -206,7 +222,8 @@ vlan_start(struct ifnet *ifp) * to create a special header for it. In this case, we just pass * the packet along. */ - if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) { + if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) && + (ifv->ifv_type == ETHERTYPE_VLAN)) { m->m_pkthdr.ether_vtag = ifv->ifv_tag + (ifv->ifv_prio << EVL_PRIO_BITS); m->m_flags |= M_VLANTAG; @@ -215,7 +232,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)); @@ -255,15 +272,17 @@ 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) { struct ifvlan *ifv; - u_int tag; struct ifnet *ifp = m->m_pkthdr.rcvif; + struct vlan_taghash *tagh; + u_int tag; + u_int16_t etype; if (m->m_flags & M_VLANTAG) { + etype = ETHERTYPE_VLAN; + tagh = vlan_tagh; tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); } else { if (m->m_len < EVL_ENCAPLEN && @@ -272,11 +291,14 @@ vlan_input(eh, m) return (0); } + etype = ntohs(eh->ether_type); + 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) @@ -336,6 +358,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) { struct ifaddr *ifa1, *ifa2; struct sockaddr_dl *sdl1, *sdl2; + struct vlan_taghash *tagh; int s; if (p->if_type != IFT_ETHER) @@ -395,6 +418,13 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) /* (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. */ @@ -409,7 +439,8 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag) 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, diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h index e46439ec00a..a1d2679671b 100644 --- a/sys/net/if_vlan_var.h +++ b/sys/net/if_vlan_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan_var.h,v 1.19 2008/11/07 00:52:40 brad Exp $ */ +/* $OpenBSD: if_vlan_var.h,v 1.20 2010/06/03 16:15:00 naddy Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -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 */ |