Module Name:    src
Committed By:   snj
Date:           Sun Sep 24 20:05:03 UTC 2017

Modified Files:
        src/sys/arch/xen/xen [netbsd-7]: if_xennet_xenbus.c xennetback_xenbus.c
        src/sys/net [netbsd-7]: if_bridge.c if_ether.h if_ethersubr.c if_vlan.c

Log Message:
Pull up following revision(s) (requested by manu in ticket #1409):
        sys/arch/xen/xen/if_xennet_xenbus.c: 1.65
        sys/arch/xen/xen/xennetback_xenbus.c: 1.53, 1.56 via patch
        sys/net/if_bridge.c: 1.105
        sys/net/if_ether.h: 1.65
        sys/net/if_ethersubr.c: 1.215, 1.235
        sys/net/if_vlan.c: 1.76, 1.77, 1.83, 1.88, 1.94
Protect vlan_unconfig with a mutex
It is not thread-safe but is likely to be executed in concurrent.
See PR 49264 for more detail.
--
Tweak vlan_unconfig
No functional change.
--
Add handling of VLAN packets in if_bridge where the parent interface supports
them (Jean-Jacques.Puig%espci.fr@localhost). Factor out the vlan_mtu enabling 
and
disabling code.
--
Enable the VLAN mtu capability and check for the adjusted packet size
(Jean-Jacques.Puig at espci.fr).
Factor out the packet-size checking function for clarity.
--
Don't increment the reference count only when it was 0...
>From Jean-Jacques.Puig
--
Account for the CRC len (Jean-Jacques.Puig)
--
Fix a bug that the parent interface's callback wasn't called when the vlan
interface is configured. A callback function uses VLAN_ATTACHED() function
which check ec->ec_nvlans, the value should be incremented before calling the
callback. This bug was added in if_vlan.c rev. 1.83 (2015/11/19).


To generate a diff of this commit:
cvs rdiff -u -r1.63.2.2 -r1.63.2.3 src/sys/arch/xen/xen/if_xennet_xenbus.c
cvs rdiff -u -r1.52.4.1 -r1.52.4.2 src/sys/arch/xen/xen/xennetback_xenbus.c
cvs rdiff -u -r1.90 -r1.90.2.1 src/sys/net/if_bridge.c
cvs rdiff -u -r1.64 -r1.64.2.1 src/sys/net/if_ether.h
cvs rdiff -u -r1.204.2.1 -r1.204.2.2 src/sys/net/if_ethersubr.c
cvs rdiff -u -r1.70.2.4 -r1.70.2.5 src/sys/net/if_vlan.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/xen/xen/if_xennet_xenbus.c
diff -u src/sys/arch/xen/xen/if_xennet_xenbus.c:1.63.2.2 src/sys/arch/xen/xen/if_xennet_xenbus.c:1.63.2.3
--- src/sys/arch/xen/xen/if_xennet_xenbus.c:1.63.2.2	Sun Mar 26 16:08:12 2017
+++ src/sys/arch/xen/xen/if_xennet_xenbus.c	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_xennet_xenbus.c,v 1.63.2.2 2017/03/26 16:08:12 snj Exp $      */
+/*      $NetBSD: if_xennet_xenbus.c,v 1.63.2.3 2017/09/24 20:05:03 snj Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -85,7 +85,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.63.2.2 2017/03/26 16:08:12 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.63.2.3 2017/09/24 20:05:03 snj Exp $");
 
 #include "opt_xen.h"
 #include "opt_nfs_boot.h"
@@ -362,6 +362,7 @@ xennet_xenbus_attach(device_t parent, de
 	    ether_sprintf(sc->sc_enaddr));
 	/* Initialize ifnet structure and attach interface */
 	strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
+	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
 	ifp->if_softc = sc;
 	ifp->if_start = xennet_start;
 	ifp->if_ioctl = xennet_ioctl;

Index: src/sys/arch/xen/xen/xennetback_xenbus.c
diff -u src/sys/arch/xen/xen/xennetback_xenbus.c:1.52.4.1 src/sys/arch/xen/xen/xennetback_xenbus.c:1.52.4.2
--- src/sys/arch/xen/xen/xennetback_xenbus.c:1.52.4.1	Fri Jan  8 21:05:14 2016
+++ src/sys/arch/xen/xen/xennetback_xenbus.c	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*      $NetBSD: xennetback_xenbus.c,v 1.52.4.1 2016/01/08 21:05:14 snj Exp $      */
+/*      $NetBSD: xennetback_xenbus.c,v 1.52.4.2 2017/09/24 20:05:03 snj Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.52.4.1 2016/01/08 21:05:14 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.52.4.2 2017/09/24 20:05:03 snj Exp $");
 
 #include "opt_xen.h"
 
@@ -301,6 +301,7 @@ xennetback_xenbus_create(struct xenbus_d
 	/* create pseudo-interface */
 	aprint_verbose_ifnet(ifp, "Ethernet address %s\n",
 	    ether_sprintf(xneti->xni_enaddr));
+	xneti->xni_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
 	ifp->if_flags =
 	    IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
 	ifp->if_snd.ifq_maxlen =
@@ -710,6 +711,24 @@ xennetback_tx_response(struct xnetback_i
 	}
 }
 
