Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_hostcache.c
Show First 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/hash.h> | |||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
Show All 40 Lines | |||||
#endif | #endif | ||||
}; | }; | ||||
struct tcp_hostcache { | struct tcp_hostcache { | ||||
struct hc_head *hashbase; | struct hc_head *hashbase; | ||||
uma_zone_t zone; | uma_zone_t zone; | ||||
u_int hashsize; | u_int hashsize; | ||||
u_int hashmask; | u_int hashmask; | ||||
u_int hashsalt; | |||||
u_int bucket_limit; | u_int bucket_limit; | ||||
u_int cache_count; | u_int cache_count; | ||||
u_int cache_limit; | u_int cache_limit; | ||||
int expire; | int expire; | ||||
int prune; | int prune; | ||||
int purgeall; | int purgeall; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
SYSCTL_PROC(_net_inet_tcp_hostcache, OID_AUTO, purgenow, | SYSCTL_PROC(_net_inet_tcp_hostcache, OID_AUTO, purgenow, | ||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | ||||
NULL, 0, sysctl_tcp_hc_purgenow, "I", | NULL, 0, sysctl_tcp_hc_purgenow, "I", | ||||
"Immediately purge all entries"); | "Immediately purge all entries"); | ||||
static MALLOC_DEFINE(M_HOSTCACHE, "hostcache", "TCP hostcache"); | static MALLOC_DEFINE(M_HOSTCACHE, "hostcache", "TCP hostcache"); | ||||
/* Use jenkins_hash32(), as in other parts of the tcp stack */ | |||||
#define HOSTCACHE_HASH(ip) \ | #define HOSTCACHE_HASH(ip) \ | ||||
(((ip)->s_addr ^ ((ip)->s_addr >> 7) ^ ((ip)->s_addr >> 17)) & \ | (jenkins_hash32((uint32_t *)(ip), 1, V_tcp_hostcache.hashsalt) & \ | ||||
V_tcp_hostcache.hashmask) | V_tcp_hostcache.hashmask) | ||||
/* XXX: What is the recommended hash to get good entropy for IPv6 addresses? */ | |||||
#define HOSTCACHE_HASH6(ip6) \ | #define HOSTCACHE_HASH6(ip6) \ | ||||
(((ip6)->s6_addr32[0] ^ \ | (jenkins_hash32((uint32_t *)&((ip6)->s6_addr32[0]), 4, \ | ||||
(ip6)->s6_addr32[1] ^ \ | V_tcp_hostcache.hashsalt) & \ | ||||
ae: Maybe would it be better to use full IPv6 address to compute hash? | |||||
Done Inline Actionsah, sorry for the noise :) ae: ah, sorry for the noise :) | |||||
(ip6)->s6_addr32[2] ^ \ | |||||
(ip6)->s6_addr32[3]) & \ | |||||
V_tcp_hostcache.hashmask) | V_tcp_hostcache.hashmask) | ||||
#define THC_LOCK(lp) mtx_lock(lp) | #define THC_LOCK(lp) mtx_lock(lp) | ||||
#define THC_UNLOCK(lp) mtx_unlock(lp) | #define THC_UNLOCK(lp) mtx_unlock(lp) | ||||
void | void | ||||
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. | ||||
*/ | */ | ||||
atomic_store_int(&V_tcp_hostcache.cache_count, 0); | atomic_store_int(&V_tcp_hostcache.cache_count, 0); | ||||
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; | ||||
V_tcp_hostcache.hashsalt = arc4random(); | |||||
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)) { | ||||
printf("WARNING: hostcache hash size is not a power of 2.\n"); | printf("WARNING: hostcache hash size is not a power of 2.\n"); | ||||
V_tcp_hostcache.hashsize = TCP_HOSTCACHE_HASHSIZE; /* default */ | V_tcp_hostcache.hashsize = TCP_HOSTCACHE_HASHSIZE; /* default */ | ||||
} | } | ||||
V_tcp_hostcache.hashmask = V_tcp_hostcache.hashsize - 1; | V_tcp_hostcache.hashmask = V_tcp_hostcache.hashsize - 1; | ||||
▲ Show 20 Lines • Show All 581 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
tcp_hc_purge(void *arg) | tcp_hc_purge(void *arg) | ||||
{ | { | ||||
CURVNET_SET((struct vnet *) arg); | CURVNET_SET((struct vnet *) arg); | ||||
int all = 0; | int all = 0; | ||||
if (V_tcp_hostcache.purgeall) { | if (V_tcp_hostcache.purgeall) { | ||||
if (V_tcp_hostcache.purgeall == 2) | |||||
V_tcp_hostcache.hashsalt = arc4random(); | |||||
all = 1; | all = 1; | ||||
V_tcp_hostcache.purgeall = 0; | V_tcp_hostcache.purgeall = 0; | ||||
} | } | ||||
tcp_hc_purge_internal(all); | tcp_hc_purge_internal(all); | ||||
callout_reset(&V_tcp_hc_callout, V_tcp_hostcache.prune * hz, | callout_reset(&V_tcp_hc_callout, V_tcp_hostcache.prune * hz, | ||||
tcp_hc_purge, arg); | tcp_hc_purge, arg); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
/* | /* | ||||
* Expire and purge all entries in hostcache immediately. | * Expire and purge all entries in hostcache immediately. | ||||
*/ | */ | ||||
static int | static int | ||||
sysctl_tcp_hc_purgenow(SYSCTL_HANDLER_ARGS) | sysctl_tcp_hc_purgenow(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error, val; | int error, val; | ||||
val = 0; | val = 0; | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return (error); | return (error); | ||||
if (val == 2) | |||||
V_tcp_hostcache.hashsalt = arc4random(); | |||||
tcp_hc_purge_internal(1); | tcp_hc_purge_internal(1); | ||||
callout_reset(&V_tcp_hc_callout, V_tcp_hostcache.prune * hz, | callout_reset(&V_tcp_hc_callout, V_tcp_hostcache.prune * hz, | ||||
tcp_hc_purge, curvnet); | tcp_hc_purge, curvnet); | ||||
return (0); | return (0); | ||||
} | } |
Maybe would it be better to use full IPv6 address to compute hash?