ifnet: Make ifnet and ifindex2ifnet MPSAFE
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 22 Jan 2015 13:28:43 +0000 (21:28 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 8 Feb 2015 11:34:59 +0000 (19:34 +0800)
- Accessing to these two global variables from non-netisr threads uses
  ifnet lock.  This kind of accessing is from
- Accessing to ifindex2ifnet from netisrs are lockless MPSAFE.
- Netisrs no longer access ifnet, instead they access ifnet array as of
  this commit, which is lockless MPSAFE.

Rules for accessing ifnet and ifindex2ifnet is commented near the
declaration of the related global variables/functions in net/if_var.h.

37 files changed:
sys/emulation/linux/i386/linprocfs/linprocfs_misc.c
sys/emulation/linux/linux_ioctl.c
sys/kern/lwkt_token.c
sys/net/altq/altq_cbq.c
sys/net/altq/altq_fairq.c
sys/net/altq/altq_hfsc.c
sys/net/altq/altq_priq.c
sys/net/altq/altq_subr.c
sys/net/bpf.c
sys/net/bridge/if_bridge.c
sys/net/if.c
sys/net/if_clone.c
sys/net/if_mib.c
sys/net/if_var.h
sys/net/lagg/if_lagg.c
sys/net/netmap/netmap.c
sys/net/netmap/netmap_vale.c
sys/net/pf/if_pfsync.c
sys/net/pf/pf_if.c
sys/net/pf/pf_ioctl.c
sys/net/rtsock.c
sys/net/vlan/if_vlan.c
sys/netgraph/ether/ng_ether.c
sys/netgraph/fec/ng_fec.c
sys/netgraph7/ng_source.c
sys/netinet/ip_icmp.c
sys/netinet/ip_output.c
sys/netinet/raw_ip.c
sys/netinet6/icmp6.c
sys/netinet6/in6.c
sys/netinet6/in6_ifattach.c
sys/netinet6/nd6.c
sys/netinet6/raw_ip6.c
sys/netproto/802_11/wlan/ieee80211_dragonfly.c
sys/platform/pc64/x86_64/autoconf.c
sys/sys/thread.h
sys/vfs/nfs/bootp_subr.c

index c3b7fb9..d4080d1 100644 (file)
@@ -650,8 +650,8 @@ linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
            "bytes    packets errs drop fifo frame compressed",
            "bytes    packets errs drop fifo frame compressed");
 
-       crit_enter();
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                linux_ifname(ifp, ifname, sizeof ifname);
                sbuf_printf(sb, "%6.6s:", ifname);
                sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
@@ -659,7 +659,7 @@ linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
                    0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
        }
-       crit_exit();
+       ifnet_unlock();
        sbuf_finish(sb);
        error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
        sbuf_delete(sb);
index cd66610..bd4878a 100644 (file)
@@ -939,7 +939,7 @@ linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
 
        /* Determine the (relative) unit number for ethernet interfaces */
        ethno = 0;
-       TAILQ_FOREACH(ifscan, &ifnet, if_link) {
+       TAILQ_FOREACH(ifscan, &ifnetlist, if_link) {
                if (ifscan == ifp)
                        return (ksnprintf(buffer, buflen, "eth%d", ethno));
                if (IFP_IS_ETH(ifscan))
@@ -974,7 +974,7 @@ ifname_linux_to_bsd(const char *lxname, char *bsdname)
                return (NULL);
        index = 0;
        is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                /*
                 * Allow Linux programs to use FreeBSD names. Don't presume
                 * we never have an interface named "eth", so don't make
@@ -1015,7 +1015,8 @@ linux_ioctl_SIOCGIFCONF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        ethno = 0;
 
        /* Return all AF_INET addresses of all interfaces */
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                struct ifaddr_container *ifac;
 
                if (uio.uio_resid <= 0)
@@ -1043,11 +1044,14 @@ linux_ioctl_SIOCGIFCONF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
 
                                error = uiomove((caddr_t)&ifr, sizeof ifr,
                                    &uio);
-                               if (error != 0)
+                               if (error != 0) {
+                                       ifnet_unlock();
                                        return (error);
+                               }
                        }
                }
        }
+       ifnet_unlock();
 
        ifc->ifc_len -= uio.uio_resid;
 
@@ -1072,11 +1076,17 @@ linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        }
 #endif
 
+       ifnet_lock();
+
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return (EINVAL);
-
+       }
        flags = ifp->if_flags;
+
+       ifnet_unlock();
+
        /* these flags have no Linux equivalent */
        flags &= ~(IFF_SMART|IFF_SIMPLEX| IFF_LINK0|IFF_LINK1|IFF_LINK2);
        /* Linux' multicast flag is in a different bit */
@@ -1101,15 +1111,20 @@ linux_ioctl_SIOCGIFINDEX(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        char ifname[IFNAMSIZ];
        l_int index;
 
+       ifnet_lock();
+
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return EINVAL;
-
+       }
 #if DEBUG
        kprintf("Interface index: %d\n", ifp->if_index);
 #endif
-
        index = ifp->if_index;
+
+       ifnet_unlock();
+
        return (copyout(&index, &ifr->ifr_ifindex, sizeof(index)));
 }
 
@@ -1121,11 +1136,17 @@ linux_ioctl_SIOCGIFMETRIC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data
        char ifname[IFNAMSIZ];
        l_int metric;
 
+       ifnet_lock();
+
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return EINVAL;
-
+       }
        metric = ifp->if_metric;
+
+       ifnet_unlock();
+
        return (copyout(&metric, &ifr->ifr_ifmetric, sizeof(metric)));
 }
 
@@ -1139,19 +1160,25 @@ linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
        struct l_sockaddr lsa;
        struct ifaddr_container *ifac;
 
+       ifnet_lock();
+
        ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
        if (ifp == NULL) {
+               ifnet_unlock();
                return EINVAL;
        }
 
        if (ifp->if_type == IFT_LOOP) {
+               ifnet_unlock();
                bzero(&ifr->ifr_hwaddr, sizeof lsa);
                ifr->ifr_hwaddr.sa_family = ARPHRD_LOOPBACK;
                return (0);
        }
        
-       if (ifp->if_type != IFT_ETHER)
+       if (ifp->if_type != IFT_ETHER) {
+               ifnet_unlock();
                return (ENOENT);
+       }
 
        TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
                struct ifaddr *ifa = ifac->ifa;
@@ -1162,10 +1189,12 @@ linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data,
                        bzero(&ifr->ifr_hwaddr, sizeof lsa);
                        ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;
                        bcopy(LLADDR(sdl), ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN);
+                       ifnet_unlock();
                        return (0);
                }
        }
-       
+
+       ifnet_unlock();
        return (ENOENT);
 }
 
