commit 19ace17d438268c5fd8e1e29c720a99046dd8cc4 Author: Ryota Ozaki Date: Wed Apr 27 18:33:17 2016 +0900 psref ifnet diff --git a/sys/altq/altq_subr.c b/sys/altq/altq_subr.c index 138d29c..53dac93 100644 --- a/sys/altq/altq_subr.c +++ b/sys/altq/altq_subr.c @@ -355,15 +355,26 @@ tbr_timeout(void *arg) int active, s; active = 0; - s = splnet(); - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + struct psref psref; if (!TBR_IS_ENABLED(&ifp->if_snd)) continue; + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + active++; - if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL) + if (!IFQ_IS_EMPTY(&ifp->if_snd) && ifp->if_start != NULL) { + int _s = splnet(); (*ifp->if_start)(ifp); + splx(_s); + } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } - splx(s); + pserialize_read_exit(s); + if (active > 0) CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0); else diff --git a/sys/arch/x86/x86/vmt.c b/sys/arch/x86/x86/vmt.c index 27adba6..1a100c5 100644 --- a/sys/arch/x86/x86/vmt.c +++ b/sys/arch/x86/x86/vmt.c @@ -803,10 +803,12 @@ vmt_tclo_tick(void *xarg) } else if (strcmp(sc->sc_rpc_buf, "Set_Option broadcastIP 1") == 0) { struct ifnet *iface; struct sockaddr_in *guest_ip; + int s; /* find first available ipv4 address */ guest_ip = NULL; - IFNET_FOREACH(iface) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(iface) { struct ifaddr *iface_addr; /* skip loopback */ @@ -824,6 +826,7 @@ vmt_tclo_tick(void *xarg) break; } } + pserialize_read_exit(s); if (guest_ip != NULL) { if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s", diff --git a/sys/compat/common/uipc_syscalls_40.c b/sys/compat/common/uipc_syscalls_40.c index ee49603..954a3e0 100644 --- a/sys/compat/common/uipc_syscalls_40.c +++ b/sys/compat/common/uipc_syscalls_40.c @@ -39,23 +39,33 @@ compat_ifconf(u_long cmd, void *data) int space = 0, error = 0; const int sz = (int)sizeof(ifr); const bool docopy = ifc->ifc_req != NULL; + int s; + int bound = curlwp->l_pflag & LP_BOUND; + struct psref psref; if (docopy) { space = ifc->ifc_len; ifrp = ifc->ifc_req; } - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + (void)strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); - if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') - return ENAMETOOLONG; + if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { + error = ENAMETOOLONG; + goto release_exit; + } if (IFADDR_EMPTY(ifp)) { memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return (error); + goto release_exit; ifrp++; } space -= sizeof(ifr); @@ -103,14 +113,25 @@ compat_ifconf(u_long cmd, void *data) } } if (error != 0) - return (error); + goto release_exit; space -= sz; } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; + if (docopy) ifc->ifc_len -= space; else ifc->ifc_len = -space; return (0); + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } #endif diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c index 7b7e07d3..75e41eb 100644 --- a/sys/compat/linux/common/linux_socket.c +++ b/sys/compat/linux/common/linux_socket.c @@ -1118,6 +1118,9 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) int space = 0, error; const int sz = (int)sizeof(ifr); bool docopy; + int s; + int bound = curlwp->l_pflag & LP_BOUND; + struct psref psref; error = copyin(data, &ifc, sizeof(ifc)); if (error) @@ -1129,11 +1132,18 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) ifrp = ifc.ifc_req; } - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + (void)strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); - if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') - return ENAMETOOLONG; + if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { + error = ENAMETOOLONG; + goto release_exit; + } if (IFADDR_EMPTY(ifp)) continue; IFADDR_FOREACH(ifa, ifp) { @@ -1147,12 +1157,17 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return error; + goto release_exit; ifrp++; } space -= sz; } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; if (docopy) ifc.ifc_len -= space; @@ -1160,6 +1175,11 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) ifc.ifc_len = -space; return copyout(&ifc, data, sizeof(ifc)); + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } int @@ -1174,6 +1194,7 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, struct sockaddr_dl *sadl; int error, found; int index, ifnum; + int s; /* * We can't emulate this ioctl by calling sys_ioctl() to run @@ -1205,14 +1226,17 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, * Try real interface name first, then fake "ethX" */ found = 0; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (found) break; if (strcmp(lreq.ifr_name, ifp->if_xname)) /* not this interface */ continue; + found=1; if (IFADDR_EMPTY(ifp)) { + pserialize_read_exit(s); error = ENODEV; goto out; } @@ -1228,10 +1252,13 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); goto out; } } + pserialize_read_exit(s); if (strncmp(lreq.ifr_name, "eth", 3) != 0) { /* unknown interface, not even an "eth*" name */ @@ -1247,10 +1274,8 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, } error = EINVAL; /* in case we don't find one */ - found = 0; - IFNET_FOREACH(ifp) { - if (found) - break; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { memcpy(lreq.ifr_name, ifp->if_xname, MIN(LINUX_IFNAMSIZ, IFNAMSIZ)); IFADDR_FOREACH(ifa, ifp) { @@ -1269,11 +1294,13 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); - found = 1; - break; + goto out; } } + pserialize_read_exit(s); out: KERNEL_UNLOCK_ONE(NULL); diff --git a/sys/compat/linux32/common/linux32_socket.c b/sys/compat/linux32/common/linux32_socket.c index 24c88ca..237a12a 100644 --- a/sys/compat/linux32/common/linux32_socket.c +++ b/sys/compat/linux32/common/linux32_socket.c @@ -419,6 +419,9 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data) int space = 0, error; const int sz = (int)sizeof(ifr); bool docopy; + int s; + int bound = curlwp->l_pflag & LP_BOUND; + struct psref psref; error = copyin(data, &ifc, sizeof(ifc)); if (error) @@ -430,11 +433,18 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data) ifrp = NETBSD32PTR64(ifc.ifc_req); } - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + (void)strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); - if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') - return ENAMETOOLONG; + if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { + error = ENAMETOOLONG; + goto release_exit; + } if (IFADDR_EMPTY(ifp)) continue; IFADDR_FOREACH(ifa, ifp) { @@ -448,12 +458,17 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data) if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return error; + goto release_exit; ifrp++; } space -= sz; } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; if (docopy) ifc.ifc_len -= space; @@ -461,6 +476,11 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data) ifc.ifc_len = -space; return copyout(&ifc, data, sizeof(ifc)); + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } int @@ -474,6 +494,7 @@ linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, struct sockaddr_dl *sadl; int error, found; int index, ifnum; + int s; /* * We can't emulate this ioctl by calling sys_ioctl() to run @@ -505,7 +526,8 @@ linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, * Try real interface name first, then fake "ethX" */ found = 0; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (found) break; if (strcmp(lreq.ifr_name, ifp->if_xname)) @@ -528,10 +550,13 @@ linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); goto out; } } + pserialize_read_exit(s); if (strncmp(lreq.ifr_name, "eth", 3) == 0) { for (ifnum = 0, index = 3; @@ -542,10 +567,8 @@ linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, } error = EINVAL; /* in case we don't find one */ - found = 0; - IFNET_FOREACH(ifp) { - if (found) - break; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { memcpy(lreq.ifr_name, ifp->if_xname, MIN(LINUX32_IFNAMSIZ, IFNAMSIZ)); IFADDR_FOREACH(ifa, ifp) { @@ -564,11 +587,13 @@ linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); - found = 1; - break; + goto out; } } + pserialize_read_exit(s); } else { /* unknown interface, not even an "eth*" name */ error = ENODEV; diff --git a/sys/compat/svr4/svr4_sockio.c b/sys/compat/svr4/svr4_sockio.c index dde39d1..4c7ef5e 100644 --- a/sys/compat/svr4/svr4_sockio.c +++ b/sys/compat/svr4/svr4_sockio.c @@ -108,6 +108,7 @@ svr4_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, { struct ifnet *ifp; struct svr4_lifnum lifnum; + int s; error = copyin(data, &lifnum, sizeof(lifnum)); if (error) @@ -115,8 +116,10 @@ svr4_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, lifnum.lifn_count = 0; /* XXX: We don't pay attention to family or flags */ - IFNET_FOREACH(ifp) + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) lifnum.lifn_count += svr4_count_ifnum(ifp); + pserialize_read_exit(s); DPRINTF(("SIOCGLIFNUM [family=%d,flags=%d,count=%d]\n", lifnum.lifn_family, lifnum.lifn_flags, @@ -128,6 +131,7 @@ svr4_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, { struct ifnet *ifp; int ifnum = 0; + int s; /* * This does not return the number of physical @@ -141,8 +145,10 @@ svr4_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, * entry per physical interface? */ - IFNET_FOREACH(ifp) + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) ifnum += svr4_count_ifnum(ifp); + pserialize_read_exit(s); DPRINTF(("SIOCGIFNUM %d\n", ifnum)); return copyout(&ifnum, data, sizeof(ifnum)); diff --git a/sys/compat/svr4_32/svr4_32_sockio.c b/sys/compat/svr4_32/svr4_32_sockio.c index 4aa57ff..2422a7ba 100644 --- a/sys/compat/svr4_32/svr4_32_sockio.c +++ b/sys/compat/svr4_32/svr4_32_sockio.c @@ -96,6 +96,7 @@ svr4_32_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, int fd, u_long { struct ifnet *ifp; int ifnum = 0; + int s; /* * This does not return the number of physical @@ -109,8 +110,10 @@ svr4_32_sock_ioctl(file_t *fp, struct lwp *l, register_t *retval, int fd, u_long * entry per physical interface? */ - IFNET_FOREACH(ifp) + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) ifnum += svr4_count_ifnum(ifp) + pserialize_read_exit(s); DPRINTF(("SIOCGIFNUM %d\n", ifnum)); return copyout(&ifnum, data, sizeof(ifnum)); diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c index aba09bc..84b8bcd 100644 --- a/sys/dev/pci/if_bge.c +++ b/sys/dev/pci/if_bge.c @@ -1516,6 +1516,7 @@ bge_update_all_threshes(int lvl) struct ifnet *ifp; const char * const namebuf = "bge"; int namelen; + int s; if (lvl < 0) lvl = 0; @@ -1526,13 +1527,15 @@ bge_update_all_threshes(int lvl) /* * Now search all the interfaces for this name/number */ - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (strncmp(ifp->if_xname, namebuf, namelen) != 0) continue; /* We got a match: update if doing auto-threshold-tuning */ if (bge_auto_thresh) bge_set_thresh(ifp, lvl); } + pserialize_read_exit(s); } /* diff --git a/sys/dist/pf/net/pf_if.c b/sys/dist/pf/net/pf_if.c index 842e824..3041776 100644 --- a/sys/dist/pf/net/pf_if.c +++ b/sys/dist/pf/net/pf_if.c @@ -100,6 +100,9 @@ RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); void pfi_initialize(void) { + int s; + int bound = curlwp->l_pflag & LP_BOUND; + if (pfi_all != NULL) /* already initialized */ return; @@ -119,10 +122,21 @@ pfi_initialize(void) #ifdef __NetBSD__ ifnet_t *ifp; - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + struct psref psref; + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + pfi_init_groups(ifp); pfi_attach_ifnet(ifp); + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; pfil_add_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, if_pfil); pfil_add_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, if_pfil); @@ -135,14 +149,27 @@ pfi_destroy(void) { struct pfi_kif *p; ifnet_t *ifp; + int s; + int bound = curlwp->l_pflag & LP_BOUND; pfil_remove_hook(pfil_ifaddr_wrapper, NULL, PFIL_IFADDR, if_pfil); pfil_remove_hook(pfil_ifnet_wrapper, NULL, PFIL_IFNET, if_pfil); - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + struct psref psref; + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + pfi_detach_ifnet(ifp); pfi_destroy_groups(ifp); + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { RB_REMOVE(pfi_ifhead, &pfi_ifs, p); diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index 4e51f69..0e01bdb 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -224,7 +224,8 @@ setroot(device_t bootdv, int bootpartition) if (vops != NULL && strcmp(rootfstype, MOUNT_NFS) == 0 && rootspec == NULL && (bootdv == NULL || device_class(bootdv) != DV_IFNET)) { - IFNET_FOREACH(ifp) { + int s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) break; @@ -242,6 +243,7 @@ setroot(device_t bootdv, int bootpartition) */ rootspec = (const char *)ifp->if_xname; } + pserialize_read_exit(s); } if (vops != NULL) vfs_delref(vops); diff --git a/sys/kern/subr_tftproot.c b/sys/kern/subr_tftproot.c index d849511..014820a 100644 --- a/sys/kern/subr_tftproot.c +++ b/sys/kern/subr_tftproot.c @@ -131,16 +131,20 @@ tftproot_dhcpboot(device_t bootdv) int error = -1; if (rootspec != NULL) { - IFNET_FOREACH(ifp) + int s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) if (strcmp(rootspec, ifp->if_xname) == 0) break; + pserialize_read_exit(s); } if ((ifp == NULL) && (bootdv != NULL && device_class(bootdv) == DV_IFNET)) { - IFNET_FOREACH(ifp) + int s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) if (strcmp(device_xname(bootdv), ifp->if_xname) == 0) break; + pserialize_read_exit(s); } if (ifp == NULL) { diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 3c46ac4..1055d9d 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -556,9 +556,23 @@ m_reclaim(void *arg, int flags) if (pr->pr_drain) (*pr->pr_drain)(); } - IFNET_FOREACH(ifp) { - if (ifp->if_drain) - (*ifp->if_drain)(ifp); + /* XXX we cannot use psref in H/W interrupt */ + if (!cpu_intr_p()) { + int bound = curlwp->l_pflag & LP_BOUND; + curlwp->l_pflag |= LP_BOUND; + IFNET_READER_FOREACH(ifp) { + struct psref psref; + + psref_acquire(&psref, &ifp->if_psref, + ifnet_psref_class); + + if (ifp->if_drain) + (*ifp->if_drain)(ifp); + + psref_release(&psref, &ifp->if_psref, + ifnet_psref_class); + } + curlwp->l_pflag ^= bound ^ LP_BOUND; } splx(s); mbstat.m_drain++; diff --git a/sys/net/if.c b/sys/net/if.c index 517e131..4430b5f 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -161,13 +161,19 @@ MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); /* * Global list of interfaces. */ +/* DEPRECATED. Remove it once kvm(3) users disappeared */ struct ifnet_head ifnet_list; + +struct pslist_head ifnet_pslist; static ifnet_t ** ifindex2ifnet = NULL; - static u_int if_index = 1; static size_t if_indexlim = 0; static uint64_t index_gen; -static kmutex_t index_gen_mtx; +/* Mutex to protect the above objects. */ +kmutex_t ifnet_mtx __cacheline_aligned; +struct psref_class *ifnet_psref_class __read_mostly; +static pserialize_t ifnet_psz; + static kmutex_t if_clone_mtx; struct ifnet *lo0ifp; @@ -269,9 +275,12 @@ ifinit(void) void ifinit1(void) { - mutex_init(&index_gen_mtx, MUTEX_DEFAULT, IPL_NONE); mutex_init(&if_clone_mtx, MUTEX_DEFAULT, IPL_NONE); TAILQ_INIT(&ifnet_list); + mutex_init(&ifnet_mtx, MUTEX_DEFAULT, IPL_NONE); + ifnet_psz = pserialize_create(); + ifnet_psref_class = psref_class_create("ifnet", IPL_SOFTNET); + PSLIST_INIT(&ifnet_pslist); if_indexlim = 8; if_pfil = pfil_head_create(PFIL_TYPE_IFNET, NULL); @@ -525,9 +534,7 @@ if_getindex(ifnet_t *ifp) { bool hitlimit = false; - mutex_enter(&index_gen_mtx); ifp->if_index_gen = index_gen++; - mutex_exit(&index_gen_mtx); ifp->if_index = if_index; if (ifindex2ifnet == NULL) { @@ -644,7 +651,12 @@ if_initialize(ifnet_t *ifp) if (ifp->if_link_si == NULL) panic("%s: softint_establish() failed", __func__); + PSLIST_ENTRY_INIT(ifp, if_pslist_entry); + psref_target_init(&ifp->if_psref, ifnet_psref_class); + + IFNET_LOCK(); if_getindex(ifp); + IFNET_UNLOCK(); } /* @@ -675,7 +687,10 @@ if_register(ifnet_t *ifp) if (ifp->if_transmit == NULL || ifp->if_transmit == if_nulltransmit) ifp->if_transmit = if_transmit; + IFNET_LOCK(); TAILQ_INSERT_TAIL(&ifnet_list, ifp, if_list); + IFNET_WRITER_INSERT_HEAD(ifp); + IFNET_UNLOCK(); } /* @@ -929,11 +944,20 @@ if_attachdomain(void) { struct ifnet *ifp; int s; + int bound = curlwp->l_pflag & LP_BOUND; - s = splnet(); - IFNET_FOREACH(ifp) + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + struct psref psref; + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); if_attachdomain1(ifp); - splx(s); + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; } static void @@ -1022,8 +1046,18 @@ if_detach(struct ifnet *ifp) s = splnet(); + sysctl_teardown(&ifp->if_sysctl_log); + + IFNET_LOCK(); ifindex2ifnet[ifp->if_index] = NULL; TAILQ_REMOVE(&ifnet_list, ifp, if_list); + IFNET_WRITER_REMOVE(ifp); + pserialize_perform(ifnet_psz); + IFNET_UNLOCK(); + + /* Wait for all readers to drain before freeing. */ + psref_target_destroy(&ifp->if_psref, ifnet_psref_class); + PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry); if (ifp->if_slowtimo != NULL) { ifp->if_slowtimo = NULL; @@ -1047,8 +1081,6 @@ if_detach(struct ifnet *ifp) if (ifp->if_snd.ifq_lock) mutex_obj_free(ifp->if_snd.ifq_lock); - sysctl_teardown(&ifp->if_sysctl_log); - #if NCARP > 0 /* Remove the interface from any carp group it is a part of. */ if (ifp->if_carp != NULL && ifp->if_type != IFT_CARP) @@ -1456,8 +1488,10 @@ ifa_ifwithaddr(const struct sockaddr *addr) { struct ifnet *ifp; struct ifaddr *ifa; + int s; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; IFADDR_FOREACH(ifa, ifp) { @@ -1473,6 +1507,7 @@ ifa_ifwithaddr(const struct sockaddr *addr) return ifa; } } + pserialize_read_exit(s); return NULL; } @@ -1485,8 +1520,10 @@ ifa_ifwithdstaddr(const struct sockaddr *addr) { struct ifnet *ifp; struct ifaddr *ifa; + int s; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; if ((ifp->if_flags & IFF_POINTOPOINT) == 0) @@ -1499,6 +1536,7 @@ ifa_ifwithdstaddr(const struct sockaddr *addr) return ifa; } } + pserialize_read_exit(s); return NULL; } @@ -1515,6 +1553,7 @@ ifa_ifwithnet(const struct sockaddr *addr) struct ifaddr *ifa_maybe = 0; u_int af = addr->sa_family; const char *addr_data = addr->sa_data, *cplim; + int s; if (af == AF_LINK) { sdl = satocsdl(addr); @@ -1528,7 +1567,8 @@ ifa_ifwithnet(const struct sockaddr *addr) if (af == AF_APPLETALK) { const struct sockaddr_at *sat, *sat2; sat = (const struct sockaddr_at *)addr; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; ifa = at_ifawithnet((const struct sockaddr_at *)addr, ifp); @@ -1542,10 +1582,12 @@ ifa_ifwithnet(const struct sockaddr *addr) ifa_maybe = ifa; } } + pserialize_read_exit(s); return ifa_maybe; } #endif - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; IFADDR_FOREACH(ifa, ifp) { @@ -1571,6 +1613,7 @@ ifa_ifwithnet(const struct sockaddr *addr) ifa_maybe = ifa; } } + pserialize_read_exit(s); return ifa_maybe; } @@ -1595,17 +1638,21 @@ struct ifaddr * ifa_ifwithaf(int af) { struct ifnet *ifp; - struct ifaddr *ifa; + struct ifaddr *ifa = NULL; + int s; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family == af) - return ifa; + goto out; } } - return NULL; +out: + pserialize_read_exit(s); + return ifa; } /* @@ -2038,6 +2085,7 @@ ifunit(const char *name) const char *cp = name; u_int unit = 0; u_int i; + int s; /* * If the entire name is a number, treat it as an ifindex. @@ -2058,13 +2106,17 @@ ifunit(const char *name) return ifp; } - IFNET_FOREACH(ifp) { + ifp = NULL; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp->if_output == if_nulloutput) continue; if (strcmp(ifp->if_xname, name) == 0) - return ifp; + goto out; } - return NULL; +out: + pserialize_read_exit(s); + return ifp; } ifnet_t * @@ -2591,17 +2643,27 @@ ifconf(u_long cmd, void *data) int space = 0, error = 0; const int sz = (int)sizeof(struct ifreq); const bool docopy = ifc->ifc_req != NULL; + int s; + int bound = curlwp->l_pflag & LP_BOUND; + struct psref psref; if (docopy) { space = ifc->ifc_len; ifrp = ifc->ifc_req; } - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + (void)strncpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); - if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') - return ENAMETOOLONG; + if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { + error = ENAMETOOLONG; + goto release_exit; + } if (IFADDR_EMPTY(ifp)) { /* Interface with no addresses - send zero sockaddr. */ memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); @@ -2612,7 +2674,7 @@ ifconf(u_long cmd, void *data) if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return error; + goto release_exit; ifrp++; space -= sz; } @@ -2631,11 +2693,17 @@ ifconf(u_long cmd, void *data) if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return (error); + goto release_exit; ifrp++; space -= sz; } } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; + if (docopy) { KASSERT(0 <= space && space <= ifc->ifc_len); ifc->ifc_len -= space; @@ -2644,6 +2712,11 @@ ifconf(u_long cmd, void *data) ifc->ifc_len = space; } return (0); + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } int diff --git a/sys/net/if.h b/sys/net/if.h index cccbf5e..0d3e5e5 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -85,6 +85,9 @@ #include #ifdef _KERNEL #include +#include +#include +#include #endif /* @@ -251,6 +254,7 @@ struct if_percpuq; typedef struct ifnet { void *if_softc; /* lower-level data for this if */ + /* DEPRECATED. Keep it to avoid breaking kvm(3) users */ TAILQ_ENTRY(ifnet) if_list; /* all struct ifnets are chained */ TAILQ_HEAD(, ifaddr) if_addrlist; /* linked list of addresses per if */ char if_xname[IFNAMSIZ]; /* external name (name + unit) */ @@ -354,6 +358,8 @@ typedef struct ifnet { struct if_percpuq *if_percpuq; /* We should remove it in the future */ void *if_link_si; /* softint to handle link state changes */ uint16_t if_link_queue; /* masked link state change queue */ + struct pslist_entry if_pslist_entry; + struct psref_target if_psref; #endif } ifnet_t; @@ -984,10 +990,6 @@ __END_DECLS #ifdef _KERNEL -#define IFNET_FIRST() TAILQ_FIRST(&ifnet_list) -#define IFNET_EMPTY() TAILQ_EMPTY(&ifnet_list) -#define IFNET_NEXT(__ifp) TAILQ_NEXT((__ifp), if_list) -#define IFNET_FOREACH(__ifp) TAILQ_FOREACH(__ifp, &ifnet_list, if_list) #define IFADDR_FIRST(__ifp) TAILQ_FIRST(&(__ifp)->if_addrlist) #define IFADDR_NEXT(__ifa) TAILQ_NEXT((__ifa), ifa_list) #define IFADDR_FOREACH(__ifa, __ifp) TAILQ_FOREACH(__ifa, \ @@ -997,7 +999,31 @@ __END_DECLS &(__ifp)->if_addrlist, ifa_list, __nifa) #define IFADDR_EMPTY(__ifp) TAILQ_EMPTY(&(__ifp)->if_addrlist) -extern struct ifnet_head ifnet_list; +#define IFNET_LOCK() mutex_enter(&ifnet_mtx) +#define IFNET_UNLOCK() mutex_exit(&ifnet_mtx) +#define IFNET_LOCKED() mutex_owned(&ifnet_mtx) + +#define IFNET_READER_EMPTY() \ + (PSLIST_READER_FIRST(&ifnet_pslist, struct ifnet, if_pslist_entry) == NULL) +#define IFNET_READER_FIRST() \ + PSLIST_READER_FIRST(&ifnet_pslist, struct ifnet, if_pslist_entry) +#define IFNET_READER_NEXT(__ifp) \ + PSLIST_READER_NEXT((__ifp), struct ifnet, if_pslist_entry) +#define IFNET_READER_FOREACH(__ifp) \ + PSLIST_READER_FOREACH((__ifp), &ifnet_pslist, struct ifnet, \ + if_pslist_entry) +#define IFNET_WRITER_INSERT_HEAD(__ifp) \ + PSLIST_WRITER_INSERT_HEAD(&ifnet_pslist, (__ifp), if_pslist_entry) +#define IFNET_WRITER_REMOVE(__ifp) \ + PSLIST_WRITER_REMOVE((__ifp), if_pslist_entry) +#define IFNET_WRITER_FOREACH(__ifp) \ + PSLIST_WRITER_FOREACH((__ifp), &ifnet_pslist, struct ifnet, \ + if_pslist_entry) + +extern struct pslist_head ifnet_pslist; +extern struct psref_class *ifnet_psref_class; +extern kmutex_t ifnet_mtx; + extern struct ifnet *lo0ifp; ifnet_t * if_byindex(u_int); diff --git a/sys/net/npf/npf_if.c b/sys/net/npf/npf_if.c index 1352686..6d3e579 100644 --- a/sys/net/npf/npf_if.c +++ b/sys/net/npf/npf_if.c @@ -139,9 +139,11 @@ npf_ifmap_flush(void) npf_ifmap_cnt = 0; KERNEL_LOCK(1, NULL); - IFNET_FOREACH(ifp) { + IFNET_LOCK(); + IFNET_WRITER_FOREACH(ifp) { ifp->if_pf_kif = (void *)(uintptr_t)0; } + IFNET_UNLOCK(); KERNEL_UNLOCK_ONE(NULL); } diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 4cca7c8..7bc38cf 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1429,13 +1429,23 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) struct ifaddr *ifa; struct rt_addrinfo info; int len, error = 0; + int s; + struct psref psref; + int bound = curlwp->l_pflag & LP_BOUND; memset(&info, 0, sizeof(info)); - IFNET_FOREACH(ifp) { + + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (w->w_arg && w->w_arg != ifp->if_index) continue; if (IFADDR_EMPTY(ifp)) continue; + + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; switch (type) { case NET_RT_IFLIST: @@ -1455,7 +1465,7 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) panic("sysctl_iflist(1)"); } if (error) - return error; + goto release_exit; info.rti_info[RTAX_IFP] = NULL; if (w->w_where && w->w_tmem && w->w_needed <= 0) { switch (type) { @@ -1469,7 +1479,7 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) ifm->ifm_addrs = info.rti_addrs; error = copyout(ifm, w->w_where, len); if (error) - return error; + goto release_exit; w->w_where = (char *)w->w_where + len; break; } @@ -1478,14 +1488,14 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) case NET_RT_OOIFLIST: error = compat_14_iflist(ifp, w, &info, len); if (error) - return error; + goto release_exit; break; #endif #ifdef COMPAT_50 case NET_RT_OIFLIST: error = compat_50_iflist(ifp, w, &info, len); if (error) - return error; + goto release_exit; break; #endif default: @@ -1499,7 +1509,7 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len))) - return error; + goto release_exit; if (w->w_where && w->w_tmem && w->w_needed <= 0) { struct ifa_xmsghdr *ifam; @@ -1510,14 +1520,25 @@ sysctl_iflist(int af, struct rt_walkarg *w, int type) ifam->ifam_addrs = info.rti_addrs; error = copyout(w->w_tmem, w->w_where, len); if (error) - return error; + goto release_exit; w->w_where = (char *)w->w_where + len; } } info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = info.rti_info[RTAX_BRD] = NULL; + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return 0; + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } static int diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index a8c3048..395c9e7 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -928,18 +928,31 @@ carp_send_ad_all(void) struct ifnet *ifp; struct carp_if *cif; struct carp_softc *vh; + int s; + int bound = curlwp->l_pflag & LP_BOUND; - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + struct psref psref; if (ifp->if_carp == NULL || ifp->if_type == IFT_CARP) continue; + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + cif = (struct carp_if *)ifp->if_carp; TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) { if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER) carp_send_ad(vh); } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 6858b05..7d1f629 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -478,7 +478,7 @@ int rip_connect_pcb(struct inpcb *inp, struct sockaddr_in *addr) { - if (IFNET_EMPTY()) + if (IFNET_READER_EMPTY()) return (EADDRNOTAVAIL); if (addr->sin_family != AF_INET) return (EAFNOSUPPORT); @@ -565,7 +565,7 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) return EINVAL; s = splsoftnet(); - if (IFNET_EMPTY()) { + if (IFNET_READER_EMPTY()) { error = EADDRNOTAVAIL; goto release; } diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index c2749ae..63e6515 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -2115,8 +2115,10 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) { struct ifnet *ifn; struct ifaddr *ifa, *nifa; + int s; - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if (stcb->asoc.loopback_scope == 0 && ifn->if_type == IFT_LOOP) { /* Skip if loopback_scope not set */ continue; @@ -2138,6 +2140,8 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) if (sctp_is_addr_restricted(stcb, ifa->ifa_addr)) continue; + pserialize_read_exit(s); + /* found a valid local v4 address to use */ return (ifa->ifa_addr); } else if (ifa->ifa_addr->sa_family == AF_INET6 && @@ -2163,11 +2167,14 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) continue; + pserialize_read_exit(s); /* found a valid local v6 address to use */ return (ifa->ifa_addr); } } } + pserialize_read_exit(s); + /* no valid addresses found */ return (NULL); } @@ -2772,9 +2779,11 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, { struct ifnet *ifn; struct ifaddr *ifa; + int s; /* go through all our known interfaces */ - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if (loopback_scope == 0 && ifn->if_type == IFT_LOOP) { /* skip loopback interface */ continue; @@ -2801,6 +2810,7 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, } } /* end foreach ifa */ } /* end foreach ifn */ + pserialize_read_exit(s); } /* diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index e1dfb76..6a50f41 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -897,6 +897,7 @@ sctp_choose_v4_boundall(struct sctp_inpcb *inp, struct sockaddr_in *sin; struct in_addr ans; struct ifaddr *ifa; + int s; /* * For v4 we can use (in boundall) any address in the association. If * non_asoc_addr_ok is set we can use any address (at least in theory). @@ -975,7 +976,8 @@ sctp_choose_v4_boundall(struct sctp_inpcb *inp, * address. If we reache here we are in trouble I think. */ bound_all_v4_plan_c: - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if (ifn == inp->next_ifn_touse) break; if (loopscope == 0 && ifn->if_type == IFT_LOOP) { @@ -1008,9 +1010,11 @@ sctp_choose_v4_boundall(struct sctp_inpcb *inp, ipv4_scope, cur_addr_num); if (sin == NULL) continue; + pserialize_read_exit(s); return (sin->sin_addr); } + pserialize_read_exit(s); /* * plan_d: We are in deep trouble. No prefered address on @@ -1021,7 +1025,8 @@ sctp_choose_v4_boundall(struct sctp_inpcb *inp, * illicit an ABORT, falling through. */ - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if (ifn == inp->next_ifn_touse) break; if (loopscope == 0 && ifn->if_type == IFT_LOOP) { @@ -1044,9 +1049,11 @@ sctp_choose_v4_boundall(struct sctp_inpcb *inp, continue; } } + pserialize_read_exit(s); return (sin->sin_addr); } } + pserialize_read_exit(s); /* * Ok we can find NO address to source from that is * not on our negative list. It is either the special @@ -1636,6 +1643,7 @@ sctp_choose_v6_boundall(struct sctp_inpcb *inp, */ struct ifnet *ifn; struct sockaddr_in6 *sin6; + int s; ifn = rt->rt_ifp; if (net) { @@ -1715,14 +1723,14 @@ sctp_choose_v6_boundall(struct sctp_inpcb *inp, #endif if (inp->next_ifn_touse == NULL) { started_at_beginning=1; - inp->next_ifn_touse = IFNET_FIRST(); + inp->next_ifn_touse = IFNET_READER_FIRST(); #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) { printf("Start at first IFN:%p\n", inp->next_ifn_touse); } #endif } else { - inp->next_ifn_touse = IFNET_NEXT(inp->next_ifn_touse); + inp->next_ifn_touse = IFNET_READER_NEXT(inp->next_ifn_touse); #ifdef SCTP_DEBUG if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) { printf("Resume at IFN:%p\n", inp->next_ifn_touse); @@ -1735,10 +1743,12 @@ sctp_choose_v6_boundall(struct sctp_inpcb *inp, } #endif started_at_beginning=1; - inp->next_ifn_touse = IFNET_FIRST(); + inp->next_ifn_touse = IFNET_READER_FIRST(); } } - IFNET_FOREACH(ifn) { + + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if (loopscope == 0 && ifn->if_type == IFT_LOOP) { /* wrong base scope */ continue; @@ -1797,8 +1807,11 @@ sctp_choose_v6_boundall(struct sctp_inpcb *inp, cur_addr_num, ifn); } #endif + pserialize_read_exit(s); return (sin6); } + pserialize_read_exit(s); + if (started_at_beginning == 0) { /* we have not been through all of them yet, force * us to go through them all. @@ -2711,9 +2724,11 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) struct ifnet *ifn; struct ifaddr *ifa; int cnt; + int s; cnt = cnt_inits_to; - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if ((stcb->asoc.loopback_scope == 0) && (ifn->if_type == IFT_LOOP)) { /* @@ -2735,8 +2750,11 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) cnt++; } } + pserialize_read_exit(s); + if (cnt > 1) { - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if ((stcb->asoc.loopback_scope == 0) && (ifn->if_type == IFT_LOOP)) { /* @@ -2758,6 +2776,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) m_at = sctp_add_addr_to_mbuf(m_at, ifa); } } + pserialize_read_exit(s); } } else { struct sctp_laddr *laddr; @@ -3657,8 +3676,10 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct ifnet *ifn; struct ifaddr *ifa; int cnt = cnt_inits_to; + int s; - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if ((stc.loopback_scope == 0) && (ifn->if_type == IFT_LOOP)) { /* @@ -3677,8 +3698,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, cnt++; } } + pserialize_read_exit(s); + if (cnt > 1) { - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if ((stc.loopback_scope == 0) && (ifn->if_type == IFT_LOOP)) { /* @@ -3698,6 +3722,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, m_at = sctp_add_addr_to_mbuf(m_at, ifa); } } + pserialize_read_exit(s); } } else { struct sctp_laddr *laddr; diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 5116423..6308287 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2338,7 +2338,10 @@ sctp_is_address_on_local_host(struct sockaddr *addr) { struct ifnet *ifn; struct ifaddr *ifa; - IFNET_FOREACH(ifn) { + int s; + + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { IFADDR_FOREACH(ifa, ifn) { if (addr->sa_family == ifa->ifa_addr->sa_family) { /* same family */ @@ -2350,6 +2353,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr) if (sin->sin_addr.s_addr == sin_c->sin_addr.s_addr) { /* we are on the same machine */ + pserialize_read_exit(s); return (1); } } else if (addr->sa_family == AF_INET6) { @@ -2360,12 +2364,15 @@ sctp_is_address_on_local_host(struct sockaddr *addr) if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &sin_c6->sin6_addr)) { /* we are on the same machine */ + pserialize_read_exit(s); return (1); } } } } } + pserialize_read_exit(s); + return (0); } diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 558f088..6c0e779 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -943,7 +943,8 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, } if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { - IFNET_FOREACH(ifn) { + int s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { if ((loopback_scope == 0) && (ifn->if_type == IFT_LOOP)) { /* Skip loopback if loopback_scope not set */ @@ -988,6 +989,7 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, actual += sizeof(*sin); } if (actual >= limit) { + pserialize_read_exit(s); return (actual); } } else if ((ifa->ifa_addr->sa_family == AF_INET6) && @@ -1010,11 +1012,13 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, sas = (struct sockaddr_storage *)((vaddr_t)sas + sizeof(*sin6)); actual += sizeof(*sin6); if (actual >= limit) { + pserialize_read_exit(s); return (actual); } } } } + pserialize_read_exit(s); } else { struct sctp_laddr *laddr; /* @@ -1095,8 +1099,10 @@ sctp_count_max_addresses(struct sctp_inpcb *inp) if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { struct ifnet *ifn; struct ifaddr *ifa; + int s; - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { IFADDR_FOREACH(ifa, ifn) { /* Count them if they are the right type */ if (ifa->ifa_addr->sa_family == AF_INET) { @@ -1109,6 +1115,7 @@ sctp_count_max_addresses(struct sctp_inpcb *inp) cnt += sizeof(struct sockaddr_in6); } } + pserialize_read_exit(s); } else { struct sctp_laddr *laddr; LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index c6436fd..fd68277 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -3607,9 +3607,11 @@ sctp_find_ifa_by_addr(struct sockaddr *sa) { struct ifnet *ifn; struct ifaddr *ifa; + int s; /* go through all our known interfaces */ - IFNET_FOREACH(ifn) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifn) { /* go through each interface addresses */ IFADDR_FOREACH(ifa, ifn) { /* correct family? */ @@ -3632,6 +3634,7 @@ sctp_find_ifa_by_addr(struct sockaddr *sa) if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(struct in6_addr)) == 0) { /* found it */ + pserialize_read_exit(s); return (ifa); } } else @@ -3644,12 +3647,15 @@ sctp_find_ifa_by_addr(struct sockaddr *sa) if (sin1->sin_addr.s_addr == sin2->sin_addr.s_addr) { /* found it */ + pserialize_read_exit(s); return (ifa); } } /* else, not AF_INET or AF_INET6, so skip */ } /* end foreach ifa */ } /* end foreach ifn */ + pserialize_read_exit(s); + /* not found! */ return (NULL); } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 420cdbd..daf65e8 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1650,7 +1650,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, } } - IFNET_FOREACH(ifp) { + IFNET_READER_FOREACH(ifp) { addrsofif = 0; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1716,7 +1716,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6, struct ifnet *ifp0, int resid) { - struct ifnet *ifp = ifp0 ? ifp0 : IFNET_FIRST(); + struct ifnet *ifp = ifp0 ? ifp0 : IFNET_READER_FIRST(); struct in6_ifaddr *ifa6; struct ifaddr *ifa; struct ifnet *ifp_dep = NULL; @@ -1730,7 +1730,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, again: - for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) + for (; ifp; ifp = IFNET_READER_NEXT(ifp)) { IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_INET6) diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 386a554..fd86680 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2178,8 +2178,10 @@ in6_setmaxmtu(void) { unsigned long maxmtu = 0; struct ifnet *ifp; + int s; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { /* this function can be called during ifnet initialization */ if (!ifp->if_afdata[AF_INET6]) continue; @@ -2187,6 +2189,7 @@ in6_setmaxmtu(void) IN6_LINKMTU(ifp) > maxmtu) maxmtu = IN6_LINKMTU(ifp); } + pserialize_read_exit(s); if (maxmtu) /* update only when maxmtu is positive */ in6_maxmtu = maxmtu; } diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 7d38e94..3e7e30d 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -454,6 +454,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, struct in6_addr *in6) { struct ifnet *ifp; + int s; /* first, try to get it from the interface itself */ if (in6_get_hw_ifid(ifp0, in6) == 0) { @@ -470,7 +471,8 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, } /* next, try to get it from some other hardware interface */ - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (ifp == ifp0) continue; if (in6_get_hw_ifid(ifp, in6) != 0) @@ -487,6 +489,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, goto success; } } + pserialize_read_exit(s); #if 0 /* get from hostid - only for certain architectures */ @@ -954,6 +957,7 @@ in6_tmpaddrtimer(void *ignored_arg) struct nd_ifinfo *ndi; u_int8_t nullbuf[8]; struct ifnet *ifp; + int s; mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); @@ -963,7 +967,8 @@ in6_tmpaddrtimer(void *ignored_arg) ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); memset(nullbuf, 0, sizeof(nullbuf)); - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { ndi = ND_IFINFO(ifp); if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { /* @@ -974,6 +979,7 @@ in6_tmpaddrtimer(void *ignored_arg) ndi->randomseed1, ndi->randomid); } } + pserialize_read_exit(s); KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 31cae04..c340407 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -2090,12 +2090,15 @@ nd6_slowtimo(void *ignored_arg) { struct nd_ifinfo *nd6if; struct ifnet *ifp; + int s; mutex_enter(softnet_lock); KERNEL_LOCK(1, NULL); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); - IFNET_FOREACH(ifp) { + + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { nd6if = ND_IFINFO(ifp); if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { @@ -2109,6 +2112,8 @@ nd6_slowtimo(void *ignored_arg) nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); } } + pserialize_read_exit(s); + KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); } diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 67c0faa..86c4a86 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -667,7 +667,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) if (addr->sin6_len != sizeof(*addr)) return EINVAL; - if (IFNET_EMPTY() || addr->sin6_family != AF_INET6) + if (IFNET_READER_EMPTY() || addr->sin6_family != AF_INET6) return EADDRNOTAVAIL; if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) @@ -712,7 +712,7 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) KASSERT(in6p != NULL); KASSERT(nam != NULL); - if (IFNET_EMPTY()) + if (IFNET_READER_EMPTY()) return EADDRNOTAVAIL; if (addr->sin6_family != AF_INET6) return EAFNOSUPPORT; diff --git a/sys/netipsec/xform_ipip.c b/sys/netipsec/xform_ipip.c index 21b9fd7..d283c44 100644 --- a/sys/netipsec/xform_ipip.c +++ b/sys/netipsec/xform_ipip.c @@ -333,7 +333,8 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) if ((m->m_pkthdr.rcvif == NULL || !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) && ipip_allow != 2) { - IFNET_FOREACH(ifp) { + int s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { IFADDR_FOREACH(ifa, ifp) { #ifdef INET if (ipo) { @@ -345,6 +346,7 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) if (sin->sin_addr.s_addr == ipo->ip_src.s_addr) { + pserialize_read_exit(s); IPIP_STATINC(IPIP_STAT_SPOOF); m_freem(m); return; @@ -361,6 +363,7 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) sin6 = (struct sockaddr_in6 *) ifa->ifa_addr; if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src)) { + pserialize_read_exit(s); IPIP_STATINC(IPIP_STAT_SPOOF); m_freem(m); return; @@ -370,6 +373,7 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) #endif /* INET6 */ } } + pserialize_read_exit(s); } /* Statistics */ diff --git a/sys/rump/librump/rumpnet/net_stub.c b/sys/rump/librump/rumpnet/net_stub.c index 9946d5c..1fd1dc6 100644 --- a/sys/rump/librump/rumpnet/net_stub.c +++ b/sys/rump/librump/rumpnet/net_stub.c @@ -28,9 +28,12 @@ #include __KERNEL_RCSID(0, "$NetBSD: net_stub.c,v 1.22 2016/04/15 01:35:26 ozaki-r Exp $"); +#include #include #include #include +#include +#include #include #include @@ -65,6 +68,9 @@ __weak_alias(pppoe_input,rumpnet_stub); __weak_alias(pppoedisc_input,rumpnet_stub); struct ifnet_head ifnet_list; +struct pslist_head ifnet_pslist; +struct psref_class *ifnet_psref_class; +kmutex_t ifnet_mtx; int compat_ifconf(u_long cmd, void *data)