diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 35eb4614e2c6..d72fb4cce587 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -726,226 +726,6 @@ out: #endif } -VNET_DEFINE_STATIC(bool, lport_cache_enable) = true; -#define V_lport_cache_enable VNET(lport_cache_enable) -SYSCTL_BOOL(_net_inet_ip_portrange, OID_AUTO, lport_cache, - CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(lport_cache_enable), 0, - "Enable local port cache for peers that have many outgoing connections to"); - -static MALLOC_DEFINE(M_LPORTS, "inp_lports", "inpcb lport cache"); -#define PORTBITS (IPPORT_MAX + 1) -BITSET_DEFINE(lportbits, PORTBITS); -struct lport_cache { - struct lportbits lports; - struct lport_cache *successor; - uint64_t age; - u_int refcount; -#ifdef INVARIANTS - union in_dependaddr faddr; - uint16_t fport; -#endif -}; - -/* - * Remove one reference from cache, potentially freeing a chain. - */ -static struct lport_cache * -lport_cache_release(struct lport_cache *cache) -{ - - while (cache != NULL && refcount_release(&cache->refcount)) { - struct lport_cache *next; - - next = atomic_load_ptr(&cache->successor); - free(cache, M_LPORTS); - cache = next; - } - - return (cache); -} - -static inline void -lport_acquire(struct lportbits *lports, uint16_t port) -{ - BIT_SET_ATOMIC(PORTBITS, port, lports); -} - -static inline void -lport_release(struct lportbits *lports, uint16_t port) -{ - BIT_CLR_ATOMIC(PORTBITS, port, lports); -} - -static inline bool -lport_check(struct lportbits *lports, uint16_t port) -{ - return (BIT_ISSET(PORTBITS, port, lports)); -} - -static inline void -lport_merge(struct lportbits *dst, struct lportbits *src) -{ - BIT_OR_ATOMIC(PORTBITS, dst, src); -} - -/* - * Return inp->inp_lport_cache, potentially promoting it. - */ -static struct lport_cache * -in_pcb_lport_cache(struct inpcb *inp) -{ - struct lport_cache *cache, *next; - - INP_WLOCK_ASSERT(inp); - - if ((cache = inp->inp_lport_cache) != NULL) - while ((next = atomic_load_ptr(&cache->successor)) != NULL) { - MPASS(next != cache); - inp->inp_lport_cache = next; - if (refcount_release(&cache->refcount)) - free(cache, M_LPORTS); - else - refcount_acquire(&next->refcount); - cache = next; - } - - return (inp->inp_lport_cache); -} - -static void -in_pcb_cache_lport(struct inpcb *new, struct inpcb *old) -{ - struct lport_cache *cache; - - INP_WLOCK_ASSERT(new); - INP_WLOCK_ASSERT(old); - - /* - * When conflicted with a wildcard bound inpcb, we could actually cache - * the port number, but do not attach the cache to the wildcard inpcb. - * This would complicate this function, making each iteration more - * expensive. With the expectation that not so many ports in the - * anonymous range are occupied by wildcard inpcbs, usually zero, seems - * it would be more effective to not cover this case and have just tiny - * increase in attempts rather then making each attempt heavier. - */ -#ifdef INET6 - if (old->inp_vflag & INP_IPV6) { - if (IN6_IS_ADDR_UNSPECIFIED(&old->in6p_faddr)) - goto out; - } else -#endif - if (in_nullhost(old->inp_faddr)) - goto out; - - (void)in_pcb_lport_cache(new); - (void)in_pcb_lport_cache(old); - - if (new->inp_lport_cache == NULL && - old->inp_lport_cache == NULL) { - static uint64_t age; - - cache = malloc(sizeof(*cache), M_LPORTS, M_ZERO | M_NOWAIT); - if (__predict_false(cache == NULL)) - goto out; - refcount_init(&cache->refcount, 2); - cache->age = atomic_fetchadd_64(&age, 1); -#ifdef INVARIANTS - cache->faddr = old->inp_inc.inc_ie.ie_dependfaddr; - cache->fport = old->inp_fport; -#endif - lport_acquire(&cache->lports, ntohs(old->inp_lport)); - new->inp_lport_cache = old->inp_lport_cache = cache; - } else if (new->inp_lport_cache == old->inp_lport_cache) { - /* Race: old has grabbed the port after our lport_check(). */ - } else if (new->inp_lport_cache == NULL) { - cache = old->inp_lport_cache; - MPASS(memcmp(&old->inp_inc.inc_ie.ie_dependfaddr, - &cache->faddr, sizeof(union in_dependaddr)) == 0); - MPASS(old->inp_fport == cache->fport); - refcount_acquire(&cache->refcount); - new->inp_lport_cache = cache; - } else if (old->inp_lport_cache == NULL) { - cache = new->inp_lport_cache; - MPASS(memcmp(&old->inp_inc.inc_ie.ie_dependfaddr, - &cache->faddr, sizeof(union in_dependaddr)) == 0); - MPASS(old->inp_fport == cache->fport); - lport_acquire(&cache->lports, ntohs(old->inp_lport)); - refcount_acquire(&cache->refcount); - old->inp_lport_cache = cache; - } else { - struct lport_cache *second; - - /* - * We can't use caches refcounts here, as it makes it possible - * for two competing caches to be linked against each other by - * two parallel threads. We use age speculating that an older - * cache usually holds more bits. - */ - if (new->inp_lport_cache->age < old->inp_lport_cache->age) { - cache = new->inp_lport_cache; - second = old->inp_lport_cache; - MPASS(cache != second); - old->inp_lport_cache = cache; - } else { - cache = old->inp_lport_cache; - second = new->inp_lport_cache; - MPASS(cache != second); - new->inp_lport_cache = cache; - } - MPASS(memcmp(&old->inp_inc.inc_ie.ie_dependfaddr, - &cache->faddr, sizeof(union in_dependaddr)) == 0); - MPASS(old->inp_fport == cache->fport); - MPASS(memcmp(&second->faddr, &cache->faddr, - sizeof(union in_dependaddr)) == 0); - MPASS(second->fport == cache->fport); - lport_merge(&cache->lports, &second->lports); - refcount_acquire(&cache->refcount); - /* - * Now both inpcbs and winning cache are all set, and tricky - * part is to dereference 'second'. Three possibilities here: - * 1) our reference was the last and we free it 2) we were not - * the last so make it point at the winner 3) we lost the race - * to other thread that was doing the same. - */ - if (lport_cache_release(second) == second && - atomic_cmpset_ptr((uintptr_t *)&second->successor, - (uintptr_t)NULL, (uintptr_t)cache)) - refcount_acquire(&cache->refcount); - } -out: - INP_WUNLOCK(old); -} - -void -in_pcb_lport_cache_free(struct inpcb *inp) -{ - struct lport_cache *cache = inp->inp_lport_cache; - - INP_WLOCK_ASSERT(inp); - - /* Free possible chain of caches, where we were the last reference. */ - while (cache != NULL && refcount_release(&cache->refcount)) { - struct lport_cache *next; - - MPASS(memcmp(&inp->inp_inc.inc_ie.ie_dependfaddr, - &cache->faddr, sizeof(union in_dependaddr)) == 0); - MPASS(inp->inp_fport == cache->fport); - next = atomic_load_ptr(&cache->successor); - free(cache, M_LPORTS); - cache = next; - } - /* Walk through the remaining chain and clear our bit. */ - while (cache != NULL) { - MPASS(memcmp(&inp->inp_inc.inc_ie.ie_dependfaddr, - &cache->faddr, sizeof(union in_dependaddr)) == 0); - MPASS(inp->inp_fport == cache->fport); - lport_release(&cache->lports, ntohs(inp->inp_lport)); - cache = atomic_load_ptr(&cache->successor); - } - inp->inp_lport_cache = NULL; -} - /* * Assign a local port like in_pcb_lport(), but also used with connect() * and a foreign address and port. If fsa is non-NULL, choose a local port @@ -967,11 +747,8 @@ in_pcb_lport_dest(struct inpcbinfo_ctx *ipictx, struct inpcb *inp, #ifdef INET6 const struct in6_addr *laddr6, *faddr6; #endif - const bool use_cache = V_lport_cache_enable && INP_WLOCKED(inp) && - fsa != NULL; INP_LOCK_ASSERT(inp); - MPASS(inp->inp_lport_cache == NULL); if (inp->inp_flags & INP_HIGHPORT) { first = V_ipport_hifirstauto; /* sysctl */ @@ -1037,11 +814,6 @@ in_pcb_lport_dest(struct inpcbinfo_ctx *ipictx, struct inpcb *inp, .pcbinfo = ipictx->pcbinfo }; struct inpcb *tmpinp = NULL; - struct lport_cache *cache; - - if ((cache = in_pcb_lport_cache(inp)) != NULL && - lport_check(&cache->lports, port)) - goto next; lport = htons(port); @@ -1060,9 +832,6 @@ in_pcb_lport_dest(struct inpcbinfo_ctx *ipictx, struct inpcb *inp, M_NODOM, RT_ALL_FIBS); } #endif - if (use_cache && tmpinp != NULL && - inp_trylock(tmpinp, INPLOOKUP_WLOCKPCB)) - in_pcb_cache_lport(inp, tmpinp); } else { #ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) { @@ -1095,22 +864,13 @@ in_pcb_lport_dest(struct inpcbinfo_ctx *ipictx, struct inpcb *inp, break; } inpcbinfo_ctx_release(&tmpctx); -next: ++port; if (port < first || port > last) port = first; } - if (count == 0) { /* completely used? */ - if (inp->inp_lport_cache != NULL) { - lport_cache_release(inp->inp_lport_cache); - inp->inp_lport_cache = NULL; - } + if (count == 0) /* completely used? */ return (EADDRNOTAVAIL); - } - - if (inp->inp_lport_cache != NULL) - lport_acquire(&inp->inp_lport_cache->lports, ntohs(lport)); *lportp = lport; @@ -1752,7 +1512,6 @@ in_pcbdisconnect(struct inpcb *inp) if (inp->inp_flags & INP_UNCONNECTED) return; - in_pcb_lport_cache_free(inp); in_pcbremhash(inp); IPI_LOCK(inp->inp_pcbinfo); CK_LIST_INSERT_HEAD(&inp->inp_pcbinfo->ipi_list_unconn.head, inp, @@ -2180,7 +1939,6 @@ in_pcbfree(struct inpcb *inp) inp->inp_socket->so_pcb = NULL; inp->inp_socket = NULL; - in_pcb_lport_cache_free(inp); RO_INVALIDATE_CACHE(&inp->inp_route); #ifdef MAC mac_inpcb_destroy(inp); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 5a6bbfd3b5b2..0d889feca7ed 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -382,7 +382,7 @@ struct inpcb { }; CK_LIST_ENTRY(inpcb) inp_portlist; /* (r:e/w:h) port list */ uint64_t inp_gencnt; /* (c) generation count */ - struct lport_cache *inp_lport_cache; + void *spare_ptr; /* Spare pointer. */ rt_gen_t inp_rt_cookie; /* generation for route entry */ union { /* cached L3 information */ struct route inp_route; diff --git a/sys/netinet/in_pcb_var.h b/sys/netinet/in_pcb_var.h index 2c6c342409dd..de9a09c6b2ca 100644 --- a/sys/netinet/in_pcb_var.h +++ b/sys/netinet/in_pcb_var.h @@ -131,7 +131,6 @@ void in_pcbrehash(struct inpcb *, struct inpcbinfo_ctx *); void in_pcbremhash(struct inpcb *); struct inpcblbgroup *in_pcblbgroup_find(struct inpcb *inp, struct lbgroupbucket **bucket); -void in_pcb_lport_cache_free(struct inpcb *); /* * Load balance groups used for the SO_REUSEPORT_LB socket option. Each group diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index e45fc0f3d832..05c04be5dd80 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -565,7 +565,6 @@ in6_pcbdisconnect(struct inpcb *inp) if (inp->inp_flags & INP_UNCONNECTED) return; - in_pcb_lport_cache_free(inp); in_pcbremhash(inp); IPI_LOCK(inp->inp_pcbinfo); CK_LIST_INSERT_HEAD(&inp->inp_pcbinfo->ipi_list_unconn.head, inp,