Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_hostcache.c
Show First 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | |||||
SYSCTL_UINT(_net_inet_tcp_hostcache, OID_AUTO, hashsize, CTLFLAG_VNET | CTLFLAG_RDTUN, | SYSCTL_UINT(_net_inet_tcp_hostcache, OID_AUTO, hashsize, CTLFLAG_VNET | CTLFLAG_RDTUN, | ||||
&VNET_NAME(tcp_hostcache.hashsize), 0, | &VNET_NAME(tcp_hostcache.hashsize), 0, | ||||
"Size of TCP hostcache hashtable"); | "Size of TCP hostcache hashtable"); | ||||
SYSCTL_UINT(_net_inet_tcp_hostcache, OID_AUTO, bucketlimit, | SYSCTL_UINT(_net_inet_tcp_hostcache, OID_AUTO, bucketlimit, | ||||
CTLFLAG_VNET | CTLFLAG_RDTUN, &VNET_NAME(tcp_hostcache.bucket_limit), 0, | CTLFLAG_VNET | CTLFLAG_RDTUN, &VNET_NAME(tcp_hostcache.bucket_limit), 0, | ||||
"Per-bucket hash limit for hostcache"); | "Per-bucket hash limit for hostcache"); | ||||
SYSCTL_UINT(_net_inet_tcp_hostcache, OID_AUTO, count, CTLFLAG_VNET | CTLFLAG_RD, | SYSCTL_COUNTER_U64(_net_inet_tcp_hostcache, OID_AUTO, count, CTLFLAG_VNET | CTLFLAG_RD, | ||||
&VNET_NAME(tcp_hostcache.cache_count), 0, | &VNET_NAME(tcp_hostcache.cache_count), | ||||
"Current number of entries in hostcache"); | "Current number of entries in hostcache"); | ||||
SYSCTL_INT(_net_inet_tcp_hostcache, OID_AUTO, expire, CTLFLAG_VNET | CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp_hostcache, OID_AUTO, expire, CTLFLAG_VNET | CTLFLAG_RW, | ||||
&VNET_NAME(tcp_hostcache.expire), 0, | &VNET_NAME(tcp_hostcache.expire), 0, | ||||
"Expire time of TCP hostcache entries"); | "Expire time of TCP hostcache entries"); | ||||
SYSCTL_INT(_net_inet_tcp_hostcache, OID_AUTO, prune, CTLFLAG_VNET | CTLFLAG_RW, | SYSCTL_INT(_net_inet_tcp_hostcache, OID_AUTO, prune, CTLFLAG_VNET | CTLFLAG_RW, | ||||
&VNET_NAME(tcp_hostcache.prune), 0, | &VNET_NAME(tcp_hostcache.prune), 0, | ||||
Show All 34 Lines | |||||
tcp_hc_init(void) | tcp_hc_init(void) | ||||
{ | { | ||||
u_int cache_limit; | u_int cache_limit; | ||||
int i; | int i; | ||||
/* | /* | ||||
* Initialize hostcache structures. | * Initialize hostcache structures. | ||||
*/ | */ | ||||
V_tcp_hostcache.cache_count = 0; | V_tcp_hostcache.cache_count = counter_u64_alloc(M_WAITOK); | ||||
counter_u64_zero(V_tcp_hostcache.cache_count); | |||||
V_tcp_hostcache.hashsize = TCP_HOSTCACHE_HASHSIZE; | V_tcp_hostcache.hashsize = TCP_HOSTCACHE_HASHSIZE; | ||||
V_tcp_hostcache.bucket_limit = TCP_HOSTCACHE_BUCKETLIMIT; | V_tcp_hostcache.bucket_limit = TCP_HOSTCACHE_BUCKETLIMIT; | ||||
V_tcp_hostcache.expire = TCP_HOSTCACHE_EXPIRE; | V_tcp_hostcache.expire = TCP_HOSTCACHE_EXPIRE; | ||||
V_tcp_hostcache.prune = TCP_HOSTCACHE_PRUNE; | V_tcp_hostcache.prune = TCP_HOSTCACHE_PRUNE; | ||||
TUNABLE_INT_FETCH("net.inet.tcp.hostcache.hashsize", | TUNABLE_INT_FETCH("net.inet.tcp.hostcache.hashsize", | ||||
&V_tcp_hostcache.hashsize); | &V_tcp_hostcache.hashsize); | ||||
if (!powerof2(V_tcp_hostcache.hashsize)) { | if (!powerof2(V_tcp_hostcache.hashsize)) { | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int i; | int i; | ||||
callout_drain(&V_tcp_hc_callout); | callout_drain(&V_tcp_hc_callout); | ||||
/* Purge all hc entries. */ | /* Purge all hc entries. */ | ||||
tcp_hc_purge_internal(1); | tcp_hc_purge_internal(1); | ||||
/* Release the counter */ | |||||
counter_u64_free(V_tcp_hostcache.cache_count); | |||||
/* Free the uma zone and the allocated hash table. */ | /* Free the uma zone and the allocated hash table. */ | ||||
uma_zdestroy(V_tcp_hostcache.zone); | uma_zdestroy(V_tcp_hostcache.zone); | ||||
for (i = 0; i < V_tcp_hostcache.hashsize; i++) | for (i = 0; i < V_tcp_hostcache.hashsize; i++) | ||||
mtx_destroy(&V_tcp_hostcache.hashbase[i].hch_mtx); | mtx_destroy(&V_tcp_hostcache.hashbase[i].hch_mtx); | ||||
free(V_tcp_hostcache.hashbase, M_HOSTCACHE); | free(V_tcp_hostcache.hashbase, M_HOSTCACHE); | ||||
} | } | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | tcp_hc_insert(struct in_conninfo *inc) | ||||
* done. | * done. | ||||
*/ | */ | ||||
THC_LOCK(&hc_head->hch_mtx); | THC_LOCK(&hc_head->hch_mtx); | ||||
/* | /* | ||||
* If the bucket limit is reached, reuse the least-used element. | * If the bucket limit is reached, reuse the least-used element. | ||||
*/ | */ | ||||
if (hc_head->hch_length >= V_tcp_hostcache.bucket_limit || | if (hc_head->hch_length >= V_tcp_hostcache.bucket_limit || | ||||
V_tcp_hostcache.cache_count >= V_tcp_hostcache.cache_limit) { | counter_u64_fetch(V_tcp_hostcache.cache_count) >= V_tcp_hostcache.cache_limit) { | ||||
hc_entry = TAILQ_LAST(&hc_head->hch_bucket, hc_qhead); | hc_entry = TAILQ_LAST(&hc_head->hch_bucket, hc_qhead); | ||||
/* | /* | ||||
* At first we were dropping the last element, just to | * At first we were dropping the last element, just to | ||||
* reacquire it in the next two lines again, which isn't very | * reacquire it in the next two lines again, which isn't very | ||||
* efficient. Instead just reuse the least used element. | * efficient. Instead just reuse the least used element. | ||||
* We may drop something that is still "in-use" but we can be | * We may drop something that is still "in-use" but we can be | ||||
* "lossy". | * "lossy". | ||||
* Just give up if this bucket row is empty and we don't have | * Just give up if this bucket row is empty and we don't have | ||||
* anything to replace. | * anything to replace. | ||||
*/ | */ | ||||
if (hc_entry == NULL) { | if (hc_entry == NULL) { | ||||
THC_UNLOCK(&hc_head->hch_mtx); | THC_UNLOCK(&hc_head->hch_mtx); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
TAILQ_REMOVE(&hc_head->hch_bucket, hc_entry, rmx_q); | TAILQ_REMOVE(&hc_head->hch_bucket, hc_entry, rmx_q); | ||||
V_tcp_hostcache.hashbase[hash].hch_length--; | V_tcp_hostcache.hashbase[hash].hch_length--; | ||||
V_tcp_hostcache.cache_count--; | counter_u64_add(V_tcp_hostcache.cache_count, -1); | ||||
TCPSTAT_INC(tcps_hc_bucketoverflow); | TCPSTAT_INC(tcps_hc_bucketoverflow); | ||||
#if 0 | #if 0 | ||||
uma_zfree(V_tcp_hostcache.zone, hc_entry); | uma_zfree(V_tcp_hostcache.zone, hc_entry); | ||||
#endif | #endif | ||||
} else { | } else { | ||||
/* | /* | ||||
* Allocate a new entry, or balk if not possible. | * Allocate a new entry, or balk if not possible. | ||||
*/ | */ | ||||
Show All 16 Lines | #endif | ||||
hc_entry->rmx_head = hc_head; | hc_entry->rmx_head = hc_head; | ||||
hc_entry->rmx_expire = V_tcp_hostcache.expire; | hc_entry->rmx_expire = V_tcp_hostcache.expire; | ||||
/* | /* | ||||
* Put it upfront. | * Put it upfront. | ||||
*/ | */ | ||||
TAILQ_INSERT_HEAD(&hc_head->hch_bucket, hc_entry, rmx_q); | TAILQ_INSERT_HEAD(&hc_head->hch_bucket, hc_entry, rmx_q); | ||||
V_tcp_hostcache.hashbase[hash].hch_length++; | V_tcp_hostcache.hashbase[hash].hch_length++; | ||||
V_tcp_hostcache.cache_count++; | counter_u64_add(V_tcp_hostcache.cache_count, 1); | ||||
TCPSTAT_INC(tcps_hc_added); | TCPSTAT_INC(tcps_hc_added); | ||||
return hc_entry; | return hc_entry; | ||||
} | } | ||||
/* | /* | ||||
* External function: look up an entry in the hostcache and fill out the | * External function: look up an entry in the hostcache and fill out the | ||||
* supplied TCP metrics structure. Fills in NULL when no entry was found or | * supplied TCP metrics structure. Fills in NULL when no entry was found or | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | #ifdef INET6 | ||||
char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
if (jailed_without_vnet(curthread->td_ucred) != 0) | if (jailed_without_vnet(curthread->td_ucred) != 0) | ||||
return (EPERM); | return (EPERM); | ||||
/* Optimize Buffer length query by sbin/sysctl */ | /* Optimize Buffer length query by sbin/sysctl */ | ||||
if (req->oldptr == NULL) { | if (req->oldptr == NULL) { | ||||
len = (V_tcp_hostcache.cache_count + 1) * linesize; | len = (counter_u64_fetch(V_tcp_hostcache.cache_count) + 1) * linesize; | ||||
return (SYSCTL_OUT(req, NULL, len)); | return (SYSCTL_OUT(req, NULL, len)); | ||||
} | } | ||||
error = sysctl_wire_old_buffer(req, 0); | error = sysctl_wire_old_buffer(req, 0); | ||||
if (error != 0) { | if (error != 0) { | ||||
return(error); | return(error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | for (i = 0; i < V_tcp_hostcache.hashsize; i++) { | ||||
THC_LOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); | THC_LOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); | ||||
TAILQ_FOREACH_SAFE(hc_entry, | TAILQ_FOREACH_SAFE(hc_entry, | ||||
&V_tcp_hostcache.hashbase[i].hch_bucket, rmx_q, hc_next) { | &V_tcp_hostcache.hashbase[i].hch_bucket, rmx_q, hc_next) { | ||||
if (all || hc_entry->rmx_expire <= 0) { | if (all || hc_entry->rmx_expire <= 0) { | ||||
TAILQ_REMOVE(&V_tcp_hostcache.hashbase[i].hch_bucket, | TAILQ_REMOVE(&V_tcp_hostcache.hashbase[i].hch_bucket, | ||||
hc_entry, rmx_q); | hc_entry, rmx_q); | ||||
uma_zfree(V_tcp_hostcache.zone, hc_entry); | uma_zfree(V_tcp_hostcache.zone, hc_entry); | ||||
V_tcp_hostcache.hashbase[i].hch_length--; | V_tcp_hostcache.hashbase[i].hch_length--; | ||||
V_tcp_hostcache.cache_count--; | counter_u64_add(V_tcp_hostcache.cache_count, -1); | ||||
} else | } else | ||||
hc_entry->rmx_expire -= V_tcp_hostcache.prune; | hc_entry->rmx_expire -= V_tcp_hostcache.prune; | ||||
} | } | ||||
THC_UNLOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); | THC_UNLOCK(&V_tcp_hostcache.hashbase[i].hch_mtx); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 41 Lines • Show Last 20 Lines |