]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/hostcache.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / net / hostcache.c
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 }