Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Make usages of ifp MP-safe in some functions of IP multi...



details:   https://anonhg.NetBSD.org/src/rev/2226c5327ed2
branches:  trunk
changeset: 822116:2226c5327ed2
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Thu Mar 02 05:24:23 2017 +0000

description:
Make usages of ifp MP-safe in some functions of IP multicast

diffstat:

 sys/netinet/ip_output.c   |  106 +++++++++++++++++++++++++++++++++------------
 sys/netinet6/ip6_output.c |   50 ++++++++++++++------
 sys/netinet6/ip6_var.h    |    6 +-
 3 files changed, 115 insertions(+), 47 deletions(-)

diffs (truncated from 426 to 300 lines):

diff -r f7d651905181 -r 2226c5327ed2 sys/netinet/ip_output.c
--- a/sys/netinet/ip_output.c   Thu Mar 02 04:33:56 2017 +0000
+++ b/sys/netinet/ip_output.c   Thu Mar 02 05:24:23 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_output.c,v 1.272 2017/02/22 07:05:04 ozaki-r Exp $  */
+/*     $NetBSD: ip_output.c,v 1.273 2017/03/02 05:24:23 ozaki-r Exp $  */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.272 2017/02/22 07:05:04 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.273 2017/03/02 05:24:23 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1444,6 +1444,7 @@
 
 /*
  * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
+ * Must be called in a pserialize critical section.
  */
 static struct ifnet *
 ip_multicast_if(struct in_addr *a, int *ifindexp)
@@ -1462,10 +1463,12 @@
                if (ifindexp)
                        *ifindexp = ifindex;
        } else {
-               LIST_FOREACH(ia, &IN_IFADDR_HASH(a->s_addr), ia_hash) {
+               IN_ADDRHASH_READER_FOREACH(ia, a->s_addr) {
                        if (in_hosteq(ia->ia_addr.sin_addr, *a) &&
                            (ia->ia_ifp->if_flags & IFF_MULTICAST) != 0) {
                                ifp = ia->ia_ifp;
+                               if (if_is_deactivated(ifp))
+                                       ifp = NULL;
                                break;
                        }
                }
@@ -1509,7 +1512,7 @@
 
 static int
 ip_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
-    struct in_addr *ia, bool add)
+    struct psref *psref, struct in_addr *ia, bool add)
 {
        int error;
        struct ip_mreq mreq;
@@ -1546,12 +1549,28 @@
                if (error != 0)
                        return error;
                *ifp = (rt = rtcache_init(&ro)) != NULL ? rt->rt_ifp : NULL;
+               if (*ifp != NULL) {
+                       if (if_is_deactivated(*ifp))
+                               *ifp = NULL;
+                       else
+                               if_acquire(*ifp, psref);
+               }
                rtcache_unref(rt, &ro);
                rtcache_free(&ro);
        } else {
+               int s = pserialize_read_enter();
                *ifp = ip_multicast_if(&mreq.imr_interface, NULL);
-               if (!add && *ifp == NULL)
+               if (!add && *ifp == NULL) {
+                       pserialize_read_exit(s);
                        return EADDRNOTAVAIL;
+               }
+               if (*ifp != NULL) {
+                       if (if_is_deactivated(*ifp))
+                               *ifp = NULL;
+                       else
+                               if_acquire(*ifp, psref);
+               }
+               pserialize_read_exit(s);
        }
        return 0;
 }
@@ -1565,26 +1584,31 @@
 {
        struct ifnet *ifp = NULL;       // XXX: gcc [ppc]
        struct in_addr ia;
-       int i, error;
+       int i, error, bound;
+       struct psref psref;
 
+       bound = curlwp_bind();
        if (sopt->sopt_size == sizeof(struct ip_mreq))
-               error = ip_get_membership(sopt, &ifp, &ia, true);
+               error = ip_get_membership(sopt, &ifp, &psref, &ia, true);
        else
 #ifdef INET6
-               error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+               error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
 #else
-               return EINVAL;  
+               error = EINVAL;
+               goto out;
 #endif
 
        if (error)
-               return error;
+               goto out;
 
        /*
         * See if we found an interface, and confirm that it
         * supports multicast.
         */
-       if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
-               return EADDRNOTAVAIL;
+       if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+               error = EADDRNOTAVAIL;
+               goto out;
+       }
 
        /*
         * See if the membership already exists or if all the
@@ -1595,21 +1619,31 @@
                    in_hosteq(imo->imo_membership[i]->inm_addr, ia))
                        break;
        }
-       if (i < imo->imo_num_memberships)
-               return EADDRINUSE;
+       if (i < imo->imo_num_memberships) {
+               error = EADDRINUSE;
+               goto out;
+       }
 
-       if (i == IP_MAX_MEMBERSHIPS)
-               return ETOOMANYREFS;
+       if (i == IP_MAX_MEMBERSHIPS) {
+               error = ETOOMANYREFS;
+               goto out;
+       }
 
        /*
         * Everything looks good; add a new record to the multicast
         * address list for the given interface.
         */
