Module Name:    src
Committed By:   snj
Date:           Tue Jan  2 10:20:34 UTC 2018

Modified Files:
        src/sys/arch/arm/sunxi [netbsd-8]: sunxi_emac.c
        src/sys/dev/ic [netbsd-8]: dwc_gmac.c
        src/sys/dev/pci [netbsd-8]: if_iwm.c if_wm.c
        src/sys/dev/pci/ixgbe [netbsd-8]: ixgbe.c ixv.c
        src/sys/kern [netbsd-8]: sys_socket.c
        src/sys/net [netbsd-8]: bpf.c if.c if.h if_bridge.c if_etherip.c
            if_ethersubr.c if_faith.c if_gif.c if_l2tp.c if_loop.c if_media.c
            if_pppoe.c if_spppsubr.c if_tun.c if_vlan.c rtsock.c
        src/sys/net/agr [netbsd-8]: if_agr.c
        src/sys/net/npf [netbsd-8]: npf_ifaddr.c npf_os.c
        src/sys/netcan [netbsd-8]: if_canloop.c
        src/sys/netinet [netbsd-8]: if_arp.c igmp.c in.c in_pcb.c ip_carp.c
            ip_flow.c ip_input.c ip_mroute.c ip_output.c
        src/sys/netinet6 [netbsd-8]: frag6.c in6.c in6_pcb.c ip6_flow.c
            ip6_input.c ip6_output.c mld6.c nd6.c nd6_nbr.c nd6_rtr.c
        src/sys/netipsec [netbsd-8]: ipsec_output.c
        src/sys/rump/net/lib/libnetinet [netbsd-8]: netinet_component.c

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #456):
        sys/arch/arm/sunxi/sunxi_emac.c: 1.9
        sys/dev/ic/dwc_gmac.c: 1.43-1.44
        sys/dev/pci/if_iwm.c: 1.75
        sys/dev/pci/if_wm.c: 1.543
        sys/dev/pci/ixgbe/ixgbe.c: 1.112
        sys/dev/pci/ixgbe/ixv.c: 1.74
        sys/kern/sys_socket.c: 1.75
        sys/net/agr/if_agr.c: 1.43
        sys/net/bpf.c: 1.219
        sys/net/if.c: 1.397, 1.399, 1.401-1.403, 1.406-1.410, 1.412-1.416
        sys/net/if.h: 1.242-1.247, 1.250, 1.252-1.257
        sys/net/if_bridge.c: 1.140 via patch, 1.142-1.146
        sys/net/if_etherip.c: 1.40
        sys/net/if_ethersubr.c: 1.243, 1.246
        sys/net/if_faith.c: 1.57
        sys/net/if_gif.c: 1.132
        sys/net/if_l2tp.c: 1.15, 1.17
        sys/net/if_loop.c: 1.98-1.101
        sys/net/if_media.c: 1.35
        sys/net/if_pppoe.c: 1.131-1.132
        sys/net/if_spppsubr.c: 1.176-1.177
        sys/net/if_tun.c: 1.142
        sys/net/if_vlan.c: 1.107, 1.109, 1.114-1.121
        sys/net/npf/npf_ifaddr.c: 1.3
        sys/net/npf/npf_os.c: 1.8-1.9
        sys/net/rtsock.c: 1.230
        sys/netcan/if_canloop.c: 1.3-1.5
        sys/netinet/if_arp.c: 1.255
        sys/netinet/igmp.c: 1.65
        sys/netinet/in.c: 1.210-1.211
        sys/netinet/in_pcb.c: 1.180
        sys/netinet/ip_carp.c: 1.92, 1.94
        sys/netinet/ip_flow.c: 1.81
        sys/netinet/ip_input.c: 1.362
        sys/netinet/ip_mroute.c: 1.147
        sys/netinet/ip_output.c: 1.283, 1.285, 1.287
        sys/netinet6/frag6.c: 1.61
        sys/netinet6/in6.c: 1.251, 1.255
        sys/netinet6/in6_pcb.c: 1.162
        sys/netinet6/ip6_flow.c: 1.35
        sys/netinet6/ip6_input.c: 1.183
        sys/netinet6/ip6_output.c: 1.196
        sys/netinet6/mld6.c: 1.90
        sys/netinet6/nd6.c: 1.239-1.240
        sys/netinet6/nd6_nbr.c: 1.139
        sys/netinet6/nd6_rtr.c: 1.136
        sys/netipsec/ipsec_output.c: 1.65
        sys/rump/net/lib/libnetinet/netinet_component.c: 1.9-1.10
kmem_intr_free kmem_intr_[z]alloced memory
the underlying pools are the same but api-wise those should match
Unify IFEF_*_MPSAFE into IFEF_MPSAFE
There are already two flags for if_output and if_start, however, it seems such
MPSAFE flags are eventually needed for all if_XXX operations. Having discrete
flags for each operation is wasteful of if_extflags bits. So let's unify
the flags into one: IFEF_MPSAFE.
Fortunately IFEF_*_MPSAFE flags have never been included in any releases, so
we can change them without breaking backward compatibility of the releases
(though the kernel version of -current should be bumped).
Note that if an interface have both MP-safe and non-MP-safe operations at a
time, we have to set the IFEF_MPSAFE flag and let callees of non-MP-safe
opeartions take the kernel lock.
Proposed on tech-kern@ and tech-net@
Provide macros for softnet_lock and KERNEL_LOCK hiding NET_MPSAFE switch
It reduces C&P codes such as "#ifndef NET_MPSAFE KERNEL_LOCK(1, NULL); ..."
scattered all over the source code and makes it easy to identify remaining
KERNEL_LOCK and/or softnet_lock that are held even if NET_MPSAFE.
No functional change
Hold KERNEL_LOCK on if_ioctl selectively based on IFEF_MPSAFE
If IFEF_MPSAFE is set, hold the lock and otherwise don't hold.
This change requires additions of KERNEL_LOCK to subsequence functions from
if_ioctl such as ifmedia_ioctl and ifioctl_common to protect non-MP-safe
components.
Proposed on tech-kern@ and tech-net@
Ensure to hold if_ioctl_lock when calling if_flags_set
Fix locking against myself on ifpromisc
vlan_unconfig_locked could be called with holding if_ioctl_lock.
Ensure to not turn on IFF_RUNNING of an interface until its initialization 
completes
And ensure to turn off it before destruction as per IFF_RUNNING's description
"resource allocated". (The description is a bit doubtful though, I believe the
change is still proper.)
Ensure to hold if_ioctl_lock on if_up and if_down
One exception for if_down is if_detach; in the case the lock isn't needed
because it's guaranteed that no other one can access ifp at that point.
Make if_link_queue MP-safe if IFEF_MPSAFE
if_link_queue is a queue to store events of link state changes, which is
used to pass events from (typically) an interrupt handler to
if_link_state_change softint. The queue was protected by KERNEL_LOCK so far,
but if IFEF_MPSAFE is enabled, it becomes unsafe because (perhaps) an interrupt
handler of an interface with IFEF_MPSAFE doesn't take KERNEL_LOCK. Protect it
by a spin mutex.
Additionally with this change KERNEL_LOCK of if_link_state_change softint is
omitted if NET_MPSAFE is enabled.
Note that the spin mutex is now ifp->if_snd.ifq_lock as well as the case of
if_timer (see the comment).
Use IFADDR_WRITER_FOREACH instead of IFADDR_READER_FOREACH
At that point no other one modifies the list so IFADDR_READER_FOREACH
is unnecessary. Use of IFADDR_READER_FOREACH is harmless in general though,
if we try to detect contract violations of pserialize, using it violates
the contract. So avoid using it makes life easy.
Ensure to call if_addr_init with holding if_ioctl_lock
Get rid of outdated comments
Fix build of kernels without ether
By throwing out if_enable_vlan_mtu and if_disable_vlan_mtu that
created a unnecessary dependency from if.c to if_ethersubr.c.
PR kern/52790
Rename IFNET_LOCK to IFNET_GLOBAL_LOCK
IFNET_LOCK will be used in another lock, if_ioctl_lock (might be renamed then).
Wrap if_ioctl_lock with IFNET_* macros (NFC)
Also if_ioctl_lock perhaps needs to be renamed to something because it's now
not just for ioctl...
Reorder some destruction routines in if_detach
- Destroy if_ioctl_lock at the end of the if_detach because it's used in various
  destruction routines
- Move psref_target_destroy after pr_purgeif because we want to use psref in
  pr_purgeif (otherwise destruction procedures can be tricky)
Ensure to call if_mcast_op with holding IFNET_LOCK
Note that CARP doesn't deal with IFNET_LOCK yet.
Remove IFNET_GLOBAL_LOCK where it's unnecessary because IFNET_LOCK is held
Describe which lock is used to protect each member variable of struct ifnet
Requested by skrll@
Write a guideline for converting an interface to IFEF_MPSAFE
Requested by skrll@
Note that IFNET_LOCK must not be held in softint
Don't set IFEF_MPSAFE unless NET_MPSAFE at this point
Because recent investigations show that interfaces with IFEF_MPSAFE need to
follow additional restrictions to work with the flag safely. We should enable it
on an interface by default only if the interface surely satisfies the
restrictions, which are described in if.h.
Note that enabling IFEF_MPSAFE solely gains a few benefit on performance because
the network stack is still serialized by the big kernel locks by default.


To generate a diff of this commit:
cvs rdiff -u -r1.4.4.3 -r1.4.4.4 src/sys/arch/arm/sunxi/sunxi_emac.c
cvs rdiff -u -r1.40.6.1 -r1.40.6.2 src/sys/dev/ic/dwc_gmac.c
cvs rdiff -u -r1.73.2.2 -r1.73.2.3 src/sys/dev/pci/if_iwm.c
cvs rdiff -u -r1.508.4.10 -r1.508.4.11 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.88.2.6 -r1.88.2.7 src/sys/dev/pci/ixgbe/ixgbe.c
cvs rdiff -u -r1.56.2.3 -r1.56.2.4 src/sys/dev/pci/ixgbe/ixv.c
cvs rdiff -u -r1.74 -r1.74.10.1 src/sys/kern/sys_socket.c
cvs rdiff -u -r1.216.6.3 -r1.216.6.4 src/sys/net/bpf.c
cvs rdiff -u -r1.394.2.3 -r1.394.2.4 src/sys/net/if.c
cvs rdiff -u -r1.239.2.2 -r1.239.2.3 src/sys/net/if.h
cvs rdiff -u -r1.134.6.4 -r1.134.6.5 src/sys/net/if_bridge.c
cvs rdiff -u -r1.38.10.1 -r1.38.10.2 src/sys/net/if_etherip.c
cvs rdiff -u -r1.242.6.1 -r1.242.6.2 src/sys/net/if_ethersubr.c
cvs rdiff -u -r1.55.8.1 -r1.55.8.2 src/sys/net/if_faith.c
cvs rdiff -u -r1.126.2.5 -r1.126.2.6 src/sys/net/if_gif.c
cvs rdiff -u -r1.11.2.2 -r1.11.2.3 src/sys/net/if_l2tp.c
cvs rdiff -u -r1.94.6.3 -r1.94.6.4 src/sys/net/if_loop.c
cvs rdiff -u -r1.32.6.1 -r1.32.6.2 src/sys/net/if_media.c
cvs rdiff -u -r1.125.6.4 -r1.125.6.5 src/sys/net/if_pppoe.c
cvs rdiff -u -r1.169.6.2 -r1.169.6.3 src/sys/net/if_spppsubr.c
cvs rdiff -u -r1.139.2.1 -r1.139.2.2 src/sys/net/if_tun.c
cvs rdiff -u -r1.97.2.10 -r1.97.2.11 src/sys/net/if_vlan.c
cvs rdiff -u -r1.213.2.3 -r1.213.2.4 src/sys/net/rtsock.c
cvs rdiff -u -r1.41 -r1.41.6.1 src/sys/net/agr/if_agr.c
cvs rdiff -u -r1.2 -r1.2.12.1 src/sys/net/npf/npf_ifaddr.c
cvs rdiff -u -r1.6.8.1 -r1.6.8.2 src/sys/net/npf/npf_os.c
cvs rdiff -u -r1.2 -r1.2.2.1 src/sys/netcan/if_canloop.c
cvs rdiff -u -r1.250.2.3 -r1.250.2.4 src/sys/netinet/if_arp.c
cvs rdiff -u -r1.64 -r1.64.6.1 src/sys/netinet/igmp.c
cvs rdiff -u -r1.203.2.3 -r1.203.2.4 src/sys/netinet/in.c
cvs rdiff -u -r1.178.4.1 -r1.178.4.2 src/sys/netinet/in_pcb.c
cvs rdiff -u -r1.90.2.2 -r1.90.2.3 src/sys/netinet/ip_carp.c
cvs rdiff -u -r1.80 -r1.80.6.1 src/sys/netinet/ip_flow.c
cvs rdiff -u -r1.355.2.2 -r1.355.2.3 src/sys/netinet/ip_input.c
cvs rdiff -u -r1.146.6.1 -r1.146.6.2 src/sys/netinet/ip_mroute.c
cvs rdiff -u -r1.279.2.2 -r1.279.2.3 src/sys/netinet/ip_output.c
cvs rdiff -u -r1.60 -r1.60.6.1 src/sys/netinet6/frag6.c
cvs rdiff -u -r1.245.2.3 -r1.245.2.4 src/sys/netinet6/in6.c
cvs rdiff -u -r1.161 -r1.161.4.1 src/sys/netinet6/in6_pcb.c
cvs rdiff -u -r1.34 -r1.34.8.1 src/sys/netinet6/ip6_flow.c
cvs rdiff -u -r1.178.2.2 -r1.178.2.3 src/sys/netinet6/ip6_input.c
cvs rdiff -u -r1.191.6.3 -r1.191.6.4 src/sys/netinet6/ip6_output.c
cvs rdiff -u -r1.89 -r1.89.2.1 src/sys/netinet6/mld6.c
cvs rdiff -u -r1.232.2.4 -r1.232.2.5 src/sys/netinet6/nd6.c
cvs rdiff -u -r1.138 -r1.138.6.1 src/sys/netinet6/nd6_nbr.c
cvs rdiff -u -r1.135 -r1.135.6.1 src/sys/netinet6/nd6_rtr.c
cvs rdiff -u -r1.48.2.1 -r1.48.2.2 src/sys/netipsec/ipsec_output.c
cvs rdiff -u -r1.8 -r1.8.6.1 \
    src/sys/rump/net/lib/libnetinet/netinet_component.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/arm/sunxi/sunxi_emac.c
diff -u src/sys/arch/arm/sunxi/sunxi_emac.c:1.4.4.3 src/sys/arch/arm/sunxi/sunxi_emac.c:1.4.4.4
--- src/sys/arch/arm/sunxi/sunxi_emac.c:1.4.4.3	Mon Sep 11 05:24:16 2017
+++ src/sys/arch/arm/sunxi/sunxi_emac.c	Tue Jan  2 10:20:32 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_emac.c,v 1.4.4.3 2017/09/11 05:24:16 snj Exp $ */
+/* $NetBSD: sunxi_emac.c,v 1.4.4.4 2018/01/02 10:20:32 snj Exp $ */
 
 /*-
  * Copyright (c) 2016-2017 Jared McNeill <jmcne...@invisible.ca>
@@ -33,7 +33,7 @@
 #include "opt_net_mpsafe.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.4.4.3 2017/09/11 05:24:16 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.4.4.4 2018/01/02 10:20:32 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -1368,7 +1368,7 @@ sunxi_emac_attach(device_t parent, devic
 	snprintf(ifp->if_xname, IFNAMSIZ, EMAC_IFNAME, device_unit(self));
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef EMAC_MPSAFE
-	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_extflags = IFEF_MPSAFE;
 #endif
 	ifp->if_start = sunxi_emac_start;
 	ifp->if_ioctl = sunxi_emac_ioctl;

Index: src/sys/dev/ic/dwc_gmac.c
diff -u src/sys/dev/ic/dwc_gmac.c:1.40.6.1 src/sys/dev/ic/dwc_gmac.c:1.40.6.2
--- src/sys/dev/ic/dwc_gmac.c:1.40.6.1	Sun Dec 10 10:10:23 2017
+++ src/sys/dev/ic/dwc_gmac.c	Tue Jan  2 10:20:32 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_gmac.c,v 1.40.6.1 2017/12/10 10:10:23 snj Exp $ */
+/* $NetBSD: dwc_gmac.c,v 1.40.6.2 2018/01/02 10:20:32 snj Exp $ */
 
 /*-
  * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.40.6.1 2017/12/10 10:10:23 snj Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.40.6.2 2018/01/02 10:20:32 snj Exp $");
 
 /* #define	DWC_GMAC_DEBUG	1 */
 
@@ -223,7 +223,9 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
 	ifp->if_softc = sc;
 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_extflags = IFEF_START_MPSAFE;
+#ifdef DWCGMAC_MPSAFE
+	ifp->if_extflags = IFEF_MPSAFE;
+#endif
 	ifp->if_ioctl = dwc_gmac_ioctl;
 	ifp->if_start = dwc_gmac_start;
 	ifp->if_init = dwc_gmac_init;
