diff options
author | wollman <wollman@FreeBSD.org> | 1997-06-18 01:24:28 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1997-06-18 01:24:28 +0000 |
commit | 58389eea9e84d5e0c70c01855b3fcaae96853393 (patch) | |
tree | 5763ebb0646b34795852d632f7a2471b8a17e885 /sys/net/hostcache.c | |
parent | e5ccd3d79ccb6d06ad75151df380d357f911bfcb (diff) | |
download | FreeBSD-src-58389eea9e84d5e0c70c01855b3fcaae96853393.zip FreeBSD-src-58389eea9e84d5e0c70c01855b3fcaae96853393.tar.gz |
Add for public examination the beginnings of the per-host cache support
which will for the basis of RTF_PRCLONING's more efficient, better-
designed replacement.
Diffstat (limited to 'sys/net/hostcache.c')
-rw-r--r-- | sys/net/hostcache.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/sys/net/hostcache.c b/sys/net/hostcache.c new file mode 100644 index 0000000..761aa1f --- /dev/null +++ b/sys/net/hostcache.c @@ -0,0 +1,248 @@ +/* + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/socket.h> + +#include <net/hostcache.h> +#include <net/route.h> + +static struct hctable hctable[AF_MAX]; +static int hc_timeout_interval = 120; +static int hc_maxidle = 1800; + +static int cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2); +static void hc_timeout(void *xhct); +static void maybe_bump_hash(struct hctable *hct); + +int +hc_init(int af, struct hccallback *hccb, int init_nelem, int primes) +{ + struct hctable *hct; + struct hchead *heads; + u_long nelem; + + hct = &hctable[af]; + nelem = init_nelem; + if (hct->hct_nentries) + return 0; + + if (primes) { + heads = phashinit(init_nelem, M_HOSTCACHE, &nelem); + } else { + int i; + MALLOC(heads, struct hchead *, nelem * sizeof *heads, + M_HOSTCACHE, M_WAITOK); + for (i = 0; i < nelem; i++) { + LIST_INIT(&heads[i]); + } + } + + hct->hct_heads = heads; + hct->hct_nentries = nelem; + hct->hct_primes = primes; + timeout(hc_timeout, hct, hc_timeout_interval * hz); + return 0; +} + +struct hcentry * +hc_get(struct sockaddr *sa) +{ + u_long hash; + struct hcentry *hc; + struct hctable *hct; + int s; + + hct = &hctable[sa->sa_family]; + if (hct->hct_nentries == 0) + return 0; + hash = hct->hct_cb->hccb_hash(sa, hct->hct_nentries); + hc = hct->hct_heads[hash].lh_first; + for (; hc; hc = hc->hc_link.le_next) { + if (cmpsa(hc->hc_host, sa) == 0) + break; + } + if (hc == 0) + return 0; + s = splnet(); + if (hc->hc_rt && (hc->hc_rt->rt_flags & RTF_UP) == 0) { + RTFREE(hc->hc_rt); + hc->hc_rt = 0; + } + if (hc->hc_rt == 0) { + hc->hc_rt = rtalloc1(hc->hc_host, 1, 0); + } + hc_ref(hc); + splx(s); + /* XXX move to front of list? */ + return hc; +} + +void +hc_ref(struct hcentry *hc) +{ + int s = splnet(); + if (hc->hc_refcnt++ == 0) { + hc->hc_hct->hct_idle--; + hc->hc_hct->hct_active++; + } + splx(s); +} + +void +hc_rele(struct hcentry *hc) +{ + int s = splnet(); +#ifdef DIAGNOSTIC + printf("hc_rele: %p: negative refcnt!\n", (void *)hc); +#endif + hc->hc_refcnt--; + if (hc->hc_refcnt == 0) { + hc->hc_hct->hct_idle++; + hc->hc_hct->hct_active--; + hc->hc_idlesince = mono_time; /* XXX right one? */ + } + splx(s); +} + +/* + * The user is expected to initialize hc_host with the address and everything + * else to the appropriate form of `0'. + */ +int +hc_insert(struct hcentry *hc) +{ + struct hcentry *hc2; + struct hctable *hct; + u_long hash; + int s; + + hct = &hctable[hc->hc_host->sa_family]; + hash = hct->hct_cb->hccb_hash(hc->hc_host, hct->hct_nentries); + + hc2 = hct->hct_heads[hash].lh_first; + for (; hc2; hc2 = hc2->hc_link.le_next) { + if (cmpsa(hc2->hc_host, hc->hc_host) == 0) + break; + } + if (hc2 != 0) + return EEXIST; + hc->hc_hct = hct; + s = splnet(); + LIST_INSERT_HEAD(&hct->hct_heads[hash], hc, hc_link); + hct->hct_idle++; + /* + * If the table is now more than 75% full, consider bumping it. + */ + if (100 * (hct->hct_idle + hct->hct_active) > 75 * hct->hct_nentries) + maybe_bump_hash(hct); + splx(s); + return 0; +} + +/* + * It's not clear to me how much sense this makes as an external interface, + * since it is expected that the deletion will normally be handled by + * the cache timeout. + */ +int +hc_delete(struct hcentry *hc) +{ + struct hctable *hct; + u_long hash; + int error, s; + + if (hc->hc_refcnt > 0) + return 0; + + hct = hc->hc_hct; + error = hct->hct_cb->hccb_delete(hc); + if (error) + return 0; + + s = splnet(); + LIST_REMOVE(hc, hc_link); + hc->hc_hct->hct_idle--; + splx(s); + FREE(hc, M_HOSTCACHE); + return 0; +} + +static void +hc_timeout(void *xhct) +{ + struct hcentry *hc; + struct hctable *hct; + int j, s; + time_t start; + + hct = xhct; + start = mono_time.tv_sec; /* for simplicity */ + + if (hct->hct_idle == 0) + return; + for (j = 0; j < hct->hct_nentries; j++) { + for (hc = hct->hct_heads[j].lh_first; hc; + hc = hc->hc_link.le_next) { + if (hc->hc_refcnt > 0) + continue; + if (hc->hc_idlesince.tv_sec + hc_maxidle <= start) { + if (hct->hct_cb->hccb_delete(hc)) + continue; + s = splnet(); + LIST_REMOVE(hc, hc_link); + hct->hct_idle--; + splx(s); + } + } + } + /* + * Fiddle something here based on tot_idle... + */ + timeout(hc_timeout, xhct, hc_timeout_interval * hz); +} + +static int +cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + if (sa1->sa_len != sa2->sa_len) + return ((int)sa1->sa_len - sa2->sa_len); + return bcmp(sa1, sa2, sa1->sa_len); +} + +static void +maybe_bump_hash(struct hctable *hct) +{ + ; /* XXX fill me in */ +} |