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

Reply via email to