@@ -1199,12 +1228,15 @@ linux_ioctl_map_ifname(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, s
        kprintf("%s(): ioctl %d on %.*s\n", __func__,
                (int)(cmd & 0xffff), LINUX_IFNAMSIZ, lifname);
 #endif
+       ifnet_lock();
        /* Replace linux ifname with bsd ifname */
        ifp = ifname_linux_to_bsd(lifname, oifname);
        if (ifp == NULL) {
                error = EINVAL;
+               ifnet_unlock():
                goto clean_ifname;
        }
+       ifnet_unlock():
 
 #ifdef DEBUG
        kprintf("%s(): %s translated to %s\n", __func__,
index af1e3d7..6ab4c97 100644 (file)
@@ -136,7 +136,6 @@ struct lwkt_token kvm_token = LWKT_TOKEN_INITIALIZER(kvm_token);
 struct lwkt_token sigio_token = LWKT_TOKEN_INITIALIZER(sigio_token);
 struct lwkt_token tty_token = LWKT_TOKEN_INITIALIZER(tty_token);
 struct lwkt_token vnode_token = LWKT_TOKEN_INITIALIZER(vnode_token);
-struct lwkt_token ifnet_token = LWKT_TOKEN_INITIALIZER(ifnet_token);
 
 static int lwkt_token_spin = 5;
 SYSCTL_INT(_lwkt, OID_AUTO, token_spin, CTLFLAG_RW,
index e2f6227..14be535 100644 (file)
@@ -230,10 +230,16 @@ cbq_add_altq(struct pf_altq *a)
        cbq_state_t     *cbqp;
        struct ifnet    *ifp;
 
-       if ((ifp = ifunit(a->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(a->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
-       if (!ifq_is_ready(&ifp->if_snd))
+       }
+       if (!ifq_is_ready(&ifp->if_snd)) {
+               ifnet_unlock();
                return (ENODEV);
+       }
 
        /* allocate and initialize cbq_state_t */
        cbqp = kmalloc(sizeof(*cbqp), M_ALTQ, M_WAITOK | M_ZERO);
@@ -242,6 +248,8 @@ cbq_add_altq(struct pf_altq *a)
        cbqp->ifnp.ifq_ = &ifp->if_snd;     /* keep the ifq */
        ifq_purge_all(&ifp->if_snd);
 
+       ifnet_unlock();
+
        /* keep the state in pf_altq */
        a->altq_disc = cbqp;
 
@@ -461,15 +469,20 @@ cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
        if (*nbytes < sizeof(stats))
                return (EINVAL);
 
+       ifnet_lock();
+
        /* XXX not MP safe */
-       if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
+       if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL) {
+               ifnet_unlock();
                return (EBADF);
+       }
        ifq = cbqp->ifnp.ifq_;
 
        CBQ_LOCK(ifq);
 
        if ((cl = clh_to_clp(cbqp, a->qid)) == NULL) {
                CBQ_UNLOCK(ifq);
+               ifnet_unlock();
                return (EINVAL);
        }
 
@@ -477,6 +490,8 @@ cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
 
        CBQ_UNLOCK(ifq);
 
+       ifnet_unlock();
+
        if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
                return (error);
        *nbytes = sizeof(stats);
index c0aeee7..3d37f20 100644 (file)
@@ -158,10 +158,16 @@ fairq_add_altq(struct pf_altq *a)
        struct fairq_if *pif;
        struct ifnet *ifp;
 
-       if ((ifp = ifunit(a->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(a->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
-       if (!ifq_is_ready(&ifp->if_snd))
+       }
+       if (!ifq_is_ready(&ifp->if_snd)) {
+               ifnet_unlock();
                return (ENODEV);
+       }
 
        pif = kmalloc(sizeof(*pif), M_ALTQ, M_WAITOK | M_ZERO);
        pif->pif_bandwidth = a->ifbandwidth;
@@ -169,6 +175,8 @@ fairq_add_altq(struct pf_altq *a)
        pif->pif_ifq = &ifp->if_snd;
        ifq_purge_all(&ifp->if_snd);
 
+       ifnet_unlock();
+
        /* keep the state in pf_altq */
        a->altq_disc = pif;
 
@@ -278,15 +286,20 @@ fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
        if (*nbytes < sizeof(stats))
                return (EINVAL);
 
+       ifnet_lock();
+
        /* XXX not MP safe */
-       if ((pif = altq_lookup(a->ifname, ALTQT_FAIRQ)) == NULL)
+       if ((pif = altq_lookup(a->ifname, ALTQT_FAIRQ)) == NULL) {
+               ifnet_unlock();
                return (EBADF);
+       }
        ifq = pif->pif_ifq;
 
        FAIRQ_LOCK(ifq);
 
        if ((cl = clh_to_clp(pif, a->qid)) == NULL) {
                FAIRQ_UNLOCK(ifq);
+               ifnet_unlock();
                return (EINVAL);
        }
 
@@ -294,6 +307,8 @@ fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
 
        FAIRQ_UNLOCK(ifq);
 
+       ifnet_unlock();
+
        if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
                return (error);
        *nbytes = sizeof(stats);
index 8261798..7b84751 100644 (file)
@@ -156,10 +156,16 @@ hfsc_add_altq(struct pf_altq *a)
        struct hfsc_if *hif;
        struct ifnet *ifp;
 
-       if ((ifp = ifunit(a->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(a->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
-       if (!ifq_is_ready(&ifp->if_snd))
+       }
+       if (!ifq_is_ready(&ifp->if_snd)) {
+               ifnet_unlock();
                return (ENODEV);
+       }
 
        hif = kmalloc(sizeof(struct hfsc_if), M_ALTQ, M_WAITOK | M_ZERO);
 
@@ -167,6 +173,8 @@ hfsc_add_altq(struct pf_altq *a)
        hif->hif_ifq = &ifp->if_snd;
        ifq_purge_all(&ifp->if_snd);
 
+       ifnet_unlock();
+
        /* keep the state in pf_altq */
        a->altq_disc = hif;
 
@@ -293,15 +301,20 @@ hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
        if (*nbytes < sizeof(stats))
                return (EINVAL);
 
+       ifnet_lock();
+
        /* XXX not MP safe */
-       if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL)
+       if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL) {
+               ifnet_unlock();
                return (EBADF);
+       }
        ifq = hif->hif_ifq;
 
        HFSC_LOCK(ifq);
 
        if ((cl = clh_to_clp(hif, a->qid)) == NULL) {
                HFSC_UNLOCK(ifq);
+               ifnet_unlock();
                return (EINVAL);
        }
 
@@ -309,6 +322,8 @@ hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
 
        HFSC_UNLOCK(ifq);
 
+       ifnet_unlock();
+
        if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
                return (error);
        *nbytes = sizeof(stats);
index d2b586d..a81a963 100644 (file)
@@ -97,10 +97,16 @@ priq_add_altq(struct pf_altq *a)
        struct priq_if *pif;
        struct ifnet *ifp;
 
-       if ((ifp = ifunit(a->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(a->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
-       if (!ifq_is_ready(&ifp->if_snd))
+       }
+       if (!ifq_is_ready(&ifp->if_snd)) {
+               ifnet_unlock();
                return (ENODEV);
+       }
 
        pif = kmalloc(sizeof(*pif), M_ALTQ, M_WAITOK | M_ZERO);
        pif->pif_bandwidth = a->ifbandwidth;
@@ -108,6 +114,8 @@ priq_add_altq(struct pf_altq *a)
        pif->pif_ifq = &ifp->if_snd;
        ifq_purge_all(&ifp->if_snd);
 
+       ifnet_unlock();
+
        /* keep the state in pf_altq */
        a->altq_disc = pif;
 
@@ -217,15 +225,20 @@ priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
        if (*nbytes < sizeof(stats))
                return (EINVAL);
 
+       ifnet_lock();
+
        /* XXX not MP safe */
-       if ((pif = altq_lookup(a->ifname, ALTQT_PRIQ)) == NULL)
+       if ((pif = altq_lookup(a->ifname, ALTQT_PRIQ)) == NULL) {
+               ifnet_unlock();
                return (EBADF);
+       }
        ifq = pif->pif_ifq;
 
        PRIQ_LOCK(ifq);
 
        if ((cl = clh_to_clp(pif, a->qid)) == NULL) {
                PRIQ_UNLOCK(ifq);
+               ifnet_unlock();
                return (EINVAL);
        }
 
@@ -233,6 +246,8 @@ priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
 
        PRIQ_UNLOCK(ifq);
 
+       ifnet_unlock();
+
        if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
                return (error);
        *nbytes = sizeof(stats);
index aee0360..4d80c76 100644 (file)
@@ -349,8 +349,8 @@ tbr_timeout(void *arg __unused)
 static void
 tbr_timeout_dispatch(netmsg_t nmsg)
 {
-       struct ifnet *ifp;
-       int active;
+       const struct ifnet_array *arr;
+       int active, i;
 
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
@@ -360,7 +360,9 @@ tbr_timeout_dispatch(netmsg_t nmsg)
        crit_exit();
 
        active = 0;
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaltq_subque *ifsq;
 
                if (ifp->if_snd.altq_tbr == NULL)
@@ -416,9 +418,13 @@ altq_pfattach(struct pf_altq *a)
        if (a->altq_disc == NULL)
                return EINVAL;
 
+       ifnet_lock();
+
        ifp = ifunit(a->ifname);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return EINVAL;
+       }
        ifq = &ifp->if_snd;
 
        ifq_lock_all(ifq);
@@ -464,6 +470,7 @@ altq_pfattach(struct pf_altq *a)
        }
 back:
        ifq_unlock_all(ifq);
+       ifnet_unlock();
        return (error);
 }
 
@@ -479,14 +486,20 @@ altq_pfdetach(struct pf_altq *a)
        struct ifaltq *ifq;
        int error = 0;
 
+       ifnet_lock();
+
        ifp = ifunit(a->ifname);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return (EINVAL);
+       }
        ifq = &ifp->if_snd;
 
        /* if this discipline is no longer referenced, just return */
-       if (a->altq_disc == NULL)
+       if (a->altq_disc == NULL) {
+               ifnet_unlock();
                return (0);
+       }
 
        ifq_lock_all(ifq);
 
@@ -500,6 +513,7 @@ altq_pfdetach(struct pf_altq *a)
 
 back:
        ifq_unlock_all(ifq);
+       ifnet_unlock();
        return (error);
 }
 
index 23d4957..33dbaba 100644 (file)
@@ -1028,9 +1028,13 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
        int error;
        struct ifnet *theywant;
 
+       ifnet_lock();
+
        theywant = ifunit(ifr->ifr_name);
-       if (theywant == NULL)
+       if (theywant == NULL) {
+               ifnet_unlock();
                return(ENXIO);
+       }
 
        /*
         * Look through attached interfaces for the named one.
@@ -1051,8 +1055,10 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
                 */
                if (d->bd_sbuf == NULL) {
                        error = bpf_allocbufs(d);
-                       if (error != 0)
+                       if (error != 0) {
+                               ifnet_unlock();
                                return(error);
+                       }
                }
                if (bp != d->bd_bif) {
                        if (d->bd_bif != NULL) {
@@ -1065,9 +1071,13 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
                        bpf_attachd(d, bp);
                }
                bpf_resetd(d);
+
+               ifnet_unlock();
                return(0);
        }
 
+       ifnet_unlock();
+
        /* Not found. */
        return(ENXIO);
 }
index ab314ba..41dce2c 100644 (file)
@@ -1158,7 +1158,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
        bifp = sc->sc_ifp;
        ASSERT_IFNET_SERIALIZED_ALL(bifp);
 
-       ifs = ifunit(req->ifbr_ifsname);
+       ifs = ifunit_netisr(req->ifbr_ifsname);
        if (ifs == NULL)
                return (ENOENT);
 
@@ -1734,7 +1734,7 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
        struct ifnet *ifs;
        struct bridge_ifinfo *bif_info;
 
-       ifs = ifunit(req->ifbr_ifsname);
+       ifs = ifunit_netisr(req->ifbr_ifsname);
        if (ifs == NULL)
                return (ENOENT);
 
@@ -1781,7 +1781,7 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
        struct bridge_iflist *bif;
        struct ifnet *ifs;
 
-       ifs = ifunit(req->ifbr_ifsname);
+       ifs = ifunit_netisr(req->ifbr_ifsname);
        if (ifs == NULL)
                return (ENOENT);
 
index 209e8f4..3c07853 100644 (file)
@@ -118,6 +118,12 @@ static void        if_slowtimo_dispatch(netmsg_t);
 /* Helper functions */
 static void    ifsq_watchdog_reset(struct ifsubq_watchdog *);
 static int     if_delmulti_serialized(struct ifnet *, struct sockaddr *);
+static struct ifnet_array *ifnet_array_alloc(int);
+static void    ifnet_array_free(struct ifnet_array *);
+static struct ifnet_array *ifnet_array_add(struct ifnet *,
+                   const struct ifnet_array *);
+static struct ifnet_array *ifnet_array_del(struct ifnet *,
+                   const struct ifnet_array *);
 
 #ifdef INET6
 /*
@@ -153,12 +159,16 @@ MALLOC_DEFINE(M_IFNET, "ifnet", "interface structure");
 int                    ifqmaxlen = IFQ_MAXLEN;
 struct ifnethead       ifnet = TAILQ_HEAD_INITIALIZER(ifnet);
 
+static struct ifnet_array      ifnet_array0;
+static struct ifnet_array      *ifnet_array = &ifnet_array0;
+
 static struct callout          if_slowtimo_timer;
 static struct netmsg_base      if_slowtimo_netmsg;
 
 int                    if_index = 0;
 struct ifnet           **ifindex2ifnet = NULL;
 static struct thread   ifnet_threads[MAXCPU];
+static struct mtx      ifnet_mtx = MTX_INITIALIZER;
 
 static struct ifsubq_stage_head        ifsubq_stage_heads[MAXCPU];
 
@@ -210,14 +220,15 @@ ifinit(void *dummy)
        netmsg_init(&if_slowtimo_netmsg, NULL, &netisr_adone_rport,
            MSGF_PRIORITY, if_slowtimo_dispatch);
 
-       crit_enter();
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       /* XXX is this necessary? */
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                if (ifp->if_snd.altq_maxlen == 0) {
                        if_printf(ifp, "XXX: driver didn't set altq_maxlen\n");
                        ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
                }
        }
-       crit_exit();
+       ifnet_unlock();
 
        /* Start if_slowtimo */
        lwkt_sendmsg(netisr_cpuport(0), &if_slowtimo_netmsg.lmsg);
@@ -456,9 +467,11 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
 {
        unsigned socksize, ifasize;
        int namelen, masklen;
-       struct sockaddr_dl *sdl;
+       struct sockaddr_dl *sdl, *sdl_addr;
        struct ifaddr *ifa;
        struct ifaltq *ifq;
+       struct ifnet **old_ifindex2ifnet = NULL;
+       struct ifnet_array *old_ifnet_array;
        int i, q;
 
        static int if_indexlim = 8;
@@ -505,10 +518,6 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        }
 
        mtx_init(&ifp->if_ioctl_mtx);
-       mtx_lock(&ifp->if_ioctl_mtx);
-
-       lwkt_gettoken(&ifnet_token);    /* protect if_index and ifnet tailq */
-       ifp->if_index = ++if_index;
 
        /*
         * XXX -
@@ -525,23 +534,6 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        TAILQ_INIT(&ifp->if_multiaddrs);
        TAILQ_INIT(&ifp->if_groups);
        getmicrotime(&ifp->if_lastchange);
-       if (ifindex2ifnet == NULL || if_index >= if_indexlim) {
-               unsigned int n;
-               struct ifnet **q;
-
-               if_indexlim <<= 1;
-
-               /* grow ifindex2ifnet */
-               n = if_indexlim * sizeof(*q);
-               q = kmalloc(n, M_IFADDR, M_WAITOK | M_ZERO);
-               if (ifindex2ifnet) {
-                       bcopy(ifindex2ifnet, q, n/2);
-                       kfree(ifindex2ifnet, M_IFADDR);
-               }
-               ifindex2ifnet = q;
-       }
-
-       ifindex2ifnet[if_index] = ifp;
 
        /*
         * create a Link Level name for this device
@@ -554,12 +546,11 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        socksize = RT_ROUNDUP(socksize);
        ifasize = sizeof(struct ifaddr) + 2 * socksize;
        ifa = ifa_create(ifasize, M_WAITOK);
-       sdl = (struct sockaddr_dl *)(ifa + 1);
+       sdl = sdl_addr = (struct sockaddr_dl *)(ifa + 1);
        sdl->sdl_len = socksize;
        sdl->sdl_family = AF_LINK;
        bcopy(ifp->if_xname, sdl->sdl_data, namelen);
        sdl->sdl_nlen = namelen;
-       sdl->sdl_index = ifp->if_index;
        sdl->sdl_type = ifp->if_type;
        ifp->if_lladdr = ifa;
        ifa->ifa_ifp = ifp;
@@ -631,18 +622,78 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        }
        ifq_set_classic(ifq);
 
+       /*
+        * Install this ifp into ifindex2inet, ifnet queue and ifnet
+        * array after it is setup.
+        *
+        * Protect ifindex2ifnet, ifnet queue and ifnet array changes
+        * by ifnet lock, so that non-netisr threads could get a
+        * consistent view.
+        */
+       ifnet_lock();
+
+       /* Don't update if_index until ifindex2ifnet is setup */
+       ifp->if_index = if_index + 1;
+       sdl_addr->sdl_index = ifp->if_index;
+
+       /*
+        * Install this ifp into ifindex2ifnet
+        */
+       if (ifindex2ifnet == NULL || ifp->if_index >= if_indexlim) {
+               unsigned int n;
+               struct ifnet **q;
+
+               /*
+                * Grow ifindex2ifnet
+                */
+               if_indexlim <<= 1;
+               n = if_indexlim * sizeof(*q);
+               q = kmalloc(n, M_IFADDR, M_WAITOK | M_ZERO);
+               if (ifindex2ifnet != NULL) {
+                       bcopy(ifindex2ifnet, q, n/2);
+                       /* Free old ifindex2ifnet after sync all netisrs */
+                       old_ifindex2ifnet = ifindex2ifnet;
+               }
+               ifindex2ifnet = q;
+       }
+       ifindex2ifnet[ifp->if_index] = ifp;
+       /*
+        * Update if_index after this ifp is installed into ifindex2ifnet,
+        * so that netisrs could get a consistent view of ifindex2ifnet.
+        */
+       cpu_sfence();
+       if_index = ifp->if_index;
+
+       /*
+        * Install this ifp into ifnet array.
+        */
+       /* Free old ifnet array after sync all netisrs */
+       old_ifnet_array = ifnet_array;
+       ifnet_array = ifnet_array_add(ifp, old_ifnet_array);
+
+       /*
+        * Install this ifp into ifnet queue.
+        */
+       TAILQ_INSERT_TAIL(&ifnetlist, ifp, if_link);
+
+       ifnet_unlock();
+
+       /*
+        * Sync all netisrs so that the old ifindex2ifnet and ifnet array
+        * are no longer accessed and we can free them safely later on.
+        */
+       netmsg_service_sync();
+       if (old_ifindex2ifnet != NULL)
+               kfree(old_ifindex2ifnet, M_IFADDR);
+       ifnet_array_free(old_ifnet_array);
+
        if (!SLIST_EMPTY(&domains))
                if_attachdomain1(ifp);
 
-       TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
-       lwkt_reltoken(&ifnet_token);
-
        /* Announce the interface. */
        EVENTHANDLER_INVOKE(ifnet_attach_event, ifp);
        devctl_notify("IFNET", ifp->if_xname, "ATTACH", NULL);
        rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
-
-       mtx_unlock(&ifp->if_ioctl_mtx);
 }
 
 static void
@@ -650,10 +701,10 @@ if_attachdomain(void *dummy)
 {
        struct ifnet *ifp;
 
-       crit_enter();
-       TAILQ_FOREACH(ifp, &ifnet, if_list)
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_list)
                if_attachdomain1(ifp);
-       crit_exit();
+       ifnet_unlock();
 }
 SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST,
        if_attachdomain, NULL);
@@ -796,11 +847,53 @@ if_rtdel_dispatch(netmsg_t msg)
 void
 if_detach(struct ifnet *ifp)
 {
+       struct ifnet_array *old_ifnet_array;
        struct netmsg_if_rtdel msg;
        struct domain *dp;
        int q;
 
+       /* Announce that the interface is gone. */
        EVENTHANDLER_INVOKE(ifnet_detach_event, ifp);
+       rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
+       devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
+
+       /*
+        * Remove this ifp from ifindex2inet, ifnet queue and ifnet
+        * array before it is whacked.
+        *
+        * Protect ifindex2ifnet, ifnet queue and ifnet array changes
+        * by ifnet lock, so that non-netisr threads could get a
+        * consistent view.
+        */
+       ifnet_lock();
+
+       /*
+        * Remove this ifp from ifindex2ifnet and maybe decrement if_index.
+        */
+       ifindex2ifnet[ifp->if_index] = NULL;
+       while (if_index > 0 && ifindex2ifnet[if_index] == NULL)
+               if_index--;
+
+       /*
+        * Remove this ifp from ifnet queue.
+        */
+       TAILQ_REMOVE(&ifnetlist, ifp, if_link);
+
+       /*
+        * Remove this ifp from ifnet array.
+        */
+       /* Free old ifnet array after sync all netisrs */
+       old_ifnet_array = ifnet_array;
+       ifnet_array = ifnet_array_del(ifp, old_ifnet_array);
+
+       ifnet_unlock();
+
+       /*
+        * Sync all netisrs so that the old ifnet array is no longer
+        * accessed and we can free it safely later on.
+        */
+       netmsg_service_sync();
+       ifnet_array_free(old_ifnet_array);
 
        /*
         * Remove routes and flush queues.
@@ -863,25 +956,11 @@ if_detach(struct ifnet *ifp)
        msg.ifp = ifp;
        rt_domsg_global(&msg.base);
 
-       /* Announce that the interface is gone. */
-       rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
-       devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
-
        SLIST_FOREACH(dp, &domains, dom_next)
                if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
                        (*dp->dom_ifdetach)(ifp,
                                ifp->if_afdata[dp->dom_family]);
 
-       /*
-        * Remove interface from ifindex2ifp[] and maybe decrement if_index.
-        */
-       lwkt_gettoken(&ifnet_token);
-       ifindex2ifnet[ifp->if_index] = NULL;
-       while (if_index > 0 && ifindex2ifnet[if_index] == NULL)
-               if_index--;
-       TAILQ_REMOVE(&ifnet, ifp, if_link);
-       lwkt_reltoken(&ifnet_token);
-
        kfree(ifp->if_addrheads, M_IFADDR);
 
        lwkt_synchronize_ipiqs("if_detach");
@@ -1143,9 +1222,12 @@ if_rtdel(struct radix_node *rn, void *arg)
 struct ifaddr *
 ifa_ifwithaddr(struct sockaddr *addr)
 {
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
+       int i;
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaddr_container *ifac;
 
                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
@@ -1171,9 +1253,12 @@ ifa_ifwithaddr(struct sockaddr *addr)
 struct ifaddr *
 ifa_ifwithdstaddr(struct sockaddr *addr)
 {
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
+       int i;
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaddr_container *ifac;
 
                if (!(ifp->if_flags & IFF_POINTOPOINT))
@@ -1199,10 +1284,11 @@ ifa_ifwithdstaddr(struct sockaddr *addr)
 struct ifaddr *
 ifa_ifwithnet(struct sockaddr *addr)
 {
-       struct ifnet *ifp;
        struct ifaddr *ifa_maybe = NULL;
        u_int af = addr->sa_family;
        char *addr_data = addr->sa_data, *cplim;
+       const struct ifnet_array *arr;
+       int i;
 
        /*
         * AF_LINK addresses can be looked up directly by their index number,
@@ -1219,7 +1305,9 @@ ifa_ifwithnet(struct sockaddr *addr)
         * Scan though each interface, looking for ones that have
         * addresses in this address family.
         */
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaddr_container *ifac;
 
                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
@@ -1456,7 +1544,8 @@ static void
 if_slowtimo_dispatch(netmsg_t nmsg)
 {
        struct globaldata *gd = mycpu;
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
+       int i;
 
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
@@ -1465,7 +1554,10 @@ if_slowtimo_dispatch(netmsg_t nmsg)
        lwkt_replymsg(&nmsg->lmsg, 0);  /* reply ASAP */
        crit_exit_gd(gd);
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                crit_enter_gd(gd);
 
                if (if_stats_compat) {
@@ -1526,41 +1618,34 @@ ifunit(const char *name)
        /*
         * Search all the interfaces for this name/number
         */
+       KASSERT(mtx_owned(&ifnet_mtx), ("ifnet is not locked"));
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                if (strncmp(ifp->if_xname, name, IFNAMSIZ) == 0)
                        break;
        }
        return (ifp);
 }
 
-
-/*
- * Map interface name in a sockaddr_dl to
- * interface structure pointer.
- */
 struct ifnet *
-if_withname(struct sockaddr *sa)
+ifunit_netisr(const char *name)
 {
-       char ifname[IFNAMSIZ+1];
-       struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
-
-       if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
-            (sdl->sdl_nlen > IFNAMSIZ) )
-               return NULL;
+       const struct ifnet_array *arr;
+       int i;
 
        /*
-        * ifunit wants a null-terminated name.  It may not be null-terminated
-        * in the sockaddr.  We don't want to change the caller's sockaddr,
-        * and there might not be room to put the trailing null anyway, so we
-        * make a local copy that we know we can null terminate safely.
+        * Search all the interfaces for this name/number
         */
 
-       bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
-       ifname[sdl->sdl_nlen] = '\0';
-       return ifunit(ifname);
-}
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
 
+               if (strncmp(ifp->if_xname, name, IFNAMSIZ) == 0)
+                       return ifp;
+       }
+       return NULL;
+}
 
 /*
  * Interface ioctls.
@@ -1613,11 +1698,14 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
         * Nominal ioctl through interface, lookup the ifp and obtain a
         * lock to serialize the ifconfig ioctl operation.
         */
+       ifnet_lock();
+
        ifp = ifunit(ifr->ifr_name);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return (ENXIO);
+       }
        error = 0;
-       mtx_lock(&ifp->if_ioctl_mtx);
 
        switch (cmd) {
        case SIOCGIFINDEX:
@@ -1984,7 +2072,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
                break;
        }
 
-       mtx_unlock(&ifp->if_ioctl_mtx);
+       ifnet_unlock();
        return (error);
 }
 
@@ -2054,7 +2142,9 @@ ifconf(u_long cmd, caddr_t data, struct ucred *cred)
        int space = ifc->ifc_len, error = 0;
 
        ifrp = ifc->ifc_req;
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                struct ifaddr_container *ifac;
                int addrs;
 
@@ -2125,6 +2215,8 @@ ifconf(u_long cmd, caddr_t data, struct ucred *cred)
                        ifrp++;
                }
        }
