diff options
Diffstat (limited to 'freebsd/sys/netinet/in.c')
-rw-r--r-- | freebsd/sys/netinet/in.c | 179 |
1 files changed, 87 insertions, 92 deletions
diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c index 28c257aa..7233f9a2 100644 --- a/freebsd/sys/netinet/in.c +++ b/freebsd/sys/netinet/in.c @@ -104,7 +104,7 @@ in_localaddr(struct in_addr in) struct in_ifaddr *ia; IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if ((i & ia->ia_subnetmask) == ia->ia_subnet) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); return (1); @@ -145,7 +145,7 @@ in_ifhasaddr(struct ifnet *ifp, struct in_addr in) struct in_ifaddr *ia; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = (struct in_ifaddr *)ifa; @@ -282,7 +282,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * first one on the interface, if possible. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = (struct in_ifaddr *)ifa; @@ -290,7 +290,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, break; } if (ifa == NULL) - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET) { ia = (struct in_ifaddr *)ifa; if (prison_check_ip4(td->td_ucred, @@ -381,7 +381,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) iaIsFirst = true; ia = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in_ifaddr *it; if (ifa->ifa_addr->sa_family != AF_INET) @@ -459,12 +459,12 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) /* if_addrhead is already referenced by ifa_alloc() */ IF_ADDR_WLOCK(ifp); - TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); + CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_ref(ifa); /* in_ifaddrhead */ IN_IFADDR_WLOCK(); - TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); IN_IFADDR_WUNLOCK(); @@ -537,12 +537,12 @@ fail1: (*carp_detach_p)(&ia->ia_ifa, false); IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ IN_IFADDR_WLOCK(); - TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ @@ -576,7 +576,7 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) iaIsLast = true; ia = NULL; IF_ADDR_WLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in_ifaddr *it; if (ifa->ifa_addr->sa_family != AF_INET) @@ -601,12 +601,12 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) return (EADDRNOTAVAIL); } - TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ IN_IFADDR_WLOCK(); - TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); @@ -636,12 +636,10 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) struct in_ifinfo *ii; ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); - IN_MULTI_LOCK(); if (ii->ii_allhosts) { - (void)in_leavegroup_locked(ii->ii_allhosts, NULL); + (void)in_leavegroup(ii->ii_allhosts, NULL); ii->ii_allhosts = NULL; } - IN_MULTI_UNLOCK(); } IF_ADDR_WLOCK(ifp); @@ -682,7 +680,7 @@ in_addprefix(struct in_ifaddr *target, int flags) IN_IFADDR_RLOCK(&in_ifa_tracker); /* Look for an existing address with the same prefix, mask, and fib */ - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { p = ia->ia_dstaddr.sin_addr; @@ -842,7 +840,7 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) } IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { p = ia->ia_dstaddr.sin_addr; @@ -918,10 +916,10 @@ in_ifscrub_all(void) struct ifaliasreq ifr; IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* Cannot lock here - lock recursion. */ /* IF_ADDR_RLOCK(ifp); */ - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { if (ifa->ifa_addr->sa_family != AF_INET) continue; @@ -982,7 +980,7 @@ in_broadcast(struct in_addr in, struct ifnet *ifp) * with a broadcast address. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET && in_ifaddr_broadcast(in, (struct in_ifaddr *)ifa)) { found = 1; @@ -998,11 +996,12 @@ in_broadcast(struct in_addr in, struct ifnet *ifp) void in_ifdetach(struct ifnet *ifp) { - + IN_MULTI_LOCK(); in_pcbpurgeif0(&V_ripcbinfo, ifp); in_pcbpurgeif0(&V_udbinfo, ifp); in_pcbpurgeif0(&V_ulitecbinfo, ifp); in_purgemaddrs(ifp); + IN_MULTI_UNLOCK(); } /* @@ -1015,12 +1014,12 @@ in_ifdetach(struct ifnet *ifp) static void in_purgemaddrs(struct ifnet *ifp) { - LIST_HEAD(,in_multi) purgeinms; - struct in_multi *inm, *tinm; - struct ifmultiaddr *ifma; + struct in_multi_head purgeinms; + struct in_multi *inm; + struct ifmultiaddr *ifma, *next; - LIST_INIT(&purgeinms); - IN_MULTI_LOCK(); + SLIST_INIT(&purgeinms); + IN_MULTI_LIST_LOCK(); /* * Extract list of in_multi associated with the detaching ifp @@ -1028,27 +1027,24 @@ in_purgemaddrs(struct ifnet *ifp) * We need to do this as IF_ADDR_LOCK() may be re-acquired * by code further down. */ - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; -#if 0 - KASSERT(ifma->ifma_protospec != NULL, - ("%s: ifma_protospec is NULL", __func__)); -#endif inm = (struct in_multi *)ifma->ifma_protospec; - LIST_INSERT_HEAD(&purgeinms, inm, inm_link); + inm_rele_locked(&purgeinms, inm); + if (__predict_false(ifma_restart)) { + ifma_restart = true; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); + IF_ADDR_WUNLOCK(ifp); - LIST_FOREACH_SAFE(inm, &purgeinms, inm_link, tinm) { - LIST_REMOVE(inm, inm_link); - inm_release_locked(inm); - } + inm_release_list_deferred(&purgeinms); igmp_ifdetach(ifp); - - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); } struct in_llentry { @@ -1063,9 +1059,11 @@ struct in_llentry { * Do actual deallocation of @lle. */ static void -in_lltable_destroy_lle_unlocked(struct llentry *lle) +in_lltable_destroy_lle_unlocked(epoch_context_t ctx) { + struct llentry *lle; + lle = __containerof(ctx, struct llentry, lle_epoch_ctx); LLE_LOCK_DESTROY(lle); LLE_REQ_DESTROY(lle); free(lle, M_LLTABLE); @@ -1093,7 +1091,7 @@ in_lltable_destroy_lle(struct llentry *lle) { LLE_WUNLOCK(lle); - in_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked); } static struct llentry * @@ -1160,7 +1158,6 @@ in_lltable_match_prefix(const struct sockaddr *saddr, static void in_lltable_free_entry(struct lltable *llt, struct llentry *lle) { - struct ifnet *ifp; size_t pkts_dropped; LLE_WLOCK_ASSERT(lle); @@ -1168,8 +1165,7 @@ in_lltable_free_entry(struct lltable *llt, struct llentry *lle) /* Unlink entry from table if not already */ if ((lle->la_flags & LLE_LINKED) != 0) { - ifp = llt->llt_ifp; - IF_AFDATA_WLOCK_ASSERT(ifp); + IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); lltable_unlink_entry(llt, lle); } @@ -1304,7 +1300,7 @@ in_lltable_find_dst(struct lltable *llt, struct in_addr dst) hashidx = in_lltable_hash_dst(dst, llt->llt_hsize); lleh = &llt->lle_head[hashidx]; - LIST_FOREACH(lle, lleh, lle_next) { + CK_LIST_FOREACH(lle, lleh, lle_next) { if (lle->la_flags & LLE_DELETED) continue; if (lle->r_l3addr.addr4.s_addr == dst.s_addr) @@ -1360,7 +1356,7 @@ in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr linkhdrsize = LLE_MAX_LINKHDR; if (lltable_calc_llheader(ifp, AF_INET, IF_LLADDR(ifp), linkhdr, &linkhdrsize, &lladdr_off) != 0) { - in_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked); return (NULL); } lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, @@ -1420,52 +1416,51 @@ in_lltable_dump_entry(struct lltable *llt, struct llentry *lle, int error; bzero(&arpc, sizeof(arpc)); - /* skip deleted entries */ - if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) - return (0); - /* Skip if jailed and not a valid IP of the prison. */ - lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin); - if (prison_if(wr->td->td_ucred, - (struct sockaddr *)&arpc.sin) != 0) - return (0); - /* - * produce a msg made of: - * struct rt_msghdr; - * struct sockaddr_in; (IPv4) - * struct sockaddr_dl; - */ - arpc.rtm.rtm_msglen = sizeof(arpc); - arpc.rtm.rtm_version = RTM_VERSION; - arpc.rtm.rtm_type = RTM_GET; - arpc.rtm.rtm_flags = RTF_UP; - arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; - - /* publish */ - if (lle->la_flags & LLE_PUB) - arpc.rtm.rtm_flags |= RTF_ANNOUNCE; - - sdl = &arpc.sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_len = sizeof(*sdl); - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - if ((lle->la_flags & LLE_VALID) == LLE_VALID) { - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); - } else { - sdl->sdl_alen = 0; - bzero(LLADDR(sdl), ifp->if_addrlen); - } + /* skip deleted entries */ + if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) + return (0); + /* Skip if jailed and not a valid IP of the prison. */ + lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin); + if (prison_if(wr->td->td_ucred, (struct sockaddr *)&arpc.sin) != 0) + return (0); + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_in; (IPv4) + * struct sockaddr_dl; + */ + arpc.rtm.rtm_msglen = sizeof(arpc); + arpc.rtm.rtm_version = RTM_VERSION; + arpc.rtm.rtm_type = RTM_GET; + arpc.rtm.rtm_flags = RTF_UP; + arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; + + /* publish */ + if (lle->la_flags & LLE_PUB) + arpc.rtm.rtm_flags |= RTF_ANNOUNCE; + + sdl = &arpc.sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + if ((lle->la_flags & LLE_VALID) == LLE_VALID) { + sdl->sdl_alen = ifp->if_addrlen; + bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + } else { + sdl->sdl_alen = 0; + bzero(LLADDR(sdl), ifp->if_addrlen); + } - arpc.rtm.rtm_rmx.rmx_expire = - lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; - arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); - if (lle->la_flags & LLE_STATIC) - arpc.rtm.rtm_flags |= RTF_STATIC; - if (lle->la_flags & LLE_IFADDR) - arpc.rtm.rtm_flags |= RTF_PINNED; - arpc.rtm.rtm_index = ifp->if_index; - error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); + arpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); + if (lle->la_flags & LLE_STATIC) + arpc.rtm.rtm_flags |= RTF_STATIC; + if (lle->la_flags & LLE_IFADDR) + arpc.rtm.rtm_flags |= RTF_PINNED; + arpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); return (error); } |