Hi, The IPv6 reassembly code looks MP safe. So we can run it in parallel. Note that ip_ours() runs with shared netlock, while ip_local() has exclusive netlock after queuing.
ok? bluhm Index: netinet/ip_input.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.372 diff -u -p -r1.372 ip_input.c --- netinet/ip_input.c 29 Jun 2022 09:01:48 -0000 1.372 +++ netinet/ip_input.c 22 Jul 2022 21:59:38 -0000 @@ -142,6 +142,11 @@ int ip_local(struct mbuf **, int *, int, int ip_dooptions(struct mbuf *, struct ifnet *); int in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **); +int ip_fragcheck(struct mbuf **, int *); +struct mbuf * ip_reass(struct ipqent *, struct ipq *); +void ip_freef(struct ipq *); +void ip_flush(void); + static void ip_send_dispatch(void *); static void ip_sendraw_dispatch(void *); static struct task ipsend_task = TASK_INITIALIZER(ip_send_dispatch, &ipsend_mq); @@ -234,6 +239,10 @@ ip_init(void) int ip_ours(struct mbuf **mp, int *offp, int nxt, int af) { + nxt = ip_fragcheck(mp, offp); + if (nxt == IPPROTO_DONE) + return IPPROTO_DONE; + /* We are already in a IPv4/IPv6 local deliver loop. */ if (af != AF_UNSPEC) return ip_local(mp, offp, nxt, af); @@ -550,14 +559,29 @@ ip_input_if(struct mbuf **mp, int *offp, int ip_local(struct mbuf **mp, int *offp, int nxt, int af) { - struct mbuf *m = *mp; - struct ip *ip = mtod(m, struct ip *); + struct ip *ip; + + NET_ASSERT_WLOCKED(); + + ip = mtod(*mp, struct ip *); + *offp = ip->ip_hl << 2; + nxt = ip->ip_p; + + /* Check whether we are already in a IPv4/IPv6 local deliver loop. */ + if (af == AF_UNSPEC) + nxt = ip_deliver(mp, offp, nxt, AF_INET); + return nxt; +} + +int +ip_fragcheck(struct mbuf **mp, int *offp) +{ + struct ip *ip; struct ipq *fp; struct ipqent *ipqe; int mff, hlen; - NET_ASSERT_WLOCKED(); - + ip = mtod(*mp, struct ip *); hlen = ip->ip_hl << 2; /* @@ -568,12 +592,12 @@ ip_local(struct mbuf **mp, int *offp, in * but it's not worth the time; just let them time out.) */ if (ip->ip_off &~ htons(IP_DF | IP_RF)) { - if (m->m_flags & M_EXT) { /* XXX */ - if ((m = *mp = m_pullup(m, hlen)) == NULL) { + if ((*mp)->m_flags & M_EXT) { /* XXX */ + if ((*mp = m_pullup(*mp, hlen)) == NULL) { ipstat_inc(ips_toosmall); return IPPROTO_DONE; } - ip = mtod(m, struct ip *); + ip = mtod(*mp, struct ip *); } mtx_enter(&ipq_mutex); @@ -630,28 +654,26 @@ ip_local(struct mbuf **mp, int *offp, in } ip_frags++; ipqe->ipqe_mff = mff; - ipqe->ipqe_m = m; + ipqe->ipqe_m = *mp; ipqe->ipqe_ip = ip; - m = *mp = ip_reass(ipqe, fp); - if (m == NULL) + *mp = ip_reass(ipqe, fp); + if (*mp == NULL) goto bad; ipstat_inc(ips_reassembled); - ip = mtod(m, struct ip *); + ip = mtod(*mp, struct ip *); hlen = ip->ip_hl << 2; ip->ip_len = htons(ntohs(ip->ip_len) + hlen); - } else - if (fp) + } else { + if (fp != NULL) ip_freef(fp); + } mtx_leave(&ipq_mutex); } *offp = hlen; - nxt = ip->ip_p; - /* Check whether we are already in a IPv4/IPv6 local deliver loop. */ - if (af == AF_UNSPEC) - nxt = ip_deliver(mp, offp, nxt, AF_INET); - return nxt; + return ip->ip_p; + bad: mtx_leave(&ipq_mutex); m_freemp(mp); Index: netinet/ip_var.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v retrieving revision 1.93 diff -u -p -r1.93 ip_var.h --- netinet/ip_var.h 5 May 2022 13:57:40 -0000 1.93 +++ netinet/ip_var.h 22 Jul 2022 21:39:01 -0000 @@ -223,9 +223,7 @@ struct route; struct inpcb; int ip_ctloutput(int, struct socket *, int, int, struct mbuf *); -void ip_flush(void); int ip_fragment(struct mbuf *, struct mbuf_list *, struct ifnet *, u_long); -void ip_freef(struct ipq *); void ip_freemoptions(struct ip_moptions *); int ip_getmoptions(int, struct ip_moptions *, struct mbuf *); void ip_init(void); @@ -235,8 +233,6 @@ int ip_mforward(struct mbuf *, struct i int ip_optcopy(struct ip *, struct ip *); int ip_output(struct mbuf *, struct mbuf *, struct route *, int, struct ip_moptions *, struct inpcb *, u_int32_t); -struct mbuf * - ip_reass(struct ipqent *, struct ipq *); u_int16_t ip_randomid(void); void ip_send(struct mbuf *);