+       ifnet_unlock();
+
        ifc->ifc_len -= space;
        return (error);
 }
@@ -2474,7 +2566,8 @@ if_getanyethermac(uint16_t *node, int minlen)
        struct ifnet *ifp;
        struct sockaddr_dl *sdl;
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                if (ifp->if_type != IFT_ETHER)
                        continue;
                sdl = IF_LLSOCKADDR(ifp);
@@ -2482,8 +2575,10 @@ if_getanyethermac(uint16_t *node, int minlen)
                        continue;
                bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, node,
                      minlen);
+               ifnet_unlock();
                return(0);
        }
+       ifnet_unlock();
        return (ENOENT);
 }
 
@@ -3275,3 +3370,119 @@ ifsq_watchdog_stop(struct ifsubq_watchdog *wd)
        wd->wd_timer = 0;
        callout_stop(&wd->wd_callout);
 }
+
+void
+ifnet_lock(void)
+{
+       KASSERT(curthread->td_type != TD_TYPE_NETISR,
+           ("try holding ifnet lock in netisr"));
+       mtx_lock(&ifnet_mtx);
+}
+
+void
+ifnet_unlock(void)
+{
+       KASSERT(curthread->td_type != TD_TYPE_NETISR,
+           ("try holding ifnet lock in netisr"));
+       mtx_unlock(&ifnet_mtx);
+}
+
+static struct ifnet_array *
+ifnet_array_alloc(int count)
+{
+       struct ifnet_array *arr;
+
+       arr = kmalloc(__offsetof(struct ifnet_array, ifnet_arr[count]),
+           M_IFNET, M_WAITOK);
+       arr->ifnet_count = count;
+
+       return arr;
+}
+
+static void
+ifnet_array_free(struct ifnet_array *arr)
+{
+       if (arr == &ifnet_array0)
+               return;
+       kfree(arr, M_IFNET);
+}
+
+static struct ifnet_array *
+ifnet_array_add(struct ifnet *ifp, const struct ifnet_array *old_arr)
+{
+       struct ifnet_array *arr;
+       int count, i;
+
+       KASSERT(old_arr->ifnet_count >= 0,
+           ("invalid ifnet array count %d", old_arr->ifnet_count));
+       count = old_arr->ifnet_count + 1;
+       arr = ifnet_array_alloc(count);
+
+       /*
+        * Save the old ifnet array and append this ifp to the end of
+        * the new ifnet array.
+        */
+       for (i = 0; i < old_arr->ifnet_count; ++i) {
+               KASSERT(old_arr->ifnet_arr[i] != ifp,
+                   ("%s is already in ifnet array", ifp->if_xname));
+               arr->ifnet_arr[i] = old_arr->ifnet_arr[i];
+       }
+       KASSERT(i == count - 1,
+           ("add %s, ifnet array index mismatch, should be %d, but got %d",
+            ifp->if_xname, count - 1, i));
+       arr->ifnet_arr[i] = ifp;
+
+       return arr;
+}
+
+static struct ifnet_array *
+ifnet_array_del(struct ifnet *ifp, const struct ifnet_array *old_arr)
+{
+       struct ifnet_array *arr;
+       int count, i, idx, found = 0;
+
+       KASSERT(old_arr->ifnet_count > 0,
+           ("invalid ifnet array count %d", old_arr->ifnet_count));
+       count = old_arr->ifnet_count - 1;
+       arr = ifnet_array_alloc(count);
+
+       /*
+        * Save the old ifnet array, but skip this ifp.
+        */
+       idx = 0;
+       for (i = 0; i < old_arr->ifnet_count; ++i) {
+               if (old_arr->ifnet_arr[i] == ifp) {
+                       KASSERT(!found,
+                           ("dup %s is in ifnet array", ifp->if_xname));
+                       found = 1;
+                       continue;
+               }
+               KASSERT(idx < count,
+                   ("invalid ifnet array index %d, count %d", idx, count));
+               arr->ifnet_arr[idx] = old_arr->ifnet_arr[i];
+               ++idx;
+       }
+       KASSERT(found, ("%s is not in ifnet array", ifp->if_xname));
+       KASSERT(idx == count,
+           ("del %s, ifnet array count mismatch, should be %d, but got %d ",
+            ifp->if_xname, count, idx));
+
+       return arr;
+}
+
+const struct ifnet_array *
+ifnet_array_get(void)
+{
+       KASSERT(curthread->td_type == TD_TYPE_NETISR, ("not in netisr"));
+       return ifnet_array;
+}
+
+int
+ifnet_array_isempty(void)
+{
+       KASSERT(curthread->td_type == TD_TYPE_NETISR, ("not in netisr"));
+       if (ifnet_array->ifnet_count == 0)
+               return 1;
+       else
+               return 0;
+}
index e3d0b94..a76dc57 100644 (file)
@@ -61,8 +61,12 @@ if_clone_create(char *name, int len, caddr_t params)
        if (ifc == NULL)
                return (EINVAL);
 
