From owner-freebsd-net@FreeBSD.ORG Tue Oct 16 19:36:51 2007 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1FCE916A417 for ; Tue, 16 Oct 2007 19:36:51 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: from heff.fud.org.nz (203-109-251-39.static.bliink.ihug.co.nz [203.109.251.39]) by mx1.freebsd.org (Postfix) with ESMTP id 45AA113C458 for ; Tue, 16 Oct 2007 19:36:47 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: by heff.fud.org.nz (Postfix, from userid 1001) id 0D99B1CC58; Wed, 17 Oct 2007 08:36:45 +1300 (NZDT) Date: Wed, 17 Oct 2007 08:36:45 +1300 From: Andrew Thompson To: FreeBSD-net Message-ID: <20071016193645.GB41359@heff.fud.org.nz> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="FL5UXtIhxfXey3p5" Content-Disposition: inline User-Agent: Mutt/1.5.13 (2006-08-11) Cc: Bruce M Simpson Subject: bridging vlan problem X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Oct 2007 19:36:51 -0000 --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, This problem has always existed but now in RELENG_7+ since the vlan tag is always stripped on the incoming packet its a little more obvious. The bridging output function puts the mbuf directly on the interfaces send queue so only network cards with VLAN_HWTAGGING will properly re-tag any outgoing vlan frames. The attached patch fixes this as well as putting the common vlan encapsulation code in to ether_vlanencap(). Any comments please, I want to commit this soon so I have more chance of getting it into 7.0 Andrew --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ether_vlanencap.diff" Index: ethernet.h =================================================================== RCS file: /home/ncvs/src/sys/net/ethernet.h,v retrieving revision 1.32 diff -u -p -r1.32 ethernet.h --- ethernet.h 29 May 2007 12:40:45 -0000 1.32 +++ ethernet.h 16 Oct 2007 01:18:28 -0000 @@ -386,6 +386,7 @@ extern int ether_output_frame(struct if extern char *ether_sprintf(const u_int8_t *); void ether_vlan_mtap(struct bpf_if *, struct mbuf *, void *, u_int); +struct mbuf * ether_vlanencap(struct mbuf *, int); #else /* _KERNEL */ Index: if_bridge.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_bridge.c,v retrieving revision 1.103 diff -u -p -r1.103 if_bridge.c --- if_bridge.c 16 Sep 2007 21:09:15 -0000 1.103 +++ if_bridge.c 16 Oct 2007 04:03:43 -0000 @@ -1653,7 +1653,23 @@ bridge_enqueue(struct bridge_softc *sc, for (; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = NULL; - + + /* + * If underlying interface can not do VLAN tag insertion itself + * then attach a packet tag that holds it. + */ + if ((m->m_flags & M_VLANTAG) && + (dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) { + m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); + if (m == NULL) { + if_printf(dst_ifp, + "unable to prepend VLAN header\n"); + dst_ifp->if_oerrors++; + continue; + } + m->m_flags &= ~M_VLANTAG; + } + if (err == 0) IFQ_ENQUEUE(&dst_ifp->if_snd, m, err); } Index: if_ethersubr.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.236 diff -u -p -r1.236 if_ethersubr.c --- if_ethersubr.c 14 Sep 2007 06:57:28 -0000 1.236 +++ if_ethersubr.c 16 Oct 2007 04:03:58 -0000 @@ -1249,5 +1249,33 @@ ether_vlan_mtap(struct bpf_if *bp, struc m->m_data -= sizeof(struct ether_header); } +struct mbuf * +ether_vlanencap(struct mbuf *m, int tag) +{ + struct ether_vlan_header *evl; + + M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT); + if (m == NULL) + return (NULL); + /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ + + if (m->m_len < sizeof(*evl)) { + m = m_pullup(m, sizeof(*evl)); + if (m == NULL) + return (NULL); + } + + /* + * Transform the Ethernet header into an Ethernet header + * with 802.1Q encapsulation. + */ + evl = mtod(m, struct ether_vlan_header *); + bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN, + (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); + evl->evl_encap_proto = htons(ETHERTYPE_VLAN); + evl->evl_tag = htons(tag); + return (m); +} + DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); MODULE_VERSION(ether, 1); Index: if_vlan.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_vlan.c,v retrieving revision 1.124 diff -u -p -r1.124 if_vlan.c --- if_vlan.c 19 Mar 2007 18:01:39 -0000 1.124 +++ if_vlan.c 16 Oct 2007 04:03:50 -0000 @@ -850,40 +850,13 @@ vlan_start(struct ifnet *ifp) m->m_pkthdr.ether_vtag = ifv->ifv_tag; m->m_flags |= M_VLANTAG; } else { - struct ether_vlan_header *evl; - - M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); + m = ether_vlanencap(m, ifv->ifv_tag); if (m == NULL) { if_printf(ifp, "unable to prepend VLAN header\n"); ifp->if_oerrors++; continue; } - /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ - - if (m->m_len < sizeof(*evl)) { - m = m_pullup(m, sizeof(*evl)); - if (m == NULL) { - if_printf(ifp, - "cannot pullup VLAN header\n"); - ifp->if_oerrors++; - continue; - } - } - - /* - * Transform the Ethernet header into an Ethernet header - * with 802.1Q encapsulation. - */ - evl = mtod(m, struct ether_vlan_header *); - bcopy((char *)evl + ifv->ifv_encaplen, - (char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN); - evl->evl_encap_proto = htons(ifv->ifv_proto); - evl->evl_tag = htons(ifv->ifv_tag); -#ifdef DEBUG - printf("%s: %*D\n", __func__, (int)sizeof(*evl), - (unsigned char *)evl, ":"); -#endif } /* --FL5UXtIhxfXey3p5--