From: Alexander Bluhm Subject: Re: use softnet for socket splicing To: David Gwynne Cc: tech@openbsd.org Date: Mon, 4 Aug 2025 13:50:31 +0200 On Thu, Jul 31, 2025 at 07:09:21PM +0200, Alexander Bluhm wrote: > On Sat, Jul 26, 2025 at 02:02:11PM +1000, David Gwynne wrote: > > On Fri, Jul 25, 2025 at 02:07:57PM +0200, Alexander Bluhm wrote: > > > Hi, > > > > > > Currently socket splicing runs on one dedicated kernel thread. This > > > design is from a time when softnet was still a soft interrupt. > > > > how time flies. > > > > > Now with multiple softnet threads, I want to retire the sosplice > > > thread. Instead call sotask() with the softnet task queue. For > > > that I have to pass the queue down in struct netstack. Basically > > > sorwakeup() and sowwakeup() get an additional argument. If netstack > > > and softnet are available, I use this specific tasks queue. Otherwise > > > softnet thread 0 is sufficient. The hot path receiving packets > > > will distribute them over all softnet threads. > > > > > > Keeping the same softnet means that we take a bunch of packets from > > > the network driver, do input processing, store them in socket > > > buffers. Then the same thread handles the splicing task, calls > > > somove() and does output processing. There is no concurrent locking > > > or scheduling, ideally packets stay on the same CPU. Before I had > > > a yield() in sotask() to allow accumulation of packets. With the > > > new design this is no longer necessary. > > > > > > As we run on softnet task queue and add splice tasks there, task > > > barrier causes deadlock. I replaced them with reference count in > > > task_add(), task_del(), and sotask(). > > > > hmm. you should be able to call taskq_barrier() from a task that's > > running on the relevant taskq. i added it in src/sys/kern/kern_task.c > > r1.28 for drm. > > > > also, this idiom: > > > > + if (task_add(soback->so_splicequeue, > > + &soback->so_splicetask)) > > + soref(soback); > > > > is unsafe. > > > > you have to assume that it's possible (regardless of how unlikely it is) > > that the task will run as soon as it's added, and before that soref is > > called. if the you're holding the only ref before the task_add call, the > > rele in the task itself can drop the count to zero and destroy the thing. > > the safe pattern is: > > > > + soref(soback); > > + if (!task_add(soback->so_splicequeue, > > + &soback->so_splicetask)) > > + sorele(soback); > > > > bouncing the refcnt around sucks though, which is why barriers can be > > useful. alternatively, you can set it up so you have an extra ref to > > mitigate some of the extra counting. > > You are right, the non working taskq_barrier() was a bug in my > previous diff. > > Below is the diff that puts the splicing task on the network task > queue. so_splicequeue is used to remember the queue that was used > first. It is set atomically, all subsequent task_add(), task_del(), > and taskq_barrier() will use that queue. Delete is done in sounplice() > with additional mutex protection to allow re-adding. Barriers are > in soclose(). > > I like this a bit more than the netstack socket queue as I can use > the task infrastructure everywhere. > > ok? Anyone? I would like to get parallel somove() commited. Which approach is best can be decided later. I need something that runs in parallel to identify more bottlenecks. bluhm > Index: kern/uipc_socket.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v > diff -u -p -r1.385 uipc_socket.c > --- kern/uipc_socket.c 25 Jul 2025 08:58:44 -0000 1.385 > +++ kern/uipc_socket.c 31 Jul 2025 11:39:04 -0000 > @@ -52,6 +52,9 @@ > #include > #include > > +#include > +#include > + > #ifdef DDB > #include > #endif > @@ -117,14 +120,13 @@ int sominconn = SOMINCONN; > struct pool socket_pool; > #ifdef SOCKET_SPLICE > struct pool sosplice_pool; > -struct taskq *sosplice_taskq; > -struct rwlock sosplice_lock = RWLOCK_INITIALIZER("sosplicelk"); > > #define so_splicelen so_sp->ssp_len > #define so_splicemax so_sp->ssp_max > #define so_spliceidletv so_sp->ssp_idletv > #define so_spliceidleto so_sp->ssp_idleto > #define so_splicetask so_sp->ssp_task > +#define so_splicequeue so_sp->ssp_queue > #endif > > void > @@ -433,6 +435,7 @@ discard: > #ifdef SOCKET_SPLICE > if (so->so_sp) { > struct socket *soback; > + struct taskq *spq, *spqback; > > sounlock_shared(so); > /* > @@ -461,7 +464,6 @@ discard: > sounsplice(so->so_sp->ssp_soback, so, freeing); > } > sbunlock(&soback->so_rcv); > - sorele(soback); > > notsplicedback: > sblock(&so->so_rcv, SBL_WAIT | SBL_NOINTR); > @@ -474,9 +476,16 @@ notsplicedback: > } > sbunlock(&so->so_rcv); > > - timeout_del_barrier(&so->so_spliceidleto); > - task_del(sosplice_taskq, &so->so_splicetask); > - taskq_barrier(sosplice_taskq); > + timeout_barrier(&so->so_spliceidleto); > + spq = READ_ONCE(so->so_splicequeue); > + if (spq != NULL) > + taskq_barrier(spq); > + if (soback != NULL) { > + spqback = READ_ONCE(soback->so_splicequeue); > + if (spqback != NULL && spqback != spq) > + taskq_barrier(spqback); > + sorele(soback); > + } > > solock_shared(so); > } > @@ -1290,7 +1299,6 @@ sosplice(struct socket *so, int fd, off_ > { > struct file *fp; > struct socket *sosp; > - struct taskq *tq; > int error = 0; > > if ((so->so_proto->pr_flags & PR_SPLICE) == 0) > @@ -1312,25 +1320,6 @@ sosplice(struct socket *so, int fd, off_ > return (error); > } > > - if (sosplice_taskq == NULL) { > - rw_enter_write(&sosplice_lock); > - if (sosplice_taskq == NULL) { > - tq = taskq_create("sosplice", 1, IPL_SOFTNET, > - TASKQ_MPSAFE); > - if (tq == NULL) { > - rw_exit_write(&sosplice_lock); > - return (ENOMEM); > - } > - /* Ensure the taskq is fully visible to other CPUs. */ > - membar_producer(); > - sosplice_taskq = tq; > - } > - rw_exit_write(&sosplice_lock); > - } else { > - /* Ensure the taskq is fully visible on this CPU. */ > - membar_consumer(); > - } > - > /* Find sosp, the drain socket where data will be spliced into. */ > if ((error = getsock(curproc, fd, &fp)) != 0) > return (error); > @@ -1435,15 +1424,15 @@ sounsplice(struct socket *so, struct soc > mtx_enter(&sosp->so_snd.sb_mtx); > so->so_rcv.sb_flags &= ~SB_SPLICE; > sosp->so_snd.sb_flags &= ~SB_SPLICE; > + timeout_del(&so->so_spliceidleto); > + if (so->so_splicequeue != NULL) > + task_del(so->so_splicequeue, &so->so_splicetask); > KASSERT(so->so_sp->ssp_socket == sosp); > KASSERT(sosp->so_sp->ssp_soback == so); > so->so_sp->ssp_socket = sosp->so_sp->ssp_soback = NULL; > mtx_leave(&sosp->so_snd.sb_mtx); > mtx_leave(&so->so_rcv.sb_mtx); > > - task_del(sosplice_taskq, &so->so_splicetask); > - timeout_del(&so->so_spliceidleto); > - > /* Do not wakeup a socket that is about to be freed. */ > if ((freeing & SOSP_FREEING_READ) == 0) { > int readable; > @@ -1453,13 +1442,13 @@ sounsplice(struct socket *so, struct soc > readable = so->so_qlen || soreadable(so); > mtx_leave(&so->so_rcv.sb_mtx); > if (readable) > - sorwakeup(so); > + sorwakeup(so, NULL); > sounlock_shared(so); > } > if ((freeing & SOSP_FREEING_WRITE) == 0) { > solock_shared(sosp); > if (sowriteable(sosp)) > - sowwakeup(sosp); > + sowwakeup(sosp, NULL); > sounlock_shared(sosp); > } > > @@ -1484,20 +1473,11 @@ void > sotask(void *arg) > { > struct socket *so = arg; > - int doyield = 0; > > sblock(&so->so_rcv, SBL_WAIT | SBL_NOINTR); > - if (so->so_rcv.sb_flags & SB_SPLICE) { > - if (so->so_proto->pr_flags & PR_WANTRCVD) > - doyield = 1; > + if (so->so_rcv.sb_flags & SB_SPLICE) > somove(so, M_DONTWAIT); > - } > sbunlock(&so->so_rcv); > - > - if (doyield) { > - /* Avoid user land starvation. */ > - yield(); > - } > } > > /* > @@ -1853,13 +1833,16 @@ somove(struct socket *so, int wait) > #endif /* SOCKET_SPLICE */ > > void > -sorwakeup(struct socket *so) > +sorwakeup(struct socket *so, struct netstack *ns) > { > #ifdef SOCKET_SPLICE > if (so->so_proto->pr_flags & PR_SPLICE) { > mtx_enter(&so->so_rcv.sb_mtx); > - if (so->so_rcv.sb_flags & SB_SPLICE) > - task_add(sosplice_taskq, &so->so_splicetask); > + if (so->so_rcv.sb_flags & SB_SPLICE) { > + atomic_cas_ptr(&so->so_splicequeue, NULL, > + ns != NULL ? ns->ns_nettaskq : net_tq(0)); > + task_add(so->so_splicequeue, &so->so_splicetask); > + } > if (isspliced(so)) { > mtx_leave(&so->so_rcv.sb_mtx); > return; > @@ -1873,14 +1856,19 @@ sorwakeup(struct socket *so) > } > > void > -sowwakeup(struct socket *so) > +sowwakeup(struct socket *so, struct netstack *ns) > { > #ifdef SOCKET_SPLICE > if (so->so_proto->pr_flags & PR_SPLICE) { > mtx_enter(&so->so_snd.sb_mtx); > - if (so->so_snd.sb_flags & SB_SPLICE) > - task_add(sosplice_taskq, > - &so->so_sp->ssp_soback->so_splicetask); > + if (so->so_snd.sb_flags & SB_SPLICE) { > + struct socket *soback = so->so_sp->ssp_soback; > + > + atomic_cas_ptr(&soback->so_splicequeue, NULL, > + ns != NULL ? ns->ns_nettaskq : net_tq(0)); > + task_add(soback->so_splicequeue, > + &soback->so_splicetask); > + } > if (issplicedback(so)) { > mtx_leave(&so->so_snd.sb_mtx); > return; > Index: kern/uipc_socket2.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket2.c,v > diff -u -p -r1.186 uipc_socket2.c > --- kern/uipc_socket2.c 14 Jul 2025 21:47:26 -0000 1.186 > +++ kern/uipc_socket2.c 31 Jul 2025 10:39:10 -0000 > @@ -113,15 +113,15 @@ soisconnected(struct socket *so) > > soqremque(so, 0); > soqinsque(head, so, 1); > - sorwakeup(head); > + sorwakeup(head, NULL); > wakeup_one(&head->so_timeo); > > sounlock(head); > sorele(head); > } else { > wakeup(&so->so_timeo); > - sorwakeup(so); > - sowwakeup(so); > + sorwakeup(so, NULL); > + sowwakeup(so, NULL); > } > } > > @@ -141,8 +141,8 @@ soisdisconnecting(struct socket *so) > mtx_leave(&so->so_snd.sb_mtx); > > wakeup(&so->so_timeo); > - sowwakeup(so); > - sorwakeup(so); > + sowwakeup(so, NULL); > + sorwakeup(so, NULL); > } > > void > @@ -162,8 +162,8 @@ soisdisconnected(struct socket *so) > so->so_state |= SS_ISDISCONNECTED; > > wakeup(&so->so_timeo); > - sowwakeup(so); > - sorwakeup(so); > + sowwakeup(so, NULL); > + sorwakeup(so, NULL); > } > > /* > @@ -233,7 +233,7 @@ sonewconn(struct socket *head, int conns > } > if (connstatus) { > so->so_state |= connstatus; > - sorwakeup(head); > + sorwakeup(head, NULL); > wakeup(&head->so_timeo); > } > > @@ -308,7 +308,7 @@ socantsendmore(struct socket *so) > mtx_enter(&so->so_snd.sb_mtx); > so->so_snd.sb_state |= SS_CANTSENDMORE; > mtx_leave(&so->so_snd.sb_mtx); > - sowwakeup(so); > + sowwakeup(so, NULL); > } > > void > @@ -317,7 +317,7 @@ socantrcvmore(struct socket *so) > mtx_enter(&so->so_rcv.sb_mtx); > so->so_rcv.sb_state |= SS_CANTRCVMORE; > mtx_leave(&so->so_rcv.sb_mtx); > - sorwakeup(so); > + sorwakeup(so, NULL); > } > > void > Index: kern/uipc_usrreq.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_usrreq.c,v > diff -u -p -r1.220 uipc_usrreq.c > --- kern/uipc_usrreq.c 12 Jun 2025 20:37:58 -0000 1.220 > +++ kern/uipc_usrreq.c 31 Jul 2025 10:39:10 -0000 > @@ -502,7 +502,7 @@ uipc_rcvd(struct socket *so) > so2->so_snd.sb_cc = so->so_rcv.sb_cc; > mtx_leave(&so2->so_snd.sb_mtx); > mtx_leave(&so->so_rcv.sb_mtx); > - sowwakeup(so2); > + sowwakeup(so2, NULL); > } > > int > @@ -568,7 +568,7 @@ uipc_send(struct socket *so, struct mbuf > mtx_leave(&so2->so_rcv.sb_mtx); > > if (dowakeup) > - sorwakeup(so2); > + sorwakeup(so2, NULL); > > m = NULL; > > @@ -636,7 +636,7 @@ uipc_dgram_send(struct socket *so, struc > mtx_leave(&so2->so_rcv.sb_mtx); > > if (dowakeup) > - sorwakeup(so2); > + sorwakeup(so2, NULL); > if (nam) > unp_disconnect(unp); > > Index: net/if.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.c,v > diff -u -p -r1.740 if.c > --- net/if.c 21 Jul 2025 20:36:41 -0000 1.740 > +++ net/if.c 31 Jul 2025 10:39:10 -0000 > @@ -270,6 +270,7 @@ ifinit(void) > TASKQ_MPSAFE); > if (sn->sn_taskq == NULL) > panic("unable to create network taskq %d", i); > + sn->sn_netstack.ns_nettaskq = sn->sn_taskq; > } > } > > @@ -973,6 +974,7 @@ if_input_process(struct ifnet *ifp, stru > { > struct mbuf *m; > struct softnet *sn; > + struct netstack *ns; > > if (ml_empty(ml)) > return; > @@ -988,19 +990,20 @@ if_input_process(struct ifnet *ifp, stru > */ > > sn = net_sn(idx); > - ml_init(&sn->sn_netstack.ns_tcp_ml); > + ns = &sn->sn_netstack; > + ml_init(&ns->ns_tcp_ml); > #ifdef INET6 > - ml_init(&sn->sn_netstack.ns_tcp6_ml); > + ml_init(&ns->ns_tcp6_ml); > #endif > > NET_LOCK_SHARED(); > > while ((m = ml_dequeue(ml)) != NULL) > - (*ifp->if_input)(ifp, m, &sn->sn_netstack); > + (*ifp->if_input)(ifp, m, ns); > > - tcp_input_mlist(&sn->sn_netstack.ns_tcp_ml, AF_INET); > + tcp_input_mlist(&ns->ns_tcp_ml, AF_INET, ns); > #ifdef INET6 > - tcp_input_mlist(&sn->sn_netstack.ns_tcp6_ml, AF_INET6); > + tcp_input_mlist(&ns->ns_tcp6_ml, AF_INET6, ns); > #endif > > NET_UNLOCK_SHARED(); > Index: net/if_ethersubr.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_ethersubr.c,v > diff -u -p -r1.303 if_ethersubr.c > --- net/if_ethersubr.c 7 Jul 2025 02:28:50 -0000 1.303 > +++ net/if_ethersubr.c 31 Jul 2025 10:39:10 -0000 > @@ -2108,7 +2108,7 @@ ether_frm_recv(struct socket *so, struct > return; > } > > - sorwakeup(so); > + sorwakeup(so, NULL); > } > > static struct mbuf * > Index: net/if_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_var.h,v > diff -u -p -r1.139 if_var.h > --- net/if_var.h 19 Jul 2025 16:40:40 -0000 1.139 > +++ net/if_var.h 31 Jul 2025 10:39:10 -0000 > @@ -92,9 +92,10 @@ struct task; > struct cpumem; > > struct netstack { > - struct route ns_route; > - struct mbuf_list ns_tcp_ml; > - struct mbuf_list ns_tcp6_ml; > + struct route ns_route; > + struct mbuf_list ns_tcp_ml; > + struct mbuf_list ns_tcp6_ml; > + struct taskq *ns_nettaskq; > }; > > /* > Index: net/pfkeyv2.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/pfkeyv2.c,v > diff -u -p -r1.270 pfkeyv2.c > --- net/pfkeyv2.c 7 Jul 2025 02:28:50 -0000 1.270 > +++ net/pfkeyv2.c 31 Jul 2025 10:39:10 -0000 > @@ -457,7 +457,7 @@ pfkey_sendup(struct pkpcb *kp, struct mb > return (ENOBUFS); > } > > - sorwakeup(so); > + sorwakeup(so, NULL); > return (0); > } > > Index: net/rtsock.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/net/rtsock.c,v > diff -u -p -r1.386 rtsock.c > --- net/rtsock.c 15 Jul 2025 09:55:49 -0000 1.386 > +++ net/rtsock.c 31 Jul 2025 10:39:10 -0000 > @@ -485,7 +485,7 @@ rtm_senddesync(struct socket *so) > > if (ret != 0) { > rop->rop_flags &= ~ROUTECB_FLAG_DESYNC; > - sorwakeup(rop->rop_socket); > + sorwakeup(rop->rop_socket, NULL); > return; > } > m_freem(desync_mbuf); > @@ -612,7 +612,7 @@ rtm_sendup(struct socket *so, struct mbu > return (ENOBUFS); > } > > - sorwakeup(so); > + sorwakeup(so, NULL); > return (0); > } > > Index: netinet/ip_divert.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_divert.c,v > diff -u -p -r1.107 ip_divert.c > --- netinet/ip_divert.c 8 Jul 2025 00:47:41 -0000 1.107 > +++ netinet/ip_divert.c 31 Jul 2025 10:39:11 -0000 > @@ -237,7 +237,7 @@ divert_packet(struct mbuf *m, int dir, u > goto bad; > } > mtx_leave(&so->so_rcv.sb_mtx); > - sorwakeup(so); > + sorwakeup(so, NULL); > > in_pcbunref(inp); > return; > Index: netinet/ip_mroute.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_mroute.c,v > diff -u -p -r1.150 ip_mroute.c > --- netinet/ip_mroute.c 19 Jul 2025 16:40:40 -0000 1.150 > +++ netinet/ip_mroute.c 31 Jul 2025 10:39:11 -0000 > @@ -1129,7 +1129,7 @@ socket_send(struct socket *so, struct mb > mtx_leave(&so->so_rcv.sb_mtx); > > if (ret != 0) { > - sorwakeup(so); > + sorwakeup(so, NULL); > return (0); > } > } > Index: netinet/raw_ip.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/raw_ip.c,v > diff -u -p -r1.167 raw_ip.c > --- netinet/raw_ip.c 8 Jul 2025 00:47:41 -0000 1.167 > +++ netinet/raw_ip.c 31 Jul 2025 10:39:11 -0000 > @@ -115,7 +115,7 @@ const struct pr_usrreqs rip_usrreqs = { > }; > > void rip_sbappend(struct inpcb *, struct mbuf *, struct ip *, > - struct sockaddr_in *); > + struct sockaddr_in *, struct netstack *); > > /* > * Initialize raw connection block q. > @@ -195,7 +195,7 @@ rip_input(struct mbuf **mp, int *offp, i > > n = m_copym(m, 0, M_COPYALL, M_NOWAIT); > if (n != NULL) > - rip_sbappend(last, n, ip, &ripsrc); > + rip_sbappend(last, n, ip, &ripsrc, ns); > in_pcbunref(last); > > mtx_enter(&rawcbtable.inpt_mtx); > @@ -222,7 +222,7 @@ rip_input(struct mbuf **mp, int *offp, i > return IPPROTO_DONE; > } > > - rip_sbappend(last, m, ip, &ripsrc); > + rip_sbappend(last, m, ip, &ripsrc, ns); > in_pcbunref(last); > > return IPPROTO_DONE; > @@ -230,7 +230,7 @@ rip_input(struct mbuf **mp, int *offp, i > > void > rip_sbappend(struct inpcb *inp, struct mbuf *m, struct ip *ip, > - struct sockaddr_in *ripsrc) > + struct sockaddr_in *ripsrc, struct netstack *ns) > { > struct socket *so = inp->inp_socket; > struct mbuf *opts = NULL; > @@ -249,7 +249,7 @@ rip_sbappend(struct inpcb *inp, struct m > m_freem(opts); > ipstat_inc(ips_noproto); > } else > - sorwakeup(so); > + sorwakeup(so, ns); > } > > /* > Index: netinet/tcp_input.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_input.c,v > diff -u -p -r1.457 tcp_input.c > --- netinet/tcp_input.c 24 Jul 2025 21:34:07 -0000 1.457 > +++ netinet/tcp_input.c 31 Jul 2025 10:39:11 -0000 > @@ -174,9 +174,10 @@ do { \ > if_put(ifp); \ > } while (0) > > -int tcp_input_solocked(struct mbuf **, int *, int, int, struct socket **); > +int tcp_input_solocked(struct mbuf **, int *, int, int, struct socket **, > + struct netstack *); > int tcp_mss_adv(struct rtentry *, int); > -int tcp_flush_queue(struct tcpcb *); > +int tcp_flush_queue(struct tcpcb *, struct netstack *); > void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); > void tcp_newreno_partialack(struct tcpcb *, struct tcphdr *); > > @@ -208,7 +209,8 @@ struct syn_cache *syn_cache_lookup(const > */ > > int > -tcp_reass(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m, int *tlen) > +tcp_reass(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m, int *tlen, > + struct netstack *ns) > { > struct tcpqent *p, *q, *nq, *tiqe; > > @@ -303,11 +305,11 @@ tcp_reass(struct tcpcb *tp, struct tcphd > if (th->th_seq != tp->rcv_nxt) > return (0); > > - return (tcp_flush_queue(tp)); > + return (tcp_flush_queue(tp, ns)); > } > > int > -tcp_flush_queue(struct tcpcb *tp) > +tcp_flush_queue(struct tcpcb *tp, struct netstack *ns) > { > struct socket *so = tp->t_inpcb->inp_socket; > struct tcpqent *q, *nq; > @@ -342,7 +344,7 @@ tcp_flush_queue(struct tcpcb *tp) > q = nq; > } while (q != NULL && q->tcpqe_tcp->th_seq == tp->rcv_nxt); > tp->t_flags |= TF_BLOCKOUTPUT; > - sorwakeup(so); > + sorwakeup(so, ns); > tp->t_flags &= ~TF_BLOCKOUTPUT; > return (flags); > } > @@ -351,7 +353,7 @@ int > tcp_input(struct mbuf **mp, int *offp, int proto, int af, struct netstack *ns) > { > if (ns == NULL) > - return tcp_input_solocked(mp, offp, proto, af, NULL); > + return tcp_input_solocked(mp, offp, proto, af, NULL, ns); > (*mp)->m_pkthdr.ph_cookie = (void *)(long)(*offp); > switch (af) { > case AF_INET: > @@ -370,7 +372,7 @@ tcp_input(struct mbuf **mp, int *offp, i > } > > void > -tcp_input_mlist(struct mbuf_list *ml, int af) > +tcp_input_mlist(struct mbuf_list *ml, int af, struct netstack *ns) > { > struct socket *so = NULL; > struct mbuf *m; > @@ -380,7 +382,7 @@ tcp_input_mlist(struct mbuf_list *ml, in > > off = (long)m->m_pkthdr.ph_cookie; > m->m_pkthdr.ph_cookie = NULL; > - nxt = tcp_input_solocked(&m, &off, IPPROTO_TCP, af, &so); > + nxt = tcp_input_solocked(&m, &off, IPPROTO_TCP, af, &so, ns); > KASSERT(nxt == IPPROTO_DONE); > } > > @@ -393,7 +395,7 @@ tcp_input_mlist(struct mbuf_list *ml, in > */ > int > tcp_input_solocked(struct mbuf **mp, int *offp, int proto, int af, > - struct socket **solocked) > + struct socket **solocked, struct netstack *ns) > { > struct mbuf *m = *mp; > int iphlen = *offp; > @@ -1075,7 +1077,7 @@ findpcb: > tcp_update_sndspace(tp); > if (sb_notify(&so->so_snd)) { > tp->t_flags |= TF_BLOCKOUTPUT; > - sowwakeup(so); > + sowwakeup(so, ns); > tp->t_flags &= ~TF_BLOCKOUTPUT; > } > if (so->so_snd.sb_cc || > @@ -1131,7 +1133,7 @@ findpcb: > mtx_leave(&so->so_rcv.sb_mtx); > } > tp->t_flags |= TF_BLOCKOUTPUT; > - sorwakeup(so); > + sorwakeup(so, ns); > tp->t_flags &= ~TF_BLOCKOUTPUT; > if (tp->t_flags & (TF_ACKNOW|TF_NEEDOUTPUT)) > (void) tcp_output(tp); > @@ -1264,7 +1266,7 @@ findpcb: > tp->snd_scale = tp->requested_s_scale; > tp->rcv_scale = tp->request_r_scale; > } > - tcp_flush_queue(tp); > + tcp_flush_queue(tp, ns); > > /* > * if we didn't have to retransmit the SYN, > @@ -1553,7 +1555,7 @@ trimthenstep6: > tp->rcv_scale = tp->request_r_scale; > tiwin = th->th_win << tp->snd_scale; > } > - tcp_flush_queue(tp); > + tcp_flush_queue(tp, ns); > tp->snd_wl1 = th->th_seq - 1; > /* fall into ... */ > > @@ -1835,7 +1837,7 @@ trimthenstep6: > tcp_update_sndspace(tp); > if (sb_notify(&so->so_snd)) { > tp->t_flags |= TF_BLOCKOUTPUT; > - sowwakeup(so); > + sowwakeup(so, ns); > tp->t_flags &= ~TF_BLOCKOUTPUT; > } > > @@ -2051,11 +2053,11 @@ dodata: /* XXX */ > mtx_leave(&so->so_rcv.sb_mtx); > } > tp->t_flags |= TF_BLOCKOUTPUT; > - sorwakeup(so); > + sorwakeup(so, ns); > tp->t_flags &= ~TF_BLOCKOUTPUT; > } else { > m_adj(m, hdroptlen); > - tiflags = tcp_reass(tp, th, m, &tlen); > + tiflags = tcp_reass(tp, th, m, &tlen, ns); > tp->t_flags |= TF_ACKNOW; > } > if (tp->sack_enable) > Index: netinet/tcp_subr.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_subr.c,v > diff -u -p -r1.216 tcp_subr.c > --- netinet/tcp_subr.c 18 Jul 2025 08:39:14 -0000 1.216 > +++ netinet/tcp_subr.c 31 Jul 2025 10:39:11 -0000 > @@ -589,8 +589,8 @@ tcp_notify(struct inpcb *inp, int error) > else > tp->t_softerror = error; > wakeup((caddr_t) &so->so_timeo); > - sorwakeup(so); > - sowwakeup(so); > + sorwakeup(so, NULL); > + sowwakeup(so, NULL); > } > > #ifdef INET6 > Index: netinet/tcp_var.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_var.h,v > diff -u -p -r1.195 tcp_var.h > --- netinet/tcp_var.h 18 Jun 2025 16:15:46 -0000 1.195 > +++ netinet/tcp_var.h 31 Jul 2025 10:39:11 -0000 > @@ -725,7 +725,7 @@ int tcp_dooptions(struct tcpcb *, u_cha > struct mbuf *, int, struct tcp_opt_info *, u_int, uint64_t); > void tcp_init(void); > int tcp_input(struct mbuf **, int *, int, int, struct netstack *); > -void tcp_input_mlist(struct mbuf_list *, int); > +void tcp_input_mlist(struct mbuf_list *, int, struct netstack *); > int tcp_mss(struct tcpcb *, int); > void tcp_mss_update(struct tcpcb *); > void tcp_softlro_glue(struct mbuf_list *, struct mbuf *, struct ifnet *); > @@ -744,7 +744,8 @@ int tcp_softtso_chop(struct mbuf_list * > int tcp_if_output_tso(struct ifnet *, struct mbuf **, struct sockaddr *, > struct rtentry *, uint32_t, u_int); > void tcp_pulloutofband(struct socket *, u_int, struct mbuf *, int); > -int tcp_reass(struct tcpcb *, struct tcphdr *, struct mbuf *, int *); > +int tcp_reass(struct tcpcb *, struct tcphdr *, struct mbuf *, int *, > + struct netstack *); > void tcp_rscale(struct tcpcb *, u_long); > void tcp_respond(struct tcpcb *, caddr_t, struct tcphdr *, tcp_seq, > tcp_seq, int, u_int, uint64_t); > Index: netinet/udp_usrreq.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v > diff -u -p -r1.349 udp_usrreq.c > --- netinet/udp_usrreq.c 18 Jul 2025 08:39:14 -0000 1.349 > +++ netinet/udp_usrreq.c 31 Jul 2025 10:39:11 -0000 > @@ -709,7 +709,7 @@ udp_sbappend(struct inpcb *inp, struct m > } > mtx_leave(&so->so_rcv.sb_mtx); > > - sorwakeup(so); > + sorwakeup(so, ns); > } > > /* > @@ -720,8 +720,8 @@ void > udp_notify(struct inpcb *inp, int errno) > { > inp->inp_socket->so_error = errno; > - sorwakeup(inp->inp_socket); > - sowwakeup(inp->inp_socket); > + sorwakeup(inp->inp_socket, NULL); > + sowwakeup(inp->inp_socket, NULL); > } > > #ifdef INET6 > Index: netinet6/ip6_divert.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_divert.c,v > diff -u -p -r1.108 ip6_divert.c > --- netinet6/ip6_divert.c 8 Jul 2025 00:47:41 -0000 1.108 > +++ netinet6/ip6_divert.c 31 Jul 2025 10:39:11 -0000 > @@ -235,7 +235,7 @@ divert6_packet(struct mbuf *m, int dir, > goto bad; > } > mtx_leave(&so->so_rcv.sb_mtx); > - sorwakeup(so); > + sorwakeup(so, NULL); > > in_pcbunref(inp); > return; > Index: netinet6/ip6_mroute.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_mroute.c,v > diff -u -p -r1.153 ip6_mroute.c > --- netinet6/ip6_mroute.c 25 Jul 2025 22:24:06 -0000 1.153 > +++ netinet6/ip6_mroute.c 31 Jul 2025 10:39:11 -0000 > @@ -906,7 +906,7 @@ socket6_send(struct socket *so, struct m > mtx_leave(&so->so_rcv.sb_mtx); > > if (ret != 0) { > - sorwakeup(so); > + sorwakeup(so, NULL); > return 0; > } > } > Index: netinet6/raw_ip6.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/raw_ip6.c,v > diff -u -p -r1.194 raw_ip6.c > --- netinet6/raw_ip6.c 8 Jul 2025 00:47:41 -0000 1.194 > +++ netinet6/raw_ip6.c 31 Jul 2025 10:39:11 -0000 > @@ -114,7 +114,7 @@ const struct pr_usrreqs rip6_usrreqs = { > }; > > void rip6_sbappend(struct inpcb *, struct mbuf *, struct ip6_hdr *, int, > - struct sockaddr_in6 *); > + struct sockaddr_in6 *, struct netstack *); > > /* > * Initialize raw connection block queue. > @@ -229,7 +229,8 @@ rip6_input(struct mbuf **mp, int *offp, > > n = m_copym(m, 0, M_COPYALL, M_NOWAIT); > if (n != NULL) > - rip6_sbappend(last, n, ip6, *offp, &rip6src); > + rip6_sbappend(last, n, ip6, *offp, &rip6src, > + ns); > in_pcbunref(last); > > mtx_enter(&rawin6pcbtable.inpt_mtx); > @@ -262,7 +263,7 @@ rip6_input(struct mbuf **mp, int *offp, > return IPPROTO_DONE; > } > > - rip6_sbappend(last, m, ip6, *offp, &rip6src); > + rip6_sbappend(last, m, ip6, *offp, &rip6src, ns); > in_pcbunref(last); > > return IPPROTO_DONE; > @@ -270,7 +271,7 @@ rip6_input(struct mbuf **mp, int *offp, > > void > rip6_sbappend(struct inpcb *inp, struct mbuf *m, struct ip6_hdr *ip6, int hlen, > - struct sockaddr_in6 *rip6src) > + struct sockaddr_in6 *rip6src, struct netstack *ns) > { > struct socket *so = inp->inp_socket; > struct mbuf *opts = NULL; > @@ -291,7 +292,7 @@ rip6_sbappend(struct inpcb *inp, struct > m_freem(opts); > rip6stat_inc(rip6s_fullsock); > } else > - sorwakeup(so); > + sorwakeup(so, ns); > } > > void > Index: sys/socketvar.h > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/sys/socketvar.h,v > diff -u -p -r1.159 socketvar.h > --- sys/socketvar.h 25 Jul 2025 08:58:44 -0000 1.159 > +++ sys/socketvar.h 31 Jul 2025 10:55:03 -0000 > @@ -74,6 +74,7 @@ struct sosplice { > struct timeval ssp_idletv; /* [I] idle timeout */ > struct timeout ssp_idleto; > struct task ssp_task; /* task for somove */ > + struct taskq *ssp_queue; /* [a] softnet queue where we add */ > }; > > /* > @@ -267,8 +268,8 @@ int sosend(struct socket *, struct mbuf > int sosetopt(struct socket *, int, int, struct mbuf *); > int soshutdown(struct socket *, int); > void sowakeup(struct socket *, struct sockbuf *); > -void sorwakeup(struct socket *); > -void sowwakeup(struct socket *); > +void sorwakeup(struct socket *, struct netstack *); > +void sowwakeup(struct socket *, struct netstack *); > int sockargs(struct mbuf **, const void *, size_t, int); > > int sosleep_nsec(struct socket *, void *, int, const char *, uint64_t);