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 *);