-       if (ifunit(name) != NULL)
+       ifnet_lock();
+       if (ifunit(name) != NULL) {
+               ifnet_unlock();
                return (EEXIST);
+       }
+       ifnet_unlock();
 
        bytoff = bitoff = 0;
        wildcard = (unit < 0);
@@ -137,16 +141,26 @@ if_clone_destroy(const char *name)
        if (unit < ifc->ifc_minifs)
                return (EINVAL);
 
+       ifnet_lock();
+
        ifp = ifunit(name);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return (ENXIO);
+       }
 
-       if (ifc->ifc_destroy == NULL)
+       if (ifc->ifc_destroy == NULL) {
+               ifnet_unlock();
                return (EOPNOTSUPP);
+       }
 
        error = ifc->ifc_destroy(ifp);
-       if (error)
+       if (error) {
+               ifnet_unlock();
                return error;
+       }
+
+       ifnet_unlock();
 
        /*
         * Compute offset in the bitmap and deallocate the unit.
index b093634..736bf61 100644 (file)
@@ -80,18 +80,23 @@ sysctl_ifdata(SYSCTL_HANDLER_ARGS) /* XXX bad syntax! */
        if (namelen != 2)
                return EINVAL;
 
-       crit_enter();
+       /*
+        * Hold the ifnet lock while we are accessing the ifp
+        * obtained through ifindex2ifnet.
+        */
+       ifnet_lock();
+
        if (name[0] <= 0 || name[0] > if_index ||
            ifindex2ifnet[name[0]] == NULL) {
-               crit_exit();
+               ifnet_unlock();
                return ENOENT;
        }
 
        ifp = ifindex2ifnet[name[0]];
