As it was reported [1] switch(4) triggers NET_ASSERT_LOCKED() while we perform ifconfig(8) destroy. ifpromisc() requires netlock to be held. This is true while switch_port_detach() and underlay ifpromisc() called through switch_ioctl(). But while we destroy switch(4) interface we call ifpromisc() without netlock. We can't add netlock just around ifpromisc() because switch_port_detach() which calls it called by switch_ioctl() with netlock held and by switch_clone_destroy() without netlock held. So the solution is to add netlock to destroy path. Diff below adds it around the whole foreach loop where we call switch_port_detach().
1. https://marc.info/?l=openbsd-bugs&m=161338077403538&w=2 Index: sys/net/if_switch.c =================================================================== RCS file: /cvs/src/sys/net/if_switch.c,v retrieving revision 1.40 diff -u -p -r1.40 if_switch.c --- sys/net/if_switch.c 19 Jan 2021 19:39:14 -0000 1.40 +++ sys/net/if_switch.c 19 Feb 2021 20:24:37 -0000 @@ -196,6 +196,7 @@ switch_clone_destroy(struct ifnet *ifp) struct switch_port *swpo, *tp; struct ifnet *ifs; + NET_LOCK(); TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) { if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) { switch_port_detach(ifs); @@ -204,6 +205,7 @@ switch_clone_destroy(struct ifnet *ifp) log(LOG_ERR, "failed to cleanup on ifindex(%d)\n", swpo->swpo_ifindex); } + NET_UNLOCK(); LIST_REMOVE(sc, sc_switch_next); bstp_destroy(sc->sc_stp); swofp_destroy(sc);