@@ -836,7 +838,7 @@ static void
 dwc_gmac_start(struct ifnet *ifp)
 {
 	struct dwc_gmac_softc *sc = ifp->if_softc;
-	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+	KASSERT(if_is_mpsafe(ifp));
 
 	mutex_enter(sc->sc_lock);
 	if (!sc->sc_stopping) {

Index: src/sys/dev/pci/if_iwm.c
diff -u src/sys/dev/pci/if_iwm.c:1.73.2.2 src/sys/dev/pci/if_iwm.c:1.73.2.3
--- src/sys/dev/pci/if_iwm.c:1.73.2.2	Sun Dec 10 10:10:24 2017
+++ src/sys/dev/pci/if_iwm.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwm.c,v 1.73.2.2 2017/12/10 10:10:24 snj Exp $	*/
+/*	$NetBSD: if_iwm.c,v 1.73.2.3 2018/01/02 10:20:33 snj Exp $	*/
 /*	OpenBSD: if_iwm.c,v 1.148 2016/11/19 21:07:08 stsp Exp	*/
 #define IEEE80211_NO_HT
 /*
@@ -106,7 +106,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.73.2.2 2017/12/10 10:10:24 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.73.2.3 2018/01/02 10:20:33 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -6321,7 +6321,7 @@ iwm_newstate_cb(struct work *wk, void *v
 	int arg = iwmns->ns_arg;
 	int s;
 
-	kmem_free(iwmns, sizeof(*iwmns));
+	kmem_intr_free(iwmns, sizeof(*iwmns));
 
 	s = splnet();
 

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.508.4.10 src/sys/dev/pci/if_wm.c:1.508.4.11
--- src/sys/dev/pci/if_wm.c:1.508.4.10	Sun Dec 10 10:16:09 2017
+++ src/sys/dev/pci/if_wm.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.508.4.10 2017/12/10 10:16:09 snj Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.508.4.11 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -83,7 +83,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.10 2017/12/10 10:16:09 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.11 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -2636,7 +2636,7 @@ alloc_retry:
 	ifp->if_softc = sc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef WM_MPSAFE
-	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_extflags = IFEF_MPSAFE;
 #endif
 	ifp->if_ioctl = wm_ioctl;
 	if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
@@ -7001,7 +7001,7 @@ wm_start(struct ifnet *ifp)
 	struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;
 
 #ifdef WM_MPSAFE
-	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+	KASSERT(if_is_mpsafe(ifp));
 #endif
 	/*
 	 * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.
@@ -7594,7 +7594,7 @@ wm_nq_start(struct ifnet *ifp)
 	struct wm_txqueue *txq = &sc->sc_queue[0].wmq_txq;
 
 #ifdef WM_MPSAFE
-	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+	KASSERT(if_is_mpsafe(ifp));
 #endif
 	/*
 	 * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.

Index: src/sys/dev/pci/ixgbe/ixgbe.c
diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.88.2.6 src/sys/dev/pci/ixgbe/ixgbe.c:1.88.2.7
--- src/sys/dev/pci/ixgbe/ixgbe.c:1.88.2.6	Thu Dec 21 19:28:54 2017
+++ src/sys/dev/pci/ixgbe/ixgbe.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.c,v 1.88.2.6 2017/12/21 19:28:54 snj Exp $ */
+/* $NetBSD: ixgbe.c,v 1.88.2.7 2018/01/02 10:20:33 snj Exp $ */
 
 /******************************************************************************
 
@@ -1219,7 +1219,7 @@ ixgbe_setup_interface(device_t dev, stru
 	ifp->if_softc = adapter;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef IXGBE_MPSAFE
-	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_extflags = IFEF_MPSAFE;
 #endif
 	ifp->if_ioctl = ixgbe_ioctl;
 #if __FreeBSD_version >= 1100045

Index: src/sys/dev/pci/ixgbe/ixv.c
diff -u src/sys/dev/pci/ixgbe/ixv.c:1.56.2.3 src/sys/dev/pci/ixgbe/ixv.c:1.56.2.4
--- src/sys/dev/pci/ixgbe/ixv.c:1.56.2.3	Thu Dec 21 19:28:54 2017
+++ src/sys/dev/pci/ixgbe/ixv.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*$NetBSD: ixv.c,v 1.56.2.3 2017/12/21 19:28:54 snj Exp $*/
+/*$NetBSD: ixv.c,v 1.56.2.4 2018/01/02 10:20:33 snj Exp $*/
 
 /******************************************************************************
 
@@ -1398,7 +1398,7 @@ ixv_setup_interface(device_t dev, struct
 	ifp->if_softc = adapter;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef IXGBE_MPSAFE
-	ifp->if_extflags = IFEF_START_MPSAFE;
+	ifp->if_extflags = IFEF_MPSAFE;
 #endif
 	ifp->if_ioctl = ixv_ioctl;
 	if (adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) {

Index: src/sys/kern/sys_socket.c
diff -u src/sys/kern/sys_socket.c:1.74 src/sys/kern/sys_socket.c:1.74.10.1
--- src/sys/kern/sys_socket.c:1.74	Thu Jul  7 06:55:43 2016
+++ src/sys/kern/sys_socket.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_socket.c,v 1.74 2016/07/07 06:55:43 msaitoh Exp $	*/
+/*	$NetBSD: sys_socket.c,v 1.74.10.1 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_socket.c,v 1.74 2016/07/07 06:55:43 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_socket.c,v 1.74.10.1 2018/01/02 10:20:33 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -197,14 +197,18 @@ soo_ioctl(file_t *fp, u_long cmd, void *
 		 * interface and routing ioctls should have a
 		 * different entry since a socket's unnecessary
 		 */
-		KERNEL_LOCK(1, NULL);
 		if (IOCGROUP(cmd) == 'i')
+			/*
+			 * KERNEL_LOCK will be held later if if_ioctl() of the
+			 * interface isn't MP-safe.
+			 */
 			error = ifioctl(so, cmd, data, curlwp);
 		else {
+			KERNEL_LOCK(1, NULL);
 			error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so,
 			    cmd, data, NULL);
+			KERNEL_UNLOCK_ONE(NULL);
 		}
-		KERNEL_UNLOCK_ONE(NULL);
 		break;
 	}
 

Index: src/sys/net/bpf.c
diff -u src/sys/net/bpf.c:1.216.6.3 src/sys/net/bpf.c:1.216.6.4
--- src/sys/net/bpf.c:1.216.6.3	Thu Dec 21 21:51:37 2017
+++ src/sys/net/bpf.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: bpf.c,v 1.216.6.3 2017/12/21 21:51:37 snj Exp $	*/
+/*	$NetBSD: bpf.c,v 1.216.6.4 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (c) 1990, 1991, 1993
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.216.6.3 2017/12/21 21:51:37 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.216.6.4 2018/01/02 10:20:33 snj Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_bpf.h"
@@ -484,13 +484,9 @@ bpf_detachd(struct bpf_d *d)
 		 * the interface was configured down, so only panic
 		 * if we don't get an unexpected error.
 		 */
-#ifndef NET_MPSAFE
-		KERNEL_LOCK(1, NULL);
-#endif
+		KERNEL_LOCK_UNLESS_NET_MPSAFE();
   		error = ifpromisc(bp->bif_ifp, 0);
-#ifndef NET_MPSAFE
-		KERNEL_UNLOCK_ONE(NULL);
-#endif
+		KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 #ifdef DIAGNOSTIC
 		if (error)
 			printf("%s: ifpromisc failed: %d", __func__, error);
@@ -1025,13 +1021,9 @@ bpf_ioctl(struct file *fp, u_long cmd, v
 			break;
 		}
 		if (d->bd_promisc == 0) {
-#ifndef NET_MPSAFE
-			KERNEL_LOCK(1, NULL);
-#endif
+			KERNEL_LOCK_UNLESS_NET_MPSAFE();
 			error = ifpromisc(d->bd_bif->bif_ifp, 1);
-#ifndef NET_MPSAFE
-			KERNEL_UNLOCK_ONE(NULL);
-#endif
+			KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 			if (error == 0)
 				d->bd_promisc = 1;
 		}
@@ -2250,13 +2242,9 @@ bpf_setdlt(struct bpf_d *d, u_int dlt)
 	bpf_attachd(d, bp);
 	reset_d(d);
 	if (opromisc) {
-#ifndef NET_MPSAFE
-		KERNEL_LOCK(1, NULL);
-#endif
+		KERNEL_LOCK_UNLESS_NET_MPSAFE();
 		error = ifpromisc(bp->bif_ifp, 1);
-#ifndef NET_MPSAFE
-		KERNEL_UNLOCK_ONE(NULL);
-#endif
+		KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 		if (error)
 			printf("%s: bpf_setdlt: ifpromisc failed (%d)\n",
 			    bp->bif_ifp->if_xname, error);

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.394.2.3 src/sys/net/if.c:1.394.2.4
--- src/sys/net/if.c:1.394.2.3	Sun Dec 10 10:10:24 2017
+++ src/sys/net/if.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.394.2.3 2017/12/10 10:10:24 snj Exp $	*/
+/*	$NetBSD: if.c,v 1.394.2.4 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.394.2.3 2017/12/10 10:10:24 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.394.2.4 2018/01/02 10:20:33 snj Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -209,6 +209,9 @@ static int if_transmit(struct ifnet *, s
 static int if_clone_create(const char *);
 static int if_clone_destroy(const char *);
 static void if_link_state_change_si(void *);
+static void if_up_locked(struct ifnet *);
+static void _if_down(struct ifnet *);
+static void if_down_deactivated(struct ifnet *);
 
 struct if_percpuq {
 	struct ifnet	*ipq_ifp;
@@ -711,7 +714,10 @@ if_initialize(ifnet_t *ifp)
 	IF_AFDATA_LOCK_INIT(ifp);
 
 	if (if_is_link_state_changeable(ifp)) {
-		ifp->if_link_si = softint_establish(SOFTINT_NET,
+		u_int flags = SOFTINT_NET;
+		flags |= ISSET(ifp->if_extflags, IFEF_MPSAFE) ?
+		    SOFTINT_MPSAFE : 0;
+		ifp->if_link_si = softint_establish(flags,
 		    if_link_state_change_si, ifp);
 		if (ifp->if_link_si == NULL) {
 			rv = ENOMEM;
@@ -725,9 +731,9 @@ if_initialize(ifnet_t *ifp)
 	ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
 	LIST_INIT(&ifp->if_multiaddrs);
 
-	IFNET_LOCK();
+	IFNET_GLOBAL_LOCK();
 	if_getindex(ifp);
-	IFNET_UNLOCK();
+	IFNET_GLOBAL_UNLOCK();
 
 	return 0;
 
@@ -774,10 +780,10 @@ if_register(ifnet_t *ifp)
 	if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit)
 		ifp->if_transmit = if_transmit;
 
-	IFNET_LOCK();
+	IFNET_GLOBAL_LOCK();
 	TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list);
 	IFNET_WRITER_INSERT_TAIL(ifp);
-	IFNET_UNLOCK();
+	IFNET_GLOBAL_UNLOCK();
 }
 
 /*
@@ -1306,23 +1312,9 @@ if_detach(struct ifnet *ifp)
 	s = splnet();
 
 	sysctl_teardown(&ifp->if_sysctl_log);
-	mutex_enter(ifp->if_ioctl_lock);
+	IFNET_LOCK(ifp);
 	if_deactivate(ifp);
-	mutex_exit(ifp->if_ioctl_lock);
-
-	IFNET_LOCK();
-	ifindex2ifnet[ifp->if_index] = NULL;
-	TAILQ_REMOVE(&ifnet_list, ifp, if_list);
-	IFNET_WRITER_REMOVE(ifp);
-	pserialize_perform(ifnet_psz);
-	IFNET_UNLOCK();
-
-	/* Wait for all readers to drain before freeing.  */
-	psref_target_destroy(&ifp->if_psref, ifnet_psref_class);
-	PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry);
-
-	mutex_obj_free(ifp->if_ioctl_lock);
-	ifp->if_ioctl_lock = NULL;
+	IFNET_UNLOCK(ifp);
 
 	if (ifp->if_slowtimo != NULL && ifp->if_slowtimo_ch != NULL) {
 		ifp->if_slowtimo = NULL;
@@ -1335,7 +1327,7 @@ if_detach(struct ifnet *ifp)
 	/*
 	 * Do an if_down() to give protocols a chance to do something.
 	 */
-	if_down(ifp);
+	if_down_deactivated(ifp);
 
 #ifdef ALTQ
 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
@@ -1368,9 +1360,11 @@ if_detach(struct ifnet *ifp)
 again:
 	/*
 	 * At this point, no other one tries to remove ifa in the list,
-	 * so we don't need to take a lock or psref.
+	 * so we don't need to take a lock or psref.  Avoid using
+	 * IFADDR_READER_FOREACH to pass over an inspection of contract
+	 * violations of pserialize.
 	 */
-	IFADDR_READER_FOREACH(ifa, ifp) {
+	IFADDR_WRITER_FOREACH(ifa, ifp) {
 		family = ifa->ifa_addr->sa_family;
 #ifdef IFAREF_DEBUG
 		printf("if_detach: ifaddr %p, family %d, refcnt %d\n",
@@ -1447,6 +1441,17 @@ again:
 		}
 	}
 
+	/* Wait for all readers to drain before freeing.  */
+	IFNET_GLOBAL_LOCK();
+	ifindex2ifnet[ifp->if_index] = NULL;
+	TAILQ_REMOVE(&ifnet_list, ifp, if_list);
+	IFNET_WRITER_REMOVE(ifp);
+	pserialize_perform(ifnet_psz);
+	IFNET_GLOBAL_UNLOCK();
+
+	psref_target_destroy(&ifp->if_psref, ifnet_psref_class);
+	PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry);
+
 	pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp);
 	(void)pfil_head_destroy(ifp->if_pfil);
 
@@ -1493,6 +1498,9 @@ again:
 		ifp->if_percpuq = NULL;
 	}
 
+	mutex_obj_free(ifp->if_ioctl_lock);
+	ifp->if_ioctl_lock = NULL;
+
 	splx(s);
 
 #ifdef IFAREF_DEBUG
@@ -1594,9 +1602,9 @@ if_clone_destroy(const char *name)
 		return ENXIO;
 
 	/* We have to disable ioctls here */
-	mutex_enter(ifp->if_ioctl_lock);
+	IFNET_LOCK(ifp);
 	ifp->if_ioctl = if_nullioctl;
-	mutex_exit(ifp->if_ioctl_lock);
+	IFNET_UNLOCK(ifp);
 
 	/*
 	 * We cannot call ifc_destroy with holding ifp.
@@ -1783,11 +1791,18 @@ ifa_insert(struct ifnet *ifp, struct ifa
 
 	ifa->ifa_ifp = ifp;
 
-	IFNET_LOCK();
+	/*
+	 * Check !IFF_RUNNING for initialization routines that normally don't
+	 * take IFNET_LOCK but it's safe because there is no competitor.
+	 * XXX there are false positive cases because IFF_RUNNING can be off on
+	 * if_stop.
+	 */
+	KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING) ||
+	    IFNET_LOCKED(ifp));
+
 	TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list);
 	IFADDR_ENTRY_INIT(ifa);
 	IFADDR_WRITER_INSERT_TAIL(ifp, ifa);
-	IFNET_UNLOCK();
 
 	ifaref(ifa);
 }