-       crit_exit();
 
        switch(name[1]) {
        default:
+               ifnet_unlock();
                return ENOENT;
 
        case IFDATA_GENERAL:
@@ -124,12 +129,16 @@ sysctl_ifdata(SYSCTL_HANDLER_ARGS) /* XXX bad syntax! */
 #endif
 
                error = SYSCTL_OUT(req, &ifmd, sizeof ifmd);
-               if (error || !req->newptr)
+               if (error || !req->newptr) {
+                       ifnet_unlock();
                        return error;
+               }
 
                error = SYSCTL_IN(req, &ifmd, sizeof ifmd);
-               if (error)
+               if (error) {
+                       ifnet_unlock();
                        return error;
+               }
 
 #define DONTCOPY(fld) ifmd.ifmd_data.ifi_##fld = ifp->if_data.ifi_##fld
                DONTCOPY(type);
@@ -165,14 +174,19 @@ sysctl_ifdata(SYSCTL_HANDLER_ARGS) /* XXX bad syntax! */
 
        case IFDATA_LINKSPECIFIC:
                error = SYSCTL_OUT(req, ifp->if_linkmib, ifp->if_linkmiblen);
-               if (error || !req->newptr)
+               if (error || !req->newptr) {
+                       ifnet_unlock();
                        return error;
+               }
 
                error = SYSCTL_IN(req, ifp->if_linkmib, ifp->if_linkmiblen);
-               if (error)
+               if (error) {
+                       ifnet_unlock();
                        return error;
-               
+               }
        }
+
+       ifnet_unlock();
        return 0;
 }
 
index 9bc9e71..aeebc5d 100644 (file)
@@ -707,6 +707,13 @@ EVENTHANDLER_DECLARE(ifnet_attach_event, ifnet_attach_event_handler_t);
 typedef void (*ifnet_detach_event_handler_t)(void *, struct ifnet *);
 EVENTHANDLER_DECLARE(ifnet_detach_event, ifnet_detach_event_handler_t);
 
+/* Array of all ifnets in the system */
+struct ifnet_array {
+       int             ifnet_count;    /* # of elem. in ifnet_arr */
+       int             ifnet_pad;      /* explicit */
+       struct ifnet    *ifnet_arr[];
+};
+
 /*
  * interface groups
  */
@@ -862,11 +869,44 @@ ifnet_serialize_array_assert(lwkt_serialize_t *_arr, int _arrcnt,
 #define REINPUT_KEEPRCVIF      0x0001  /* ether_reinput_oncpu() */
 #define REINPUT_RUNBPF                 0x0002  /* ether_reinput_oncpu() */
 
-extern struct ifnethead ifnet;
-extern struct  ifnet   **ifindex2ifnet;
+/*
+ * MPSAFE NOTE for ifnet queue (ifnet), ifnet array, ifunit() and
+ * ifindex2ifnet.
+ *
+ * - ifnet queue must only be accessed by non-netisr threads and
+ *   ifnet lock must be held (by ifnet_lock()).
+ * - If accessing ifnet queue is needed in netisrs, ifnet array
+ *   (obtained through ifnet_array_get()) must be used instead.
+ *   There is no need to (must not, actually) hold ifnet lock for
+ *   ifnet array accessing.
+ * - ifindex2ifnet could be accessed by both non-netisr threads and
+ *   netisrs.  Accessing ifindex2ifnet in non-netisr threads must be
+ *   protected by ifnet lock (by ifnet_lock()).  Accessing
+ *   ifindex2ifnet in netisrs is lockless MPSAFE and ifnet lock must
+ *   not be held.  However, ifindex2ifnet should be saved in a stack
+ *   variable to get a consistent view of ifindex2ifnet, if
+ *   ifindex2ifnet is accessed multiple times from a function in
+ *   netisrs.
+ * - ifunit() must only be called in non-netisr threads and ifnet
+ *   lock must be held before calling this function and for the
+ *   accessing of the ifp returned by this function.
+ * - If ifunit() is needed in netisr, ifunit_netisr() must be used
+ *   instead.  There is no need to (must not, actually) hold ifnet
+ *   lock for ifunit_netisr() and the returned ifp.
+ */
+extern struct ifnethead        ifnet;
+#define ifnetlist      ifnet   /* easily distinguished ifnet alias */
+
+extern struct ifnet    **ifindex2ifnet;
+extern int             if_index;
+
+struct ifnet           *ifunit(const char *);
+struct ifnet           *ifunit_netisr(const char *);
+const struct ifnet_array *ifnet_array_get(void);
+int                    ifnet_array_isempty(void);
+
 extern int ifqmaxlen;
 extern struct ifnet loif[];
-extern int if_index;
 
 struct ip;
 struct tcphdr;
@@ -912,8 +952,6 @@ void        if_up(struct ifnet *);
 /*void ifinit(void);*/ /* declared in systm.h for main() */
 int    ifioctl(struct socket *, u_long, caddr_t, struct ucred *);
 int    ifpromisc(struct ifnet *, int);
-struct ifnet *ifunit(const char *);
-struct ifnet *if_withname(struct sockaddr *);
 
 struct ifg_group *if_creategroup(const char *);
 int     if_addgroup(struct ifnet *, const char *);
@@ -943,6 +981,9 @@ void        if_devstart(struct ifnet *ifp); /* COMPAT */
 void   if_devstart_sched(struct ifnet *ifp); /* COMPAT */
 int    if_ring_count2(int cnt, int cnt_max);
 
+void   ifnet_lock(void);
+void   ifnet_unlock(void);
+
 #define IF_LLSOCKADDR(ifp)                                             \
     ((struct sockaddr_dl *)(ifp)->if_lladdr->ifa_addr)
 #define IF_LLADDR(ifp) LLADDR(IF_LLSOCKADDR(ifp))
index c7f20c5..5fb022c 100644 (file)
@@ -819,6 +819,8 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
        struct lagg_port *lp = NULL;
        int error = 0;
 
+       ASSERT_IFNET_SERIALIZED_ALL(ifp);
+
        /* Should be checked by the caller */
        if (ifp->if_type != IFT_IEEE8023ADLAG ||
            (lp = ifp->if_lagg) == NULL || (sc = lp->lp_softc) == NULL)
@@ -826,12 +828,26 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
 
        switch (cmd) {
        case SIOCGLAGGPORT:
-               if (rp->rp_portname[0] == '\0' ||
-                   ifunit(rp->rp_portname) != ifp) {
+               if (rp->rp_portname[0] == '\0') {
                        error = EINVAL;
                        break;
                }
 
+               /*
+                * Release ifp serializers before ifnet_lock
+                * to prevent lock order reversal.
+                */
+               ifnet_deserialize_all(ifp);
+               ifnet_lock();
+               if (ifunit(rp->rp_portname) != ifp) {
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
+                       error = EINVAL;
+                       break;
+               }
+               ifnet_unlock();
+               ifnet_serialize_all(ifp);
+
                LAGG_RLOCK(sc);
                if ((lp = ifp->if_lagg) == NULL || lp->lp_softc != sc) {
                        error = ENOENT;
@@ -1125,8 +1141,16 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                LAGG_WUNLOCK(sc);
                break;
        case SIOCGLAGGPORT:
+               /*
+                * Release ifp serializers before ifnet_lock
+                * to prevent lock order reversal.
+                */
+               ifnet_deserialize_all(ifp);
+               ifnet_lock();
                if (rp->rp_portname[0] == '\0' ||
                    (tpif = ifunit(rp->rp_portname)) == NULL) {
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
                        error = EINVAL;
                        break;
                }
@@ -1136,31 +1160,53 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                    lp->lp_softc != sc) {
                        error = ENOENT;
                        LAGG_RUNLOCK(sc);
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
                        break;
                }
 
                lagg_port2req(lp, rp);
                LAGG_RUNLOCK(sc);
+               ifnet_unlock();
+               ifnet_serialize_all(ifp);
                break;
        case SIOCSLAGGPORT:
                error = priv_check(td, PRIV_NET_LAGG);
                if (error)
                        break;
+               /*
+                * Release ifp serializers before ifnet_lock
+                * to prevent lock order reversal.
+                */
+               ifnet_deserialize_all(ifp);
+               ifnet_lock();
                if (rp->rp_portname[0] == '\0' ||
                    (tpif = ifunit(rp->rp_portname)) == NULL) {
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
                        error = EINVAL;
                        break;
                }
                LAGG_WLOCK(sc);
                error = lagg_port_create(sc, tpif);
                LAGG_WUNLOCK(sc);
+               ifnet_unlock();
+               ifnet_serialize_all(ifp);
                break;
        case SIOCSLAGGDELPORT:
                error = priv_check(td, PRIV_NET_LAGG);
                if (error)
                        break;
+               /*
+                * Release ifp serializers before ifnet_lock
+                * to prevent lock order reversal.
+                */
+               ifnet_deserialize_all(ifp);
+               ifnet_lock();
                if (rp->rp_portname[0] == '\0' ||
                    (tpif = ifunit(rp->rp_portname)) == NULL) {
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
                        error = EINVAL;
                        break;
                }
@@ -1170,11 +1216,15 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                    lp->lp_softc != sc) {
                        error = ENOENT;
                        LAGG_WUNLOCK(sc);
+                       ifnet_unlock();
+                       ifnet_serialize_all(ifp);
                        break;
                }
 
                error = lagg_port_destroy(lp, 1);
                LAGG_WUNLOCK(sc);
+               ifnet_unlock();
+               ifnet_serialize_all(ifp);
                break;
        case SIOCSIFFLAGS:
                /* Set flags on ports too */
index 65a80b8..2b956fc 100644 (file)
@@ -1062,9 +1062,12 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
        if (error || *na != NULL) /* valid match in netmap_get_bdg_na() */
                return error;
 
+       ifnet_lock();
+
        ifp = ifunit(nmr->nr_name);
        if (ifp == NULL) {
-               return ENXIO;
+               error = ENXIO;
+               goto out;
        }
 
        error = netmap_get_hw_na(ifp, &ret);
@@ -1082,10 +1085,7 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
                netmap_adapter_get(ret);
        }
 out:
-#if 0
-       if_rele(ifp);
-#endif
-
+       ifnet_unlock();
        return error;
 }
 
