Run raw IPv6 input in parallel.
authorbluhm <bluhm@openbsd.org>
Tue, 16 Apr 2024 12:40:40 +0000 (12:40 +0000)
committerbluhm <bluhm@openbsd.org>
Tue, 16 Apr 2024 12:40:40 +0000 (12:40 +0000)
Get rip6_input() in the same shape as rip_input().  Call
soisdisconnected() from rip6_disconnect().  This means that the raw
IP socket cannot be reconnected later.  Now raw IPv6 behaves like
IPv4 in this regard, KAME code is quite inconsistent here.  Also
make sure that there is no race between disconnect, input and wakeup.
The inpcb fileds inp_icmp6filt and inp_cksum6 are protected by
exclusive net lock in icmp6_ctloutput().  With all that, mark raw
IPv6 sockets to handle input in parallel.

OK mvs@

sys/netinet6/in6_proto.c
sys/netinet6/raw_ip6.c

index db218af..f73e00b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6_proto.c,v 1.113 2024/01/11 14:15:12 bluhm Exp $   */
+/*     $OpenBSD: in6_proto.c,v 1.114 2024/04/16 12:40:40 bluhm Exp $   */
 /*     $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $      */
 
 /*
@@ -158,7 +158,7 @@ const struct protosw inet6sw[] = {
   .pr_type     = SOCK_RAW,
   .pr_domain   = &inet6domain,
   .pr_protocol = IPPROTO_RAW,
-  .pr_flags    = PR_ATOMIC|PR_ADDR,
+  .pr_flags    = PR_ATOMIC|PR_ADDR|PR_MPINPUT,
   .pr_input    = rip6_input,
   .pr_ctlinput = rip6_ctlinput,
   .pr_ctloutput        = rip6_ctloutput,
@@ -322,7 +322,7 @@ const struct protosw inet6sw[] = {
   /* raw wildcard */
   .pr_type     = SOCK_RAW,
   .pr_domain   = &inet6domain,
-  .pr_flags    = PR_ATOMIC|PR_ADDR,
+  .pr_flags    = PR_ATOMIC|PR_ADDR|PR_MPINPUT,
   .pr_input    = rip6_input,
   .pr_ctloutput        = rip6_ctloutput,
   .pr_usrreqs  = &rip6_usrreqs,
index 177eeb8..5804af2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: raw_ip6.c,v 1.182 2024/02/13 12:22:09 bluhm Exp $     */
+/*     $OpenBSD: raw_ip6.c,v 1.183 2024/04/16 12:40:40 bluhm Exp $     */
 /*     $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $        */
 
 /*
@@ -155,9 +155,9 @@ rip6_input(struct mbuf **mp, int *offp, int proto, int af)
        } else
                rip6stat_inc(rip6s_ipackets);
 
-       bzero(&rip6src, sizeof(rip6src));
-       rip6src.sin6_len = sizeof(struct sockaddr_in6);
+       memset(&rip6src, 0, sizeof(rip6src));
        rip6src.sin6_family = AF_INET6;
+       rip6src.sin6_len = sizeof(rip6src);
        /* KAME hack: recover scopeid */
        in6_recoverscope(&rip6src, &ip6->ip6_src);
 
@@ -186,7 +186,13 @@ rip6_input(struct mbuf **mp, int *offp, int proto, int af)
        TAILQ_FOREACH(inp, &rawin6pcbtable.inpt_queue, inp_queue) {
                KASSERT(ISSET(inp->inp_flags, INP_IPV6));
 
-               if (inp->inp_socket->so_rcv.sb_state & SS_CANTRCVMORE)
+               /*
+                * Packet must not be inserted after disconnected wakeup
+                * call.  To avoid race, check again when holding receive
+                * buffer mutex.
+                */
+               if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state),
+                   SS_CANTRCVMORE))
                        continue;
                if (rtable_l2(inp->inp_rtableid) !=
                    rtable_l2(m->m_pkthdr.ph_rtableid))
@@ -264,7 +270,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto, int af)
                        n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
                if (n != NULL) {
                        struct socket *so = inp->inp_socket;
-                       int ret;
+                       int ret = 0;
 
                        if (inp->inp_flags & IN6P_CONTROLOPTS)
                                ip6_savecontrol(inp, n, &opts);
@@ -272,12 +278,14 @@ rip6_input(struct mbuf **mp, int *offp, int proto, int af)
                        m_adj(n, *offp);
 
                        mtx_enter(&so->so_rcv.sb_mtx);
-                       ret = sbappendaddr(so, &so->so_rcv,
-                           sin6tosa(&rip6src), n, opts);
+                       if (!ISSET(inp->inp_socket->so_rcv.sb_state,
+                           SS_CANTRCVMORE)) {
+                               ret = sbappendaddr(so, &so->so_rcv,
+                                   sin6tosa(&rip6src), n, opts);
+                       }
                        mtx_leave(&so->so_rcv.sb_mtx);
 
                        if (ret == 0) {
-                               /* should notify about lost packet */
                                m_freem(n);
                                m_freem(opts);
                                rip6stat_inc(rip6s_fullsock);
@@ -727,7 +735,7 @@ rip6_disconnect(struct socket *so)
        if ((so->so_state & SS_ISCONNECTED) == 0)
                return (ENOTCONN);
 
-       so->so_state &= ~SS_ISCONNECTED;        /* XXX */
+       soisdisconnected(so);
        mtx_enter(&rawin6pcbtable.inpt_mtx);
        inp->inp_faddr6 = in6addr_any;
        mtx_leave(&rawin6pcbtable.inpt_mtx);