From 822a7690599bf519ea6b67468992d7d69e3d20ac Mon Sep 17 00:00:00 2001 From: mpi Date: Mon, 22 Jan 2018 09:05:06 +0000 Subject: [PATCH] Do not call ip_output() recursively in vxlan_start(). ip_output() currently needs the NET_LOCK() which is not held when an interface is added to a pf(4) queue. Fix an issue reported by Jason Tubnor, ok dlg@ --- sys/net/if_vxlan.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 107f6a51bde..ad4139bb72d 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vxlan.c,v 1.65 2018/01/09 15:24:24 bluhm Exp $ */ +/* $OpenBSD: if_vxlan.c,v 1.66 2018/01/22 09:05:06 mpi Exp $ */ /* * Copyright (c) 2013 Reyk Floeter @@ -73,6 +73,8 @@ struct vxlan_softc { int64_t sc_vnetid; u_int8_t sc_ttl; + struct task sc_sendtask; + LIST_ENTRY(vxlan_softc) sc_entry; }; @@ -91,6 +93,7 @@ int vxlan_output(struct ifnet *, struct mbuf *); void vxlan_addr_change(void *); void vxlan_if_change(void *); void vxlan_link_change(void *); +void vxlan_send_dispatch(void *); int vxlan_sockaddr_cmp(struct sockaddr *, struct sockaddr *); uint16_t vxlan_sockaddr_port(struct sockaddr *); @@ -132,6 +135,7 @@ vxlan_clone_create(struct if_clone *ifc, int unit) sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; sc->sc_dstport = htons(VXLAN_PORT); sc->sc_vnetid = VXLAN_VNI_UNSET; + task_set(&sc->sc_sendtask, vxlan_send_dispatch, sc); ifp = &sc->sc_ac.ac_if; snprintf(ifp->if_xname, sizeof ifp->if_xname, "vxlan%d", unit); @@ -186,6 +190,10 @@ vxlan_clone_destroy(struct ifnet *ifp) ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); ether_ifdetach(ifp); if_detach(ifp); + + if (!task_del(net_tq(ifp->if_index), &sc->sc_sendtask)) + taskq_barrier(net_tq(ifp->if_index)); + free(sc->sc_imo.imo_membership, M_IPMOPTS, 0); free(sc, M_DEVBUF, sizeof(*sc)); @@ -299,22 +307,44 @@ vxlan_multicast_join(struct ifnet *ifp, struct sockaddr *src, void vxlanstart(struct ifnet *ifp) { + struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; + + task_add(net_tq(ifp->if_index), &sc->sc_sendtask); +} + +void +vxlan_send_dispatch(void *xsc) +{ + struct vxlan_softc *sc = xsc; + struct ifnet *ifp = &sc->sc_ac.ac_if; struct mbuf *m; + struct mbuf_list ml; + ml_init(&ml); for (;;) { IFQ_DEQUEUE(&ifp->if_snd, m); if (m == NULL) - return; + break; #if NBPFILTER > 0 if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif + ml_enqueue(&ml, m); + } + + if (ml_empty(&ml)) + return; + + NET_RLOCK(); + while ((m = ml_dequeue(&ml)) != NULL) { vxlan_output(ifp, m); } + NET_RUNLOCK(); } + int vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) { -- 2.20.1