index 6a070e7..0345879 100644 (file)
@@ -569,6 +569,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
         * try see if there is a matching NIC with this name
         * (after the bridge's name)
         */
+       ifnet_lock();
        ifp = ifunit(name + b->bdg_namelen + 1);
        if (!ifp) { /* this is a virtual port */
                /* Create a temporary NA with arguments, then
@@ -577,6 +578,8 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
                 */
                struct netmap_adapter tmp_na;
 
+               ifnet_unlock();
+
                if (nmr->nr_cmd) {
                        /* nr_cmd must be 0 for a virtual port */
                        return EINVAL;
@@ -643,9 +646,8 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
                ret = NA(fake_ifp);
                if (nmr->nr_arg1 != NETMAP_BDG_HOST)
                        cand2 = -1; /* only need one port */
-#if 0
-               if_rele(ifp);
-#endif
+
+               ifnet_unlock();
        }
        vpna = (struct netmap_vp_adapter *)ret;
 
@@ -672,10 +674,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
        return 0;
 
 out:
-#if 0
-       if_rele(ifp);
-#endif
-
+       ifnet_unlock();
        return error;
 }
 
index 1f44198..aaad1c4 100644 (file)
@@ -1106,7 +1106,16 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
                        break;
                }
 
-               if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
+               /*
+                * XXX not that MPSAFE; pfsync needs serious rework
+                */
+               ifnet_deserialize_all(ifp);
+               ifnet_lock();
+               sifp = ifunit(pfsyncr.pfsyncr_syncdev);
+               ifnet_unlock();
+               ifnet_serialize_all(ifp);
+
+               if (sifp == NULL) {
                        lwkt_reltoken(&pf_token);
                        return (EINVAL);
                }
index 294cea8..a7c0a43 100644 (file)
@@ -113,10 +113,13 @@ pfi_initialize(void)
        if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL)
                panic("pfi_kif_get for pfi_all failed");
 
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       /* XXX ALMOST MPSAFE */
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                if (ifp->if_dunit != IF_DUNIT_NONE)
                        pfi_attach_ifnet(ifp);
        }
+       ifnet_unlock();
        pfi_attach_cookie = EVENTHANDLER_REGISTER(ifnet_attach_event,
            pfi_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
        pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_detach_event,
@@ -139,12 +142,15 @@ pfi_cleanup(void)
        EVENTHANDLER_DEREGISTER(if_clone_event, pfi_clone_cookie);
 
        /* release PFI_IFLAG_INSTANCE */
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       /* XXX ALMOST MPSAFE */
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                strlcpy(key.pfik_name, ifp->if_xname, sizeof(key.pfik_name));
                p = RB_FIND(pfi_ifhead, &pfi_ifs, &key);
                if (p != NULL)
                        pfi_detach_ifnet(ifp);
        }
+       ifnet_unlock();
 
        /* XXX clear all other interface group */
        while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) {
index 64d4acd..ccfbd26 100644 (file)
@@ -660,8 +660,12 @@ pf_enable_altq(struct pf_altq *altq)
        struct tb_profile        tb;
        int                      error = 0;
 
-       if ((ifp = ifunit(altq->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(altq->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
+       }
 
        if (ifp->if_snd.altq_type != ALTQT_NONE)
                error = altq_enable(&ifp->if_snd);
@@ -675,6 +679,7 @@ pf_enable_altq(struct pf_altq *altq)
                crit_exit();
        }
 
+       ifnet_unlock();
        return (error);
 }
 
@@ -685,15 +690,21 @@ pf_disable_altq(struct pf_altq *altq)
        struct tb_profile        tb;
        int                      error;
 
-       if ((ifp = ifunit(altq->ifname)) == NULL)
+       ifnet_lock();
+
+       if ((ifp = ifunit(altq->ifname)) == NULL) {
+               ifnet_unlock();
                return (EINVAL);
+       }
 
        /*
         * when the discipline is no longer referenced, it was overridden
         * by a new one.  if so, just return.
         */
-       if (altq->altq_disc != ifp->if_snd.altq_disc)
+       if (altq->altq_disc != ifp->if_snd.altq_disc) {
+               ifnet_unlock();
                return (0);
+       }
 
        error = altq_disable(&ifp->if_snd);
 
@@ -705,6 +716,7 @@ pf_disable_altq(struct pf_altq *altq)
                crit_exit();
        }
 
+       ifnet_unlock();
        return (error);
 }
 #endif /* ALTQ */
@@ -1904,11 +1916,13 @@ pfioctl(struct dev_ioctl_args *ap)
                if (psp->ifname[0] != 0) {
                        /* Can we completely trust user-land? */
                        strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
+                       ifnet_lock();
                        ifp = ifunit(ps.ifname);
                        if (ifp )
                                psp->baudrate = ifp->if_baudrate;
                        else
                                error = EINVAL;
+                       ifnet_unlock();
                } else
                        error = EINVAL;
                break;
index 3b925be..e92d60b 100644 (file)
@@ -1302,7 +1302,9 @@ sysctl_iflist(int af, struct walkarg *w)
        int msglen, error;
 
        bzero(&rtinfo, sizeof(struct rt_addrinfo));
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                struct ifaddr_container *ifac;
                struct ifaddr *ifa;
 
@@ -1312,8 +1314,10 @@ sysctl_iflist(int af, struct walkarg *w)
                ifa = ifac->ifa;
                rtinfo.rti_ifpaddr = ifa->ifa_addr;
                msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
-               if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
+               if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) {
+                       ifnet_unlock();
                        return (ENOMEM);
+               }
                rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen);
                rtinfo.rti_ifpaddr = NULL;
                if (w->w_req != NULL && w->w_tmem != NULL) {
@@ -1325,8 +1329,10 @@ sysctl_iflist(int af, struct walkarg *w)
                        ifm->ifm_data = ifp->if_data;
                        ifm->ifm_addrs = rtinfo.rti_addrs;
                        error = SYSCTL_OUT(w->w_req, ifm, msglen);
-                       if (error)
+                       if (error) {
+                               ifnet_unlock();
                                return (error);
+                       }
                }
                while ((ifac = TAILQ_NEXT(ifac, ifa_link)) != NULL) {
                        ifa = ifac->ifa;
@@ -1341,8 +1347,10 @@ sysctl_iflist(int af, struct walkarg *w)
                        rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
                        msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
                        if (w->w_tmemsize < msglen &&
-                           resizewalkarg(w, msglen) != 0)
+                           resizewalkarg(w, msglen) != 0) {
+                               ifnet_unlock();
                                return (ENOMEM);
+                       }
                        rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen);
                        if (w->w_req != NULL) {
                                struct ifa_msghdr *ifam = w->w_tmem;
@@ -1352,14 +1360,17 @@ sysctl_iflist(int af, struct walkarg *w)
                                ifam->ifam_metric = ifa->ifa_metric;
                                ifam->ifam_addrs = rtinfo.rti_addrs;
                                error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
-                               if (error)
+                               if (error) {
+                                       ifnet_unlock();
                                        return (error);
+                               }
                        }
                }
                rtinfo.rti_netmask = NULL;
                rtinfo.rti_ifaaddr = NULL;
                rtinfo.rti_bcastaddr = NULL;
        }
+       ifnet_unlock();
        return (0);
 }
 