-       if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL)
-               return ENOBUFS;
+       if ((imo->imo_membership[i] = in_addmulti(&ia, ifp)) == NULL) {
+               error = ENOBUFS;
+               goto out;
+       }
 
        ++imo->imo_num_memberships;
-       return 0;
+       error = 0;
+out:
+       if_put(ifp, &psref);
+       curlwp_bindx(bound);
+       return error;
 }
 
 /*
@@ -1621,19 +1655,24 @@
 {
        struct in_addr ia = { .s_addr = 0 };    // XXX: gcc [ppc]
        struct ifnet *ifp = NULL;               // XXX: gcc [ppc]
-       int i, error;
+       int i, error, bound;
+       struct psref psref;
 
+       /* imo is protected by solock or referenced only by the caller */
+
+       bound = curlwp_bind();
        if (sopt->sopt_size == sizeof(struct ip_mreq))
-               error = ip_get_membership(sopt, &ifp, &ia, false);
+               error = ip_get_membership(sopt, &ifp, &psref, &ia, false);
        else
 #ifdef INET6
-               error = ip6_get_membership(sopt, &ifp, &ia, sizeof(ia));
+               error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
 #else
-               return EINVAL;
+               error = EINVAL;
+               goto out;
 #endif
 
        if (error)
-               return error;
+               goto out;
 
        /*
         * Find the membership in the membership array.
@@ -1644,8 +1683,10 @@
                    in_hosteq(imo->imo_membership[i]->inm_addr, ia))
                        break;
        }
-       if (i == imo->imo_num_memberships)
-               return EADDRNOTAVAIL;
+       if (i == imo->imo_num_memberships) {
+               error = EADDRNOTAVAIL;
+               goto out;
+       }
 
        /*
         * Give up the multicast address record to which the
@@ -1659,7 +1700,11 @@
        for (++i; i < imo->imo_num_memberships; ++i)
                imo->imo_membership[i-1] = imo->imo_membership[i];
        --imo->imo_num_memberships;
-       return 0;
+       error = 0;
+out:
+       curlwp_bindx(bound);
+       if_put(ifp, &psref);
+       return error;
 }
 
 /*
@@ -1691,7 +1736,8 @@
        }
 
        switch (sopt->sopt_name) {
-       case IP_MULTICAST_IF:
+       case IP_MULTICAST_IF: {
+               int s;
                /*
                 * Select the interface for outgoing multicast packets.
                 */
@@ -1713,17 +1759,21 @@
                 * IP address.  Find the interface and confirm that
                 * it supports multicasting.
                 */
+               s = pserialize_read_enter();
                ifp = ip_multicast_if(&addr, &ifindex);
                if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+                       pserialize_read_exit(s);
                        error = EADDRNOTAVAIL;
                        break;
                }
                imo->imo_multicast_if_index = ifp->if_index;
+               pserialize_read_exit(s);
                if (ifindex)
                        imo->imo_multicast_addr = addr;
                else
                        imo->imo_multicast_addr.s_addr = INADDR_ANY;
                break;
+           }
 
        case IP_MULTICAST_TTL:
                /*
diff -r f7d651905181 -r 2226c5327ed2 sys/netinet6/ip6_output.c
--- a/sys/netinet6/ip6_output.c Thu Mar 02 04:33:56 2017 +0000
+++ b/sys/netinet6/ip6_output.c Thu Mar 02 05:24:23 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip6_output.c,v 1.188 2017/03/02 01:05:02 ozaki-r Exp $ */
+/*     $NetBSD: ip6_output.c,v 1.189 2017/03/02 05:24:23 ozaki-r Exp $ */
 /*     $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $    */
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.188 2017/03/02 01:05:02 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.189 2017/03/02 05:24:23 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -2380,13 +2380,14 @@
 }
 
 int
-ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp, void *v,
-    size_t l)
+ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
+    struct psref *psref, void *v, size_t l)
 {
        struct ipv6_mreq mreq;
        int error;
        struct in6_addr *ia = &mreq.ipv6mr_multiaddr;
        struct in_addr *ia4 = (void *)&ia->s6_addr32[3];
+
        error = sockopt_get(sopt, &mreq, sizeof(mreq));
        if (error != 0)
                return error;
@@ -2437,15 +2438,16 @@
                if (error != 0)
                        return error;
                rt = rtcache_init(&ro);
-               *ifp = rt != NULL ? rt->rt_ifp : NULL;
-               /* FIXME *ifp is NOMPSAFE */
+               *ifp = rt != NULL ?
+                   if_get_byindex(rt->rt_ifp->if_index, psref) : NULL;
                rtcache_unref(rt, &ro);
                rtcache_free(&ro);
        } else {
                /*
                 * If the interface is specified, validate it.
                 */
-               if ((*ifp = if_byindex(mreq.ipv6mr_interface)) == NULL)
+               *ifp = if_get_byindex(mreq.ipv6mr_interface, psref);
+               if (*ifp == NULL)
                        return ENXIO;   /* XXX EINVAL? */
        }
        if (sizeof(*ia) == l)



Home | Main Index | Thread Index | Old Index