|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright 1997 Massachusetts Institute of Technology
24: *
25: * Permission to use, copy, modify, and distribute this software and
26: * its documentation for any purpose and without fee is hereby
27: * granted, provided that both the above copyright notice and this
28: * permission notice appear in all copies, that both the above
29: * copyright notice and this permission notice appear in all
30: * supporting documentation, and that the name of M.I.T. not be used
31: * in advertising or publicity pertaining to distribution of the
32: * software without specific, written prior permission. M.I.T. makes
33: * no representations about the suitability of this software for any
34: * purpose. It is provided "as is" without express or implied
35: * warranty.
36: *
37: * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
38: * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
39: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
41: * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48: * SUCH DAMAGE.
49: *
50: */
51:
52: #include <sys/param.h>
53: #include <sys/systm.h>
54: #include <sys/kernel.h>
55: #include <sys/malloc.h>
56: #include <sys/socket.h>
57:
58: #include <net/hostcache.h>
59: #include <net/route.h>
60:
61: MALLOC_DEFINE(M_HOSTCACHE, "hostcache", "per-host cache structure");
62:
63: static struct hctable hctable[AF_MAX];
64: static int hc_timeout_interval = 120;
65: static int hc_maxidle = 1800;
66:
67: static int cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2);
68: static void hc_timeout(void *xhct);
69: static void maybe_bump_hash(struct hctable *hct);
70:
71: int
72: hc_init(int af, struct hccallback *hccb, int init_nelem, int primes)
73: {
74: struct hctable *hct;
75: struct hchead *heads;
76: u_long nelem;
77:
78: hct = &hctable[af];
79: nelem = init_nelem;
80: if (hct->hct_nentries)
81: return 0;
82:
83: if (primes) {
84: heads = phashinit(init_nelem, M_HOSTCACHE, &nelem);
85: } else {
86: int i;
87: MALLOC(heads, struct hchead *, nelem * sizeof *heads,
88: M_HOSTCACHE, M_WAITOK);
89: for (i = 0; i < nelem; i++) {
90: LIST_INIT(&heads[i]);
91: }
92: }
93:
94: hct->hct_heads = heads;
95: hct->hct_nentries = nelem;
96: hct->hct_primes = primes;
97: timeout(hc_timeout, hct, hc_timeout_interval * hz);
98: return 0;
99: }
100:
101: struct hcentry *
102: hc_get(struct sockaddr *sa)
103: {
104: u_long hash;
105: struct hcentry *hc;
106: struct hctable *hct;
107: int s;
108:
109: hct = &hctable[sa->sa_family];
110: if (hct->hct_nentries == 0)
111: return 0;
112: hash = hct->hct_cb->hccb_hash(sa, hct->hct_nentries);
113: hc = hct->hct_heads[hash].lh_first;
114: for (; hc; hc = hc->hc_link.le_next) {
115: if (cmpsa(hc->hc_host, sa) == 0)
116: break;
117: }
118: if (hc == 0)
119: return 0;
120: s = splnet();
121: if (hc->hc_rt && (hc->hc_rt->rt_flags & RTF_UP) == 0) {
122: RTFREE(hc->hc_rt);
123: hc->hc_rt = 0;
124: }
125: if (hc->hc_rt == 0) {
126: hc->hc_rt = rtalloc1(hc->hc_host, 1, 0);
127: }
128: hc_ref(hc);
129: splx(s);
130: /* XXX move to front of list? */
131: return hc;
132: }
133:
134: void
135: hc_ref(struct hcentry *hc)
136: {
137: int s = splnet();
138: if (hc->hc_refcnt++ == 0) {
139: hc->hc_hct->hct_idle--;
140: hc->hc_hct->hct_active++;
141: }
142: splx(s);
143: }
144:
145: void
146: hc_rele(struct hcentry *hc)
147: {
148: int s = splnet();
149: #ifdef DIAGNOSTIC
150: printf("hc_rele: %p: negative refcnt!\n", (void *)hc);
151: #endif
152: hc->hc_refcnt--;
153: if (hc->hc_refcnt == 0) {
154: hc->hc_hct->hct_idle++;
155: hc->hc_hct->hct_active--;
156: hc->hc_idlesince = mono_time; /* XXX right one? */
157: }
158: splx(s);
159: }
160:
161: /*
162: * The user is expected to initialize hc_host with the address and everything
163: * else to the appropriate form of `0'.
164: */
165: int
166: hc_insert(struct hcentry *hc)
167: {
168: struct hcentry *hc2;
169: struct hctable *hct;
170: u_long hash;
171: int s;
172:
173: hct = &hctable[hc->hc_host->sa_family];
174: hash = hct->hct_cb->hccb_hash(hc->hc_host, hct->hct_nentries);
175:
176: hc2 = hct->hct_heads[hash].lh_first;
177: for (; hc2; hc2 = hc2->hc_link.le_next) {
178: if (cmpsa(hc2->hc_host, hc->hc_host) == 0)
179: break;
180: }
181: if (hc2 != 0)
182: return EEXIST;
183: hc->hc_hct = hct;
184: s = splnet();
185: LIST_INSERT_HEAD(&hct->hct_heads[hash], hc, hc_link);
186: hct->hct_idle++;
187: /*
188: * If the table is now more than 75% full, consider bumping it.
189: */
190: if (100 * (hct->hct_idle + hct->hct_active) > 75 * hct->hct_nentries)
191: maybe_bump_hash(hct);
192: splx(s);
193: return 0;
194: }
195:
196: /*
197: * It's not clear to me how much sense this makes as an external interface,
198: * since it is expected that the deletion will normally be handled by
199: * the cache timeout.
200: */
201: int
202: hc_delete(struct hcentry *hc)
203: {
204: struct hctable *hct;
205: int error, s;
206:
207: if (hc->hc_refcnt > 0)
208: return 0;
209:
210: hct = hc->hc_hct;
211: error = hct->hct_cb->hccb_delete(hc);
212: if (error)
213: return 0;
214:
215: s = splnet();
216: LIST_REMOVE(hc, hc_link);
217: hc->hc_hct->hct_idle--;
218: splx(s);
219: FREE(hc, M_HOSTCACHE);
220: return 0;
221: }
222:
223: static void
224: hc_timeout(void *xhct)
225: {
226: struct hcentry *hc;
227: struct hctable *hct;
228: int j, s;
229: time_t start;
230:
231: hct = xhct;
232: start = mono_time.tv_sec; /* for simplicity */
233:
234: if (hct->hct_idle == 0)
235: return;
236: for (j = 0; j < hct->hct_nentries; j++) {
237: for (hc = hct->hct_heads[j].lh_first; hc;
238: hc = hc->hc_link.le_next) {
239: if (hc->hc_refcnt > 0)
240: continue;
241: if (hc->hc_idlesince.tv_sec + hc_maxidle <= start) {
242: if (hct->hct_cb->hccb_delete(hc))
243: continue;
244: s = splnet();
245: LIST_REMOVE(hc, hc_link);
246: hct->hct_idle--;
247: splx(s);
248: }
249: }
250: }
251: /*
252: * Fiddle something here based on tot_idle...
253: */
254: timeout(hc_timeout, xhct, hc_timeout_interval * hz);
255: }
256:
257: static int
258: cmpsa(const struct sockaddr *sa1, const struct sockaddr *sa2)
259: {
260: if (sa1->sa_len != sa2->sa_len)
261: return ((int)sa1->sa_len - sa2->sa_len);
262: return bcmp(sa1, sa2, sa1->sa_len);
263: }
264:
265: static void
266: maybe_bump_hash(struct hctable *hct)
267: {
268: ; /* XXX fill me in */
269: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.