]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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 | } |