index 75d164c..a7e75a9 100644 (file)
@@ -686,7 +686,7 @@ vlan_config_dispatch(netmsg_t msg)
 
        /* Assert in netisr0 */
 
-       ifp_p = ifunit(vmsg->nv_parent_name);
+       ifp_p = ifunit_netisr(vmsg->nv_parent_name);
        if (ifp_p == NULL) {
                error = ENOENT;
                goto reply;
index 418340f..7cbea71 100644 (file)
@@ -696,11 +696,13 @@ ng_ether_mod_event(module_t mod, int event, void *data)
                ng_ether_input_orphan_p = ng_ether_input_orphan;
 
                /* Create nodes for any already-existing Ethernet interfaces */
-               TAILQ_FOREACH(ifp, &ifnet, if_link) {
+               ifnet_lock();
+               TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                        if (ifp->if_type == IFT_ETHER ||
                            ifp->if_type == IFT_L2VLAN)
                                ng_ether_attach(ifp);
                }
+               ifnet_unlock();
                break;
 
        case MOD_UNLOAD:
index c7eeb59..5160437 100644 (file)
@@ -339,9 +339,12 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
        b = &priv->fec_bundle;
        ifp = &priv->arpcom.ac_if;
 
+       ifnet_lock();
+
        /* Find the interface */
        bifp = ifunit(iface);
        if (bifp == NULL) {
+               ifnet_unlock();
                kprintf("fec%d: tried to add iface %s, which "
                    "doesn't seem to exist\n", priv->unit, iface);
                return(ENOENT);
@@ -349,6 +352,7 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
 
        /* See if we have room in the bundle */
        if (b->fec_ifcnt == FEC_BUNDLESIZ) {
+               ifnet_unlock();
                kprintf("fec%d: can't add new iface; bundle is full\n",
                    priv->unit);
                return(ENOSPC);
@@ -357,6 +361,7 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
        /* See if the interface is already in the bundle */
        TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) {
                if (p->fec_if == bifp) {
+                       ifnet_unlock();
                        kprintf("fec%d: iface %s is already in this "
                            "bundle\n", priv->unit, iface);
                        return(EINVAL);
@@ -365,8 +370,10 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
 
        /* Allocate new list entry. */
        new = kmalloc(sizeof(struct ng_fec_portlist), M_NETGRAPH, M_NOWAIT);
-       if (new == NULL)
+       if (new == NULL) {
+               ifnet_unlock();
                return(ENOMEM);
+       }
 
        ac = (struct arpcom *)bifp;
        ac->ac_netgraph = priv->node;
@@ -401,6 +408,8 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
        new->fec_if = bifp;
        TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list);
 
+       ifnet_unlock();
+
        return(0);
 }
 
@@ -418,9 +427,12 @@ ng_fec_delport(struct ng_fec_private *priv, char *iface)
 
        b = &priv->fec_bundle;
 
+       ifnet_lock();
+
        /* Find the interface */
        bifp = ifunit(iface);
        if (bifp == NULL) {
+               ifnet_unlock();
                kprintf("fec%d: tried to remove iface %s, which "
                    "doesn't seem to exist\n", priv->unit, iface);
                return(ENOENT);
@@ -432,6 +444,7 @@ ng_fec_delport(struct ng_fec_private *priv, char *iface)
        }
 
        if (p == NULL) {
+               ifnet_unlock();
                kprintf("fec%d: tried to remove iface %s which "
                    "is not in our bundle\n", priv->unit, iface);
                return(EINVAL);
@@ -452,6 +465,8 @@ ng_fec_delport(struct ng_fec_private *priv, char *iface)
        kfree(p, M_NETGRAPH);
        b->fec_ifcnt--;
 
+       ifnet_unlock();
+
        return(0);
 }
 
index 0af2a64..a5fa195 100644 (file)
@@ -611,9 +611,12 @@ ng_source_store_output_ifp(sc_p sc, char *ifname)
        struct ifnet *ifp;
        int s;
 
+       ifnet_lock();
+
        ifp = ifunit(ifname);
 
        if (ifp == NULL) {
+               ifnet_unlock();
                kprintf("%s: can't find interface %d\n", __func__, if_index);
                return (EINVAL);
        }
@@ -633,6 +636,7 @@ ng_source_store_output_ifp(sc_p sc, char *ifname)
        }
        splx(s);
 #endif
+       ifnet_unlock();
        return (0);
 }
 
index 275b518..35bba5f 100644 (file)
@@ -1027,7 +1027,8 @@ icmp_reflect(struct mbuf *m)
         * net.inet.icmp.reply_src (default not set). Otherwise continue
         * with normal source selection.
         */
