The IPv4 reassembly code is MP safe, so we can run it in parallel.
authorbluhm <bluhm@openbsd.org>
Mon, 25 Jul 2022 23:19:34 +0000 (23:19 +0000)
committerbluhm <bluhm@openbsd.org>
Mon, 25 Jul 2022 23:19:34 +0000 (23:19 +0000)
Note that ip_ours() runs with shared netlock, while ip_local() has
exclusive netlock after queuing.  Move existing the code into
function ip_fragcheck() and call it from ip_ours().
OK mvs@

sys/netinet/ip_input.c
sys/netinet/ip_var.h

index 081ed00..8ec2807 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_input.c,v 1.373 2022/07/24 22:38:25 bluhm Exp $    */
+/*     $OpenBSD: ip_input.c,v 1.374 2022/07/25 23:19:34 bluhm Exp $    */
 /*     $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $   */
 
 /*
@@ -142,6 +142,11 @@ int        ip_local(struct mbuf **, int *, 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,12 +559,27 @@ ip_input_if(struct mbuf **mp, int *offp, int nxt, int af, struct ifnet *ifp)
 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;
+
+       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;
 
+       ip = mtod(*mp, struct ip *);
        hlen = ip->ip_hl << 2;
 
        /*
@@ -566,12 +590,12 @@ ip_local(struct mbuf **mp, int *offp, int nxt, int af)
         * 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);
@@ -628,28 +652,26 @@ ip_local(struct mbuf **mp, int *offp, int nxt, int af)
                        }
                        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 3df8ffe..f5e2a76 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_var.h,v 1.93 2022/05/05 13:57:40 claudio Exp $     */
+/*     $OpenBSD: ip_var.h,v 1.94 2022/07/25 23:19:34 bluhm Exp $       */
 /*     $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $     */
 
 /*
@@ -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 ifnet *);
 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 *);