summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile3
-rw-r--r--share/man/man4/vlan.440
-rw-r--r--sys/net/if_bridge.c5
-rw-r--r--sys/net/if_ethersubr.c9
-rw-r--r--sys/net/if_vlan.c75
-rw-r--r--sys/net/if_vlan_var.h4
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 */