-       if (icmp_reply_src[0] != '\0' && (ifp = ifunit(icmp_reply_src))) {
+       if (icmp_reply_src[0] != '\0' &&
+           (ifp = ifunit_netisr(icmp_reply_src))) {
                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
                        struct ifaddr *ifa = ifac->ifa;
 
index cac869e..e01bd93 100644 (file)
@@ -147,7 +147,7 @@ ip_localforward(struct mbuf *m, const struct sockaddr_in *dst, int hlen)
                struct ip *ip;
 
                if (m->m_pkthdr.rcvif == NULL)
-                       m->m_pkthdr.rcvif = ifunit("lo0");
+                       m->m_pkthdr.rcvif = ifunit_netisr("lo0");
                if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
                        m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
                                                  CSUM_PSEUDO_HDR;
index a6d964c..c6de373 100644 (file)
@@ -666,7 +666,7 @@ rip_bind(netmsg_t msg)
            ("not in netisr0"));
 
        if (nam->sa_len == sizeof(*addr)) {
-               if (TAILQ_EMPTY(&ifnet) ||
+               if (ifnet_array_isempty() ||
                    ((addr->sin_family != AF_INET) &&
                     (addr->sin_family != AF_IMPLINK)) ||
                    (addr->sin_addr.s_addr != INADDR_ANY &&
@@ -696,7 +696,7 @@ rip_connect(netmsg_t msg)
 
        if (nam->sa_len != sizeof(*addr)) {
                error = EINVAL;
-       } else if (TAILQ_EMPTY(&ifnet)) {
+       } else if (ifnet_array_isempty()) {
                error = EADDRNOTAVAIL;
        } else {
                if ((addr->sin_family != AF_INET) &&
index ee68e27..a7c3573 100644 (file)
@@ -1567,11 +1567,12 @@ static int
 ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
          char *subj)
 {
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
        struct in6_ifaddr *ifa6;
        struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
        int addrs = 0, addrsofif, iffound = 0;
        int niflags = ni6->ni_flags;
+       int i;
 
        if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
                switch (ni6->ni_code) {
@@ -1589,8 +1590,9 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
                }
        }
 
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
-       {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaddr_container *ifac;
 
                addrsofif = 0;
@@ -1663,21 +1665,31 @@ static int
 ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
                struct ifnet *ifp0, int resid)
 {
-       struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
+       const struct ifnet_array *arr;
        struct in6_ifaddr *ifa6;
-       struct ifnet *ifp_dep = NULL;
        int copied = 0, allow_deprecated = 0;
        u_char *cp = (u_char *)(nni6 + 1);
        int niflags = ni6->ni_flags;
        u_int32_t ltime;
+       int idx, idx_dep = -1;
 
        if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
                return (0);     /* needless to copy */
 
+       arr = ifnet_array_get();
+       if (ifp0 == NULL) {
+               idx = 0;
+       } else {
+               for (idx = 0; idx < arr->ifnet_count; ++idx) {
+                       if (arr->ifnet_arr[idx] == ifp0)
+                               break;
+               }
+       }
+
 again:
 
-       for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
-       {
+       for (; idx < arr->ifnet_count; ++idx) {
+               struct ifnet *ifp = arr->ifnet_arr[idx];
                struct ifaddr_container *ifac;
 
                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
@@ -1695,8 +1707,8 @@ again:
                                 */
 
                                /* record the interface for later search */
-                               if (ifp_dep == NULL)
-                                       ifp_dep = ifp;
+                               if (idx_dep < 0)
+                                       idx_dep = idx;
 
                                continue;
                        }
@@ -1790,8 +1802,8 @@ again:
                        break;
        }
 
-       if (allow_deprecated == 0 && ifp_dep != NULL) {
-               ifp = ifp_dep;
+       if (allow_deprecated == 0 && idx_dep >= 0) {
+               idx = idx_dep;
                allow_deprecated = 1;
 
                goto again;
index f110880..3447766 100644 (file)
@@ -2080,9 +2080,10 @@ in6_ifawithscope(struct ifnet *oifp, struct in6_addr *dst, struct ucred *cred)
 {
        int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
        int blen = -1;
-       struct ifnet *ifp;
        struct in6_ifaddr *ifa_best = NULL;
        int jailed = 0;
+       const struct ifnet_array *arr;
+       int i;
 
        if(cred && cred->cr_prison)
                jailed = 1;
@@ -2099,8 +2100,9 @@ in6_ifawithscope(struct ifnet *oifp, struct in6_addr *dst, struct ucred *cred)
         * Comparing an interface with the outgoing interface will be done
         * only at the final stage of tiebreaking.
         */
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
-       {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
                struct ifaddr_container *ifac;
 
                /*
@@ -2536,13 +2538,16 @@ void
 in6_setmaxmtu(void)
 {
        unsigned long maxmtu = 0;
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
+       int i;
 
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
 
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
-       {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                /* this function can be called during ifnet initialization */
                if (ifp->if_afdata[AF_INET6] == NULL)
                        continue;
index 3aa69c4..2ef1eae 100644 (file)
@@ -76,7 +76,7 @@ static struct netmsg_base in6_tmpaddrtimer_netmsg;
 
 extern struct inpcbinfo ripcbinfo;
 
-static int get_rand_ifid (struct ifnet *, struct in6_addr *);
+static int get_rand_ifid (struct in6_addr *);
 static int generate_tmp_ifid (u_int8_t *, const u_int8_t *, u_int8_t *);
 static int get_hw_ifid (struct ifnet *, struct in6_addr *);
 static int get_ifid (struct ifnet *, struct ifnet *, struct in6_addr *);
@@ -102,8 +102,7 @@ static int in6_ifattach_loopback (struct ifnet *);
  * We currently use MD5(hostname) for it.
  */
 static int
-get_rand_ifid(struct ifnet *ifp,
-             struct in6_addr *in6)     /* upper 64bits are preserved */
+get_rand_ifid(struct in6_addr *in6)    /* upper 64bits are preserved */
 {
        MD5_CTX ctxt;
        u_int8_t digest[16];
@@ -339,7 +338,8 @@ get_ifid(struct ifnet *ifp0,
         struct ifnet *altifp,  /* secondary EUI64 source */
         struct in6_addr *in6)
 {
-       struct ifnet *ifp;
+       const struct ifnet_array *arr;
+       int i;
 
        /* first, try to get it from the interface itself */
        if (get_hw_ifid(ifp0, in6) == 0) {
@@ -356,7 +356,10 @@ get_ifid(struct ifnet *ifp0,
        }
 
        /* next, try to get it from some other hardware interface */
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                if (ifp == ifp0)
                        continue;
                if (get_hw_ifid(ifp, in6) != 0)
@@ -375,7 +378,7 @@ get_ifid(struct ifnet *ifp0,
        }
 
        /* last resort: get from random number source */
-       if (get_rand_ifid(ifp, in6) == 0) {
+       if (get_rand_ifid(in6) == 0) {
                nd6log((LOG_DEBUG,
                    "%s: interface identifier generated by random number\n",
                    if_name(ifp0)));
@@ -640,10 +643,10 @@ static void
 in6_nigroup_attach_dispatch(netmsg_t msg)
 {
        struct netmsg_nigroup *nmsg = (struct netmsg_nigroup *)msg;
-       struct ifnet *ifp;
        struct sockaddr_in6 mltaddr;
        struct in6_multi *in6m;
-       int error;
+       const struct ifnet_array *arr;
+       int error, i;
 
        bzero(&mltaddr, sizeof(mltaddr));
        mltaddr.sin6_family = AF_INET6;
@@ -652,7 +655,10 @@ in6_nigroup_attach_dispatch(netmsg_t msg)
            &mltaddr.sin6_addr) != 0)
                goto done;
 
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                in6m = IN6_LOOKUP_MULTI(&mltaddr.sin6_addr, ifp);
                if (!in6m) {
@@ -684,9 +690,10 @@ static void
 in6_nigroup_detach_dispatch(netmsg_t msg)
 {
        struct netmsg_nigroup *nmsg = (struct netmsg_nigroup *)msg;
-       struct ifnet *ifp;
        struct sockaddr_in6 mltaddr;
        struct in6_multi *in6m;
+       const struct ifnet_array *arr;
+       int i;
 
        bzero(&mltaddr, sizeof(mltaddr));
        mltaddr.sin6_family = AF_INET6;
@@ -695,7 +702,10 @@ in6_nigroup_detach_dispatch(netmsg_t msg)
            &mltaddr.sin6_addr) != 0)
                goto done;
 
-       TAILQ_FOREACH(ifp, &ifnet, if_list) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                in6m = IN6_LOOKUP_MULTI(&mltaddr.sin6_addr, ifp);
                if (in6m)
@@ -929,9 +939,10 @@ in6_tmpaddrtimer(void *arg __unused)
 static void
 in6_tmpaddrtimer_dispatch(netmsg_t nmsg)
 {
+       const struct ifnet_array *arr;
        struct nd_ifinfo *ndi;
        u_int8_t nullbuf[8];
-       struct ifnet *ifp;
+       int i;
 
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
@@ -941,7 +952,10 @@ in6_tmpaddrtimer_dispatch(netmsg_t nmsg)
        crit_exit();
 
        bzero(nullbuf, sizeof(nullbuf));
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+       arr = ifnet_array_get();
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                if (ifp->if_afdata[AF_INET6] == NULL)
                        continue;
                ndi = ND_IFINFO(ifp);
index 29b7da0..42fd51c 100644 (file)
@@ -1822,8 +1822,9 @@ nd6_slowtimo(void *arg __unused)
 static void
 nd6_slowtimo_dispatch(netmsg_t nmsg)
 {
+       const struct ifnet_array *arr;
        struct nd_ifinfo *nd6if;
-       struct ifnet *ifp;
+       int i;
 
        KASSERT(&curthread->td_msgport == netisr_cpuport(0),
            ("not in netisr0"));
@@ -1832,8 +1833,12 @@ nd6_slowtimo_dispatch(netmsg_t nmsg)
        lwkt_replymsg(&nmsg->lmsg, 0);  /* reply ASAP */
        crit_exit();
 
+       arr = ifnet_array_get();
+
        mtx_lock(&nd6_mtx);
-       for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
+       for (i = 0; i < arr->ifnet_count; ++i) {
+               struct ifnet *ifp = arr->ifnet_arr[i];
+
                if (ifp->if_afdata[AF_INET6] == NULL)
                        continue;
                nd6if = ND_IFINFO(ifp);
index 68f5a7a..cc3b79a 100644 (file)
@@ -672,7 +672,7 @@ rip6_bind(netmsg_t msg)
                goto out;
        }
 
-       if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) {
+       if (ifnet_array_isempty() || addr->sin6_family != AF_INET6) {
                error = EADDRNOTAVAIL;
                goto out;
        }
@@ -720,7 +720,7 @@ rip6_connect(netmsg_t msg)
                error = EINVAL;
                goto out;
        }
-       if (TAILQ_EMPTY(&ifnet)) {
+       if (ifnet_array_isempty()) {
                error = EADDRNOTAVAIL;
                goto out;
        }
index 4204802..f8d3f70 100644 (file)
@@ -113,23 +113,31 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
        error = copyin(params, &cp, sizeof(cp));
        if (error)
                return error;
+
+       ifnet_lock();
+
        ifp = ifunit(cp.icp_parent);
-       if (ifp == NULL)
+       if (ifp == NULL) {
+               ifnet_unlock();
                return ENXIO;
+       }
        /* XXX move printfs to DIAGNOSTIC before release */
        if (ifp->if_type != IFT_IEEE80211) {
                if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__);
+               ifnet_unlock();
                return ENXIO;
        }
        if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
                if_printf(ifp, "%s: invalid opmode %d\n",
                    __func__, cp.icp_opmode);
+               ifnet_unlock();
                return EINVAL;
        }
        ic = ifp->if_l2com;
        if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
                if_printf(ifp, "%s mode not supported\n",
                    ieee80211_opmode_name[cp.icp_opmode]);
+               ifnet_unlock();
                return EOPNOTSUPP;
        }
        if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
@@ -140,12 +148,16 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
 #endif
        ) {
                if_printf(ifp, "TDMA not supported\n");
+               ifnet_unlock();
                return EOPNOTSUPP;
        }
        vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
                        cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
                        cp.icp_flags & IEEE80211_CLONE_MACADDR ?
                            cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp));
+
+       ifnet_unlock();
+
        return (vap == NULL ? EIO : 0);
 }
 
index a0ac8ba..f81cfc6 100644 (file)
@@ -436,7 +436,8 @@ pxe_setup_nfsdiskless(void)
                kprintf("PXE: no hardware address\n");
                return;
        }
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                struct ifaddr_container *ifac;
 
                TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
@@ -448,16 +449,20 @@ pxe_setup_nfsdiskless(void)
                                    (sdl->sdl_alen == ourdl.sdl_alen) &&
                                    !bcmp(sdl->sdl_data + sdl->sdl_nlen,
                                          ourdl.sdl_data + ourdl.sdl_nlen, 
-                                         sdl->sdl_alen))
-                                   goto match_done;
+                                         sdl->sdl_alen)) {
+                                       strlcpy(nd->myif.ifra_name,
+                                           ifp->if_xname,
+                                           sizeof(nd->myif.ifra_name));
+                                       ifnet_unlock();
+                                       goto match_done;
+                               }
                        }
                }
        }
+       ifnet_unlock();
        kprintf("PXE: no interface\n");
        return; /* no matching interface */
 match_done:
-       strlcpy(nd->myif.ifra_name, ifp->if_xname, sizeof(nd->myif.ifra_name));
-       
        /* set up gateway */
        inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
 
index f334062..3e5bcad 100644 (file)
@@ -427,7 +427,6 @@ extern struct lwkt_token kvm_token;
 extern struct lwkt_token sigio_token;
 extern struct lwkt_token tty_token;
 extern struct lwkt_token vnode_token;
-extern struct lwkt_token ifnet_token;
 
 /*
  * Procedures
index a4ed4ef..9ac8a23 100644 (file)
@@ -1545,7 +1545,9 @@ bootpc_init(void)
               __XSTRING(BOOTP_WIRED_TO));
 #endif
        bzero(&ifctx->ireq, sizeof(ifctx->ireq));
-       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+       /* XXX ALMOST MPSAFE */
+       ifnet_lock();
+       TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
                strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
                         sizeof(ifctx->ireq.ifr_name));
 #ifdef BOOTP_WIRED_TO
@@ -1566,6 +1568,7 @@ bootpc_init(void)
                gctx->lastinterface = ifctx;
                ifctx = allocifctx(gctx);
        }
+       ifnet_unlock();
        kfree(ifctx, M_TEMP);
        
        if (gctx->interfaces == NULL) {