+static inline const char *
+xennetback_tx_check_packet(const netif_tx_request_t *txreq, int vlan)
+{
+	if (__predict_false(txreq->size < ETHER_HDR_LEN))
+		return "too small";
+
+	if (__predict_false(txreq->offset + txreq->size > PAGE_SIZE))
+		return "crossing a page boundary";
+
+	int maxlen = ETHER_MAX_LEN - ETHER_CRC_LEN;
+	if (vlan)
+		maxlen += ETHER_VLAN_ENCAP_LEN;
+	if (__predict_false(txreq->size > maxlen))
+		return "too big";
+
+	return NULL;
+}
+
 static int
 xennetback_evthandler(void *arg)
 {
@@ -748,25 +767,17 @@ xennetback_evthandler(void *arg)
 		/*
 		 * Do some sanity checks, and map the packet's page.
 		 */
-		if (__predict_false(txreq.size < ETHER_HDR_LEN ||
-		   txreq.size > (ETHER_MAX_LEN - ETHER_CRC_LEN))) {
-			printf("%s: packet size %d too big\n",
-			    ifp->if_xname, txreq.size);
-			xennetback_tx_response(xneti, txreq.id,
-			    NETIF_RSP_ERROR);
-			ifp->if_ierrors++;
-			continue;
-		}
-		/* don't cross page boundaries */
-		if (__predict_false(
-		    txreq.offset + txreq.size > PAGE_SIZE)) {
-			printf("%s: packet cross page boundary\n",
-			    ifp->if_xname);
+		const char *msg = xennetback_tx_check_packet(&txreq,
+		    xneti->xni_ec.ec_capenable & ETHERCAP_VLAN_MTU);
+		if (msg) {
+			printf("%s: packet with size %d is %s\n",
+			    ifp->if_xname, txreq.size, msg);
 			xennetback_tx_response(xneti, txreq.id,
 			    NETIF_RSP_ERROR);
 			ifp->if_ierrors++;
 			continue;
 		}
+
 		/* get a mbuf for this packet */
 		MGETHDR(m, M_DONTWAIT, MT_DATA);
 		if (__predict_false(m == NULL)) {

Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.90 src/sys/net/if_bridge.c:1.90.2.1
--- src/sys/net/if_bridge.c:1.90	Wed Jul 23 05:32:23 2014
+++ src/sys/net/if_bridge.c	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_bridge.c,v 1.90 2014/07/23 05:32:23 ozaki-r Exp $	*/
+/*	$NetBSD: if_bridge.c,v 1.90.2.1 2017/09/24 20:05:03 snj Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.90 2014/07/23 05:32:23 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.90.2.1 2017/09/24 20:05:03 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_bridge_ipf.h"
@@ -806,6 +806,8 @@ bridge_ioctl_add(struct bridge_softc *sc
 
 	switch (ifs->if_type) {
 	case IFT_ETHER:
+		if ((error = ether_enable_vlan_mtu(ifs)) > 0)
+			goto out;
 		/*
 		 * Place the interface into promiscuous mode.
 		 */
@@ -883,6 +885,7 @@ bridge_ioctl_del(struct bridge_softc *sc
 		 * Don't call it with holding sc_iflist_lock.
 		 */
 		(void) ifpromisc(ifs, 0);
+		(void) ether_disable_vlan_mtu(ifs);
 		break;
 	default:
 #ifdef DIAGNOSTIC

Index: src/sys/net/if_ether.h
diff -u src/sys/net/if_ether.h:1.64 src/sys/net/if_ether.h:1.64.2.1
--- src/sys/net/if_ether.h:1.64	Mon Jul 28 14:24:48 2014
+++ src/sys/net/if_ether.h	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ether.h,v 1.64 2014/07/28 14:24:48 ozaki-r Exp $	*/
+/*	$NetBSD: if_ether.h,v 1.64.2.1 2017/09/24 20:05:03 snj Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -337,6 +337,8 @@ uint32_t ether_crc32_le(const uint8_t *,
 uint32_t ether_crc32_be(const uint8_t *, size_t);
 
 int	ether_aton_r(u_char *, size_t, const char *);
+int	ether_enable_vlan_mtu(struct ifnet *);
+int	ether_disable_vlan_mtu(struct ifnet *);
 #else
 /*
  * Prototype ethers(3) functions.

Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.204.2.1 src/sys/net/if_ethersubr.c:1.204.2.2
--- src/sys/net/if_ethersubr.c:1.204.2.1	Sun Feb  5 19:14:17 2017
+++ src/sys/net/if_ethersubr.c	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ethersubr.c,v 1.204.2.1 2017/02/05 19:14:17 snj Exp $	*/
+/*	$NetBSD: if_ethersubr.c,v 1.204.2.2 2017/09/24 20:05:03 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.204.2.1 2017/02/05 19:14:17 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.204.2.2 2017/09/24 20:05:03 snj Exp $");
 
 #include "opt_inet.h"
 #include "opt_atalk.h"
@@ -1477,6 +1477,71 @@ ether_ioctl(struct ifnet *ifp, u_long cm
 	return 0;
 }
 
+/*
+ * Enable/disable passing VLAN packets if the parent interface supports it.
+ * Return:
+ * 	 0: Ok
+ *	-1: Parent interface does not support vlans
+ *	>0: Error
+ */
+int
+ether_enable_vlan_mtu(struct ifnet *ifp)
+{
+	int error;
+	struct ethercom *ec = (void *)ifp;
+
+	/* Parent does not support VLAN's */
+	if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0)
+		return -1;
+
+	/*
+	 * Parent supports the VLAN_MTU capability,
+	 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames;
+	 * enable it.
+	 */
+	ec->ec_capenable |= ETHERCAP_VLAN_MTU;
+
+	/* Interface is down, defer for later */
+	if ((ifp->if_flags & IFF_UP) == 0)
+		return 0;
+
+	if ((error = if_flags_set(ifp, ifp->if_flags)) == 0)
+		return 0;
+
+	ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
+	return error;
+}
+
+int
+ether_disable_vlan_mtu(struct ifnet *ifp)
+{
+	int error;
+	struct ethercom *ec = (void *)ifp;
+
+	/* We still have VLAN's, defer for later */
+	if (ec->ec_nvlans != 0)
+		return 0;
+
+	/* Parent does not support VLAB's, nothing to do. */
+	if ((ec->ec_capenable & ETHERCAP_VLAN_MTU) == 0)
+		return -1;
+
+	/*
+	 * Disable Tx/Rx of VLAN-sized frames.
+	 */
+	ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
+	
+	/* Interface is down, defer for later */
+	if ((ifp->if_flags & IFF_UP) == 0)
+		return 0;
+
+	if ((error = if_flags_set(ifp, ifp->if_flags)) == 0)
+		return 0;
+
+	ec->ec_capenable |= ETHERCAP_VLAN_MTU;
+	return error;
+}
+
 static int
 ether_multicast_sysctl(SYSCTLFN_ARGS)
 {

Index: src/sys/net/if_vlan.c
diff -u src/sys/net/if_vlan.c:1.70.2.4 src/sys/net/if_vlan.c:1.70.2.5
--- src/sys/net/if_vlan.c:1.70.2.4	Sat Dec  3 12:34:23 2016
+++ src/sys/net/if_vlan.c	Sun Sep 24 20:05:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vlan.c,v 1.70.2.4 2016/12/03 12:34:23 martin Exp $	*/
+/*	$NetBSD: if_vlan.c,v 1.70.2.5 2017/09/24 20:05:03 snj Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.70.2.4 2016/12/03 12:34:23 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.70.2.5 2017/09/24 20:05:03 snj Exp $");
 
 #include "opt_inet.h"
 
@@ -91,6 +91,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 
 #include <sys/systm.h>
 #include <sys/proc.h>
 #include <sys/kauth.h>
+#include <sys/mutex.h>
 
 #include <net/bpf.h>
 #include <net/if.h>
@@ -180,6 +181,8 @@ void		vlanattach(int);
 /* XXX This should be a hash table with the tag as the basis of the key. */
 static LIST_HEAD(, ifvlan) ifv_list;
 
+static kmutex_t ifv_mtx __cacheline_aligned;
+
 struct if_clone vlan_cloner =
     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
 
@@ -191,6 +194,7 @@ vlanattach(int n)
 {
 
 	LIST_INIT(&ifv_list);
+	mutex_init(&ifv_mtx, MUTEX_DEFAULT, IPL_NONE);
 	if_clone_attach(&vlan_cloner);
 }
 
@@ -277,36 +281,23 @@ vlan_config(struct ifvlan *ifv, struct i
 		ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
 		ifv->ifv_mintu = ETHERMIN;
 
-		/*
-		 * If the parent supports the VLAN_MTU capability,
-		 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
-		 * enable it.
-		 */
-		if (ec->ec_nvlans++ == 0 &&
-		    (ec->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
-			/*
-			 * Enable Tx/Rx of VLAN-sized frames.
-			 */
-			ec->ec_capenable |= ETHERCAP_VLAN_MTU;
-			if (p->if_flags & IFF_UP) {
-				error = if_flags_set(p, p->if_flags);
+		if (ec->ec_nvlans++ == 0) {
+			if ((error = ether_enable_vlan_mtu(p)) >= 0) {
 				if (error) {
-					if (ec->ec_nvlans-- == 1)
-						ec->ec_capenable &=
-						    ~ETHERCAP_VLAN_MTU;
-					return (error);
+					ec->ec_nvlans--;
+					return error;
 				}
+				ifv->ifv_mtufudge = 0;
+			} else {
+				/*
+				 * Fudge the MTU by the encapsulation size. This
+				 * makes us incompatible with strictly compliant
+				 * 802.1Q implementations, but allows us to use
+				 * the feature with other NetBSD
+				 * implementations, which might still be useful.
+				 */
+				ifv->ifv_mtufudge = ifv->ifv_encaplen;
 			}
-			ifv->ifv_mtufudge = 0;
-		} else if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) {
-			/*
-			 * Fudge the MTU by the encapsulation size.  This
-			 * makes us incompatible with strictly compliant
-			 * 802.1Q implementations, but allows us to use
-			 * the feature with other NetBSD implementations,
-			 * which might still be useful.
-			 */
-			ifv->ifv_mtufudge = ifv->ifv_encaplen;
 		}
 
 		/*
@@ -358,9 +349,15 @@ static void
 vlan_unconfig(struct ifnet *ifp)
 {
 	struct ifvlan *ifv = ifp->if_softc;
+	struct ifnet *p;
 
-	if (ifv->ifv_p == NULL)
+	mutex_enter(&ifv_mtx);
+	p = ifv->ifv_p;
+
+	if (p == NULL) {
+		mutex_exit(&ifv_mtx);
 		return;
+	}
 
 	/*
  	 * Since the interface is being unconfigured, we need to empty the
@@ -370,21 +367,12 @@ vlan_unconfig(struct ifnet *ifp)
 	(*ifv->ifv_msw->vmsw_purgemulti)(ifv);
 
 	/* Disconnect from parent. */
-	switch (ifv->ifv_p->if_type) {
+	switch (p->if_type) {
 	case IFT_ETHER:
 	    {
-		struct ethercom *ec = (void *) ifv->ifv_p;
-
-		if (ec->ec_nvlans-- == 1) {
-			/*
-			 * Disable Tx/Rx of VLAN-sized frames.
-			 */
-			ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
-			if (ifv->ifv_p->if_flags & IFF_UP) {
-				(void)if_flags_set(ifv->ifv_p,
-				    ifv->ifv_p->if_flags);
-			}
-		}
+		struct ethercom *ec = (void *)p;
+		if (--ec->ec_nvlans == 0)
+			(void)ether_disable_vlan_mtu(p);
 
 		ether_ifdetach(ifp);
 		/* Restore vlan_ioctl overwritten by ether_ifdetach */
@@ -412,6 +400,8 @@ vlan_unconfig(struct ifnet *ifp)
 	if_down(ifp);
 	ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
 	ifp->if_capabilities = 0;
+
+	mutex_exit(&ifv_mtx);
 }
 
 /*

Reply via email to