I got splassert with pppx(4) and net/ifq.c rev 1.38 raised by NET_ASSERT_LOCKED() in netinet/ip_output.c:113 and underlaying routines.
net/ifq.c rev 1.38 is not in snapshot yet so you need to checkout and build kernel to reproduce. ---- dmesg begin ---- splassert: ip_output: want 2 have 0 Starting stack trace... ip_output(fffffd801f8c8800,0,0,0,0,0) at ip_output+0x8f pipex_l2tp_output(fffffd801f8c8800,ffff80000e787808) at pipex_l2tp_output+0x21d pipex_ppp_output(fffffd801f8c8800,ffff80000e787808,21) at pipex_ppp_output+0xda pppx_if_start(ffff80000e787268) at pppx_if_start+0x83 if_qstart_compat(ffff80000e7874e0) at if_qstart_compat+0x2e ifq_serialize(ffff80000e7874e0,ffff80000e7875b0) at ifq_serialize+0x103 taskq_thread(ffffffff81f3df30) at taskq_thread+0x4d end trace frame: 0x0, count: 250 End of stack trace. splassert: ipsp_spd_lookup: want 2 have 0 Starting stack trace... ipsp_spd_lookup(fffffd801f8c8800,2,14,ffff80000e726c9c,2,0) at ipsp_spd_lookup+0x80 ip_output_ipsec_lookup(fffffd801f8c8800,14,ffff80000e726c9c,0,1) at ip_output_ipsec_lookup+0x4d ip_output(fffffd801f8c8800,0,0,0,0,0) at ip_output+0x4fa pipex_l2tp_output(fffffd801f8c8800,ffff80000e787808) at pipex_l2tp_output+0x21d pipex_ppp_output(fffffd801f8c8800,ffff80000e787808,21) at pipex_ppp_output+0xda pppx_if_start(ffff80000e787268) at pppx_if_start+0x83 if_qstart_compat(ffff80000e7874e0) at if_qstart_compat+0x2e ifq_serialize(ffff80000e7874e0,ffff80000e7875b0) at ifq_serialize+0x103 taskq_thread(ffffffff81f3df30) at taskq_thread+0x4d end trace frame: 0x0, count: 248 End of stack trace. splassert: spd_table_get: want 2 have 0 ---- dmesg end ---- 1. `pxi_if' owned by struct pppx_if has IFXF_MPSAFE flag unset 1.1 pppx(4) sets IFQ_SET_MAXLEN(&ifp->if_snd, 1) at net/if_pppx.c:866 2. pppx_if_output() is called under NET_LOCK() 3. pppx_if_output() calls if_enqueue() at net/if_pppx.c:1123 4. pppx(4) doesn't set `ifp->if_enqueue' so if_enqueue() calls if_enqueue_ifq() at net/if.c:709 (which is set in net/if.c:639) 5. if_enqueue_ifq() calls ifq_start() at net/if.c:734 6. ifq_start() we a still under NET_LOCK() here 6.a. in net/ifq.c rev 1.37 ifq_start() checks "ifq_len(ifq) >= min(ifp->if_txmit, ifq->ifq_maxlen)" and this was always true because (1.1) so we always call ifq_run_start() which calls ifq_serialize(). ifq_serialize() will call if_qstart_compat() which calls pppx_if_start() which calls pipex_ppp_output() etc while we still holding NET_LOCK() so the assertions I reported above are not raised. 6.b. net/ifq.c rev 1.38 introduce checks of IFXF_MPSAFE flag. so we are always going to net/ifq.c:132 where we adding out task to `systq' referenced by `ifq_softnet' (ifq_softnet set to `systq' at net/ifq.c:199). taskq_thread() doesn't grab NET_LOCK() so after net/ifq.c rev 1.38 ifq_serialize() and underlaying pppx_if_start() call without NET_LOCK() and corresponding asserts raised. The problem I pointed is not in net/ifq.c rev 1.38 but in pppx(4). `if_start' routines should grab NET_LOCK() by themself if it is required but pppx_if_start() and pppac_start() did't do that. pppac_start() has no underlaying NET_ASSERT_LOCKED() so the pppx(4) is the only case were the problem is shown. Since NET_LOCK() is required by pipex(4), diff below adds it to pppx_if_start() and pppac_start(). After net/ifq.c rev 1.38 pppx_if_start() will newer be called from pppx_if_output() but from `systq' only so I don't add lock/unlock dances around if_enqueue() at net/if_pppx.c:1123. Diff tested for both pppx(4) and pppac(4) cases. Index: sys/net/if_pppx.c =================================================================== RCS file: /cvs/src/sys/net/if_pppx.c,v retrieving revision 1.84 diff -u -p -r1.84 if_pppx.c --- sys/net/if_pppx.c 18 Apr 2020 04:03:56 -0000 1.84 +++ sys/net/if_pppx.c 20 May 2020 14:17:20 -0000 @@ -1054,8 +1054,9 @@ pppx_if_start(struct ifnet *ifp) struct mbuf *m; int proto; + NET_LOCK(); if (!ISSET(ifp->if_flags, IFF_RUNNING)) - return; + goto unlock; for (;;) { IFQ_DEQUEUE(&ifp->if_snd, m); @@ -1071,6 +1072,8 @@ pppx_if_start(struct ifnet *ifp) pipex_ppp_output(m, &pxi->pxi_session, proto); } +unlock: + NET_UNLOCK(); } int @@ -1640,6 +1643,8 @@ pppac_start(struct ifnet *ifp) struct pppac_softc *sc = ifp->if_softc; struct mbuf *m; + NET_LOCK(); + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { #if NBPFILTER > 0 if (ifp->if_bpf) { @@ -1668,4 +1673,6 @@ pppac_start(struct ifnet *ifp) wakeup(sc); selwakeup(&sc->sc_rsel); } + + NET_UNLOCK(); }