@@ -1797,14 +1812,19 @@ ifa_remove(struct ifnet *ifp, struct ifa
 {
 
 	KASSERT(ifa->ifa_ifp == ifp);
+	/*
+	 * if_is_deactivated indicates ifa_remove is called form if_detach
+	 * where is safe even if IFNET_LOCK isn't held.
+	 */
+	KASSERT(if_is_deactivated(ifp) || IFNET_LOCKED(ifp));
 
-	IFNET_LOCK();
 	TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
 	IFADDR_WRITER_REMOVE(ifa);
 #ifdef NET_MPSAFE
+	IFNET_GLOBAL_LOCK();
 	pserialize_perform(ifnet_psz);
+	IFNET_GLOBAL_UNLOCK();
 #endif
-	IFNET_UNLOCK();
 
 #ifdef NET_MPSAFE
 	psref_target_destroy(&ifa->ifa_psref, ifa_psref_class);
@@ -2184,6 +2204,21 @@ link_rtrequest(int cmd, struct rtentry *
 		if (LQ_ITEM((q), (i)) == LINK_STATE_UNSET)		      \
 			break;						      \
 	}
+
+/*
+ * XXX reusing (ifp)->if_snd->ifq_lock rather than having another spin mutex
+ * for each ifnet.  It doesn't matter because:
+ * - if IFEF_MPSAFE is enabled, if_snd isn't used and lock contentions on
+ *   ifq_lock don't happen
+ * - if IFEF_MPSAFE is disabled, there is no lock contention on ifq_lock
+ *   because if_snd, if_link_state_change and if_link_state_change_softint
+ *   are all called with KERNEL_LOCK
+ */
+#define IF_LINK_STATE_CHANGE_LOCK(ifp)		\
+	mutex_enter((ifp)->if_snd.ifq_lock)
+#define IF_LINK_STATE_CHANGE_UNLOCK(ifp)	\
+	mutex_exit((ifp)->if_snd.ifq_lock)
+
 /*
  * Handle a change in the interface link state and
  * queue notifications.
@@ -2191,7 +2226,7 @@ link_rtrequest(int cmd, struct rtentry *
 void
 if_link_state_change(struct ifnet *ifp, int link_state)
 {
-	int s, idx;
+	int idx;
 
 	KASSERTMSG(if_is_link_state_changeable(ifp),
 	    "%s: IFEF_NO_LINK_STATE_CHANGE must not be set, but if_extflags=0x%x",
@@ -2211,7 +2246,7 @@ if_link_state_change(struct ifnet *ifp, 
 		return;
 	}
 
-	s = splnet();
+	IF_LINK_STATE_CHANGE_LOCK(ifp);
 
 	/* Find the last unset event in the queue. */
 	LQ_FIND_UNSET(ifp->if_link_queue, idx);
@@ -2255,7 +2290,7 @@ if_link_state_change(struct ifnet *ifp, 
 	softint_schedule(ifp->if_link_si);
 
 out:
-	splx(s);
+	IF_LINK_STATE_CHANGE_UNLOCK(ifp);
 }
 
 /*
@@ -2266,12 +2301,15 @@ if_link_state_change_softint(struct ifne
 {
 	struct domain *dp;
 	int s = splnet();
+	bool notify;
 
 	KASSERT(!cpu_intr_p());
 
+	IF_LINK_STATE_CHANGE_LOCK(ifp);
+
 	/* Ensure the change is still valid. */
 	if (ifp->if_link_state == link_state) {
-		splx(s);
+		IF_LINK_STATE_CHANGE_UNLOCK(ifp);
 		return;
 	}
 
@@ -2294,9 +2332,14 @@ if_link_state_change_softint(struct ifne
 	 * listeners would have an address and expect it to work right
 	 * away.
 	 */
-	if (link_state == LINK_STATE_UP &&
-	    ifp->if_link_state == LINK_STATE_UNKNOWN)
-	{
+	notify = (link_state == LINK_STATE_UP &&
+	    ifp->if_link_state == LINK_STATE_UNKNOWN);
+	ifp->if_link_state = link_state;
+	/* The following routines may sleep so release the spin mutex */
+	IF_LINK_STATE_CHANGE_UNLOCK(ifp);
+
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
+	if (notify) {
 		DOMAIN_FOREACH(dp) {
 			if (dp->dom_if_link_state_change != NULL)
 				dp->dom_if_link_state_change(ifp,
@@ -2304,8 +2347,6 @@ if_link_state_change_softint(struct ifne
 		}
 	}
 
-	ifp->if_link_state = link_state;
-
 	/* Notify that the link state has changed. */
 	rt_ifmsg(ifp);
 
@@ -2318,6 +2359,7 @@ if_link_state_change_softint(struct ifne
 		if (dp->dom_if_link_state_change != NULL)
 			dp->dom_if_link_state_change(ifp, link_state);
 	}
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 	splx(s);
 }
 
@@ -2330,26 +2372,27 @@ if_link_state_change_si(void *arg)
 	struct ifnet *ifp = arg;
 	int s;
 	uint8_t state;
+	bool schedule;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	s = splnet();
 
 	/* Pop a link state change from the queue and process it. */
+	IF_LINK_STATE_CHANGE_LOCK(ifp);
 	LQ_POP(ifp->if_link_queue, state);
+	IF_LINK_STATE_CHANGE_UNLOCK(ifp);
+
 	if_link_state_change_softint(ifp, state);
 
 	/* If there is a link state change to come, schedule it. */
-	if (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET)
+	IF_LINK_STATE_CHANGE_LOCK(ifp);
+	schedule = (LQ_ITEM(ifp->if_link_queue, 0) != LINK_STATE_UNSET);
+	IF_LINK_STATE_CHANGE_UNLOCK(ifp);
+	if (schedule)
 		softint_schedule(ifp->if_link_si);
 
 	splx(s);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*
@@ -2404,13 +2447,8 @@ p2p_rtrequest(int req, struct rtentry *r
 	pserialize_read_exit(s);
 }
 
-/*
- * Mark an interface down and notify protocols of
- * the transition.
- * NOTE: must be called at splsoftnet or equivalent.
- */
-void
-if_down(struct ifnet *ifp)
+static void
+_if_down(struct ifnet *ifp)
 {
 	struct ifaddr *ifa;
 	struct domain *dp;
@@ -2446,19 +2484,50 @@ if_down(struct ifnet *ifp)
 	}
 }
 
+static void
+if_down_deactivated(struct ifnet *ifp)
+{
+
+	KASSERT(if_is_deactivated(ifp));
+	_if_down(ifp);
+}
+
+void
+if_down_locked(struct ifnet *ifp)
+{
+
+	KASSERT(IFNET_LOCKED(ifp));
+	_if_down(ifp);
+}
+
 /*
- * Mark an interface up and notify protocols of
+ * Mark an interface down and notify protocols of
  * the transition.
  * NOTE: must be called at splsoftnet or equivalent.
  */
 void
-if_up(struct ifnet *ifp)
+if_down(struct ifnet *ifp)
+{
+
+	IFNET_LOCK(ifp);
+	if_down_locked(ifp);
+	IFNET_UNLOCK(ifp);
+}
+
+/*
+ * Must be called with holding if_ioctl_lock.
+ */
+static void
+if_up_locked(struct ifnet *ifp)
 {
 #ifdef notyet
 	struct ifaddr *ifa;
 #endif
 	struct domain *dp;
 
+	KASSERT(IFNET_LOCKED(ifp));
+
+	KASSERT(!if_is_deactivated(ifp));
 	ifp->if_flags |= IFF_UP;
 	nanotime(&ifp->if_lastchange);
 #ifdef notyet
@@ -2504,17 +2573,33 @@ if_slowtimo(void *arg)
 }
 
 /*
+ * Mark an interface up and notify protocols of
+ * the transition.
+ * NOTE: must be called at splsoftnet or equivalent.
+ */
+void
+if_up(struct ifnet *ifp)
+{
+
+	IFNET_LOCK(ifp);
+	if_up_locked(ifp);
+	IFNET_UNLOCK(ifp);
+}
+
+/*
  * Set/clear promiscuous mode on interface ifp based on the truth value
  * of pswitch.  The calls are reference counted so that only the first
  * "on" request actually has an effect, as does the final "off" request.
  * Results are undefined if the "off" and "on" requests are not matched.
  */
 int
-ifpromisc(struct ifnet *ifp, int pswitch)
+ifpromisc_locked(struct ifnet *ifp, int pswitch)
 {
-	int pcount, ret;
+	int pcount, ret = 0;
 	short nflags;
 
+	KASSERT(IFNET_LOCKED(ifp));
+
 	pcount = ifp->if_pcount;
 	if (pswitch) {
 		/*
@@ -2523,11 +2608,11 @@ ifpromisc(struct ifnet *ifp, int pswitch
 		 * consult IFF_PROMISC when it is brought up.
 		 */
 		if (ifp->if_pcount++ != 0)
-			return 0;
+			goto out;
 		nflags = ifp->if_flags | IFF_PROMISC;
 	} else {
 		if (--ifp->if_pcount > 0)
-			return 0;
+			goto out;
 		nflags = ifp->if_flags & ~IFF_PROMISC;
 	}
 	ret = if_flags_set(ifp, nflags);
@@ -2535,9 +2620,22 @@ ifpromisc(struct ifnet *ifp, int pswitch
 	if (ret != 0) {
 		ifp->if_pcount = pcount;
 	}
+out:
 	return ret;
 }
 
+int
+ifpromisc(struct ifnet *ifp, int pswitch)
+{
+	int e;
+
+	IFNET_LOCK(ifp);
+	e = ifpromisc_locked(ifp, pswitch);
+	IFNET_UNLOCK(ifp);
+
+	return e;
+}
+
 /*
  * Map interface name to
  * interface structure pointer.
@@ -2634,12 +2732,27 @@ if_put(const struct ifnet *ifp, struct p
 	psref_release(psref, &ifp->if_psref, ifnet_psref_class);
 }
 
+/*
+ * Return ifp having idx. Return NULL if not found.  Normally if_byindex
+ * should be used.
+ */
+ifnet_t *
+_if_byindex(u_int idx)
+{
+
+	return (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL;
+}
+
+/*
+ * Return ifp having idx. Return NULL if not found or the found ifp is
+ * already deactivated.
+ */
 ifnet_t *
 if_byindex(u_int idx)
 {
 	ifnet_t *ifp;
 
-	ifp = (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL;
+	ifp = _if_byindex(idx);
 	if (ifp != NULL && if_is_deactivated(ifp))
 		ifp = NULL;
 	return ifp;
@@ -2771,16 +2884,22 @@ ifioctl_common(struct ifnet *ifp, u_long
 		return 0;
 	case SIOCSIFFLAGS:
 		ifr = data;
+		/*
+		 * If if_is_mpsafe(ifp), KERNEL_LOCK isn't held here, but if_up
+		 * and if_down aren't MP-safe yet, so we must hold the lock.
+		 */
+		KERNEL_LOCK_IF_IFP_MPSAFE(ifp);
 		if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
 			s = splsoftnet();
-			if_down(ifp);
+			if_down_locked(ifp);
 			splx(s);
 		}
 		if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) {
 			s = splsoftnet();
-			if_up(ifp);
+			if_up_locked(ifp);
 			splx(s);
 		}
+		KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp);
 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
 			(ifr->ifr_flags &~ IFF_CANTCHANGE);
 		break;
@@ -2852,8 +2971,10 @@ ifioctl_common(struct ifnet *ifp, u_long
 		 * If the link MTU changed, do network layer specific procedure.
 		 */
 #ifdef INET6
+		KERNEL_LOCK_UNLESS_NET_MPSAFE();
 		if (in6_present)
 			nd6_setmtu(ifp);
+		KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 #endif
 		return ENETRESET;
 	default:
@@ -2997,11 +3118,13 @@ doifioctl(struct socket *so, u_long cmd,
 				return error;
 			}
 		}
+		KERNEL_LOCK_UNLESS_NET_MPSAFE();
 		mutex_enter(&if_clone_mtx);
 		r = (cmd == SIOCIFCREATE) ?
 			if_clone_create(ifr->ifr_name) :
 			if_clone_destroy(ifr->ifr_name);
 		mutex_exit(&if_clone_mtx);
+		KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 		curlwp_bindx(bound);
 		return r;
 
@@ -3059,7 +3182,8 @@ doifioctl(struct socket *so, u_long cmd,
 
 	oif_flags = ifp->if_flags;
 
-	mutex_enter(ifp->if_ioctl_lock);
+	KERNEL_LOCK_UNLESS_IFP_MPSAFE(ifp);
+	IFNET_LOCK(ifp);
 
 	error = (*ifp->if_ioctl)(ifp, cmd, data);
 	if (error != ENOTTY)
@@ -3067,6 +3191,7 @@ doifioctl(struct socket *so, u_long cmd,
 	else if (so->so_proto == NULL)
 		error = EOPNOTSUPP;
 	else {
+		KERNEL_LOCK_IF_IFP_MPSAFE(ifp);
 #ifdef COMPAT_OSOCK
 		if (vec_compat_ifioctl != NULL)
 			error = (*vec_compat_ifioctl)(so, ocmd, cmd, data, l);
@@ -3074,12 +3199,13 @@ doifioctl(struct socket *so, u_long cmd,
 #endif
 			error = (*so->so_proto->pr_usrreqs->pr_ioctl)(so,
 			    cmd, data, ifp);
+		KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp);
 	}
 
 	if (((oif_flags ^ ifp->if_flags) & IFF_UP) != 0) {
 		if ((ifp->if_flags & IFF_UP) != 0) {
 			int s = splsoftnet();
-			if_up(ifp);
+			if_up_locked(ifp);
 			splx(s);
 		}
 	}
@@ -3088,7 +3214,8 @@ doifioctl(struct socket *so, u_long cmd,
 		ifreqn2o(oifr, ifr);
 #endif
 
-	mutex_exit(ifp->if_ioctl_lock);
+	IFNET_UNLOCK(ifp);
+	KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(ifp);
 out:
 	if_put(ifp, &psref);
 	curlwp_bindx(bound);
@@ -3345,10 +3472,10 @@ if_addr_init(ifnet_t *ifp, struct ifaddr
 {
 	int rc;
 
+	KASSERT(IFNET_LOCKED(ifp));
 	if (ifp->if_initaddr != NULL)
 		rc = (*ifp->if_initaddr)(ifp, ifa, src);
 	else if (src ||
-		/* FIXME: may not hold if_ioctl_lock */
 	         (rc = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY)
 		rc = (*ifp->if_ioctl)(ifp, SIOCINITIFADDR, ifa);
 
@@ -3393,6 +3520,8 @@ if_flags_set(ifnet_t *ifp, const short f
 {
 	int rc;
 
+	KASSERT(IFNET_LOCKED(ifp));
+
 	if (ifp->if_setflags != NULL)
 		rc = (*ifp->if_setflags)(ifp, flags);
 	else {
@@ -3415,7 +3544,6 @@ if_flags_set(ifnet_t *ifp, const short f
 		memset(&ifr, 0, sizeof(ifr));
 
 		ifr.ifr_flags = flags & ~IFF_CANTCHANGE;
-		/* FIXME: may not hold if_ioctl_lock */
 		rc = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr);
 
 		if (rc != 0 && cantflags != 0)
@@ -3431,6 +3559,10 @@ if_mcast_op(ifnet_t *ifp, const unsigned
 	int rc;
 	struct ifreq ifr;
 
+	/* CARP still doesn't deal with the lock yet */
+#if !defined(NCARP) || (NCARP == 0)
+	KASSERT(IFNET_LOCKED(ifp));
+#endif
 	if (ifp->if_mcastop != NULL)
 		rc = (*ifp->if_mcastop)(ifp, cmd, sa);
 	else {

Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.239.2.2 src/sys/net/if.h:1.239.2.3
--- src/sys/net/if.h:1.239.2.2	Sun Dec 10 10:10:24 2017
+++ src/sys/net/if.h	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.h,v 1.239.2.2 2017/12/10 10:10:24 snj Exp $	*/
+/*	$NetBSD: if.h,v 1.239.2.3 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -235,86 +235,111 @@ struct in6_multi;
 
 typedef unsigned short if_index_t;
 
+/*
+ * Interface.  Field markings and the corresponding locks:
+ *
+ * i:	IFNET_LOCK (a.k.a., if_ioctl_lock)
+ * q:	ifq_lock (struct ifaltq)
+ * a:	if_afdata_lock
+ * 6:	in6_multilock (global lock)
+ * ::	unlocked, stable
+ * ?:	unkown, maybe unsafe
+ *
+ * Lock order: IFNET_LOCK => in6_multilock => if_afdata_lock => ifq_lock
+ *   Note that currently if_afdata_lock and ifq_lock aren't held
+ *   at the same time, but define the order anyway.
+ *
+ * Lock order of IFNET_LOCK with other locks:
+ *     softnet_lock => solock => IFNET_LOCK => ND6_LOCK, in_multilock
+ */
 typedef struct ifnet {
-	void	*if_softc;		/* lower-level data for this if */
+	void		*if_softc;	/* :: lower-level data for this if */
 	/* DEPRECATED. Keep it to avoid breaking kvm(3) users */
-	TAILQ_ENTRY(ifnet) if_list;	/* all struct ifnets are chained */
-	TAILQ_HEAD(, ifaddr) if_addrlist; /* linked list of addresses per if */
-	char	if_xname[IFNAMSIZ];	/* external name (name + unit) */
-	int	if_pcount;		/* number of promiscuous listeners */
-	struct bpf_if *if_bpf;		/* packet filter structure */
-	if_index_t	if_index;	/* numeric abbreviation for this if */
-	short	if_timer;		/* time 'til if_slowtimo called */
-	unsigned short	if_flags;	/* up/down, broadcast, etc. */
-	short	if_extflags;		/* if_output MP-safe, etc. */
-	struct	if_data if_data;	/* statistics and other data about if */
+	TAILQ_ENTRY(ifnet)
+			if_list;	/* i: all struct ifnets are chained */
+	TAILQ_HEAD(, ifaddr)
+			if_addrlist;	/* i: linked list of addresses per if */
+	char		if_xname[IFNAMSIZ];
+					/* :: external name (name + unit) */
+	int		if_pcount;	/* i: number of promiscuous listeners */
+	struct bpf_if	*if_bpf;	/* :: packet filter structure */
+	if_index_t	if_index;	/* :: numeric abbreviation for this if */
+	short		if_timer;	/* ?: time 'til if_slowtimo called */
+	unsigned short	if_flags;	/* i: up/down, broadcast, etc. */
+	short		if_extflags;	/* :: if_output MP-safe, etc. */
+	struct if_data	if_data;	/* ?: statistics and other data about if */
 	/*
 	 * Procedure handles.  If you add more of these, don't forget the
 	 * corresponding NULL stub in if.c.
 	 */
-	int	(*if_output)		/* output routine (enqueue) */
-		    (struct ifnet *, struct mbuf *, const struct sockaddr *,
-		     const struct rtentry *);
-	void	(*_if_input)		/* input routine (from h/w driver) */
-		    (struct ifnet *, struct mbuf *);
-	void	(*if_start)		/* initiate output routine */
-		    (struct ifnet *);
-	int	(*if_transmit)		/* output routine, must be MP-safe */
-		    (struct ifnet *, struct mbuf *);
-	int	(*if_ioctl)		/* ioctl routine */
-		    (struct ifnet *, u_long, void *);
-	int	(*if_init)		/* init routine */
-		    (struct ifnet *);
-	void	(*if_stop)		/* stop routine */
-		    (struct ifnet *, int);
-	void	(*if_slowtimo)		/* timer routine */
-		    (struct ifnet *);
+	int		(*if_output)	/* :: output routine (enqueue) */
+			    (struct ifnet *, struct mbuf *, const struct sockaddr *,
+			     const struct rtentry *);
+	void		(*_if_input)	/* :: input routine (from h/w driver) */
+			    (struct ifnet *, struct mbuf *);
+	void		(*if_start)	/* :: initiate output routine */
+			    (struct ifnet *);
+	int		(*if_transmit)	/* :: output routine, must be MP-safe */
+			    (struct ifnet *, struct mbuf *);
+	int		(*if_ioctl)	/* :: ioctl routine */
+			    (struct ifnet *, u_long, void *);
+	int		(*if_init)	/* :: init routine */
+			    (struct ifnet *);
+	void		(*if_stop)	/* :: stop routine */
+			    (struct ifnet *, int);
+	void		(*if_slowtimo)	/* :: timer routine */
+			    (struct ifnet *);
 #define	if_watchdog	if_slowtimo
-	void	(*if_drain)		/* routine to release resources */
-		    (struct ifnet *);
-	struct ifaltq if_snd;		/* output queue (includes altq) */
-	struct ifaddr	*if_dl;		/* identity of this interface. */
-	const struct	sockaddr_dl *if_sadl;	/* pointer to sockaddr_dl
-						 * of if_dl
-						 */
-	/* if_hwdl: h/w identity
-	 *
+	void		(*if_drain)	/* :: routine to release resources */
+			    (struct ifnet *);
+	struct ifaltq	if_snd;		/* q: output queue (includes altq) */
+	struct ifaddr	*if_dl;		/* i: identity of this interface. */
+	const struct sockaddr_dl
+			*if_sadl;	/* i: pointer to sockaddr_dl of if_dl */
+	/*
 	 * May be NULL.  If not NULL, it is the address assigned
 	 * to the interface by the manufacturer, so it very likely
 	 * to be unique.  It MUST NOT be deleted.  It is highly
 	 * suitable for deriving the EUI64 for the interface.
 	 */
-	struct ifaddr	*if_hwdl;
-	const uint8_t *if_broadcastaddr;/* linklevel broadcast bytestring */
-	struct bridge_softc	*if_bridge;	/* bridge glue */
-	struct bridge_iflist	*if_bridgeif;	/* shortcut to interface list entry */
-	int	if_dlt;			/* data link type (<net/dlt.h>) */
-	pfil_head_t *	if_pfil;	/* filtering point */
-	uint64_t if_capabilities;	/* interface capabilities */
-	uint64_t if_capenable;		/* capabilities enabled */
+	struct ifaddr	*if_hwdl;	/* i: h/w identity */
+	const uint8_t	*if_broadcastaddr;
+					/* :: linklevel broadcast bytestring */
+	struct bridge_softc
+			*if_bridge;	/* i: bridge glue */
+	struct bridge_iflist
+			*if_bridgeif;	/* i: shortcut to interface list entry */
+	int		if_dlt;		/* :: data link type (<net/dlt.h>) */
+	pfil_head_t *	if_pfil;	/* :: filtering point */
+	uint64_t	if_capabilities;
+					/* i: interface capabilities */
+	uint64_t	if_capenable;	/* i: capabilities enabled */
 	union {
 		void *		carp_s;	/* carp structure (used by !carp ifs) */
 		struct ifnet	*carp_d;/* ptr to carpdev (used by carp ifs) */
-	} if_carp_ptr;
+	}		if_carp_ptr;	/* ?: */
 #define if_carp		if_carp_ptr.carp_s
 #define if_carpdev	if_carp_ptr.carp_d
 	/*
 	 * These are pre-computed based on an interfaces enabled
 	 * capabilities, for speed elsewhere.
 	 */
-	int	if_csum_flags_tx;	/* M_CSUM_* flags for Tx */
-	int	if_csum_flags_rx;	/* M_CSUM_* flags for Rx */
-
-	void	*if_afdata[AF_MAX];
-	struct	mowner *if_mowner;	/* who owns mbufs for this interface */
+	int		if_csum_flags_tx;
+					/* i: M_CSUM_* flags for Tx */
+	int		if_csum_flags_rx;
+					/* i: M_CSUM_* flags for Rx */
+
+	void		*if_afdata[AF_MAX];
+					/* a: */
+	struct mowner	*if_mowner;	/* ?: who owns mbufs for this interface */
 
-	void	*if_agrprivate;		/* used only when #if NAGR > 0 */
+	void		*if_agrprivate;	/* ?: used only when #if NAGR > 0 */
 
 	/*
 	 * pf specific data, used only when #if NPF > 0.
 	 */
-	void	*if_pf_kif;		/* pf interface abstraction */
-	void	*if_pf_groups;		/* pf interface groups */
+	void		*if_pf_kif;	/* ?: pf interface abstraction */
+	void		*if_pf_groups;	/* ?: pf interface groups */
 	/*
 	 * During an ifnet's lifetime, it has only one if_index, but
 	 * and if_index is not sufficient to identify an ifnet
@@ -324,29 +349,40 @@ typedef struct ifnet {
 	 * is assigned when it if_attach()s.  Now, the kernel can use the
 	 * pair (if_index, if_index_gen) as a weak reference to an ifnet.
 	 */
-	uint64_t if_index_gen;		/* generation number for the ifnet
+	uint64_t	if_index_gen;	/* :: generation number for the ifnet
 					 * at if_index: if two ifnets' index
 					 * and generation number are both the
 					 * same, they are the same ifnet.
 					 */
-	struct sysctllog	*if_sysctl_log;
-	int (*if_initaddr)(struct ifnet *, struct ifaddr *, bool);
-	int (*if_mcastop)(struct ifnet *, const unsigned long,
-	    const struct sockaddr *);
-	int (*if_setflags)(struct ifnet *, const short);
-	kmutex_t	*if_ioctl_lock;
+	struct sysctllog
+			*if_sysctl_log;	/* :: */
+	int		(*if_initaddr)  /* :: */
+			    (struct ifnet *, struct ifaddr *, bool);
+	int		(*if_mcastop)	/* :: */
+			    (struct ifnet *, const unsigned long,
+			    const struct sockaddr *);
+	int		(*if_setflags)	/* :: */
+			    (struct ifnet *, const short);
+	kmutex_t	*if_ioctl_lock;	/* :: */
 #ifdef _KERNEL /* XXX kvm(3) */
-	struct callout *if_slowtimo_ch;
-	struct krwlock	*if_afdata_lock;
-	struct if_percpuq	*if_percpuq; /* We should remove it in the future */
-	void	*if_link_si;		/* softint to handle link state changes */
-	uint16_t	if_link_queue;	/* masked link state change queue */
-	struct pslist_entry	if_pslist_entry;
-	struct psref_target     if_psref;
-	struct pslist_head	if_addr_pslist;
-	struct if_deferred_start	*if_deferred_start;
+	struct callout	*if_slowtimo_ch;/* :: */
+	struct krwlock	*if_afdata_lock;/* :: */
+	struct if_percpuq
+			*if_percpuq;	/* :: we should remove it in the future */
+	void		*if_link_si;	/* :: softint to handle link state changes */
+	uint16_t	if_link_queue;	/* q: masked link state change queue */
+	struct pslist_entry
+			if_pslist_entry;/* i: */
+	struct psref_target
+			if_psref;	/* :: */
+	struct pslist_head
+			if_addr_pslist;	/* i: */
+	struct if_deferred_start
+			*if_deferred_start;
+					/* :: */
 	/* XXX should be protocol independent */
-	LIST_HEAD(, in6_multi) if_multiaddrs;
+	LIST_HEAD(, in6_multi)
+			if_multiaddrs;	/* 6: */
 #endif
 } ifnet_t;
  
@@ -387,16 +423,55 @@ typedef struct ifnet {
 #define	IFF_LINK2	0x4000		/* per link layer defined bit */
 #define	IFF_MULTICAST	0x8000		/* supports multicast */
 
-#define	IFEF_OUTPUT_MPSAFE		__BIT(0)	/* if_output() can run parallel */
-#define	IFEF_START_MPSAFE		__BIT(1)	/* if_start() can run parallel */
-#define	IFEF_NO_LINK_STATE_CHANGE	__BIT(2)	/* doesn't use link state interrupts */
+#define	IFEF_MPSAFE			__BIT(0)	/* handlers can run in parallel (see below) */
+#define	IFEF_NO_LINK_STATE_CHANGE	__BIT(1)	/* doesn't use link state interrupts */
+
+/*
+ * The guidelines for converting an interface to IFEF_MPSAFE are as follows
+ *
+ * Enabling IFEF_MPSAFE on an interface suppresses taking KERNEL_LOCK when
+ * calling the following handlers:
+ * - if_start
+ *   - Note that if_transmit is always called without KERNEL_LOCK
+ * - if_output
+ * - if_ioctl
+ * - if_init
+ * - if_stop
+ *
+ * This means that an interface with IFEF_MPSAFE must make the above handlers
+ * MP-safe or take KERNEL_LOCK by itself inside handlers that aren't MP-safe
+ * yet.
+ *
+ * There are some additional restrictions to access member variables of struct
+ * ifnet:
+ * - if_flags
+ *   - Must be updated with holding IFNET_LOCK
+ *   - You cannot use the flag in Tx/Rx paths anymore because there is no
+ *     synchronization on the flag except for IFNET_LOCK
+ *   - Note that IFNET_LOCK can't be taken in softint because it's known
+ *     that it causes a deadlock
+ *     - Some synchronization mechanisms such as pserialize_perform are called
+ *       with IFNET_LOCK and also require context switches on every CPUs
+ *       that mean softints finish so trying to take IFNET_LOCK in softint
+ *       might block on IFNET_LOCK and prevent such synchronization mechanisms
+ *       from being completed
+ *     - Currently the deadlock occurs only if NET_MPSAFE is enabled, however,
+ *       we should deal with the restriction because NET_MPSAFE will be enabled
+ *       by default in the future
+ * - if_watchdog and if_timer
+ *   - The watchdog framework works only for non-IFEF_MPSAFE interfaces
+ *     that rely on KERNEL_LOCK
+ *   - Interfaces with IFEF_MPSAFE have to provide its own watchdog mechanism
+ *     if needed
+ *     - Keep if_watchdog NULL when calling if_attach
+ */
 
 #ifdef _KERNEL
 static inline bool
-if_output_is_mpsafe(struct ifnet *ifp)
+if_is_mpsafe(struct ifnet *ifp)
 {
 
-	return ((ifp->if_extflags & IFEF_OUTPUT_MPSAFE) != 0);
+	return ((ifp->if_extflags & IFEF_MPSAFE) != 0);
 }
 
 static inline int
@@ -404,7 +479,7 @@ if_output_lock(struct ifnet *cifp, struc
     const struct sockaddr *dst, const struct rtentry *rt)
 {
 
-	if (if_output_is_mpsafe(cifp)) {
+	if (if_is_mpsafe(cifp)) {
 		return (*cifp->if_output)(ifp, m, dst, rt);
 	} else {
 		int ret;
@@ -416,18 +491,11 @@ if_output_lock(struct ifnet *cifp, struc
 	}
 }
 
-static inline bool
-if_start_is_mpsafe(struct ifnet *ifp)
-{
-
-	return ((ifp->if_extflags & IFEF_START_MPSAFE) != 0);
-}
-
 static inline void
 if_start_lock(struct ifnet *ifp)
 {
 
-	if (if_start_is_mpsafe(ifp)) {
+	if (if_is_mpsafe(ifp)) {
 		(*ifp->if_start)(ifp);
 	} else {
 		KERNEL_LOCK(1, NULL);
@@ -442,6 +510,56 @@ if_is_link_state_changeable(struct ifnet
 
 	return ((ifp->if_extflags & IFEF_NO_LINK_STATE_CHANGE) == 0);
 }
+
+#define KERNEL_LOCK_IF_IFP_MPSAFE(ifp)					\
+	do { if (if_is_mpsafe(ifp)) { KERNEL_LOCK(1, NULL); } } while (0)
+#define KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp)				\
+	do { if (if_is_mpsafe(ifp)) { KERNEL_UNLOCK_ONE(NULL); } } while (0)
+
+#define KERNEL_LOCK_UNLESS_IFP_MPSAFE(ifp)				\
+	do { if (!if_is_mpsafe(ifp)) { KERNEL_LOCK(1, NULL); } } while (0)
+#define KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(ifp)				\
+	do { if (!if_is_mpsafe(ifp)) { KERNEL_UNLOCK_ONE(NULL); } } while (0)
+
+#ifdef _KERNEL_OPT
+#include "opt_net_mpsafe.h"
+#endif
+
+/* XXX explore a better place to define */
+#ifdef NET_MPSAFE
+
+#define KERNEL_LOCK_UNLESS_NET_MPSAFE()		do { } while (0)
+#define KERNEL_UNLOCK_UNLESS_NET_MPSAFE()	do { } while (0)
+
+#define SOFTNET_LOCK_UNLESS_NET_MPSAFE()	do { } while (0)
+#define SOFTNET_UNLOCK_UNLESS_NET_MPSAFE()	do { } while (0)
+
+#else /* NET_MPSAFE */
+
+#define KERNEL_LOCK_UNLESS_NET_MPSAFE()					\
+	do { KERNEL_LOCK(1, NULL); } while (0)
+#define KERNEL_UNLOCK_UNLESS_NET_MPSAFE()				\
+	do { KERNEL_UNLOCK_ONE(NULL); } while (0)
+
+#define SOFTNET_LOCK_UNLESS_NET_MPSAFE()				\
+	do { mutex_enter(softnet_lock); } while (0)
+#define SOFTNET_UNLOCK_UNLESS_NET_MPSAFE()				\
+	do { mutex_exit(softnet_lock); } while (0)
+
+#endif /* NET_MPSAFE */
+
+#define SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE()				\
+	do {								\
+		SOFTNET_LOCK_UNLESS_NET_MPSAFE();			\
+		KERNEL_LOCK_UNLESS_NET_MPSAFE();			\
+	} while (0)
+
+#define SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE()			\
+	do {								\
+		KERNEL_UNLOCK_UNLESS_NET_MPSAFE();			\
+		SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();			\
+	} while (0)
+
 #endif /* _KERNEL */
 
 #define	IFFBITS \
@@ -956,6 +1074,7 @@ bool	if_is_deactivated(const struct ifne
 void	if_purgeaddrs(struct ifnet *, int, void (*)(struct ifaddr *));
 void	if_detach(struct ifnet *);
 void	if_down(struct ifnet *);
+void	if_down_locked(struct ifnet *);
 void	if_link_state_change(struct ifnet *, int);
 void	if_link_state_change_softint(struct ifnet *, int);
 void	if_up(struct ifnet *);
@@ -965,6 +1084,7 @@ int	ifaddrpref_ioctl(struct socket *, u_
 extern int (*ifioctl)(struct socket *, u_long, void *, struct lwp *);
 int	ifioctl_common(struct ifnet *, u_long, void *);
 int	ifpromisc(struct ifnet *, int);
+int	ifpromisc_locked(struct ifnet *, int);
 int	if_addr_init(ifnet_t *, struct ifaddr *, bool);
 int	if_do_dad(struct ifnet *);
 int	if_mcast_op(ifnet_t *, const unsigned long, const struct sockaddr *);
@@ -974,6 +1094,7 @@ int	if_clone_list(int, char *, int *);
 struct	ifnet *ifunit(const char *);
 struct	ifnet *if_get(const char *, struct psref *);
 ifnet_t *if_byindex(u_int);
+ifnet_t *_if_byindex(u_int);
 ifnet_t *if_get_byindex(u_int, struct psref *);
 ifnet_t *if_get_bylla(const void *, unsigned char, struct psref *);
 void	if_put(const struct ifnet *, struct psref *);
@@ -1131,9 +1252,9 @@ __END_DECLS
 		}							\
 	} while (0)
 
-#define	IFNET_LOCK()			mutex_enter(&ifnet_mtx)
-#define	IFNET_UNLOCK()			mutex_exit(&ifnet_mtx)
-#define	IFNET_LOCKED()			mutex_owned(&ifnet_mtx)
+#define	IFNET_GLOBAL_LOCK()			mutex_enter(&ifnet_mtx)
+#define	IFNET_GLOBAL_UNLOCK()			mutex_exit(&ifnet_mtx)
+#define	IFNET_GLOBAL_LOCKED()			mutex_owned(&ifnet_mtx)
 
 #define IFNET_READER_EMPTY() \
 	(PSLIST_READER_FIRST(&ifnet_pslist, struct ifnet, if_pslist_entry) == NULL)
@@ -1173,6 +1294,10 @@ __END_DECLS
 		}							\
 	} while (0)
 
+#define IFNET_LOCK(ifp)		mutex_enter((ifp)->if_ioctl_lock)
+#define IFNET_UNLOCK(ifp)	mutex_exit((ifp)->if_ioctl_lock)
+#define IFNET_LOCKED(ifp)	mutex_owned((ifp)->if_ioctl_lock)
+
 extern struct pslist_head ifnet_pslist;
 extern kmutex_t ifnet_mtx;
 

Index: src/sys/net/if_bridge.c
diff -u src/sys/net/if_bridge.c:1.134.6.4 src/sys/net/if_bridge.c:1.134.6.5
--- src/sys/net/if_bridge.c:1.134.6.4	Sun Dec 10 10:10:24 2017
+++ src/sys/net/if_bridge.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_bridge.c,v 1.134.6.4 2017/12/10 10:10:24 snj Exp $	*/
+/*	$NetBSD: if_bridge.c,v 1.134.6.5 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.134.6.4 2017/12/10 10:10:24 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.134.6.5 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_bridge_ipf.h"
@@ -424,7 +424,10 @@ bridge_clone_create(struct if_clone *ifc
 
 	if_initname(ifp, ifc->ifc_name, unit);
 	ifp->if_softc = sc;
-	ifp->if_extflags = IFEF_OUTPUT_MPSAFE | IFEF_NO_LINK_STATE_CHANGE;
+	ifp->if_extflags = IFEF_NO_LINK_STATE_CHANGE;
+#ifdef NET_MPSAFE
+	ifp->if_extflags |= IFEF_MPSAFE;
+#endif
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_ioctl = bridge_ioctl;
 	ifp->if_output = bridge_output;
@@ -777,7 +780,10 @@ bridge_ioctl_add(struct bridge_softc *sc
 		}
 		/* FALLTHROUGH */
 	case IFT_L2TP:
-		if ((error = ether_enable_vlan_mtu(ifs)) > 0)
+		IFNET_LOCK(ifs);
+		error = ether_enable_vlan_mtu(ifs);
+		IFNET_UNLOCK(ifs);
+		if (error > 0)
 			goto out;
 		/*
 		 * Place the interface into promiscuous mode.
@@ -858,7 +864,9 @@ bridge_ioctl_del(struct bridge_softc *sc
 		 * Don't call it with holding a spin lock.
 		 */
 		(void) ifpromisc(ifs, 0);
+		IFNET_LOCK(ifs);
 		(void) ether_disable_vlan_mtu(ifs);
+		IFNET_UNLOCK(ifs);
 		break;
 	default:
 #ifdef DIAGNOSTIC
@@ -1332,14 +1340,13 @@ bridge_init(struct ifnet *ifp)
 {
 	struct bridge_softc *sc = ifp->if_softc;
 
-	if (ifp->if_flags & IFF_RUNNING)
-		return 0;
+	KASSERT((ifp->if_flags & IFF_RUNNING) == 0);
 
 	callout_reset(&sc->sc_brcallout, bridge_rtable_prune_period * hz,
 	    bridge_timer, sc);
+	bstp_initialization(sc);
 
 	ifp->if_flags |= IFF_RUNNING;
-	bstp_initialization(sc);
 	return 0;
 }
 
@@ -1353,15 +1360,12 @@ bridge_stop(struct ifnet *ifp, int disab
 {
 	struct bridge_softc *sc = ifp->if_softc;
 
-	if ((ifp->if_flags & IFF_RUNNING) == 0)
-		return;
+	KASSERT((ifp->if_flags & IFF_RUNNING) != 0);
+	ifp->if_flags &= ~IFF_RUNNING;
 
 	callout_stop(&sc->sc_brcallout);
 	bstp_stop(sc);
-
 	bridge_rtflush(sc, IFBF_FLUSHDYN);
-
-	ifp->if_flags &= ~IFF_RUNNING;
 }
 
 /*
@@ -1445,7 +1449,7 @@ bridge_output(struct ifnet *ifp, struct 
 	/*
 	 * bridge_output() is called from ether_output(), furthermore
 	 * ifp argument doesn't point to bridge(4). So, don't assert
-	 * IFEF_OUTPUT_MPSAFE here.
+	 * IFEF_MPSAFE here.
 	 */
 
 	if (m->m_len < ETHER_HDR_LEN) {

Index: src/sys/net/if_etherip.c
diff -u src/sys/net/if_etherip.c:1.38.10.1 src/sys/net/if_etherip.c:1.38.10.2
--- src/sys/net/if_etherip.c:1.38.10.1	Sun Dec 10 10:10:25 2017
+++ src/sys/net/if_etherip.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_etherip.c,v 1.38.10.1 2017/12/10 10:10:25 snj Exp $        */
+/*      $NetBSD: if_etherip.c,v 1.38.10.2 2018/01/02 10:20:33 snj Exp $        */
 
 /*
  *  Copyright (c) 2006, Hans Rosenfeld <rosenf...@grumpf.hope-2000.org>
@@ -86,7 +86,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_etherip.c,v 1.38.10.1 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_etherip.c,v 1.38.10.2 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -549,12 +549,11 @@ etherip_set_tunnel(struct ifnet *ifp,
 	if (odst)
 		sockaddr_free(odst);
 
-	ifp->if_flags |= IFF_RUNNING;
-
 	sc->sc_si = softint_establish(SOFTINT_NET, etheripintr, sc);
 	if (sc->sc_si == NULL)
 		error = ENOMEM;
 
+	ifp->if_flags |= IFF_RUNNING;
 out:
 	splx(s);
 
@@ -569,6 +568,8 @@ etherip_delete_tunnel(struct ifnet *ifp)
 
 	s = splsoftnet();
 
+	ifp->if_flags &= ~IFF_RUNNING;
+
 	if (sc->sc_si) {
 		softint_disestablish(sc->sc_si);
 		sc->sc_si = NULL;
@@ -583,7 +584,6 @@ etherip_delete_tunnel(struct ifnet *ifp)
 		sc->sc_dst = NULL;
 	}
 
-	ifp->if_flags &= ~IFF_RUNNING;
 	splx(s);
 }
 

Index: src/sys/net/if_ethersubr.c
diff -u src/sys/net/if_ethersubr.c:1.242.6.1 src/sys/net/if_ethersubr.c:1.242.6.2
--- src/sys/net/if_ethersubr.c:1.242.6.1	Tue Oct 24 08:38:59 2017
+++ src/sys/net/if_ethersubr.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ethersubr.c,v 1.242.6.1 2017/10/24 08:38:59 snj Exp $	*/
+/*	$NetBSD: if_ethersubr.c,v 1.242.6.2 2018/01/02 10:20:33 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.242.6.1 2017/10/24 08:38:59 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.242.6.2 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -204,13 +204,6 @@ ether_output(struct ifnet * const ifp0, 
 	struct at_ifaddr *aa;
 #endif /* NETATALK */
 
-	/*
-	 * some paths such as carp_output() call ethr_output() with "ifp"
-	 * argument as other than ether ifnet.
-	 */
-	KASSERT(ifp->if_output != ether_output
-	    || ifp->if_extflags & IFEF_OUTPUT_MPSAFE);
-
 #ifdef MBUFTRACE
 	m_claimm(m, ifp->if_mowner);
 #endif
@@ -951,7 +944,6 @@ ether_ifattach(struct ifnet *ifp, const 
 {
 	struct ethercom *ec = (struct ethercom *)ifp;
 
-	ifp->if_extflags |= IFEF_OUTPUT_MPSAFE;
 	ifp->if_type = IFT_ETHER;
 	ifp->if_hdrlen = ETHER_HDR_LEN;
 	ifp->if_dlt = DLT_EN10MB;
@@ -1013,7 +1005,7 @@ ether_ifdetach(struct ifnet *ifp)
 	mutex_enter(ec->ec_lock);
 	while ((enm = LIST_FIRST(&ec->ec_multiaddrs)) != NULL) {
 		LIST_REMOVE(enm, enm_list);
-		kmem_free(enm, sizeof(*enm));
+		kmem_intr_free(enm, sizeof(*enm));
 		ec->ec_multicnt--;
 	}
 	mutex_exit(ec->ec_lock);
@@ -1277,7 +1269,7 @@ ether_addmulti(const struct sockaddr *sa
 out:
 	mutex_exit(ec->ec_lock);
 	if (enm != NULL)
-		kmem_free(enm, sizeof(*enm));
+		kmem_intr_free(enm, sizeof(*enm));
 	return error;
 }
 
@@ -1319,7 +1311,7 @@ ether_delmulti(const struct sockaddr *sa
 	ec->ec_multicnt--;
 	mutex_exit(ec->ec_lock);
 
-	kmem_free(enm, sizeof(*enm));
+	kmem_intr_free(enm, sizeof(*enm));
 	/*
 	 * Return ENETRESET to inform the driver that the list has changed
 	 * and its reception filter should be adjusted accordingly.

Index: src/sys/net/if_faith.c
diff -u src/sys/net/if_faith.c:1.55.8.1 src/sys/net/if_faith.c:1.55.8.2
--- src/sys/net/if_faith.c:1.55.8.1	Sun Dec 10 10:10:25 2017
+++ src/sys/net/if_faith.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_faith.c,v 1.55.8.1 2017/12/10 10:10:25 snj Exp $	*/
+/*	$NetBSD: if_faith.c,v 1.55.8.2 2018/01/02 10:20:33 snj Exp $	*/
 /*	$KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $	*/
 
 /*
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_faith.c,v 1.55.8.1 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_faith.c,v 1.55.8.2 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -263,9 +263,9 @@ faithioctl(struct ifnet *ifp, u_long cmd
 	switch (cmd) {
 
 	case SIOCINITIFADDR:
-		ifp->if_flags |= IFF_UP | IFF_RUNNING;
 		ifa = (struct ifaddr *)data;
 		ifa->ifa_rtrequest = faithrtrequest;
+		ifp->if_flags |= IFF_UP | IFF_RUNNING;
 		/*
 		 * Everything else is done at a higher level.
 		 */

Index: src/sys/net/if_gif.c
diff -u src/sys/net/if_gif.c:1.126.2.5 src/sys/net/if_gif.c:1.126.2.6
--- src/sys/net/if_gif.c:1.126.2.5	Thu Dec 21 19:14:41 2017
+++ src/sys/net/if_gif.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gif.c,v 1.126.2.5 2017/12/21 19:14:41 snj Exp $	*/
+/*	$NetBSD: if_gif.c,v 1.126.2.6 2018/01/02 10:20:33 snj Exp $	*/
 /*	$KAME: if_gif.c,v 1.76 2001/08/20 02:01:02 kjc Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.126.2.5 2017/12/21 19:14:41 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gif.c,v 1.126.2.6 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -275,7 +275,7 @@ gifattach0(struct gif_softc *sc)
 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
 	sc->gif_if.if_extflags  = IFEF_NO_LINK_STATE_CHANGE;
 #ifdef GIF_MPSAFE
-	sc->gif_if.if_extflags  |= IFEF_OUTPUT_MPSAFE;
+	sc->gif_if.if_extflags  |= IFEF_MPSAFE;
 #endif
 	sc->gif_if.if_ioctl  = gif_ioctl;
 	sc->gif_if.if_output = gif_output;

Index: src/sys/net/if_l2tp.c
diff -u src/sys/net/if_l2tp.c:1.11.2.2 src/sys/net/if_l2tp.c:1.11.2.3
--- src/sys/net/if_l2tp.c:1.11.2.2	Wed Nov  8 22:20:59 2017
+++ src/sys/net/if_l2tp.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_l2tp.c,v 1.11.2.2 2017/11/08 22:20:59 snj Exp $	*/
+/*	$NetBSD: if_l2tp.c,v 1.11.2.3 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (c) 2017 Internet Initiative Japan Inc.
@@ -31,10 +31,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_l2tp.c,v 1.11.2.2 2017/11/08 22:20:59 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_l2tp.c,v 1.11.2.3 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
+#include "opt_net_mpsafe.h"
 #endif
 
 #include <sys/param.h>
@@ -261,8 +262,10 @@ l2tpattach0(struct l2tp_softc *sc)
 	sc->l2tp_ec.ec_if.if_addrlen = 0;
 	sc->l2tp_ec.ec_if.if_mtu    = L2TP_MTU;
 	sc->l2tp_ec.ec_if.if_flags  = IFF_POINTOPOINT|IFF_MULTICAST|IFF_SIMPLEX;
-	sc->l2tp_ec.ec_if.if_extflags  = IFEF_OUTPUT_MPSAFE |
-	    IFEF_START_MPSAFE | IFEF_NO_LINK_STATE_CHANGE;
+	sc->l2tp_ec.ec_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE;
+#ifdef NET_MPSAFE
+	sc->l2tp_ec.ec_if.if_extflags |= IFEF_MPSAFE;
+#endif
 	sc->l2tp_ec.ec_if.if_ioctl  = l2tp_ioctl;
 	sc->l2tp_ec.ec_if.if_output = l2tp_output;
 	sc->l2tp_ec.ec_if.if_type   = IFT_L2TP;

Index: src/sys/net/if_loop.c
diff -u src/sys/net/if_loop.c:1.94.6.3 src/sys/net/if_loop.c:1.94.6.4
--- src/sys/net/if_loop.c:1.94.6.3	Sun Dec 10 10:10:25 2017
+++ src/sys/net/if_loop.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_loop.c,v 1.94.6.3 2017/12/10 10:10:25 snj Exp $	*/
+/*	$NetBSD: if_loop.c,v 1.94.6.4 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_loop.c,v 1.94.6.3 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_loop.c,v 1.94.6.4 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -182,8 +182,10 @@ loop_clone_create(struct if_clone *ifc, 
 	if_initname(ifp, ifc->ifc_name, unit);
 
 	ifp->if_mtu = LOMTU;
-	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST | IFF_RUNNING;
-	ifp->if_extflags = IFEF_OUTPUT_MPSAFE;
+	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
+#ifdef NET_MPSAFE
+	ifp->if_extflags = IFEF_MPSAFE;
+#endif
 	ifp->if_ioctl = loioctl;
 	ifp->if_output = looutput;
 #ifdef ALTQ
@@ -211,6 +213,8 @@ loop_clone_create(struct if_clone *ifc, 
 	MOWNER_ATTACH(ifp->if_mowner);
 #endif
 
+	ifp->if_flags |= IFF_RUNNING;
+
 	return (0);
 }
 
@@ -221,6 +225,8 @@ loop_clone_destroy(struct ifnet *ifp)
 	if (ifp == lo0ifp)
 		return (EPERM);
 
+	ifp->if_flags &= ~IFF_RUNNING;
+
 #ifdef MBUFTRACE
 	MOWNER_DETACH(ifp->if_mowner);
 	free(ifp->if_mowner, M_DEVBUF);
@@ -247,9 +253,7 @@ looutput(struct ifnet *ifp, struct mbuf 
 
 	MCLAIM(m, ifp->if_mowner);
 
-#ifndef NET_MPSAFE
-	KERNEL_LOCK(1, NULL);
-#endif
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	if ((m->m_flags & M_PKTHDR) == 0)
 		panic("looutput: no header mbuf");
@@ -375,9 +379,7 @@ looutput(struct ifnet *ifp, struct mbuf 
 	schednetisr(isr);
 	splx(s);
 out:
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-#endif
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 	return error;
 }
 

Index: src/sys/net/if_media.c
diff -u src/sys/net/if_media.c:1.32.6.1 src/sys/net/if_media.c:1.32.6.2
--- src/sys/net/if_media.c:1.32.6.1	Wed Nov 22 14:36:55 2017
+++ src/sys/net/if_media.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_media.c,v 1.32.6.1 2017/11/22 14:36:55 martin Exp $	*/
+/*	$NetBSD: if_media.c,v 1.32.6.2 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_media.c,v 1.32.6.1 2017/11/22 14:36:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_media.c,v 1.32.6.2 2018/01/02 10:20:33 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -225,8 +225,8 @@ ifmedia_set(struct ifmedia *ifm, int tar
 /*
  * Device-independent media ioctl support function.
  */
-int
-ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
+static int
+_ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
     u_long cmd)
 {
 	struct ifmedia_entry *match;
@@ -360,6 +360,22 @@ ifmedia_ioctl(struct ifnet *ifp, struct 
 	return error;
 }
 
+int
+ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
+    u_long cmd)
+{
+	int e;
+
+	/*
+	 * If if_is_mpsafe(ifp), KERNEL_LOCK isn't held here, but _ifmedia_ioctl
+	 * isn't MP-safe yet, so we must hold the lock.
+	 */
+	KERNEL_LOCK_IF_IFP_MPSAFE(ifp);
+	e = _ifmedia_ioctl(ifp, ifr, ifm, cmd);
+	KERNEL_UNLOCK_IF_IFP_MPSAFE(ifp);
+	return e;
+}
+
 /*
  * Find media entry matching a given ifm word.
  */

Index: src/sys/net/if_pppoe.c
diff -u src/sys/net/if_pppoe.c:1.125.6.4 src/sys/net/if_pppoe.c:1.125.6.5
--- src/sys/net/if_pppoe.c:1.125.6.4	Sun Dec 10 10:10:25 2017
+++ src/sys/net/if_pppoe.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_pppoe.c,v 1.125.6.4 2017/12/10 10:10:25 snj Exp $ */
+/* $NetBSD: if_pppoe.c,v 1.125.6.5 2018/01/02 10:20:33 snj Exp $ */
 
 /*-
  * Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.125.6.4 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_pppoe.c,v 1.125.6.5 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "pppoe.h"
@@ -301,7 +301,7 @@ pppoe_clone_create(struct if_clone *ifc,
 	sc->sc_sppp.pp_if.if_mtu = PPPOE_MAXMTU;
 	sc->sc_sppp.pp_if.if_flags = IFF_SIMPLEX|IFF_POINTOPOINT|IFF_MULTICAST;
 #ifdef PPPOE_MPSAFE
-	sc->sc_sppp.pp_if.if_extflags = IFEF_OUTPUT_MPSAFE;
+	sc->sc_sppp.pp_if.if_extflags = IFEF_MPSAFE;
 #endif
 	sc->sc_sppp.pp_if.if_type = IFT_PPP;
 	sc->sc_sppp.pp_if.if_hdrlen = sizeof(struct ether_header) + PPPOE_HEADERLEN;
@@ -475,9 +475,7 @@ pppoeintr(void)
 	struct mbuf *m;
 	int disc_done, data_done;
 
-#ifndef PPPOE_MPSAFE
-		mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 
 	do {
 		disc_done = 0;
@@ -500,9 +498,8 @@ pppoeintr(void)
 			pppoe_data_input(m);
 		}
 	} while (disc_done || data_done);
-#ifndef PPPOE_MPSAFE
-		mutex_exit(softnet_lock);
-#endif
+
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /* analyze and handle a single received packet while not in session state */

Index: src/sys/net/if_spppsubr.c
diff -u src/sys/net/if_spppsubr.c:1.169.6.2 src/sys/net/if_spppsubr.c:1.169.6.3
--- src/sys/net/if_spppsubr.c:1.169.6.2	Thu Nov 30 15:57:37 2017
+++ src/sys/net/if_spppsubr.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_spppsubr.c,v 1.169.6.2 2017/11/30 15:57:37 martin Exp $	 */
+/*	$NetBSD: if_spppsubr.c,v 1.169.6.3 2018/01/02 10:20:33 snj Exp $	 */
 
 /*
  * Synchronous PPP/Cisco link level subroutines.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.169.6.2 2017/11/30 15:57:37 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.169.6.3 2018/01/02 10:20:33 snj Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -5271,6 +5271,8 @@ sppp_set_ip_addrs_work(struct work *wk, 
 	uint32_t myaddr = 0, hisaddr = 0;
 	int s;
 
+	IFNET_LOCK(ifp);
+
 	/*
 	 * Pick the first AF_INET address from the list,
 	 * aliases don't make any sense on a p2p link anyway.
@@ -5334,6 +5336,8 @@ sppp_set_ip_addrs_work(struct work *wk, 
 			    ifp->if_xname, ifp->if_mtu);
 	}
 
+	IFNET_UNLOCK(ifp);
+
 	sppp_notify_con(sp);
 }
 
@@ -5365,6 +5369,8 @@ sppp_clear_ip_addrs_work(struct work *wk
 	struct sockaddr_in *si, *dest;
 	int s;
 
+	IFNET_LOCK(ifp);
+
 	/*
 	 * Pick the first AF_INET address from the list,
 	 * aliases don't make any sense on a p2p link anyway.
@@ -5414,6 +5420,8 @@ sppp_clear_ip_addrs_work(struct work *wk
 			    "%s: resetting MTU to %" PRIu64 " bytes\n",
 			    ifp->if_xname, ifp->if_mtu);
 	}
+
+	IFNET_UNLOCK(ifp);
 }
 
 static void
@@ -5531,6 +5539,8 @@ sppp_set_ip6_addr(struct sppp *sp, const
 	int s;
 	struct psref psref;
 
+	IFNET_LOCK(ifp);
+
 	/*
 	 * Pick the first link-local AF_INET6 address from the list,
 	 * aliases don't make any sense on a p2p link anyway.
@@ -5568,6 +5578,8 @@ sppp_set_ip6_addr(struct sppp *sp, const
 		}
 		ifa_release(ifa, &psref);
 	}
+
+	IFNET_UNLOCK(ifp);
 }
 #endif
 

Index: src/sys/net/if_tun.c
diff -u src/sys/net/if_tun.c:1.139.2.1 src/sys/net/if_tun.c:1.139.2.2
--- src/sys/net/if_tun.c:1.139.2.1	Wed Nov  8 22:20:59 2017
+++ src/sys/net/if_tun.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_tun.c,v 1.139.2.1 2017/11/08 22:20:59 snj Exp $	*/
+/*	$NetBSD: if_tun.c,v 1.139.2.2 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (c) 1988, Julian Onions <j...@cs.nott.ac.uk>
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.139.2.1 2017/11/08 22:20:59 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.139.2.2 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -421,8 +421,6 @@ tun_enable(struct tun_softc *tp, const s
 	TUNDEBUG("%s: %s\n", __func__, ifp->if_xname);
 
 	mutex_enter(&tp->tun_lock);
-	ifp->if_flags |= IFF_UP | IFF_RUNNING;
-
 	tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR);
 
 	switch (ifa->ifa_addr->sa_family) {
@@ -462,6 +460,7 @@ tun_enable(struct tun_softc *tp, const s
 	default:
 		break;
 	}
+	ifp->if_flags |= IFF_UP | IFF_RUNNING;
 	mutex_exit(&tp->tun_lock);
 }
 

Index: src/sys/net/if_vlan.c
diff -u src/sys/net/if_vlan.c:1.97.2.10 src/sys/net/if_vlan.c:1.97.2.11
--- src/sys/net/if_vlan.c:1.97.2.10	Sun Dec 10 10:10:25 2017
+++ src/sys/net/if_vlan.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_vlan.c,v 1.97.2.10 2017/12/10 10:10:25 snj Exp $	*/
+/*	$NetBSD: if_vlan.c,v 1.97.2.11 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -78,10 +78,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.97.2.10 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.97.2.11 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
+#include "opt_net_mpsafe.h"
 #endif
 
 #include <sys/param.h>
@@ -245,6 +246,26 @@ struct if_clone vlan_cloner =
 /* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
 static char vlan_zero_pad_buff[ETHER_MIN_LEN];
 
+static inline int
+vlan_safe_ifpromisc(struct ifnet *ifp, int pswitch)
+{
+	int e;
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
+	e = ifpromisc(ifp, pswitch);
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
+	return e;
+}
+
+static inline int
+vlan_safe_ifpromisc_locked(struct ifnet *ifp, int pswitch)
+{
+	int e;
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
+	e = ifpromisc_locked(ifp, pswitch);
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
+	return e;
+}
+
 void
 vlanattach(int n)
 {
@@ -338,7 +359,10 @@ vlan_clone_create(struct if_clone *ifc, 
 	if_initname(ifp, ifc->ifc_name, unit);
 	ifp->if_softc = ifv;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_extflags = IFEF_START_MPSAFE | IFEF_NO_LINK_STATE_CHANGE;
+	ifp->if_extflags = IFEF_NO_LINK_STATE_CHANGE;
+#ifdef NET_MPSAFE
+	ifp->if_extflags |= IFEF_MPSAFE;
+#endif
 	ifp->if_start = vlan_start;
 	ifp->if_transmit = vlan_transmit;
 	ifp->if_ioctl = vlan_ioctl;
@@ -377,7 +401,9 @@ vlan_clone_destroy(struct ifnet *ifp)
 	LIST_REMOVE(ifv, ifv_list);
 	mutex_exit(&ifv_list.lock);
 
+	IFNET_LOCK(ifp);
 	vlan_unconfig(ifp);
+	IFNET_UNLOCK(ifp);
 	if_detach(ifp);
 
 	psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
@@ -437,7 +463,10 @@ vlan_config(struct ifvlan *ifv, struct i
 		nmib->ifvm_mintu = ETHERMIN;
 
 		if (ec->ec_nvlans++ == 0) {
-			if ((error = ether_enable_vlan_mtu(p)) >= 0) {
+			IFNET_LOCK(p);
+			error = ether_enable_vlan_mtu(p);
+			IFNET_UNLOCK(p);
+			if (error >= 0) {
 				if (error) {
 					ec->ec_nvlans--;
 					goto done;
@@ -534,6 +563,8 @@ vlan_unconfig(struct ifnet *ifp)
 	struct ifvlan_linkmib *nmib = NULL;
 	int error;
 
+	KASSERT(IFNET_LOCKED(ifp));
+
 	nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
 
 	mutex_enter(&ifv->ifv_lock);
@@ -552,8 +583,11 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 	struct ifvlan_linkmib *omib;
 	int error = 0;
 
+	KASSERT(IFNET_LOCKED(ifp));
 	KASSERT(mutex_owned(&ifv->ifv_lock));
 
+	ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
+
 	omib = ifv->ifv_mib;
 	p = omib->ifvm_p;
 
@@ -578,8 +612,11 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 	case IFT_ETHER:
 	    {
 		struct ethercom *ec = (void *)p;
-		if (--ec->ec_nvlans == 0)
-			(void)ether_disable_vlan_mtu(p);
+		if (--ec->ec_nvlans == 0) {
+			IFNET_LOCK(p);
+			(void) ether_disable_vlan_mtu(p);
+			IFNET_UNLOCK(p);
+		}
 
 		ether_ifdetach(ifp);
 		/* Restore vlan_ioctl overwritten by ether_ifdetach */
@@ -612,15 +649,16 @@ vlan_unconfig_locked(struct ifvlan *ifv,
 	kmem_free(omib, sizeof(*omib));
 
 #ifdef INET6
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	/* To delete v6 link local addresses */
 	if (in6_present)
 		in6_ifdetach(ifp);
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 #endif
 
 	if ((ifp->if_flags & IFF_PROMISC) != 0)
-		ifpromisc(ifp, 0);
-	if_down(ifp);
-	ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
+		vlan_safe_ifpromisc_locked(ifp, 0);
+	if_down_locked(ifp);
 	ifp->if_capabilities = 0;
 	mutex_enter(&ifv->ifv_lock);
 done:
@@ -789,6 +827,10 @@ vlan_ifdetach(struct ifnet *p)
 
 	i = 0;
 	LIST_FOREACH(ifv, &ifv_list.list, ifv_list) {
+		struct ifnet *ifp = &ifv->ifv_if;
+
+		/* Need IFNET_LOCK that must be held before ifv_lock. */
+		IFNET_LOCK(ifp);
 		mutex_enter(&ifv->ifv_lock);
 		if (ifv->ifv_mib->ifvm_p == p) {
 			KASSERTMSG(i < cnt, "no memory for unconfig, parent=%s",
@@ -801,6 +843,7 @@ vlan_ifdetach(struct ifnet *p)
 
 		}
 		mutex_exit(&ifv->ifv_lock);
+		IFNET_UNLOCK(ifp);
 	}
 
 	mutex_exit(&ifv_list.lock);
@@ -834,13 +877,13 @@ vlan_set_promisc(struct ifnet *ifp)
 
 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
 		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
-			error = ifpromisc(mib->ifvm_p, 1);
+			error = vlan_safe_ifpromisc(mib->ifvm_p, 1);
 			if (error == 0)
 				ifv->ifv_flags |= IFVF_PROMISC;
 		}
 	} else {
 		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
-			error = ifpromisc(mib->ifvm_p, 0);
+			error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
 			if (error == 0)
 				ifv->ifv_flags &= ~IFVF_PROMISC;
 		}
@@ -917,7 +960,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
 
 			if (mib->ifvm_p != NULL &&
 			    (ifp->if_flags & IFF_PROMISC) != 0)
-				error = ifpromisc(mib->ifvm_p, 0);
+				error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
 
 			vlan_putref_linkmib(mib, &psref);
 			curlwp_bindx(bound);
@@ -937,10 +980,11 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
 		if (error != 0) {
 			break;
 		}
-		ifp->if_flags |= IFF_RUNNING;
 
 		/* Update promiscuous mode, if necessary. */
 		vlan_set_promisc(ifp);
+
+		ifp->if_flags |= IFF_RUNNING;
 		break;
 
 	case SIOCGETVLAN:
@@ -1114,7 +1158,12 @@ vlan_ether_addmulti(struct ifvlan *ifv, 
 	LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
 
 	mib = ifv->ifv_mib;
+
+	KERNEL_LOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
+	IFNET_LOCK(mib->ifvm_p);
 	error = if_mcast_op(mib->ifvm_p, SIOCADDMULTI, sa);
+	IFNET_UNLOCK(mib->ifvm_p);
+	KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
 
 	if (error != 0)
 		goto ioctl_failed;
@@ -1154,7 +1203,9 @@ vlan_ether_delmulti(struct ifvlan *ifv, 
 
 	/* We no longer use this multicast address.  Tell parent so. */
 	mib = ifv->ifv_mib;
+	IFNET_LOCK(mib->ifvm_p);
 	error = if_mcast_op(mib->ifvm_p, SIOCDELMULTI, sa);
+	IFNET_UNLOCK(mib->ifvm_p);
 
 	if (error == 0) {
 		/* And forget about this address. */
@@ -1189,8 +1240,10 @@ vlan_ether_purgemulti(struct ifvlan *ifv
 	}
 
 	while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
+		IFNET_LOCK(mib->ifvm_p);
 		(void)if_mcast_op(mib->ifvm_p, SIOCDELMULTI,
 		    (const struct sockaddr *)&mc->mc_addr);
+		IFNET_UNLOCK(mib->ifvm_p);
 		LIST_REMOVE(mc, mc_entries);
 		free(mc, M_DEVBUF);
 	}

Index: src/sys/net/rtsock.c
diff -u src/sys/net/rtsock.c:1.213.2.3 src/sys/net/rtsock.c:1.213.2.4
--- src/sys/net/rtsock.c:1.213.2.3	Sat Oct 21 19:43:54 2017
+++ src/sys/net/rtsock.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtsock.c,v 1.213.2.3 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: rtsock.c,v 1.213.2.4 2018/01/02 10:20:33 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.213.2.3 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.213.2.4 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -2038,10 +2038,7 @@ COMPATNAME(route_intr)(void *cookie)
 	struct route_info * const ri = &COMPATNAME(route_info);
 	struct mbuf *m;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	for (;;) {
 		IFQ_LOCK(&ri->ri_intrq);
 		IF_DEQUEUE(&ri->ri_intrq, m);
@@ -2057,10 +2054,7 @@ COMPATNAME(route_intr)(void *cookie)
 		mutex_exit(rt_so_mtx);
 #endif
 	}
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*

Index: src/sys/net/agr/if_agr.c
diff -u src/sys/net/agr/if_agr.c:1.41 src/sys/net/agr/if_agr.c:1.41.6.1
--- src/sys/net/agr/if_agr.c:1.41	Sat Jan 28 22:56:09 2017
+++ src/sys/net/agr/if_agr.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_agr.c,v 1.41 2017/01/28 22:56:09 maya Exp $	*/
+/*	$NetBSD: if_agr.c,v 1.41.6.1 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c)2005 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.41 2017/01/28 22:56:09 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_agr.c,v 1.41.6.1 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -703,8 +703,6 @@ agr_addport(struct ifnet *ifp, struct if
 		goto cleanup;
 	}
 
-	ifp->if_flags |= IFF_RUNNING;
-
 	agrport_config_promisc(port, (ifp->if_flags & IFF_PROMISC) != 0);
 	error = (*sc->sc_iftop->iftop_configmulti_port)(sc, port, true);
 	if (error) {
@@ -719,6 +717,8 @@ out:
 	if (error && port) {
 		free(port, M_DEVBUF);
 	}
+	if (error == 0)
+		ifp->if_flags |= IFF_RUNNING;
 	return error;
 
 cleanup:

Index: src/sys/net/npf/npf_ifaddr.c
diff -u src/sys/net/npf/npf_ifaddr.c:1.2 src/sys/net/npf/npf_ifaddr.c:1.2.12.1
--- src/sys/net/npf/npf_ifaddr.c:1.2	Tue Jan  3 00:58:05 2017
+++ src/sys/net/npf/npf_ifaddr.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ifaddr.c,v 1.2 2017/01/03 00:58:05 rmind Exp $	*/
+/*	$NetBSD: npf_ifaddr.c,v 1.2.12.1 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ifaddr.c,v 1.2 2017/01/03 00:58:05 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ifaddr.c,v 1.2.12.1 2018/01/02 10:20:33 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -170,11 +170,11 @@ npf_ifaddr_syncall(npf_t *npf)
 	ifnet_t *ifp;
 
 	KERNEL_LOCK(1, NULL);
-	IFNET_LOCK();
+	IFNET_GLOBAL_LOCK();
 	IFNET_WRITER_FOREACH(ifp) {
 		npf_ifaddr_sync(npf, ifp);
 	}
-	IFNET_UNLOCK();
+	IFNET_GLOBAL_UNLOCK();
 	KERNEL_UNLOCK_ONE(NULL);
 }
 

Index: src/sys/net/npf/npf_os.c
diff -u src/sys/net/npf/npf_os.c:1.6.8.1 src/sys/net/npf/npf_os.c:1.6.8.2
--- src/sys/net/npf/npf_os.c:1.6.8.1	Tue Jul 25 02:17:16 2017
+++ src/sys/net/npf/npf_os.c	Tue Jan  2 10:20:33 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_os.c,v 1.6.8.1 2017/07/25 02:17:16 snj Exp $	*/
+/*	$NetBSD: npf_os.c,v 1.6.8.2 2018/01/02 10:20:33 snj Exp $	*/
 
 /*-
  * Copyright (c) 2009-2016 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #ifdef _KERNEL
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.6.8.1 2017/07/25 02:17:16 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.6.8.2 2018/01/02 10:20:33 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "pf.h"
@@ -313,11 +313,11 @@ npf_ifop_flush(void *arg)
 	ifnet_t *ifp;
 
 	KERNEL_LOCK(1, NULL);
-	IFNET_LOCK();
+	IFNET_GLOBAL_LOCK();
 	IFNET_WRITER_FOREACH(ifp) {
 		ifp->if_pf_kif = arg;
 	}
-	IFNET_UNLOCK();
+	IFNET_GLOBAL_UNLOCK();
 	KERNEL_UNLOCK_ONE(NULL);
 }
 
@@ -397,10 +397,7 @@ npf_pfil_register(bool init)
 	npf_t *npf = npf_getkernctx();
 	int error = 0;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	/* Init: interface re-config and attach/detach hook. */
 	if (!npf_ph_if) {
@@ -455,10 +452,7 @@ npf_pfil_register(bool init)
 	npf_ifaddr_syncall(npf);
 	pfil_registered = true;
 out:
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 
 	return error;
 }
@@ -471,10 +465,7 @@ npf_pfil_unregister(bool fini)
 {
 	npf_t *npf = npf_getkernctx();
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	if (fini && npf_ph_if) {
 		(void)pfil_remove_ihook(npf_ifhook, NULL,
@@ -492,10 +483,7 @@ npf_pfil_unregister(bool fini)
 	}
 	pfil_registered = false;
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 bool

Index: src/sys/netcan/if_canloop.c
diff -u src/sys/netcan/if_canloop.c:1.2 src/sys/netcan/if_canloop.c:1.2.2.1
--- src/sys/netcan/if_canloop.c:1.2	Sat May 27 21:02:56 2017
+++ src/sys/netcan/if_canloop.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $	*/
+/*	$NetBSD: if_canloop.c,v 1.2.2.1 2018/01/02 10:20:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 2017 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.2.2.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_can.h"
@@ -111,8 +111,10 @@ canloop_clone_create(struct if_clone *if
 
 	if_initname(ifp, ifc->ifc_name, unit);
 
-	ifp->if_flags = IFF_LOOPBACK | IFF_RUNNING;
-	ifp->if_extflags = IFEF_OUTPUT_MPSAFE;
+	ifp->if_flags = IFF_LOOPBACK;
+#ifdef NET_MPSAFE
+	ifp->if_extflags = IFEF_MPSAFE;
+#endif
 	ifp->if_ioctl = canloop_ioctl;
 	ifp->if_start = canloop_ifstart;
 	can_ifattach(ifp);
@@ -124,6 +126,7 @@ canloop_clone_create(struct if_clone *if
 	MOWNER_ATTACH(ifp->if_mowner);
 #endif
 	canloop_count++;
+	ifp->if_flags |= IFF_RUNNING;
 
 	return (0);
 }
@@ -132,6 +135,8 @@ static int
 canloop_clone_destroy(struct ifnet *ifp)
 {
 
+	ifp->if_flags &= ~IFF_RUNNING;
+
 #ifdef MBUFTRACE
 	MOWNER_DETACH(ifp->if_mowner);
 	free(ifp->if_mowner, M_DEVBUF);

Index: src/sys/netinet/if_arp.c
diff -u src/sys/netinet/if_arp.c:1.250.2.3 src/sys/netinet/if_arp.c:1.250.2.4
--- src/sys/netinet/if_arp.c:1.250.2.3	Fri Nov 17 20:24:05 2017
+++ src/sys/netinet/if_arp.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_arp.c,v 1.250.2.3 2017/11/17 20:24:05 snj Exp $	*/
+/*	$NetBSD: if_arp.c,v 1.250.2.4 2018/01/02 10:20:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.3 2017/11/17 20:24:05 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.4 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -920,10 +920,7 @@ arpintr(void)
 	int s;
 	int arplen;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	for (;;) {
 		struct ifnet *rcvif;
 
@@ -980,12 +977,8 @@ free:
 		m_freem(m);
 	}
 out:
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#else
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 	return; /* XXX gcc */
-#endif
 }
 
 /*
@@ -1689,10 +1682,7 @@ arp_dad_timer(struct ifaddr *ifa)
 	char ipbuf[INET_ADDRSTRLEN];
 	bool need_free = false;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&arp_dad_lock);
 
 	/* Sanity check */
@@ -1783,10 +1773,7 @@ done:
 		ifafree(ifa);
 	}
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 static void

Index: src/sys/netinet/igmp.c
diff -u src/sys/netinet/igmp.c:1.64 src/sys/netinet/igmp.c:1.64.6.1
--- src/sys/netinet/igmp.c:1.64	Tue Jan 24 07:09:24 2017
+++ src/sys/netinet/igmp.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: igmp.c,v 1.64 2017/01/24 07:09:24 ozaki-r Exp $	*/
+/*	$NetBSD: igmp.c,v 1.64.6.1 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.64 2017/01/24 07:09:24 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.64.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_mrouting.h"
@@ -542,10 +542,8 @@ igmp_fasttimo(void)
 		return;
 	}
 
-#ifndef NET_MPSAFE
 	/* XXX: Needed for ip_output(). */
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 
 	in_multi_lock(RW_WRITER);
 	igmp_timers_on = false;
@@ -569,9 +567,7 @@ igmp_fasttimo(void)
 		inm = in_next_multi(&step);
 	}
 	in_multi_unlock();
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 void

Index: src/sys/netinet/in.c
diff -u src/sys/netinet/in.c:1.203.2.3 src/sys/netinet/in.c:1.203.2.4
--- src/sys/netinet/in.c:1.203.2.3	Thu Dec 21 21:08:13 2017
+++ src/sys/netinet/in.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: in.c,v 1.203.2.3 2017/12/21 21:08:13 snj Exp $	*/
+/*	$NetBSD: in.c,v 1.203.2.4 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.203.2.3 2017/12/21 21:08:13 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.203.2.4 2018/01/02 10:20:34 snj Exp $");
 
 #include "arp.h"
 
@@ -751,13 +751,9 @@ in_control(struct socket *so, u_long cmd
 {
 	int error;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 	error = in_control0(so, cmd, data, ifp);
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 
 	return error;
 }
@@ -916,11 +912,14 @@ in_addrhash_remove(struct in_ifaddr *ia)
 void
 in_purgeif(struct ifnet *ifp)		/* MUST be called at splsoftnet() */
 {
+
+	IFNET_LOCK(ifp);
 	if_purgeaddrs(ifp, AF_INET, in_purgeaddr);
 	igmp_purgeif(ifp);		/* manipulates pools */
 #ifdef MROUTING
 	ip_mrouter_detach(ifp);
 #endif
+	IFNET_UNLOCK(ifp);
 }
 
 /*

Index: src/sys/netinet/in_pcb.c
diff -u src/sys/netinet/in_pcb.c:1.178.4.1 src/sys/netinet/in_pcb.c:1.178.4.2
--- src/sys/netinet/in_pcb.c:1.178.4.1	Thu Dec 21 21:08:13 2017
+++ src/sys/netinet/in_pcb.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_pcb.c,v 1.178.4.1 2017/12/21 21:08:13 snj Exp $	*/
+/*	$NetBSD: in_pcb.c,v 1.178.4.2 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -93,7 +93,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.178.4.1 2017/12/21 21:08:13 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.178.4.2 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -777,7 +777,10 @@ in_pcbpurgeif0(struct inpcbtable *table,
 			need_unlock = true;
 		}
 
+		/* IFNET_LOCK must be taken after solock */
+		IFNET_LOCK(ifp);
 		in_purgeifmcast(inp->inp_moptions, ifp);
+		IFNET_UNLOCK(ifp);
 
 		if (need_unlock)
 			inp_unlock(inp);

Index: src/sys/netinet/ip_carp.c
diff -u src/sys/netinet/ip_carp.c:1.90.2.2 src/sys/netinet/ip_carp.c:1.90.2.3
--- src/sys/netinet/ip_carp.c:1.90.2.2	Sun Dec 10 10:10:25 2017
+++ src/sys/netinet/ip_carp.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_carp.c,v 1.90.2.2 2017/12/10 10:10:25 snj Exp $	*/
+/*	$NetBSD: ip_carp.c,v 1.90.2.3 2018/01/02 10:20:34 snj Exp $	*/
 /*	$OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $	*/
 
 /*
@@ -33,7 +33,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.90.2.2 2017/12/10 10:10:25 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.90.2.3 2018/01/02 10:20:34 snj Exp $");
 
 /*
  * TODO:
@@ -895,7 +895,6 @@ carp_clone_create(struct if_clone *ifc, 
 	/* Overwrite ethernet defaults */
 	ifp->if_type = IFT_CARP;
 	ifp->if_output = carp_output;
-	ifp->if_extflags &= ~IFEF_OUTPUT_MPSAFE;
 	if_register(ifp);
 
 	return (0);
@@ -2236,7 +2235,13 @@ carp_set_state(struct carp_softc *sc, in
 		link_state = LINK_STATE_UNKNOWN;
 		break;
 	}
+	/*
+	 * The lock is needed to serialize a call of
+	 * if_link_state_change_softint from here and a call from softint.
+	 */
+	KERNEL_LOCK(1, NULL);
 	if_link_state_change_softint(&sc->sc_if, link_state);
+	KERNEL_UNLOCK_ONE(NULL);
 }
 
 void

Index: src/sys/netinet/ip_flow.c
diff -u src/sys/netinet/ip_flow.c:1.80 src/sys/netinet/ip_flow.c:1.80.6.1
--- src/sys/netinet/ip_flow.c:1.80	Tue Feb  7 02:38:08 2017
+++ src/sys/netinet/ip_flow.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_flow.c,v 1.80 2017/02/07 02:38:08 ozaki-r Exp $	*/
+/*	$NetBSD: ip_flow.c,v 1.80.6.1 2018/01/02 10:20:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.80 2017/02/07 02:38:08 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.80.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -482,10 +482,7 @@ ipflow_slowtimo_work(struct work *wk, vo
 	/* We can allow enqueuing another work at this point */
 	atomic_swap_uint(&ipflow_work_enqueued, 0);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&ipflow_lock);
 	for (ipf = TAILQ_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) {
 		next_ipf = TAILQ_NEXT(ipf, ipf_list);
@@ -505,10 +502,7 @@ ipflow_slowtimo_work(struct work *wk, vo
 		}
 	}
 	mutex_exit(&ipflow_lock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 void
@@ -529,9 +523,7 @@ ipflow_create(struct route *ro, struct m
 	struct ipflow *ipf;
 	size_t hash;
 
-#ifndef NET_MPSAFE
-	KERNEL_LOCK(1, NULL);
-#endif
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&ipflow_lock);
 
 	/*
@@ -582,9 +574,7 @@ ipflow_create(struct route *ro, struct m
 
  out:
 	mutex_exit(&ipflow_lock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-#endif
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 int
@@ -622,19 +612,13 @@ sysctl_net_inet_ip_maxflows(SYSCTLFN_ARG
 	if (error || newp == NULL)
 		return (error);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&ipflow_lock);
 
 	ipflow_reap(false);
 
 	mutex_exit(&ipflow_lock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 
 	return (0);
 }
@@ -656,15 +640,9 @@ sysctl_net_inet_ip_hashsize(SYSCTLFN_ARG
 		/*
 		 * Can only fail due to malloc()
 		 */
-#ifndef NET_MPSAFE
-		mutex_enter(softnet_lock);
-		KERNEL_LOCK(1, NULL);
-#endif
+		SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 		error = ipflow_invalidate_all(tmp);
-#ifndef NET_MPSAFE
-		KERNEL_UNLOCK_ONE(NULL);
-		mutex_exit(softnet_lock);
-#endif
+		SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 	} else {
 		/*
 		 * EINVAL if not a power of 2

Index: src/sys/netinet/ip_input.c
diff -u src/sys/netinet/ip_input.c:1.355.2.2 src/sys/netinet/ip_input.c:1.355.2.3
--- src/sys/netinet/ip_input.c:1.355.2.2	Sun Dec 10 09:24:30 2017
+++ src/sys/netinet/ip_input.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_input.c,v 1.355.2.2 2017/12/10 09:24:30 snj Exp $	*/
+/*	$NetBSD: ip_input.c,v 1.355.2.3 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.355.2.2 2017/12/10 09:24:30 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.355.2.3 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -438,15 +438,11 @@ ipintr(void *arg __unused)
 
 	KASSERT(cpu_softintr_p());
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 	while ((m = pktq_dequeue(ip_pktq)) != NULL) {
 		ip_input(m);
 	}
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*
@@ -854,17 +850,11 @@ void
 ip_slowtimo(void)
 {
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	ip_reass_slowtimo();
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*

Index: src/sys/netinet/ip_mroute.c
diff -u src/sys/netinet/ip_mroute.c:1.146.6.1 src/sys/netinet/ip_mroute.c:1.146.6.2
--- src/sys/netinet/ip_mroute.c:1.146.6.1	Sun Dec 10 09:41:31 2017
+++ src/sys/netinet/ip_mroute.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_mroute.c,v 1.146.6.1 2017/12/10 09:41:31 snj Exp $	*/
+/*	$NetBSD: ip_mroute.c,v 1.146.6.2 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -93,7 +93,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.146.6.1 2017/12/10 09:41:31 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.146.6.2 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1586,7 +1586,7 @@ expire_upcalls(void *v)
 				struct bw_meter *x = rt->mfc_bw_meter;
 
 				rt->mfc_bw_meter = x->bm_mfc_next;
-				kmem_free(x, sizeof(*x));
+				kmem_intr_free(x, sizeof(*x));
 			}
 
 			++mrtstat.mrts_cache_cleanups;
@@ -2531,7 +2531,7 @@ free_bw_list(struct bw_meter *list)
 
 	list = list->bm_mfc_next;
 	unschedule_bw_meter(x);
-	kmem_free(x, sizeof(*x));
+	kmem_intr_free(x, sizeof(*x));
     }
 }
 
@@ -2590,7 +2590,7 @@ del_bw_upcall(struct bw_upcall *req)
 	    unschedule_bw_meter(x);
 	    splx(s);
 	    /* Free the bw_meter entry */
-	    kmem_free(x, sizeof(*x));
+	    kmem_intr_free(x, sizeof(*x));
 	    return 0;
 	} else {
 	    splx(s);

Index: src/sys/netinet/ip_output.c
diff -u src/sys/netinet/ip_output.c:1.279.2.2 src/sys/netinet/ip_output.c:1.279.2.3
--- src/sys/netinet/ip_output.c:1.279.2.2	Thu Dec 21 21:08:13 2017
+++ src/sys/netinet/ip_output.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_output.c,v 1.279.2.2 2017/12/21 21:08:13 snj Exp $	*/
+/*	$NetBSD: ip_output.c,v 1.279.2.3 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.279.2.2 2017/12/21 21:08:13 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.279.2.3 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1771,7 +1771,10 @@ ip_add_membership(struct ip_moptions *im
 	 * Everything looks good; add a new record to the multicast
 	 * address list for the given interface.
 	 */
-	if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL) {
+	IFNET_LOCK(ifp);
+	imo->imo_membership[i] = in_addmulti(&ia, ifp);
+	IFNET_UNLOCK(ifp);
+	if (imo->imo_membership[i] == NULL) {
 		error = ENOBUFS;
 		goto out;
 	}
@@ -1830,7 +1833,9 @@ ip_drop_membership(struct ip_moptions *i
 	 * Give up the multicast address record to which the
 	 * membership points.
 	 */
+	IFNET_LOCK(ifp);
 	in_delmulti(imo->imo_membership[i]);
+	IFNET_UNLOCK(ifp);
 
 	/*
 	 * Remove the gap in the membership array.
@@ -1950,7 +1955,7 @@ ip_setmoptions(struct ip_moptions **pimo
 	    imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
 	    imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
 	    imo->imo_num_memberships == 0) {
-		kmem_free(imo, sizeof(*imo));
+		kmem_intr_free(imo, sizeof(*imo));
 		*pimo = NULL;
 	}
 
@@ -2023,9 +2028,16 @@ ip_freemoptions(struct ip_moptions *imo)
 	/* The owner of imo (inp) should be protected by solock */
 
 	if (imo != NULL) {
-		for (i = 0; i < imo->imo_num_memberships; ++i)
-			in_delmulti(imo->imo_membership[i]);
-		kmem_free(imo, sizeof(*imo));
+		for (i = 0; i < imo->imo_num_memberships; ++i) {
+			struct in_multi *inm = imo->imo_membership[i];
+			struct ifnet *ifp = inm->inm_ifp;
+			IFNET_LOCK(ifp);
+			in_delmulti(inm);
+			/* ifp should not leave thanks to solock */
+			IFNET_UNLOCK(ifp);
+		}
+
+		kmem_intr_free(imo, sizeof(*imo));
 	}
 }
 
@@ -2061,13 +2073,9 @@ ip_mloopback(struct ifnet *ifp, struct m
 
 	ip->ip_sum = 0;
 	ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
-#ifndef NET_MPSAFE
-	KERNEL_LOCK(1, NULL);
-#endif
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	(void)looutput(ifp, copym, sintocsa(dst), NULL);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-#endif
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*

Index: src/sys/netinet6/frag6.c
diff -u src/sys/netinet6/frag6.c:1.60 src/sys/netinet6/frag6.c:1.60.6.1
--- src/sys/netinet6/frag6.c:1.60	Tue Jan 24 07:09:25 2017
+++ src/sys/netinet6/frag6.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: frag6.c,v 1.60 2017/01/24 07:09:25 ozaki-r Exp $	*/
+/*	$NetBSD: frag6.c,v 1.60.6.1 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.60 2017/01/24 07:09:25 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.60.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -597,20 +597,14 @@ void
 frag6_fasttimo(void)
 {
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	if (frag6_drainwanted) {
 		frag6_drain();
 		frag6_drainwanted = 0;
 	}
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*
@@ -623,10 +617,7 @@ frag6_slowtimo(void)
 {
 	struct ip6q *q6;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	mutex_enter(&frag6_lock);
 	q6 = ip6q.ip6q_next;
@@ -653,10 +644,7 @@ frag6_slowtimo(void)
 	}
 	mutex_exit(&frag6_lock);
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 
 #if 0
 	/*

Index: src/sys/netinet6/in6.c
diff -u src/sys/netinet6/in6.c:1.245.2.3 src/sys/netinet6/in6.c:1.245.2.4
--- src/sys/netinet6/in6.c:1.245.2.3	Thu Nov 30 15:57:37 2017
+++ src/sys/netinet6/in6.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.245.2.3 2017/11/30 15:57:37 martin Exp $	*/
+/*	$NetBSD: in6.c,v 1.245.2.4 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.3 2017/11/30 15:57:37 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.4 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -767,13 +767,9 @@ in6_control(struct socket *so, u_long cm
 	}
 
 	s = splsoftnet();
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 	error = in6_control1(so , cmd, data, ifp);
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 	splx(s);
 	return error;
 }
@@ -1389,6 +1385,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	struct in6_multi_mship *imm;
 
 	KASSERT(!ifa_held(ifa));
+	KASSERT(IFNET_LOCKED(ifp));
 
 	ifa->ifa_flags |= IFA_DESTROYING;
 
@@ -1404,12 +1401,14 @@ in6_purgeaddr(struct ifaddr *ifa)
 	/*
 	 * leave from multicast groups we have joined for the interface
 	 */
+    again:
 	mutex_enter(&in6_ifaddr_lock);
 	while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
 		LIST_REMOVE(imm, i6mm_chain);
 		mutex_exit(&in6_ifaddr_lock);
+		KASSERT(imm->i6mm_maddr->in6m_ifp == ifp);
 		in6_leavegroup(imm);
-		mutex_enter(&in6_ifaddr_lock);
+		goto again;
 	}
 	mutex_exit(&in6_ifaddr_lock);
 
@@ -1460,7 +1459,9 @@ void
 in6_purgeif(struct ifnet *ifp)
 {
 
+	IFNET_LOCK(ifp);
 	in6_ifdetach(ifp);
+	IFNET_UNLOCK(ifp);
 }
 
 void
@@ -2716,13 +2717,9 @@ in6_domifdetach(struct ifnet *ifp, void 
 
 	lltable_free(ext->lltable);
 	ext->lltable = NULL;
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 	nd6_ifdetach(ifp, ext);
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 	free(ext->in6_ifstat, M_IFADDR);
 	free(ext->icmp6_ifstat, M_IFADDR);
 	scope6_ifdetach(ext->scope6_id);

Index: src/sys/netinet6/in6_pcb.c
diff -u src/sys/netinet6/in6_pcb.c:1.161 src/sys/netinet6/in6_pcb.c:1.161.4.1
--- src/sys/netinet6/in6_pcb.c:1.161	Tue Apr 25 05:44:11 2017
+++ src/sys/netinet6/in6_pcb.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_pcb.c,v 1.161 2017/04/25 05:44:11 ozaki-r Exp $	*/
+/*	$NetBSD: in6_pcb.c,v 1.161.4.1 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.161 2017/04/25 05:44:11 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.161.4.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -875,11 +875,18 @@ in6_pcbpurgeif0(struct inpcbtable *table
 			    i6mm_chain, nimm) {
 				if (imm->i6mm_maddr->in6m_ifp == ifp) {
 					LIST_REMOVE(imm, i6mm_chain);
+					IFNET_LOCK(ifp);
 					in6_leavegroup(imm);
+					IFNET_UNLOCK(ifp);
 				}
 			}
 		}
+
+		/* IFNET_LOCK must be taken after solock */
+		IFNET_LOCK(ifp);
 		in_purgeifmcast(in6p->in6p_v4moptions, ifp);
+		IFNET_UNLOCK(ifp);
+
 		if (need_unlock)
 			in6p_unlock(in6p);
 	}

Index: src/sys/netinet6/ip6_flow.c
diff -u src/sys/netinet6/ip6_flow.c:1.34 src/sys/netinet6/ip6_flow.c:1.34.8.1
--- src/sys/netinet6/ip6_flow.c:1.34	Wed Jan 11 13:08:29 2017
+++ src/sys/netinet6/ip6_flow.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_flow.c,v 1.34 2017/01/11 13:08:29 ozaki-r Exp $	*/
+/*	$NetBSD: ip6_flow.c,v 1.34.8.1 2018/01/02 10:20:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.34 2017/01/11 13:08:29 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.34.8.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -519,10 +519,7 @@ ip6flow_slowtimo_work(struct work *wk, v
 	/* We can allow enqueuing another work at this point */
 	atomic_swap_uint(&ip6flow_work_enqueued, 0);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&ip6flow_lock);
 
 	for (ip6f = TAILQ_FIRST(&ip6flowlist); ip6f != NULL; ip6f = next_ip6f) {
@@ -542,10 +539,7 @@ ip6flow_slowtimo_work(struct work *wk, v
 	}
 
 	mutex_exit(&ip6flow_lock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 void
@@ -572,9 +566,7 @@ ip6flow_create(struct route *ro, struct 
 
 	ip6 = mtod(m, const struct ip6_hdr *);
 
-#ifndef NET_MPSAFE
-	KERNEL_LOCK(1, NULL);
-#endif
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&ip6flow_lock);
 
 	/*
@@ -636,9 +628,7 @@ ip6flow_create(struct route *ro, struct 
 
  out:
 	mutex_exit(&ip6flow_lock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-#endif
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*
@@ -681,17 +671,11 @@ sysctl_net_inet6_ip6_maxflows(SYSCTLFN_A
 	if (error || newp == NULL)
 		return (error);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	ip6flow_reap(0);
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 
 	return (0);
 }
@@ -713,15 +697,9 @@ sysctl_net_inet6_ip6_hashsize(SYSCTLFN_A
 		/*
 		 * Can only fail due to malloc()
 		 */
-#ifndef NET_MPSAFE
-		mutex_enter(softnet_lock);
-		KERNEL_LOCK(1, NULL);
-#endif
+		SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 		error = ip6flow_invalidate_all(tmp);
-#ifndef NET_MPSAFE
-		KERNEL_UNLOCK_ONE(NULL);
-		mutex_exit(softnet_lock);
-#endif
+		SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 	} else {
 		/*
 		 * EINVAL if not a power of 2

Index: src/sys/netinet6/ip6_input.c
diff -u src/sys/netinet6/ip6_input.c:1.178.2.2 src/sys/netinet6/ip6_input.c:1.178.2.3
--- src/sys/netinet6/ip6_input.c:1.178.2.2	Sun Dec 10 09:24:30 2017
+++ src/sys/netinet6/ip6_input.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_input.c,v 1.178.2.2 2017/12/10 09:24:30 snj Exp $	*/
+/*	$NetBSD: ip6_input.c,v 1.178.2.3 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.178.2.2 2017/12/10 09:24:30 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.178.2.3 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_gateway.h"
@@ -228,9 +228,7 @@ ip6intr(void *arg __unused)
 {
 	struct mbuf *m;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-#endif
+	SOFTNET_LOCK_UNLESS_NET_MPSAFE();
 	while ((m = pktq_dequeue(ip6_pktq)) != NULL) {
 		struct psref psref;
 		struct ifnet *rcvif = m_get_rcvif_psref(m, &psref);
@@ -250,9 +248,7 @@ ip6intr(void *arg __unused)
 		ip6_input(m, rcvif);
 		m_put_rcvif_psref(rcvif, &psref);
 	}
-#ifndef NET_MPSAFE
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 void

Index: src/sys/netinet6/ip6_output.c
diff -u src/sys/netinet6/ip6_output.c:1.191.6.3 src/sys/netinet6/ip6_output.c:1.191.6.4
--- src/sys/netinet6/ip6_output.c:1.191.6.3	Sun Dec 10 09:24:30 2017
+++ src/sys/netinet6/ip6_output.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_output.c,v 1.191.6.3 2017/12/10 09:24:30 snj Exp $	*/
+/*	$NetBSD: ip6_output.c,v 1.191.6.4 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.191.6.3 2017/12/10 09:24:30 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.191.6.4 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -2606,7 +2606,9 @@ ip6_setmoptions(const struct sockopt *so
 		 * Everything looks good; add a new record to the multicast
 		 * address list for the given interface.
 		 */
+		IFNET_LOCK(ifp);
 		imm = in6_joingroup(ifp, &ia, &error, 0);
+		IFNET_UNLOCK(ifp);
 		if (imm == NULL)
 			goto put_break;
 		LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
@@ -2616,7 +2618,8 @@ ip6_setmoptions(const struct sockopt *so
 		break;
 	    }
 
-	case IPV6_LEAVE_GROUP:
+	case IPV6_LEAVE_GROUP: {
+		struct ifnet *in6m_ifp;
 		/*
 		 * Drop a multicast group membership.
 		 * Group must be a valid IP6 multicast address.
@@ -2698,8 +2701,13 @@ ip6_setmoptions(const struct sockopt *so
 		 * membership points.
 		 */
 		LIST_REMOVE(imm, i6mm_chain);
+		in6m_ifp = imm->i6mm_maddr->in6m_ifp;
+		IFNET_LOCK(in6m_ifp);
 		in6_leavegroup(imm);
+		/* in6m_ifp should not leave thanks to in6p_lock */
+		IFNET_UNLOCK(in6m_ifp);
 		break;
+	    }
 
 	default:
 		error = EOPNOTSUPP;
@@ -2778,8 +2786,15 @@ ip6_freemoptions(struct ip6_moptions *im
 
 	/* The owner of im6o (in6p) should be protected by solock */
 	LIST_FOREACH_SAFE(imm, &im6o->im6o_memberships, i6mm_chain, nimm) {
+		struct ifnet *ifp;
+
 		LIST_REMOVE(imm, i6mm_chain);
+
+		ifp = imm->i6mm_maddr->in6m_ifp;
+		IFNET_LOCK(ifp);
 		in6_leavegroup(imm);
+		/* ifp should not leave thanks to solock */
+		IFNET_UNLOCK(ifp);
 	}
 	free(im6o, M_IPMOPTS);
 }

Index: src/sys/netinet6/mld6.c
diff -u src/sys/netinet6/mld6.c:1.89 src/sys/netinet6/mld6.c:1.89.2.1
--- src/sys/netinet6/mld6.c:1.89	Sat May 13 20:13:26 2017
+++ src/sys/netinet6/mld6.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mld6.c,v 1.89 2017/05/13 20:13:26 kardel Exp $	*/
+/*	$NetBSD: mld6.c,v 1.89.2.1 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $	*/
 
 /*
@@ -102,7 +102,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.89 2017/05/13 20:13:26 kardel Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.89.2.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -242,10 +242,7 @@ mld_timeo(void *arg)
 
 	KASSERT(in6m->in6m_refcount > 0);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	rw_enter(&in6_multilock, RW_WRITER);
 	if (in6m->in6m_timer == IN6M_TIMER_UNDEF)
 		goto out;
@@ -263,12 +260,7 @@ mld_timeo(void *arg)
 
 out:
 	rw_exit(&in6_multilock);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#else
-	return;
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 static u_long

Index: src/sys/netinet6/nd6.c
diff -u src/sys/netinet6/nd6.c:1.232.2.4 src/sys/netinet6/nd6.c:1.232.2.5
--- src/sys/netinet6/nd6.c:1.232.2.4	Fri Nov 17 20:26:19 2017
+++ src/sys/netinet6/nd6.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6.c,v 1.232.2.4 2017/11/17 20:26:19 snj Exp $	*/
+/*	$NetBSD: nd6.c,v 1.232.2.5 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.4 2017/11/17 20:26:19 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.5 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -450,10 +450,7 @@ nd6_llinfo_timer(void *arg)
 	bool send_ns = false;
 	const struct in6_addr *daddr6 = NULL;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	LLE_WLOCK(ln);
 	if ((ln->la_flags & LLE_LINKED) == 0)
 		goto out;
@@ -569,10 +566,7 @@ nd6_llinfo_timer(void *arg)
 out:
 	if (ln != NULL)
 		LLE_FREE_LOCKED(ln);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*
@@ -590,10 +584,7 @@ nd6_timer_work(struct work *wk, void *ar
 	callout_reset(&nd6_timer_ch, nd6_prune * hz,
 	    nd6_timer, NULL);
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 
 	/* expire default router list */
 
@@ -623,6 +614,7 @@ nd6_timer_work(struct work *wk, void *ar
 		/* check address lifetime */
 		if (IFA6_IS_INVALID(ia6)) {
 			int regen = 0;
+			struct ifnet *ifp;
 
 			/*
 			 * If the expiring address is temporary, try
@@ -636,13 +628,30 @@ nd6_timer_work(struct work *wk, void *ar
 			 */
 			if (ip6_use_tempaddr &&
 			    (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
+				IFNET_LOCK(ia6->ia_ifa.ifa_ifp);
 				if (regen_tmpaddr(ia6) == 0)
 					regen = 1;
+				IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp);
 			}
 
-			ia6_release(ia6, &psref);
- 			in6_purgeaddr(&ia6->ia_ifa);
+			ifp = ia6->ia_ifa.ifa_ifp;
+			IFNET_LOCK(ifp);
+			/*
+			 * Need to take the lock first to prevent if_detach
+			 * from running in6_purgeaddr concurrently.
+			 */
+			if (!if_is_deactivated(ifp)) {
+				ia6_release(ia6, &psref);
+				in6_purgeaddr(&ia6->ia_ifa);
+			} else {
+				/*
+				 * ifp is being destroyed, ia6 will be destroyed
+				 * by if_detach.
+				 */
+				ia6_release(ia6, &psref);
+			}
 			ia6 = NULL;
+			IFNET_UNLOCK(ifp);
 
 			if (regen)
 				goto addrloop; /* XXX: see below */
@@ -717,10 +726,7 @@ nd6_timer_work(struct work *wk, void *ar
 	}
 	ND6_UNLOCK();
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 static void
@@ -1895,20 +1901,53 @@ nd6_ioctl(u_long cmd, void *data, struct
 			_s = pserialize_read_enter();
 			for (ia = IN6_ADDRLIST_READER_FIRST(); ia;
 			     ia = ia_next) {
+				struct ifnet *ifa_ifp;
+				int bound;
+				struct psref psref;
+
 				/* ia might be removed.  keep the next ptr. */
 				ia_next = IN6_ADDRLIST_READER_NEXT(ia);
 
 				if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
 					continue;
 
-				if (ia->ia6_ndpr == pfx) {
-					pserialize_read_exit(_s);
-					ND6_UNLOCK();
-					/* XXX NOMPSAFE? */
-					/* in6_purgeaddr may destroy pfx. */
+				if (ia->ia6_ndpr != pfx)
+					continue;
+
+				bound = curlwp_bind();
+				ia6_acquire(ia, &psref);
+				pserialize_read_exit(_s);
+				ND6_UNLOCK();
+
+				ifa_ifp = ia->ia_ifa.ifa_ifp;
+				if (ifa_ifp == ifp) {
+					/* Already have IFNET_LOCK(ifp) */
+					KASSERT(!if_is_deactivated(ifp));
+					ia6_release(ia, &psref);
 					in6_purgeaddr(&ia->ia_ifa);
+					curlwp_bindx(bound);
 					goto restart;
 				}
+				IFNET_LOCK(ifa_ifp);
+				/*
+				 * Need to take the lock first to prevent
+				 * if_detach from running in6_purgeaddr
+				 * concurrently.
+				 */
+				if (!if_is_deactivated(ifa_ifp)) {
+					ia6_release(ia, &psref);
+					in6_purgeaddr(&ia->ia_ifa);
+				} else {
+					/*
+					 * ifp is being destroyed, ia will be
+					 * destroyed by if_detach.
+					 */
+					ia6_release(ia, &psref);
+					/* XXX may cause busy loop */
+				}
+				IFNET_UNLOCK(ifa_ifp);
+				curlwp_bindx(bound);
+				goto restart;
 			}
 			pserialize_read_exit(_s);
 
@@ -2228,10 +2267,7 @@ nd6_slowtimo(void *ignored_arg)
 	struct ifnet *ifp;
 	int s;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
 	    nd6_slowtimo, NULL);
 
@@ -2252,10 +2288,7 @@ nd6_slowtimo(void *ignored_arg)
 	}
 	pserialize_read_exit(s);
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 /*

Index: src/sys/netinet6/nd6_nbr.c
diff -u src/sys/netinet6/nd6_nbr.c:1.138 src/sys/netinet6/nd6_nbr.c:1.138.6.1
--- src/sys/netinet6/nd6_nbr.c:1.138	Tue Mar 14 04:25:10 2017
+++ src/sys/netinet6/nd6_nbr.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_nbr.c,v 1.138 2017/03/14 04:25:10 ozaki-r Exp $	*/
+/*	$NetBSD: nd6_nbr.c,v 1.138.6.1 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.138 2017/03/14 04:25:10 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.138.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1228,10 +1228,7 @@ nd6_dad_timer(struct ifaddr *ifa)
 	char ip6buf[INET6_ADDRSTRLEN];
 	bool need_free = false;
 
-#ifndef NET_MPSAFE
-	mutex_enter(softnet_lock);
-	KERNEL_LOCK(1, NULL);
-#endif
+	SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	mutex_enter(&nd6_dad_lock);
 
 	/* Sanity check */
@@ -1327,10 +1324,7 @@ done:
 	if (duplicate)
 		nd6_dad_duplicated(ifa);
 
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-	mutex_exit(softnet_lock);
-#endif
+	SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 }
 
 static void

Index: src/sys/netinet6/nd6_rtr.c
diff -u src/sys/netinet6/nd6_rtr.c:1.135 src/sys/netinet6/nd6_rtr.c:1.135.6.1
--- src/sys/netinet6/nd6_rtr.c:1.135	Tue Mar 14 04:21:38 2017
+++ src/sys/netinet6/nd6_rtr.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_rtr.c,v 1.135 2017/03/14 04:21:38 ozaki-r Exp $	*/
+/*	$NetBSD: nd6_rtr.c,v 1.135.6.1 2018/01/02 10:20:34 snj Exp $	*/
 /*	$KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.135 2017/03/14 04:21:38 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.135.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -319,6 +319,7 @@ nd6_ra_input(struct mbuf *m, int off, in
 			   IN6_PRINT(ip6buf, &ip6->ip6_src),
 			   if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit);
 	}
+	IFNET_LOCK(ifp);
 	ND6_WLOCK();
 	dr = defrtrlist_update(&drtr);
     }
@@ -378,6 +379,7 @@ nd6_ra_input(struct mbuf *m, int off, in
 		}
 	}
 	ND6_UNLOCK();
+	IFNET_UNLOCK(ifp);
 
 	/*
 	 * MTU

Index: src/sys/netipsec/ipsec_output.c
diff -u src/sys/netipsec/ipsec_output.c:1.48.2.1 src/sys/netipsec/ipsec_output.c:1.48.2.2
--- src/sys/netipsec/ipsec_output.c:1.48.2.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/ipsec_output.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_output.c,v 1.48.2.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: ipsec_output.c,v 1.48.2.2 2018/01/02 10:20:34 snj Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.48.2.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.48.2.2 2018/01/02 10:20:34 snj Exp $");
 
 /*
  * IPsec output processing.
@@ -117,9 +117,7 @@ ipsec_reinject_ipstack(struct mbuf *m, i
 
 	KASSERT(af == AF_INET || af == AF_INET6);
 
-#ifndef NET_MPSAFE
-	KERNEL_LOCK(1, NULL);
-#endif
+	KERNEL_LOCK_UNLESS_NET_MPSAFE();
 	ro = percpu_getref(ipsec_rtcache_percpu);
 	switch (af) {
 #ifdef INET
@@ -139,9 +137,7 @@ ipsec_reinject_ipstack(struct mbuf *m, i
 #endif
 	}
 	percpu_putref(ipsec_rtcache_percpu);
-#ifndef NET_MPSAFE
-	KERNEL_UNLOCK_ONE(NULL);
-#endif
+	KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
 
 	return rv;
 }

Index: src/sys/rump/net/lib/libnetinet/netinet_component.c
diff -u src/sys/rump/net/lib/libnetinet/netinet_component.c:1.8 src/sys/rump/net/lib/libnetinet/netinet_component.c:1.8.6.1
--- src/sys/rump/net/lib/libnetinet/netinet_component.c:1.8	Fri Jan 20 08:35:33 2017
+++ src/sys/rump/net/lib/libnetinet/netinet_component.c	Tue Jan  2 10:20:34 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: netinet_component.c,v 1.8 2017/01/20 08:35:33 ozaki-r Exp $	*/
+/*	$NetBSD: netinet_component.c,v 1.8.6.1 2018/01/02 10:20:34 snj Exp $	*/
 
 /*
  * Copyright (c) 2009 Antti Kantee.  All Rights Reserved.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netinet_component.c,v 1.8 2017/01/20 08:35:33 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netinet_component.c,v 1.8.6.1 2018/01/02 10:20:34 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/domain.h>
@@ -94,7 +94,9 @@ RUMP_COMPONENT(RUMP_COMPONENT_NET_IFCFG)
 	sin->sin_len = sizeof(struct sockaddr_in);
 	sin->sin_addr.s_addr = inet_addr("127.255.255.255");
 
+	IFNET_LOCK(lo0ifp);
 	in_control(so, SIOCAIFADDR, &ia, lo0ifp);
+	IFNET_UNLOCK(lo0ifp);
 	if_up(lo0ifp);
 	soclose(so);
 }

Reply via email to