tcp_vtw.c revision 1.6.2.2 1 1.6.2.2 jruoho /*
2 1.6.2.2 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc.
3 1.6.2.2 jruoho * All rights reserved.
4 1.6.2.2 jruoho *
5 1.6.2.2 jruoho * This code is derived from software contributed to The NetBSD Foundation
6 1.6.2.2 jruoho * by Coyote Point Systems, Inc.
7 1.6.2.2 jruoho *
8 1.6.2.2 jruoho * Redistribution and use in source and binary forms, with or without
9 1.6.2.2 jruoho * modification, are permitted provided that the following conditions
10 1.6.2.2 jruoho * are met:
11 1.6.2.2 jruoho * 1. Redistributions of source code must retain the above copyright
12 1.6.2.2 jruoho * notice, this list of conditions and the following disclaimer.
13 1.6.2.2 jruoho * 2. Redistributions in binary form must reproduce the above copyright
14 1.6.2.2 jruoho * notice, this list of conditions and the following disclaimer in the
15 1.6.2.2 jruoho * documentation and/or other materials provided with the distribution.
16 1.6.2.2 jruoho *
17 1.6.2.2 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 1.6.2.2 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.6.2.2 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.6.2.2 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 1.6.2.2 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.6.2.2 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.6.2.2 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.6.2.2 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.6.2.2 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.6.2.2 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.6.2.2 jruoho * POSSIBILITY OF SUCH DAMAGE.
28 1.6.2.2 jruoho */
29 1.6.2.2 jruoho #include <sys/cdefs.h>
30 1.6.2.2 jruoho
31 1.6.2.2 jruoho #include "opt_ddb.h"
32 1.6.2.2 jruoho #include "opt_inet.h"
33 1.6.2.2 jruoho #include "opt_ipsec.h"
34 1.6.2.2 jruoho #include "opt_inet_csum.h"
35 1.6.2.2 jruoho #include "opt_tcp_debug.h"
36 1.6.2.2 jruoho
37 1.6.2.2 jruoho #include <sys/param.h>
38 1.6.2.2 jruoho #include <sys/systm.h>
39 1.6.2.2 jruoho #include <sys/malloc.h>
40 1.6.2.2 jruoho #include <sys/kmem.h>
41 1.6.2.2 jruoho #include <sys/mbuf.h>
42 1.6.2.2 jruoho #include <sys/protosw.h>
43 1.6.2.2 jruoho #include <sys/socket.h>
44 1.6.2.2 jruoho #include <sys/socketvar.h>
45 1.6.2.2 jruoho #include <sys/errno.h>
46 1.6.2.2 jruoho #include <sys/syslog.h>
47 1.6.2.2 jruoho #include <sys/pool.h>
48 1.6.2.2 jruoho #include <sys/domain.h>
49 1.6.2.2 jruoho #include <sys/kernel.h>
50 1.6.2.2 jruoho #include <net/if.h>
51 1.6.2.2 jruoho #include <net/route.h>
52 1.6.2.2 jruoho #include <net/if_types.h>
53 1.6.2.2 jruoho
54 1.6.2.2 jruoho #include <netinet/in.h>
55 1.6.2.2 jruoho #include <netinet/in_systm.h>
56 1.6.2.2 jruoho #include <netinet/ip.h>
57 1.6.2.2 jruoho #include <netinet/in_pcb.h>
58 1.6.2.2 jruoho #include <netinet/in_var.h>
59 1.6.2.2 jruoho #include <netinet/ip_var.h>
60 1.6.2.2 jruoho #include <netinet/in_offload.h>
61 1.6.2.2 jruoho #include <netinet/ip6.h>
62 1.6.2.2 jruoho #include <netinet6/ip6_var.h>
63 1.6.2.2 jruoho #include <netinet6/in6_pcb.h>
64 1.6.2.2 jruoho #include <netinet6/ip6_var.h>
65 1.6.2.2 jruoho #include <netinet6/in6_var.h>
66 1.6.2.2 jruoho #include <netinet/icmp6.h>
67 1.6.2.2 jruoho #include <netinet6/nd6.h>
68 1.6.2.2 jruoho
69 1.6.2.2 jruoho #include <netinet/tcp.h>
70 1.6.2.2 jruoho #include <netinet/tcp_fsm.h>
71 1.6.2.2 jruoho #include <netinet/tcp_seq.h>
72 1.6.2.2 jruoho #include <netinet/tcp_timer.h>
73 1.6.2.2 jruoho #include <netinet/tcp_var.h>
74 1.6.2.2 jruoho #include <netinet/tcp_private.h>
75 1.6.2.2 jruoho #include <netinet/tcpip.h>
76 1.6.2.2 jruoho
77 1.6.2.2 jruoho #include <machine/stdarg.h>
78 1.6.2.2 jruoho #include <netinet/tcp_vtw.h>
79 1.6.2.2 jruoho
80 1.6.2.2 jruoho __KERNEL_RCSID(0, "$NetBSD: tcp_vtw.c,v 1.6.2.2 2011/06/06 09:09:57 jruoho Exp $");
81 1.6.2.2 jruoho
82 1.6.2.2 jruoho #define db_trace(__a, __b) do { } while (/*CONSTCOND*/0)
83 1.6.2.2 jruoho
84 1.6.2.2 jruoho static void vtw_debug_init(void);
85 1.6.2.2 jruoho
86 1.6.2.2 jruoho fatp_ctl_t fat_tcpv4;
87 1.6.2.2 jruoho fatp_ctl_t fat_tcpv6;
88 1.6.2.2 jruoho vtw_ctl_t vtw_tcpv4[VTW_NCLASS];
89 1.6.2.2 jruoho vtw_ctl_t vtw_tcpv6[VTW_NCLASS];
90 1.6.2.2 jruoho vtw_stats_t vtw_stats;
91 1.6.2.2 jruoho
92 1.6.2.2 jruoho /* We provide state for the lookup_ports iterator.
93 1.6.2.2 jruoho * As currently we are netlock-protected, there is one.
94 1.6.2.2 jruoho * If we were finer-grain, we would have one per CPU.
95 1.6.2.2 jruoho * I do not want to be in the business of alloc/free.
96 1.6.2.2 jruoho * The best alternate would be allocate on the caller's
97 1.6.2.2 jruoho * stack, but that would require them to know the struct,
98 1.6.2.2 jruoho * or at least the size.
99 1.6.2.2 jruoho * See how she goes.
100 1.6.2.2 jruoho */
101 1.6.2.2 jruoho struct tcp_ports_iterator {
102 1.6.2.2 jruoho union {
103 1.6.2.2 jruoho struct in_addr v4;
104 1.6.2.2 jruoho struct in6_addr v6;
105 1.6.2.2 jruoho } addr;
106 1.6.2.2 jruoho u_int port;
107 1.6.2.2 jruoho
108 1.6.2.2 jruoho uint32_t wild : 1;
109 1.6.2.2 jruoho
110 1.6.2.2 jruoho vtw_ctl_t *ctl;
111 1.6.2.2 jruoho fatp_t *fp;
112 1.6.2.2 jruoho
113 1.6.2.2 jruoho uint16_t slot_idx;
114 1.6.2.2 jruoho uint16_t ctl_idx;
115 1.6.2.2 jruoho };
116 1.6.2.2 jruoho
117 1.6.2.2 jruoho static struct tcp_ports_iterator tcp_ports_iterator_v4;
118 1.6.2.2 jruoho static struct tcp_ports_iterator tcp_ports_iterator_v6;
119 1.6.2.2 jruoho
120 1.6.2.2 jruoho static int vtw_age(vtw_ctl_t *, struct timeval *);
121 1.6.2.2 jruoho
122 1.6.2.2 jruoho /*!\brief allocate a fat pointer from a collection.
123 1.6.2.2 jruoho */
124 1.6.2.2 jruoho static fatp_t *
125 1.6.2.2 jruoho fatp_alloc(fatp_ctl_t *fat)
126 1.6.2.2 jruoho {
127 1.6.2.2 jruoho fatp_t *fp = 0;
128 1.6.2.2 jruoho
129 1.6.2.2 jruoho if (fat->nfree) {
130 1.6.2.2 jruoho fp = fat->free;
131 1.6.2.2 jruoho if (fp) {
132 1.6.2.2 jruoho fat->free = fatp_next(fat, fp);
133 1.6.2.2 jruoho --fat->nfree;
134 1.6.2.2 jruoho ++fat->nalloc;
135 1.6.2.2 jruoho fp->nxt = 0;
136 1.6.2.2 jruoho
137 1.6.2.2 jruoho KASSERT(!fp->inuse);
138 1.6.2.2 jruoho }
139 1.6.2.2 jruoho }
140 1.6.2.2 jruoho
141 1.6.2.2 jruoho return fp;
142 1.6.2.2 jruoho }
143 1.6.2.2 jruoho
144 1.6.2.2 jruoho /*!\brief free a fat pointer.
145 1.6.2.2 jruoho */
146 1.6.2.2 jruoho static void
147 1.6.2.2 jruoho fatp_free(fatp_ctl_t *fat, fatp_t *fp)
148 1.6.2.2 jruoho {
149 1.6.2.2 jruoho if (fp) {
150 1.6.2.2 jruoho KASSERT(!fp->inuse);
151 1.6.2.2 jruoho KASSERT(!fp->nxt);
152 1.6.2.2 jruoho
153 1.6.2.2 jruoho fp->nxt = fatp_index(fat, fat->free);
154 1.6.2.2 jruoho fat->free = fp;
155 1.6.2.2 jruoho
156 1.6.2.2 jruoho ++fat->nfree;
157 1.6.2.2 jruoho --fat->nalloc;
158 1.6.2.2 jruoho }
159 1.6.2.2 jruoho }
160 1.6.2.2 jruoho
161 1.6.2.2 jruoho /*!\brief initialise a collection of fat pointers.
162 1.6.2.2 jruoho *
163 1.6.2.2 jruoho *\param n # hash buckets
164 1.6.2.2 jruoho *\param m total # fat pointers to allocate
165 1.6.2.2 jruoho *
166 1.6.2.2 jruoho * We allocate 2x as much, as we have two hashes: full and lport only.
167 1.6.2.2 jruoho */
168 1.6.2.2 jruoho static void
169 1.6.2.2 jruoho fatp_init(fatp_ctl_t *fat, uint32_t n, uint32_t m,
170 1.6.2.2 jruoho fatp_t *fat_base, fatp_t **fat_hash)
171 1.6.2.2 jruoho {
172 1.6.2.2 jruoho fatp_t *fp;
173 1.6.2.2 jruoho
174 1.6.2.2 jruoho KASSERT(n <= FATP_MAX / 2);
175 1.6.2.2 jruoho
176 1.6.2.2 jruoho fat->hash = fat_hash;
177 1.6.2.2 jruoho fat->base = fat_base;
178 1.6.2.2 jruoho
179 1.6.2.2 jruoho fat->port = &fat->hash[m];
180 1.6.2.2 jruoho
181 1.6.2.2 jruoho fat->mask = m - 1; // ASSERT is power of 2 (m)
182 1.6.2.2 jruoho fat->lim = fat->base + 2*n - 1;
183 1.6.2.2 jruoho fat->nfree = 0;
184 1.6.2.2 jruoho fat->nalloc = 2*n;
185 1.6.2.2 jruoho
186 1.6.2.2 jruoho /* Initialise the free list.
187 1.6.2.2 jruoho */
188 1.6.2.2 jruoho for (fp = fat->lim; fp >= fat->base; --fp) {
189 1.6.2.2 jruoho fatp_free(fat, fp);
190 1.6.2.2 jruoho }
191 1.6.2.2 jruoho }
192 1.6.2.2 jruoho
193 1.6.2.2 jruoho /*
194 1.6.2.2 jruoho * The `xtra' is XORed into the tag stored.
195 1.6.2.2 jruoho */
196 1.6.2.2 jruoho static uint32_t fatp_xtra[] = {
197 1.6.2.2 jruoho 0x11111111,0x22222222,0x33333333,0x44444444,
198 1.6.2.2 jruoho 0x55555555,0x66666666,0x77777777,0x88888888,
199 1.6.2.2 jruoho 0x12121212,0x21212121,0x34343434,0x43434343,
200 1.6.2.2 jruoho 0x56565656,0x65656565,0x78787878,0x87878787,
201 1.6.2.2 jruoho 0x11221122,0x22112211,0x33443344,0x44334433,
202 1.6.2.2 jruoho 0x55665566,0x66556655,0x77887788,0x88778877,
203 1.6.2.2 jruoho 0x11112222,0x22221111,0x33334444,0x44443333,
204 1.6.2.2 jruoho 0x55556666,0x66665555,0x77778888,0x88887777,
205 1.6.2.2 jruoho };
206 1.6.2.2 jruoho
207 1.6.2.2 jruoho /*!\brief turn a {fatp_t*,slot} into an integral key.
208 1.6.2.2 jruoho *
209 1.6.2.2 jruoho * The key can be used to obtain the fatp_t, and the slot,
210 1.6.2.2 jruoho * as it directly encodes them.
211 1.6.2.2 jruoho */
212 1.6.2.2 jruoho static inline uint32_t
213 1.6.2.2 jruoho fatp_key(fatp_ctl_t *fat, fatp_t *fp, uint32_t slot)
214 1.6.2.2 jruoho {
215 1.6.2.2 jruoho CTASSERT(CACHE_LINE_SIZE == 32 ||
216 1.6.2.2 jruoho CACHE_LINE_SIZE == 64 ||
217 1.6.2.2 jruoho CACHE_LINE_SIZE == 128);
218 1.6.2.2 jruoho
219 1.6.2.2 jruoho switch (fatp_ntags()) {
220 1.6.2.2 jruoho case 7:
221 1.6.2.2 jruoho return (fatp_index(fat, fp) << 3) | slot;
222 1.6.2.2 jruoho case 15:
223 1.6.2.2 jruoho return (fatp_index(fat, fp) << 4) | slot;
224 1.6.2.2 jruoho case 31:
225 1.6.2.2 jruoho return (fatp_index(fat, fp) << 5) | slot;
226 1.6.2.2 jruoho default:
227 1.6.2.2 jruoho KASSERT(0 && "no support, for no good reason");
228 1.6.2.2 jruoho return ~0;
229 1.6.2.2 jruoho }
230 1.6.2.2 jruoho }
231 1.6.2.2 jruoho
232 1.6.2.2 jruoho static inline uint32_t
233 1.6.2.2 jruoho fatp_slot_from_key(fatp_ctl_t *fat, uint32_t key)
234 1.6.2.2 jruoho {
235 1.6.2.2 jruoho CTASSERT(CACHE_LINE_SIZE == 32 ||
236 1.6.2.2 jruoho CACHE_LINE_SIZE == 64 ||
237 1.6.2.2 jruoho CACHE_LINE_SIZE == 128);
238 1.6.2.2 jruoho
239 1.6.2.2 jruoho switch (fatp_ntags()) {
240 1.6.2.2 jruoho case 7:
241 1.6.2.2 jruoho return key & 7;
242 1.6.2.2 jruoho case 15:
243 1.6.2.2 jruoho return key & 15;
244 1.6.2.2 jruoho case 31:
245 1.6.2.2 jruoho return key & 31;
246 1.6.2.2 jruoho default:
247 1.6.2.2 jruoho KASSERT(0 && "no support, for no good reason");
248 1.6.2.2 jruoho return ~0;
249 1.6.2.2 jruoho }
250 1.6.2.2 jruoho }
251 1.6.2.2 jruoho
252 1.6.2.2 jruoho static inline fatp_t *
253 1.6.2.2 jruoho fatp_from_key(fatp_ctl_t *fat, uint32_t key)
254 1.6.2.2 jruoho {
255 1.6.2.2 jruoho CTASSERT(CACHE_LINE_SIZE == 32 ||
256 1.6.2.2 jruoho CACHE_LINE_SIZE == 64 ||
257 1.6.2.2 jruoho CACHE_LINE_SIZE == 128);
258 1.6.2.2 jruoho
259 1.6.2.2 jruoho switch (fatp_ntags()) {
260 1.6.2.2 jruoho case 7:
261 1.6.2.2 jruoho key >>= 3;
262 1.6.2.2 jruoho break;
263 1.6.2.2 jruoho case 15:
264 1.6.2.2 jruoho key >>= 4;
265 1.6.2.2 jruoho break;
266 1.6.2.2 jruoho case 31:
267 1.6.2.2 jruoho key >>= 5;
268 1.6.2.2 jruoho break;
269 1.6.2.2 jruoho default:
270 1.6.2.2 jruoho KASSERT(0 && "no support, for no good reason");
271 1.6.2.2 jruoho return 0;
272 1.6.2.2 jruoho }
273 1.6.2.2 jruoho
274 1.6.2.2 jruoho return key ? fat->base + key - 1 : 0;
275 1.6.2.2 jruoho }
276 1.6.2.2 jruoho
277 1.6.2.2 jruoho static inline uint32_t
278 1.6.2.2 jruoho idx_encode(vtw_ctl_t *ctl, uint32_t idx)
279 1.6.2.2 jruoho {
280 1.6.2.2 jruoho return (idx << ctl->idx_bits) | idx;
281 1.6.2.2 jruoho }
282 1.6.2.2 jruoho
283 1.6.2.2 jruoho static inline uint32_t
284 1.6.2.2 jruoho idx_decode(vtw_ctl_t *ctl, uint32_t bits)
285 1.6.2.2 jruoho {
286 1.6.2.2 jruoho uint32_t idx = bits & ctl->idx_mask;
287 1.6.2.2 jruoho
288 1.6.2.2 jruoho if (idx_encode(ctl, idx) == bits)
289 1.6.2.2 jruoho return idx;
290 1.6.2.2 jruoho else
291 1.6.2.2 jruoho return ~0;
292 1.6.2.2 jruoho }
293 1.6.2.2 jruoho
294 1.6.2.2 jruoho /*!\brief insert index into fatp hash
295 1.6.2.2 jruoho *
296 1.6.2.2 jruoho *\param idx - index of element being placed in hash chain
297 1.6.2.2 jruoho *\param tag - 32-bit tag identifier
298 1.6.2.2 jruoho *
299 1.6.2.2 jruoho *\returns
300 1.6.2.2 jruoho * value which can be used to locate entry.
301 1.6.2.2 jruoho *
302 1.6.2.2 jruoho *\note
303 1.6.2.2 jruoho * we rely on the fact that there are unused high bits in the index
304 1.6.2.2 jruoho * for verification purposes on lookup.
305 1.6.2.2 jruoho */
306 1.6.2.2 jruoho
307 1.6.2.2 jruoho static inline uint32_t
308 1.6.2.2 jruoho fatp_vtw_inshash(fatp_ctl_t *fat, uint32_t idx, uint32_t tag, int which,
309 1.6.2.2 jruoho void *dbg)
310 1.6.2.2 jruoho {
311 1.6.2.2 jruoho fatp_t *fp;
312 1.6.2.2 jruoho fatp_t **hash = (which ? fat->port : fat->hash);
313 1.6.2.2 jruoho int i;
314 1.6.2.2 jruoho
315 1.6.2.2 jruoho fp = hash[tag & fat->mask];
316 1.6.2.2 jruoho
317 1.6.2.2 jruoho while (!fp || fatp_full(fp)) {
318 1.6.2.2 jruoho fatp_t *fq;
319 1.6.2.2 jruoho
320 1.6.2.2 jruoho /* All entries are inuse at the top level.
321 1.6.2.2 jruoho * We allocate a spare, and push the top level
322 1.6.2.2 jruoho * down one. All entries in the fp we push down
323 1.6.2.2 jruoho * (think of a tape worm here) will be expelled sooner than
324 1.6.2.2 jruoho * any entries added subsequently to this hash bucket.
325 1.6.2.2 jruoho * This is a property of the time waits we are exploiting.
326 1.6.2.2 jruoho */
327 1.6.2.2 jruoho
328 1.6.2.2 jruoho fq = fatp_alloc(fat);
329 1.6.2.2 jruoho if (!fq) {
330 1.6.2.2 jruoho vtw_age(fat->vtw, 0);
331 1.6.2.2 jruoho fp = hash[tag & fat->mask];
332 1.6.2.2 jruoho continue;
333 1.6.2.2 jruoho }
334 1.6.2.2 jruoho
335 1.6.2.2 jruoho fq->inuse = 0;
336 1.6.2.2 jruoho fq->nxt = fatp_index(fat, fp);
337 1.6.2.2 jruoho
338 1.6.2.2 jruoho hash[tag & fat->mask] = fq;
339 1.6.2.2 jruoho
340 1.6.2.2 jruoho fp = fq;
341 1.6.2.2 jruoho }
342 1.6.2.2 jruoho
343 1.6.2.2 jruoho KASSERT(!fatp_full(fp));
344 1.6.2.2 jruoho
345 1.6.2.2 jruoho /* Fill highest index first. Lookup is lowest first.
346 1.6.2.2 jruoho */
347 1.6.2.2 jruoho for (i = fatp_ntags(); --i >= 0; ) {
348 1.6.2.2 jruoho if (!((1 << i) & fp->inuse)) {
349 1.6.2.2 jruoho break;
350 1.6.2.2 jruoho }
351 1.6.2.2 jruoho }
352 1.6.2.2 jruoho
353 1.6.2.2 jruoho fp->inuse |= 1 << i;
354 1.6.2.2 jruoho fp->tag[i] = tag ^ idx_encode(fat->vtw, idx) ^ fatp_xtra[i];
355 1.6.2.2 jruoho
356 1.6.2.2 jruoho db_trace(KTR_VTW
357 1.6.2.2 jruoho , (fp, "fat: inuse %5.5x tag[%x] %8.8x"
358 1.6.2.2 jruoho , fp->inuse
359 1.6.2.2 jruoho , i, fp->tag[i]));
360 1.6.2.2 jruoho
361 1.6.2.2 jruoho return fatp_key(fat, fp, i);
362 1.6.2.2 jruoho }
363 1.6.2.2 jruoho
364 1.6.2.2 jruoho static inline int
365 1.6.2.2 jruoho vtw_alive(const vtw_t *vtw)
366 1.6.2.2 jruoho {
367 1.6.2.2 jruoho return vtw->hashed && vtw->expire.tv_sec;
368 1.6.2.2 jruoho }
369 1.6.2.2 jruoho
370 1.6.2.2 jruoho static inline uint32_t
371 1.6.2.2 jruoho vtw_index_v4(vtw_ctl_t *ctl, vtw_v4_t *v4)
372 1.6.2.2 jruoho {
373 1.6.2.2 jruoho if (ctl->base.v4 <= v4 && v4 <= ctl->lim.v4)
374 1.6.2.2 jruoho return v4 - ctl->base.v4;
375 1.6.2.2 jruoho
376 1.6.2.2 jruoho KASSERT(0 && "vtw out of bounds");
377 1.6.2.2 jruoho
378 1.6.2.2 jruoho return ~0;
379 1.6.2.2 jruoho }
380 1.6.2.2 jruoho
381 1.6.2.2 jruoho static inline uint32_t
382 1.6.2.2 jruoho vtw_index_v6(vtw_ctl_t *ctl, vtw_v6_t *v6)
383 1.6.2.2 jruoho {
384 1.6.2.2 jruoho if (ctl->base.v6 <= v6 && v6 <= ctl->lim.v6)
385 1.6.2.2 jruoho return v6 - ctl->base.v6;
386 1.6.2.2 jruoho
387 1.6.2.2 jruoho KASSERT(0 && "vtw out of bounds");
388 1.6.2.2 jruoho
389 1.6.2.2 jruoho return ~0;
390 1.6.2.2 jruoho }
391 1.6.2.2 jruoho
392 1.6.2.2 jruoho static inline uint32_t
393 1.6.2.2 jruoho vtw_index(vtw_ctl_t *ctl, vtw_t *vtw)
394 1.6.2.2 jruoho {
395 1.6.2.2 jruoho if (ctl->clidx)
396 1.6.2.2 jruoho ctl = ctl->ctl;
397 1.6.2.2 jruoho
398 1.6.2.2 jruoho if (ctl->is_v4)
399 1.6.2.2 jruoho return vtw_index_v4(ctl, (vtw_v4_t *)vtw);
400 1.6.2.2 jruoho
401 1.6.2.2 jruoho if (ctl->is_v6)
402 1.6.2.2 jruoho return vtw_index_v6(ctl, (vtw_v6_t *)vtw);
403 1.6.2.2 jruoho
404 1.6.2.2 jruoho KASSERT(0 && "neither 4 nor 6. most curious.");
405 1.6.2.2 jruoho
406 1.6.2.2 jruoho return ~0;
407 1.6.2.2 jruoho }
408 1.6.2.2 jruoho
409 1.6.2.2 jruoho static inline vtw_t *
410 1.6.2.2 jruoho vtw_from_index(vtw_ctl_t *ctl, uint32_t idx)
411 1.6.2.2 jruoho {
412 1.6.2.2 jruoho if (ctl->clidx)
413 1.6.2.2 jruoho ctl = ctl->ctl;
414 1.6.2.2 jruoho
415 1.6.2.2 jruoho /* See if the index looks like it might be an index.
416 1.6.2.2 jruoho * Bits on outside of the valid index bits is a give away.
417 1.6.2.2 jruoho */
418 1.6.2.2 jruoho idx = idx_decode(ctl, idx);
419 1.6.2.2 jruoho
420 1.6.2.2 jruoho if (idx == ~0) {
421 1.6.2.2 jruoho return 0;
422 1.6.2.2 jruoho } else if (ctl->is_v4) {
423 1.6.2.2 jruoho vtw_v4_t *vtw = ctl->base.v4 + idx;
424 1.6.2.2 jruoho
425 1.6.2.2 jruoho return (ctl->base.v4 <= vtw && vtw <= ctl->lim.v4)
426 1.6.2.2 jruoho ? &vtw->common : 0;
427 1.6.2.2 jruoho } else if (ctl->is_v6) {
428 1.6.2.2 jruoho vtw_v6_t *vtw = ctl->base.v6 + idx;
429 1.6.2.2 jruoho
430 1.6.2.2 jruoho return (ctl->base.v6 <= vtw && vtw <= ctl->lim.v6)
431 1.6.2.2 jruoho ? &vtw->common : 0;
432 1.6.2.2 jruoho } else {
433 1.6.2.2 jruoho KASSERT(0 && "badness");
434 1.6.2.2 jruoho return 0;
435 1.6.2.2 jruoho }
436 1.6.2.2 jruoho }
437 1.6.2.2 jruoho
438 1.6.2.2 jruoho /*!\brief return the next vtw after this one.
439 1.6.2.2 jruoho *
440 1.6.2.2 jruoho * Due to the differing sizes of the entries in differing
441 1.6.2.2 jruoho * arenas, we have to ensure we ++ the correct pointer type.
442 1.6.2.2 jruoho *
443 1.6.2.2 jruoho * Also handles wrap.
444 1.6.2.2 jruoho */
445 1.6.2.2 jruoho static inline vtw_t *
446 1.6.2.2 jruoho vtw_next(vtw_ctl_t *ctl, vtw_t *vtw)
447 1.6.2.2 jruoho {
448 1.6.2.2 jruoho if (ctl->is_v4) {
449 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
450 1.6.2.2 jruoho
451 1.6.2.2 jruoho vtw = &(++v4)->common;
452 1.6.2.2 jruoho } else {
453 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
454 1.6.2.2 jruoho
455 1.6.2.2 jruoho vtw = &(++v6)->common;
456 1.6.2.2 jruoho }
457 1.6.2.2 jruoho
458 1.6.2.2 jruoho if (vtw > ctl->lim.v)
459 1.6.2.2 jruoho vtw = ctl->base.v;
460 1.6.2.2 jruoho
461 1.6.2.2 jruoho return vtw;
462 1.6.2.2 jruoho }
463 1.6.2.2 jruoho
464 1.6.2.2 jruoho /*!\brief remove entry from FATP hash chains
465 1.6.2.2 jruoho */
466 1.6.2.2 jruoho static inline void
467 1.6.2.2 jruoho vtw_unhash(vtw_ctl_t *ctl, vtw_t *vtw)
468 1.6.2.2 jruoho {
469 1.6.2.2 jruoho fatp_ctl_t *fat = ctl->fat;
470 1.6.2.2 jruoho fatp_t *fp;
471 1.6.2.2 jruoho uint32_t key = vtw->key;
472 1.6.2.2 jruoho uint32_t tag, slot, idx;
473 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
474 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
475 1.6.2.2 jruoho
476 1.6.2.2 jruoho if (!vtw->hashed) {
477 1.6.2.2 jruoho KASSERT(0 && "unhashed");
478 1.6.2.2 jruoho return;
479 1.6.2.2 jruoho }
480 1.6.2.2 jruoho
481 1.6.2.2 jruoho if (fat->vtw->is_v4) {
482 1.6.2.2 jruoho tag = v4_tag(v4->faddr, v4->fport, v4->laddr, v4->lport);
483 1.6.2.2 jruoho } else if (fat->vtw->is_v6) {
484 1.6.2.2 jruoho tag = v6_tag(&v6->faddr, v6->fport, &v6->laddr, v6->lport);
485 1.6.2.2 jruoho } else {
486 1.6.2.2 jruoho tag = 0;
487 1.6.2.2 jruoho KASSERT(0 && "not reached");
488 1.6.2.2 jruoho }
489 1.6.2.2 jruoho
490 1.6.2.2 jruoho /* Remove from fat->hash[]
491 1.6.2.2 jruoho */
492 1.6.2.2 jruoho slot = fatp_slot_from_key(fat, key);
493 1.6.2.2 jruoho fp = fatp_from_key(fat, key);
494 1.6.2.2 jruoho idx = vtw_index(ctl, vtw);
495 1.6.2.2 jruoho
496 1.6.2.2 jruoho db_trace(KTR_VTW
497 1.6.2.2 jruoho , (fp, "fat: del inuse %5.5x slot %x idx %x key %x tag %x"
498 1.6.2.2 jruoho , fp->inuse, slot, idx, key, tag));
499 1.6.2.2 jruoho
500 1.6.2.2 jruoho KASSERT(fp->inuse & (1 << slot));
501 1.6.2.2 jruoho KASSERT(fp->tag[slot] == (tag ^ idx_encode(ctl, idx)
502 1.6.2.2 jruoho ^ fatp_xtra[slot]));
503 1.6.2.2 jruoho
504 1.6.2.2 jruoho if ((fp->inuse & (1 << slot))
505 1.6.2.2 jruoho && fp->tag[slot] == (tag ^ idx_encode(ctl, idx)
506 1.6.2.2 jruoho ^ fatp_xtra[slot])) {
507 1.6.2.2 jruoho fp->inuse ^= 1 << slot;
508 1.6.2.2 jruoho fp->tag[slot] = 0;
509 1.6.2.2 jruoho
510 1.6.2.2 jruoho /* When we delete entries, we do not compact. This is
511 1.6.2.2 jruoho * due to temporality. We add entries, and they
512 1.6.2.2 jruoho * (eventually) expire. Older entries will be further
513 1.6.2.2 jruoho * down the chain.
514 1.6.2.2 jruoho */
515 1.6.2.2 jruoho if (!fp->inuse) {
516 1.6.2.2 jruoho uint32_t hi = tag & fat->mask;
517 1.6.2.2 jruoho fatp_t *fq = 0;
518 1.6.2.2 jruoho fatp_t *fr = fat->hash[hi];
519 1.6.2.2 jruoho
520 1.6.2.2 jruoho while (fr && fr != fp) {
521 1.6.2.2 jruoho fr = fatp_next(fat, fq = fr);
522 1.6.2.2 jruoho }
523 1.6.2.2 jruoho
524 1.6.2.2 jruoho if (fr == fp) {
525 1.6.2.2 jruoho if (fq) {
526 1.6.2.2 jruoho fq->nxt = fp->nxt;
527 1.6.2.2 jruoho fp->nxt = 0;
528 1.6.2.2 jruoho fatp_free(fat, fp);
529 1.6.2.2 jruoho } else {
530 1.6.2.2 jruoho KASSERT(fat->hash[hi] == fp);
531 1.6.2.2 jruoho
532 1.6.2.2 jruoho if (fp->nxt) {
533 1.6.2.2 jruoho fat->hash[hi]
534 1.6.2.2 jruoho = fatp_next(fat, fp);
535 1.6.2.2 jruoho fp->nxt = 0;
536 1.6.2.2 jruoho fatp_free(fat, fp);
537 1.6.2.2 jruoho } else {
538 1.6.2.2 jruoho /* retain for next use.
539 1.6.2.2 jruoho */
540 1.6.2.2 jruoho ;
541 1.6.2.2 jruoho }
542 1.6.2.2 jruoho }
543 1.6.2.2 jruoho } else {
544 1.6.2.2 jruoho fr = fat->hash[hi];
545 1.6.2.2 jruoho
546 1.6.2.2 jruoho do {
547 1.6.2.2 jruoho db_trace(KTR_VTW
548 1.6.2.2 jruoho , (fr
549 1.6.2.2 jruoho , "fat:*del inuse %5.5x"
550 1.6.2.2 jruoho " nxt %x"
551 1.6.2.2 jruoho , fr->inuse, fr->nxt));
552 1.6.2.2 jruoho
553 1.6.2.2 jruoho fr = fatp_next(fat, fq = fr);
554 1.6.2.2 jruoho } while (fr && fr != fp);
555 1.6.2.2 jruoho
556 1.6.2.2 jruoho KASSERT(0 && "oops");
557 1.6.2.2 jruoho }
558 1.6.2.2 jruoho }
559 1.6.2.2 jruoho vtw->key ^= ~0;
560 1.6.2.2 jruoho }
561 1.6.2.2 jruoho
562 1.6.2.2 jruoho if (fat->vtw->is_v4) {
563 1.6.2.2 jruoho tag = v4_port_tag(v4->lport);
564 1.6.2.2 jruoho } else if (fat->vtw->is_v6) {
565 1.6.2.2 jruoho tag = v6_port_tag(v6->lport);
566 1.6.2.2 jruoho }
567 1.6.2.2 jruoho
568 1.6.2.2 jruoho /* Remove from fat->port[]
569 1.6.2.2 jruoho */
570 1.6.2.2 jruoho key = vtw->port_key;
571 1.6.2.2 jruoho slot = fatp_slot_from_key(fat, key);
572 1.6.2.2 jruoho fp = fatp_from_key(fat, key);
573 1.6.2.2 jruoho idx = vtw_index(ctl, vtw);
574 1.6.2.2 jruoho
575 1.6.2.2 jruoho db_trace(KTR_VTW
576 1.6.2.2 jruoho , (fp, "fatport: del inuse %5.5x"
577 1.6.2.2 jruoho " slot %x idx %x key %x tag %x"
578 1.6.2.2 jruoho , fp->inuse, slot, idx, key, tag));
579 1.6.2.2 jruoho
580 1.6.2.2 jruoho KASSERT(fp->inuse & (1 << slot));
581 1.6.2.2 jruoho KASSERT(fp->tag[slot] == (tag ^ idx_encode(ctl, idx)
582 1.6.2.2 jruoho ^ fatp_xtra[slot]));
583 1.6.2.2 jruoho
584 1.6.2.2 jruoho if ((fp->inuse & (1 << slot))
585 1.6.2.2 jruoho && fp->tag[slot] == (tag ^ idx_encode(ctl, idx)
586 1.6.2.2 jruoho ^ fatp_xtra[slot])) {
587 1.6.2.2 jruoho fp->inuse ^= 1 << slot;
588 1.6.2.2 jruoho fp->tag[slot] = 0;
589 1.6.2.2 jruoho
590 1.6.2.2 jruoho if (!fp->inuse) {
591 1.6.2.2 jruoho uint32_t hi = tag & fat->mask;
592 1.6.2.2 jruoho fatp_t *fq = 0;
593 1.6.2.2 jruoho fatp_t *fr = fat->port[hi];
594 1.6.2.2 jruoho
595 1.6.2.2 jruoho while (fr && fr != fp) {
596 1.6.2.2 jruoho fr = fatp_next(fat, fq = fr);
597 1.6.2.2 jruoho }
598 1.6.2.2 jruoho
599 1.6.2.2 jruoho if (fr == fp) {
600 1.6.2.2 jruoho if (fq) {
601 1.6.2.2 jruoho fq->nxt = fp->nxt;
602 1.6.2.2 jruoho fp->nxt = 0;
603 1.6.2.2 jruoho fatp_free(fat, fp);
604 1.6.2.2 jruoho } else {
605 1.6.2.2 jruoho KASSERT(fat->port[hi] == fp);
606 1.6.2.2 jruoho
607 1.6.2.2 jruoho if (fp->nxt) {
608 1.6.2.2 jruoho fat->port[hi]
609 1.6.2.2 jruoho = fatp_next(fat, fp);
610 1.6.2.2 jruoho fp->nxt = 0;
611 1.6.2.2 jruoho fatp_free(fat, fp);
612 1.6.2.2 jruoho } else {
613 1.6.2.2 jruoho /* retain for next use.
614 1.6.2.2 jruoho */
615 1.6.2.2 jruoho ;
616 1.6.2.2 jruoho }
617 1.6.2.2 jruoho }
618 1.6.2.2 jruoho }
619 1.6.2.2 jruoho }
620 1.6.2.2 jruoho vtw->port_key ^= ~0;
621 1.6.2.2 jruoho }
622 1.6.2.2 jruoho
623 1.6.2.2 jruoho vtw->hashed = 0;
624 1.6.2.2 jruoho }
625 1.6.2.2 jruoho
626 1.6.2.2 jruoho /*!\brief remove entry from hash, possibly free.
627 1.6.2.2 jruoho */
628 1.6.2.2 jruoho void
629 1.6.2.2 jruoho vtw_del(vtw_ctl_t *ctl, vtw_t *vtw)
630 1.6.2.2 jruoho {
631 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
632 1.6.2.2 jruoho
633 1.6.2.2 jruoho if (vtw->hashed) {
634 1.6.2.2 jruoho ++vtw_stats.del;
635 1.6.2.2 jruoho vtw_unhash(ctl, vtw);
636 1.6.2.2 jruoho }
637 1.6.2.2 jruoho
638 1.6.2.2 jruoho /* We only delete the oldest entry.
639 1.6.2.2 jruoho */
640 1.6.2.2 jruoho if (vtw != ctl->oldest.v)
641 1.6.2.2 jruoho return;
642 1.6.2.2 jruoho
643 1.6.2.2 jruoho --ctl->nalloc;
644 1.6.2.2 jruoho ++ctl->nfree;
645 1.6.2.2 jruoho
646 1.6.2.2 jruoho vtw->expire.tv_sec = 0;
647 1.6.2.2 jruoho vtw->expire.tv_usec = ~0;
648 1.6.2.2 jruoho
649 1.6.2.2 jruoho if (!ctl->nalloc)
650 1.6.2.2 jruoho ctl->oldest.v = 0;
651 1.6.2.2 jruoho
652 1.6.2.2 jruoho ctl->oldest.v = vtw_next(ctl, vtw);
653 1.6.2.2 jruoho }
654 1.6.2.2 jruoho
655 1.6.2.2 jruoho /*!\brief insert vestigial timewait in hash chain
656 1.6.2.2 jruoho */
657 1.6.2.2 jruoho static void
658 1.6.2.2 jruoho vtw_inshash_v4(vtw_ctl_t *ctl, vtw_t *vtw)
659 1.6.2.2 jruoho {
660 1.6.2.2 jruoho uint32_t idx = vtw_index(ctl, vtw);
661 1.6.2.2 jruoho uint32_t tag;
662 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
663 1.6.2.2 jruoho
664 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
665 1.6.2.2 jruoho KASSERT(!vtw->hashed);
666 1.6.2.2 jruoho KASSERT(ctl->clidx == vtw->msl_class);
667 1.6.2.2 jruoho
668 1.6.2.2 jruoho ++vtw_stats.ins;
669 1.6.2.2 jruoho
670 1.6.2.2 jruoho tag = v4_tag(v4->faddr, v4->fport,
671 1.6.2.2 jruoho v4->laddr, v4->lport);
672 1.6.2.2 jruoho
673 1.6.2.2 jruoho vtw->key = fatp_vtw_inshash(ctl->fat, idx, tag, 0, vtw);
674 1.6.2.2 jruoho
675 1.6.2.2 jruoho db_trace(KTR_VTW, (ctl
676 1.6.2.2 jruoho , "vtw: ins %8.8x:%4.4x %8.8x:%4.4x"
677 1.6.2.2 jruoho " tag %8.8x key %8.8x"
678 1.6.2.2 jruoho , v4->faddr, v4->fport
679 1.6.2.2 jruoho , v4->laddr, v4->lport
680 1.6.2.2 jruoho , tag
681 1.6.2.2 jruoho , vtw->key));
682 1.6.2.2 jruoho
683 1.6.2.2 jruoho tag = v4_port_tag(v4->lport);
684 1.6.2.2 jruoho vtw->port_key = fatp_vtw_inshash(ctl->fat, idx, tag, 1, vtw);
685 1.6.2.2 jruoho
686 1.6.2.2 jruoho db_trace(KTR_VTW, (ctl, "vtw: ins %P - %4.4x tag %8.8x key %8.8x"
687 1.6.2.2 jruoho , v4->lport, v4->lport
688 1.6.2.2 jruoho , tag
689 1.6.2.2 jruoho , vtw->key));
690 1.6.2.2 jruoho
691 1.6.2.2 jruoho vtw->hashed = 1;
692 1.6.2.2 jruoho }
693 1.6.2.2 jruoho
694 1.6.2.2 jruoho /*!\brief insert vestigial timewait in hash chain
695 1.6.2.2 jruoho */
696 1.6.2.2 jruoho static void
697 1.6.2.2 jruoho vtw_inshash_v6(vtw_ctl_t *ctl, vtw_t *vtw)
698 1.6.2.2 jruoho {
699 1.6.2.2 jruoho uint32_t idx = vtw_index(ctl, vtw);
700 1.6.2.2 jruoho uint32_t tag;
701 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
702 1.6.2.2 jruoho
703 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
704 1.6.2.2 jruoho KASSERT(!vtw->hashed);
705 1.6.2.2 jruoho KASSERT(ctl->clidx == vtw->msl_class);
706 1.6.2.2 jruoho
707 1.6.2.2 jruoho ++vtw_stats.ins;
708 1.6.2.2 jruoho
709 1.6.2.2 jruoho tag = v6_tag(&v6->faddr, v6->fport,
710 1.6.2.2 jruoho &v6->laddr, v6->lport);
711 1.6.2.2 jruoho
712 1.6.2.2 jruoho vtw->key = fatp_vtw_inshash(ctl->fat, idx, tag, 0, vtw);
713 1.6.2.2 jruoho
714 1.6.2.2 jruoho tag = v6_port_tag(v6->lport);
715 1.6.2.2 jruoho vtw->port_key = fatp_vtw_inshash(ctl->fat, idx, tag, 1, vtw);
716 1.6.2.2 jruoho
717 1.6.2.2 jruoho db_trace(KTR_VTW, (ctl, "vtw: ins %P - %4.4x tag %8.8x key %8.8x"
718 1.6.2.2 jruoho , v6->lport, v6->lport
719 1.6.2.2 jruoho , tag
720 1.6.2.2 jruoho , vtw->key));
721 1.6.2.2 jruoho
722 1.6.2.2 jruoho vtw->hashed = 1;
723 1.6.2.2 jruoho }
724 1.6.2.2 jruoho
725 1.6.2.2 jruoho static vtw_t *
726 1.6.2.2 jruoho vtw_lookup_hash_v4(vtw_ctl_t *ctl, uint32_t faddr, uint16_t fport
727 1.6.2.2 jruoho , uint32_t laddr, uint16_t lport
728 1.6.2.2 jruoho , int which)
729 1.6.2.2 jruoho {
730 1.6.2.2 jruoho vtw_v4_t *v4;
731 1.6.2.2 jruoho vtw_t *vtw;
732 1.6.2.2 jruoho uint32_t tag;
733 1.6.2.2 jruoho fatp_t *fp;
734 1.6.2.2 jruoho int i;
735 1.6.2.2 jruoho uint32_t fatps = 0, probes = 0, losings = 0;
736 1.6.2.2 jruoho
737 1.6.2.2 jruoho if (!ctl || !ctl->fat)
738 1.6.2.2 jruoho return 0;
739 1.6.2.2 jruoho
740 1.6.2.2 jruoho ++vtw_stats.look[which];
741 1.6.2.2 jruoho
742 1.6.2.2 jruoho if (which) {
743 1.6.2.2 jruoho tag = v4_port_tag(lport);
744 1.6.2.2 jruoho fp = ctl->fat->port[tag & ctl->fat->mask];
745 1.6.2.2 jruoho } else {
746 1.6.2.2 jruoho tag = v4_tag(faddr, fport, laddr, lport);
747 1.6.2.2 jruoho fp = ctl->fat->hash[tag & ctl->fat->mask];
748 1.6.2.2 jruoho }
749 1.6.2.2 jruoho
750 1.6.2.2 jruoho while (fp && fp->inuse) {
751 1.6.2.2 jruoho uint32_t inuse = fp->inuse;
752 1.6.2.2 jruoho
753 1.6.2.2 jruoho ++fatps;
754 1.6.2.2 jruoho
755 1.6.2.2 jruoho for (i = 0; inuse && i < fatp_ntags(); ++i) {
756 1.6.2.2 jruoho uint32_t idx;
757 1.6.2.2 jruoho
758 1.6.2.2 jruoho if (!(inuse & (1 << i)))
759 1.6.2.2 jruoho continue;
760 1.6.2.2 jruoho
761 1.6.2.2 jruoho inuse ^= 1 << i;
762 1.6.2.2 jruoho
763 1.6.2.2 jruoho ++probes;
764 1.6.2.2 jruoho ++vtw_stats.probe[which];
765 1.6.2.2 jruoho
766 1.6.2.2 jruoho idx = fp->tag[i] ^ tag ^ fatp_xtra[i];
767 1.6.2.2 jruoho vtw = vtw_from_index(ctl, idx);
768 1.6.2.2 jruoho
769 1.6.2.2 jruoho if (!vtw) {
770 1.6.2.2 jruoho /* Hopefully fast path.
771 1.6.2.2 jruoho */
772 1.6.2.2 jruoho db_trace(KTR_VTW
773 1.6.2.2 jruoho , (fp, "vtw: fast %A:%P %A:%P"
774 1.6.2.2 jruoho " idx %x tag %x"
775 1.6.2.2 jruoho , faddr, fport
776 1.6.2.2 jruoho , laddr, lport
777 1.6.2.2 jruoho , idx, tag));
778 1.6.2.2 jruoho continue;
779 1.6.2.2 jruoho }
780 1.6.2.2 jruoho
781 1.6.2.2 jruoho v4 = (void*)vtw;
782 1.6.2.2 jruoho
783 1.6.2.2 jruoho /* The de-referencing of vtw is what we want to avoid.
784 1.6.2.2 jruoho * Losing.
785 1.6.2.2 jruoho */
786 1.6.2.2 jruoho if (vtw_alive(vtw)
787 1.6.2.2 jruoho && ((which ? vtw->port_key : vtw->key)
788 1.6.2.2 jruoho == fatp_key(ctl->fat, fp, i))
789 1.6.2.2 jruoho && (which
790 1.6.2.2 jruoho || (v4->faddr == faddr && v4->laddr == laddr
791 1.6.2.2 jruoho && v4->fport == fport))
792 1.6.2.2 jruoho && v4->lport == lport) {
793 1.6.2.2 jruoho ++vtw_stats.hit[which];
794 1.6.2.2 jruoho
795 1.6.2.2 jruoho db_trace(KTR_VTW
796 1.6.2.2 jruoho , (fp, "vtw: hit %8.8x:%4.4x"
797 1.6.2.2 jruoho " %8.8x:%4.4x idx %x key %x"
798 1.6.2.2 jruoho , faddr, fport
799 1.6.2.2 jruoho , laddr, lport
800 1.6.2.2 jruoho , idx_decode(ctl, idx), vtw->key));
801 1.6.2.2 jruoho
802 1.6.2.2 jruoho KASSERT(vtw->hashed);
803 1.6.2.2 jruoho
804 1.6.2.2 jruoho goto out;
805 1.6.2.2 jruoho }
806 1.6.2.2 jruoho ++vtw_stats.losing[which];
807 1.6.2.2 jruoho ++losings;
808 1.6.2.2 jruoho
809 1.6.2.2 jruoho if (vtw_alive(vtw)) {
810 1.6.2.2 jruoho db_trace(KTR_VTW
811 1.6.2.2 jruoho , (fp, "vtw:!mis %8.8x:%4.4x"
812 1.6.2.2 jruoho " %8.8x:%4.4x key %x tag %x"
813 1.6.2.2 jruoho , faddr, fport
814 1.6.2.2 jruoho , laddr, lport
815 1.6.2.2 jruoho , fatp_key(ctl->fat, fp, i)
816 1.6.2.2 jruoho , v4_tag(faddr, fport
817 1.6.2.2 jruoho , laddr, lport)));
818 1.6.2.2 jruoho db_trace(KTR_VTW
819 1.6.2.2 jruoho , (vtw, "vtw:!mis %8.8x:%4.4x"
820 1.6.2.2 jruoho " %8.8x:%4.4x key %x tag %x"
821 1.6.2.2 jruoho , v4->faddr, v4->fport
822 1.6.2.2 jruoho , v4->laddr, v4->lport
823 1.6.2.2 jruoho , vtw->key
824 1.6.2.2 jruoho , v4_tag(v4->faddr, v4->fport
825 1.6.2.2 jruoho , v4->laddr, v4->lport)));
826 1.6.2.2 jruoho
827 1.6.2.2 jruoho if (vtw->key == fatp_key(ctl->fat, fp, i)) {
828 1.6.2.2 jruoho db_trace(KTR_VTW
829 1.6.2.2 jruoho , (vtw, "vtw:!mis %8.8x:%4.4x"
830 1.6.2.2 jruoho " %8.8x:%4.4x key %x"
831 1.6.2.2 jruoho " which %x"
832 1.6.2.2 jruoho , v4->faddr, v4->fport
833 1.6.2.2 jruoho , v4->laddr, v4->lport
834 1.6.2.2 jruoho , vtw->key
835 1.6.2.2 jruoho , which));
836 1.6.2.2 jruoho
837 1.6.2.2 jruoho } else {
838 1.6.2.2 jruoho db_trace(KTR_VTW
839 1.6.2.2 jruoho , (vtw
840 1.6.2.2 jruoho , "vtw:!mis"
841 1.6.2.2 jruoho " key %8.8x != %8.8x"
842 1.6.2.2 jruoho " idx %x i %x which %x"
843 1.6.2.2 jruoho , vtw->key
844 1.6.2.2 jruoho , fatp_key(ctl->fat, fp, i)
845 1.6.2.2 jruoho , idx_decode(ctl, idx)
846 1.6.2.2 jruoho , i
847 1.6.2.2 jruoho , which));
848 1.6.2.2 jruoho }
849 1.6.2.2 jruoho } else {
850 1.6.2.2 jruoho db_trace(KTR_VTW
851 1.6.2.2 jruoho , (fp
852 1.6.2.2 jruoho , "vtw:!mis free entry"
853 1.6.2.2 jruoho " idx %x vtw %p which %x"
854 1.6.2.2 jruoho , idx_decode(ctl, idx)
855 1.6.2.2 jruoho , vtw, which));
856 1.6.2.2 jruoho }
857 1.6.2.2 jruoho }
858 1.6.2.2 jruoho
859 1.6.2.2 jruoho if (fp->nxt) {
860 1.6.2.2 jruoho fp = fatp_next(ctl->fat, fp);
861 1.6.2.2 jruoho } else {
862 1.6.2.2 jruoho break;
863 1.6.2.2 jruoho }
864 1.6.2.2 jruoho }
865 1.6.2.2 jruoho ++vtw_stats.miss[which];
866 1.6.2.2 jruoho vtw = 0;
867 1.6.2.2 jruoho out:
868 1.6.2.2 jruoho if (fatps > vtw_stats.max_chain[which])
869 1.6.2.2 jruoho vtw_stats.max_chain[which] = fatps;
870 1.6.2.2 jruoho if (probes > vtw_stats.max_probe[which])
871 1.6.2.2 jruoho vtw_stats.max_probe[which] = probes;
872 1.6.2.2 jruoho if (losings > vtw_stats.max_loss[which])
873 1.6.2.2 jruoho vtw_stats.max_loss[which] = losings;
874 1.6.2.2 jruoho
875 1.6.2.2 jruoho return vtw;
876 1.6.2.2 jruoho }
877 1.6.2.2 jruoho
878 1.6.2.2 jruoho static vtw_t *
879 1.6.2.2 jruoho vtw_lookup_hash_v6(vtw_ctl_t *ctl, const struct in6_addr *faddr, uint16_t fport
880 1.6.2.2 jruoho , const struct in6_addr *laddr, uint16_t lport
881 1.6.2.2 jruoho , int which)
882 1.6.2.2 jruoho {
883 1.6.2.2 jruoho vtw_v6_t *v6;
884 1.6.2.2 jruoho vtw_t *vtw;
885 1.6.2.2 jruoho uint32_t tag;
886 1.6.2.2 jruoho fatp_t *fp;
887 1.6.2.2 jruoho int i;
888 1.6.2.2 jruoho uint32_t fatps = 0, probes = 0, losings = 0;
889 1.6.2.2 jruoho
890 1.6.2.2 jruoho ++vtw_stats.look[which];
891 1.6.2.2 jruoho
892 1.6.2.2 jruoho if (!ctl || !ctl->fat)
893 1.6.2.2 jruoho return 0;
894 1.6.2.2 jruoho
895 1.6.2.2 jruoho if (which) {
896 1.6.2.2 jruoho tag = v6_port_tag(lport);
897 1.6.2.2 jruoho fp = ctl->fat->port[tag & ctl->fat->mask];
898 1.6.2.2 jruoho } else {
899 1.6.2.2 jruoho tag = v6_tag(faddr, fport, laddr, lport);
900 1.6.2.2 jruoho fp = ctl->fat->hash[tag & ctl->fat->mask];
901 1.6.2.2 jruoho }
902 1.6.2.2 jruoho
903 1.6.2.2 jruoho while (fp && fp->inuse) {
904 1.6.2.2 jruoho uint32_t inuse = fp->inuse;
905 1.6.2.2 jruoho
906 1.6.2.2 jruoho ++fatps;
907 1.6.2.2 jruoho
908 1.6.2.2 jruoho for (i = 0; inuse && i < fatp_ntags(); ++i) {
909 1.6.2.2 jruoho uint32_t idx;
910 1.6.2.2 jruoho
911 1.6.2.2 jruoho if (!(inuse & (1 << i)))
912 1.6.2.2 jruoho continue;
913 1.6.2.2 jruoho
914 1.6.2.2 jruoho inuse ^= 1 << i;
915 1.6.2.2 jruoho
916 1.6.2.2 jruoho ++probes;
917 1.6.2.2 jruoho ++vtw_stats.probe[which];
918 1.6.2.2 jruoho
919 1.6.2.2 jruoho idx = fp->tag[i] ^ tag ^ fatp_xtra[i];
920 1.6.2.2 jruoho vtw = vtw_from_index(ctl, idx);
921 1.6.2.2 jruoho
922 1.6.2.2 jruoho db_trace(KTR_VTW
923 1.6.2.2 jruoho , (fp, "probe: %2d %6A:%4.4x %6A:%4.4x idx %x"
924 1.6.2.2 jruoho , i
925 1.6.2.2 jruoho , db_store(faddr, sizeof (*faddr)), fport
926 1.6.2.2 jruoho , db_store(laddr, sizeof (*laddr)), lport
927 1.6.2.2 jruoho , idx_decode(ctl, idx)));
928 1.6.2.2 jruoho
929 1.6.2.2 jruoho if (!vtw) {
930 1.6.2.2 jruoho /* Hopefully fast path.
931 1.6.2.2 jruoho */
932 1.6.2.2 jruoho continue;
933 1.6.2.2 jruoho }
934 1.6.2.2 jruoho
935 1.6.2.2 jruoho v6 = (void*)vtw;
936 1.6.2.2 jruoho
937 1.6.2.2 jruoho if (vtw_alive(vtw)
938 1.6.2.2 jruoho && ((which ? vtw->port_key : vtw->key)
939 1.6.2.2 jruoho == fatp_key(ctl->fat, fp, i))
940 1.6.2.2 jruoho && v6->lport == lport
941 1.6.2.2 jruoho && (which
942 1.6.2.2 jruoho || (v6->fport == fport
943 1.6.2.2 jruoho && !bcmp(&v6->faddr, faddr, sizeof (*faddr))
944 1.6.2.2 jruoho && !bcmp(&v6->laddr, laddr
945 1.6.2.2 jruoho , sizeof (*laddr))))) {
946 1.6.2.2 jruoho ++vtw_stats.hit[which];
947 1.6.2.2 jruoho
948 1.6.2.2 jruoho KASSERT(vtw->hashed);
949 1.6.2.2 jruoho goto out;
950 1.6.2.2 jruoho } else {
951 1.6.2.2 jruoho ++vtw_stats.losing[which];
952 1.6.2.2 jruoho ++losings;
953 1.6.2.2 jruoho }
954 1.6.2.2 jruoho }
955 1.6.2.2 jruoho
956 1.6.2.2 jruoho if (fp->nxt) {
957 1.6.2.2 jruoho fp = fatp_next(ctl->fat, fp);
958 1.6.2.2 jruoho } else {
959 1.6.2.2 jruoho break;
960 1.6.2.2 jruoho }
961 1.6.2.2 jruoho }
962 1.6.2.2 jruoho ++vtw_stats.miss[which];
963 1.6.2.2 jruoho vtw = 0;
964 1.6.2.2 jruoho out:
965 1.6.2.2 jruoho if (fatps > vtw_stats.max_chain[which])
966 1.6.2.2 jruoho vtw_stats.max_chain[which] = fatps;
967 1.6.2.2 jruoho if (probes > vtw_stats.max_probe[which])
968 1.6.2.2 jruoho vtw_stats.max_probe[which] = probes;
969 1.6.2.2 jruoho if (losings > vtw_stats.max_loss[which])
970 1.6.2.2 jruoho vtw_stats.max_loss[which] = losings;
971 1.6.2.2 jruoho
972 1.6.2.2 jruoho return vtw;
973 1.6.2.2 jruoho }
974 1.6.2.2 jruoho
975 1.6.2.2 jruoho /*!\brief port iterator
976 1.6.2.2 jruoho */
977 1.6.2.2 jruoho static vtw_t *
978 1.6.2.2 jruoho vtw_next_port_v4(struct tcp_ports_iterator *it)
979 1.6.2.2 jruoho {
980 1.6.2.2 jruoho vtw_ctl_t *ctl = it->ctl;
981 1.6.2.2 jruoho vtw_v4_t *v4;
982 1.6.2.2 jruoho vtw_t *vtw;
983 1.6.2.2 jruoho uint32_t tag;
984 1.6.2.2 jruoho uint16_t lport = it->port;
985 1.6.2.2 jruoho fatp_t *fp;
986 1.6.2.2 jruoho int i;
987 1.6.2.2 jruoho uint32_t fatps = 0, probes = 0, losings = 0;
988 1.6.2.2 jruoho
989 1.6.2.2 jruoho tag = v4_port_tag(lport);
990 1.6.2.2 jruoho if (!it->fp) {
991 1.6.2.2 jruoho it->fp = ctl->fat->port[tag & ctl->fat->mask];
992 1.6.2.2 jruoho it->slot_idx = 0;
993 1.6.2.2 jruoho }
994 1.6.2.2 jruoho fp = it->fp;
995 1.6.2.2 jruoho
996 1.6.2.2 jruoho while (fp) {
997 1.6.2.2 jruoho uint32_t inuse = fp->inuse;
998 1.6.2.2 jruoho
999 1.6.2.2 jruoho ++fatps;
1000 1.6.2.2 jruoho
1001 1.6.2.2 jruoho for (i = it->slot_idx; inuse && i < fatp_ntags(); ++i) {
1002 1.6.2.2 jruoho uint32_t idx;
1003 1.6.2.2 jruoho
1004 1.6.2.2 jruoho if (!(inuse & (1 << i)))
1005 1.6.2.2 jruoho continue;
1006 1.6.2.2 jruoho
1007 1.6.2.2 jruoho inuse &= ~0 << i;
1008 1.6.2.2 jruoho
1009 1.6.2.2 jruoho if (i < it->slot_idx)
1010 1.6.2.2 jruoho continue;
1011 1.6.2.2 jruoho
1012 1.6.2.2 jruoho ++vtw_stats.probe[1];
1013 1.6.2.2 jruoho ++probes;
1014 1.6.2.2 jruoho
1015 1.6.2.2 jruoho idx = fp->tag[i] ^ tag ^ fatp_xtra[i];
1016 1.6.2.2 jruoho vtw = vtw_from_index(ctl, idx);
1017 1.6.2.2 jruoho
1018 1.6.2.2 jruoho if (!vtw) {
1019 1.6.2.2 jruoho /* Hopefully fast path.
1020 1.6.2.2 jruoho */
1021 1.6.2.2 jruoho continue;
1022 1.6.2.2 jruoho }
1023 1.6.2.2 jruoho
1024 1.6.2.2 jruoho v4 = (void*)vtw;
1025 1.6.2.2 jruoho
1026 1.6.2.2 jruoho if (vtw_alive(vtw)
1027 1.6.2.2 jruoho && vtw->port_key == fatp_key(ctl->fat, fp, i)
1028 1.6.2.2 jruoho && v4->lport == lport) {
1029 1.6.2.2 jruoho ++vtw_stats.hit[1];
1030 1.6.2.2 jruoho
1031 1.6.2.2 jruoho it->slot_idx = i + 1;
1032 1.6.2.2 jruoho
1033 1.6.2.2 jruoho goto out;
1034 1.6.2.2 jruoho } else if (vtw_alive(vtw)) {
1035 1.6.2.2 jruoho ++vtw_stats.losing[1];
1036 1.6.2.2 jruoho ++losings;
1037 1.6.2.2 jruoho
1038 1.6.2.2 jruoho db_trace(KTR_VTW
1039 1.6.2.2 jruoho , (vtw, "vtw:!mis"
1040 1.6.2.2 jruoho " port %8.8x:%4.4x %8.8x:%4.4x"
1041 1.6.2.2 jruoho " key %x port %x"
1042 1.6.2.2 jruoho , v4->faddr, v4->fport
1043 1.6.2.2 jruoho , v4->laddr, v4->lport
1044 1.6.2.2 jruoho , vtw->key
1045 1.6.2.2 jruoho , lport));
1046 1.6.2.2 jruoho } else {
1047 1.6.2.2 jruoho /* Really losing here. We are coming
1048 1.6.2.2 jruoho * up with references to free entries.
1049 1.6.2.2 jruoho * Might find it better to use
1050 1.6.2.2 jruoho * traditional, or need another
1051 1.6.2.2 jruoho * add-hockery. The other add-hockery
1052 1.6.2.2 jruoho * would be to pul more into into the
1053 1.6.2.2 jruoho * cache line to reject the false
1054 1.6.2.2 jruoho * hits.
1055 1.6.2.2 jruoho */
1056 1.6.2.2 jruoho ++vtw_stats.losing[1];
1057 1.6.2.2 jruoho ++losings;
1058 1.6.2.2 jruoho db_trace(KTR_VTW
1059 1.6.2.2 jruoho , (fp, "vtw:!mis port %x"
1060 1.6.2.2 jruoho " - free entry idx %x vtw %p"
1061 1.6.2.2 jruoho , lport
1062 1.6.2.2 jruoho , idx_decode(ctl, idx)
1063 1.6.2.2 jruoho , vtw));
1064 1.6.2.2 jruoho }
1065 1.6.2.2 jruoho }
1066 1.6.2.2 jruoho
1067 1.6.2.2 jruoho if (fp->nxt) {
1068 1.6.2.2 jruoho it->fp = fp = fatp_next(ctl->fat, fp);
1069 1.6.2.2 jruoho it->slot_idx = 0;
1070 1.6.2.2 jruoho } else {
1071 1.6.2.2 jruoho it->fp = 0;
1072 1.6.2.2 jruoho break;
1073 1.6.2.2 jruoho }
1074 1.6.2.2 jruoho }
1075 1.6.2.2 jruoho ++vtw_stats.miss[1];
1076 1.6.2.2 jruoho
1077 1.6.2.2 jruoho vtw = 0;
1078 1.6.2.2 jruoho out:
1079 1.6.2.2 jruoho if (fatps > vtw_stats.max_chain[1])
1080 1.6.2.2 jruoho vtw_stats.max_chain[1] = fatps;
1081 1.6.2.2 jruoho if (probes > vtw_stats.max_probe[1])
1082 1.6.2.2 jruoho vtw_stats.max_probe[1] = probes;
1083 1.6.2.2 jruoho if (losings > vtw_stats.max_loss[1])
1084 1.6.2.2 jruoho vtw_stats.max_loss[1] = losings;
1085 1.6.2.2 jruoho
1086 1.6.2.2 jruoho return vtw;
1087 1.6.2.2 jruoho }
1088 1.6.2.2 jruoho
1089 1.6.2.2 jruoho /*!\brief port iterator
1090 1.6.2.2 jruoho */
1091 1.6.2.2 jruoho static vtw_t *
1092 1.6.2.2 jruoho vtw_next_port_v6(struct tcp_ports_iterator *it)
1093 1.6.2.2 jruoho {
1094 1.6.2.2 jruoho vtw_ctl_t *ctl = it->ctl;
1095 1.6.2.2 jruoho vtw_v6_t *v6;
1096 1.6.2.2 jruoho vtw_t *vtw;
1097 1.6.2.2 jruoho uint32_t tag;
1098 1.6.2.2 jruoho uint16_t lport = it->port;
1099 1.6.2.2 jruoho fatp_t *fp;
1100 1.6.2.2 jruoho int i;
1101 1.6.2.2 jruoho uint32_t fatps = 0, probes = 0, losings = 0;
1102 1.6.2.2 jruoho
1103 1.6.2.2 jruoho tag = v6_port_tag(lport);
1104 1.6.2.2 jruoho if (!it->fp) {
1105 1.6.2.2 jruoho it->fp = ctl->fat->port[tag & ctl->fat->mask];
1106 1.6.2.2 jruoho it->slot_idx = 0;
1107 1.6.2.2 jruoho }
1108 1.6.2.2 jruoho fp = it->fp;
1109 1.6.2.2 jruoho
1110 1.6.2.2 jruoho while (fp) {
1111 1.6.2.2 jruoho uint32_t inuse = fp->inuse;
1112 1.6.2.2 jruoho
1113 1.6.2.2 jruoho ++fatps;
1114 1.6.2.2 jruoho
1115 1.6.2.2 jruoho for (i = it->slot_idx; inuse && i < fatp_ntags(); ++i) {
1116 1.6.2.2 jruoho uint32_t idx;
1117 1.6.2.2 jruoho
1118 1.6.2.2 jruoho if (!(inuse & (1 << i)))
1119 1.6.2.2 jruoho continue;
1120 1.6.2.2 jruoho
1121 1.6.2.2 jruoho inuse &= ~0 << i;
1122 1.6.2.2 jruoho
1123 1.6.2.2 jruoho if (i < it->slot_idx)
1124 1.6.2.2 jruoho continue;
1125 1.6.2.2 jruoho
1126 1.6.2.2 jruoho ++vtw_stats.probe[1];
1127 1.6.2.2 jruoho ++probes;
1128 1.6.2.2 jruoho
1129 1.6.2.2 jruoho idx = fp->tag[i] ^ tag ^ fatp_xtra[i];
1130 1.6.2.2 jruoho vtw = vtw_from_index(ctl, idx);
1131 1.6.2.2 jruoho
1132 1.6.2.2 jruoho if (!vtw) {
1133 1.6.2.2 jruoho /* Hopefully fast path.
1134 1.6.2.2 jruoho */
1135 1.6.2.2 jruoho continue;
1136 1.6.2.2 jruoho }
1137 1.6.2.2 jruoho
1138 1.6.2.2 jruoho v6 = (void*)vtw;
1139 1.6.2.2 jruoho
1140 1.6.2.2 jruoho db_trace(KTR_VTW
1141 1.6.2.2 jruoho , (vtw, "vtw: i %x idx %x fp->tag %x"
1142 1.6.2.2 jruoho " tag %x xtra %x"
1143 1.6.2.2 jruoho , i, idx_decode(ctl, idx)
1144 1.6.2.2 jruoho , fp->tag[i], tag, fatp_xtra[i]));
1145 1.6.2.2 jruoho
1146 1.6.2.2 jruoho if (vtw_alive(vtw)
1147 1.6.2.2 jruoho && vtw->port_key == fatp_key(ctl->fat, fp, i)
1148 1.6.2.2 jruoho && v6->lport == lport) {
1149 1.6.2.2 jruoho ++vtw_stats.hit[1];
1150 1.6.2.2 jruoho
1151 1.6.2.2 jruoho db_trace(KTR_VTW
1152 1.6.2.2 jruoho , (fp, "vtw: nxt port %P - %4.4x"
1153 1.6.2.2 jruoho " idx %x key %x"
1154 1.6.2.2 jruoho , lport, lport
1155 1.6.2.2 jruoho , idx_decode(ctl, idx), vtw->key));
1156 1.6.2.2 jruoho
1157 1.6.2.2 jruoho it->slot_idx = i + 1;
1158 1.6.2.2 jruoho goto out;
1159 1.6.2.2 jruoho } else if (vtw_alive(vtw)) {
1160 1.6.2.2 jruoho ++vtw_stats.losing[1];
1161 1.6.2.2 jruoho
1162 1.6.2.2 jruoho db_trace(KTR_VTW
1163 1.6.2.2 jruoho , (vtw, "vtw:!mis port %6A:%4.4x"
1164 1.6.2.2 jruoho " %6A:%4.4x key %x port %x"
1165 1.6.2.2 jruoho , db_store(&v6->faddr
1166 1.6.2.2 jruoho , sizeof (v6->faddr))
1167 1.6.2.2 jruoho , v6->fport
1168 1.6.2.2 jruoho , db_store(&v6->laddr
1169 1.6.2.2 jruoho , sizeof (v6->faddr))
1170 1.6.2.2 jruoho , v6->lport
1171 1.6.2.2 jruoho , vtw->key
1172 1.6.2.2 jruoho , lport));
1173 1.6.2.2 jruoho } else {
1174 1.6.2.2 jruoho /* Really losing here. We are coming
1175 1.6.2.2 jruoho * up with references to free entries.
1176 1.6.2.2 jruoho * Might find it better to use
1177 1.6.2.2 jruoho * traditional, or need another
1178 1.6.2.2 jruoho * add-hockery. The other add-hockery
1179 1.6.2.2 jruoho * would be to pul more into into the
1180 1.6.2.2 jruoho * cache line to reject the false
1181 1.6.2.2 jruoho * hits.
1182 1.6.2.2 jruoho */
1183 1.6.2.2 jruoho ++vtw_stats.losing[1];
1184 1.6.2.2 jruoho ++losings;
1185 1.6.2.2 jruoho
1186 1.6.2.2 jruoho db_trace(KTR_VTW
1187 1.6.2.2 jruoho , (fp
1188 1.6.2.2 jruoho , "vtw:!mis port %x"
1189 1.6.2.2 jruoho " - free entry idx %x vtw %p"
1190 1.6.2.2 jruoho , lport, idx_decode(ctl, idx)
1191 1.6.2.2 jruoho , vtw));
1192 1.6.2.2 jruoho }
1193 1.6.2.2 jruoho }
1194 1.6.2.2 jruoho
1195 1.6.2.2 jruoho if (fp->nxt) {
1196 1.6.2.2 jruoho it->fp = fp = fatp_next(ctl->fat, fp);
1197 1.6.2.2 jruoho it->slot_idx = 0;
1198 1.6.2.2 jruoho } else {
1199 1.6.2.2 jruoho it->fp = 0;
1200 1.6.2.2 jruoho break;
1201 1.6.2.2 jruoho }
1202 1.6.2.2 jruoho }
1203 1.6.2.2 jruoho ++vtw_stats.miss[1];
1204 1.6.2.2 jruoho
1205 1.6.2.2 jruoho vtw = 0;
1206 1.6.2.2 jruoho out:
1207 1.6.2.2 jruoho if (fatps > vtw_stats.max_chain[1])
1208 1.6.2.2 jruoho vtw_stats.max_chain[1] = fatps;
1209 1.6.2.2 jruoho if (probes > vtw_stats.max_probe[1])
1210 1.6.2.2 jruoho vtw_stats.max_probe[1] = probes;
1211 1.6.2.2 jruoho if (losings > vtw_stats.max_loss[1])
1212 1.6.2.2 jruoho vtw_stats.max_loss[1] = losings;
1213 1.6.2.2 jruoho
1214 1.6.2.2 jruoho return vtw;
1215 1.6.2.2 jruoho }
1216 1.6.2.2 jruoho
1217 1.6.2.2 jruoho /*!\brief initialise the VTW allocation arena
1218 1.6.2.2 jruoho *
1219 1.6.2.2 jruoho * There are 1+3 allocation classes:
1220 1.6.2.2 jruoho * 0 classless
1221 1.6.2.2 jruoho * {1,2,3} MSL-class based allocation
1222 1.6.2.2 jruoho *
1223 1.6.2.2 jruoho * The allocation arenas are all initialised. Classless gets all the
1224 1.6.2.2 jruoho * space. MSL-class based divides the arena, so that allocation
1225 1.6.2.2 jruoho * within a class can proceed without having to consider entries
1226 1.6.2.2 jruoho * (aka: cache lines) from different classes.
1227 1.6.2.2 jruoho *
1228 1.6.2.2 jruoho * Usually, we are completely classless or class-based, but there can be
1229 1.6.2.2 jruoho * transition periods, corresponding to dynamic adjustments in the config
1230 1.6.2.2 jruoho * by the operator.
1231 1.6.2.2 jruoho */
1232 1.6.2.2 jruoho static void
1233 1.6.2.2 jruoho vtw_init(fatp_ctl_t *fat, vtw_ctl_t *ctl, const uint32_t n, vtw_t *ctl_base_v)
1234 1.6.2.2 jruoho {
1235 1.6.2.2 jruoho int class_n, i;
1236 1.6.2.2 jruoho vtw_t *base;
1237 1.6.2.2 jruoho
1238 1.6.2.2 jruoho ctl->base.v = ctl_base_v;
1239 1.6.2.2 jruoho
1240 1.6.2.2 jruoho if (ctl->is_v4) {
1241 1.6.2.2 jruoho ctl->lim.v4 = ctl->base.v4 + n - 1;
1242 1.6.2.2 jruoho ctl->alloc.v4 = ctl->base.v4;
1243 1.6.2.2 jruoho } else {
1244 1.6.2.2 jruoho ctl->lim.v6 = ctl->base.v6 + n - 1;
1245 1.6.2.2 jruoho ctl->alloc.v6 = ctl->base.v6;
1246 1.6.2.2 jruoho }
1247 1.6.2.2 jruoho
1248 1.6.2.2 jruoho ctl->nfree = n;
1249 1.6.2.2 jruoho ctl->ctl = ctl;
1250 1.6.2.2 jruoho
1251 1.6.2.2 jruoho ctl->idx_bits = 32;
1252 1.6.2.2 jruoho for (ctl->idx_mask = ~0; (ctl->idx_mask & (n-1)) == n-1; ) {
1253 1.6.2.2 jruoho ctl->idx_mask >>= 1;
1254 1.6.2.2 jruoho ctl->idx_bits -= 1;
1255 1.6.2.2 jruoho }
1256 1.6.2.2 jruoho
1257 1.6.2.2 jruoho ctl->idx_mask <<= 1;
1258 1.6.2.2 jruoho ctl->idx_mask |= 1;
1259 1.6.2.2 jruoho ctl->idx_bits += 1;
1260 1.6.2.2 jruoho
1261 1.6.2.2 jruoho ctl->fat = fat;
1262 1.6.2.2 jruoho fat->vtw = ctl;
1263 1.6.2.2 jruoho
1264 1.6.2.2 jruoho /* Divide the resources equally amongst the classes.
1265 1.6.2.2 jruoho * This is not optimal, as the different classes
1266 1.6.2.2 jruoho * arrive and leave at different rates, but it is
1267 1.6.2.2 jruoho * the best I can do for now.
1268 1.6.2.2 jruoho */
1269 1.6.2.2 jruoho class_n = n / (VTW_NCLASS-1);
1270 1.6.2.2 jruoho base = ctl->base.v;
1271 1.6.2.2 jruoho
1272 1.6.2.2 jruoho for (i = 1; i < VTW_NCLASS; ++i) {
1273 1.6.2.2 jruoho int j;
1274 1.6.2.2 jruoho
1275 1.6.2.2 jruoho ctl[i] = ctl[0];
1276 1.6.2.2 jruoho ctl[i].clidx = i;
1277 1.6.2.2 jruoho
1278 1.6.2.2 jruoho ctl[i].base.v = base;
1279 1.6.2.2 jruoho ctl[i].alloc = ctl[i].base;
1280 1.6.2.2 jruoho
1281 1.6.2.2 jruoho for (j = 0; j < class_n - 1; ++j) {
1282 1.6.2.2 jruoho if (tcp_msl_enable)
1283 1.6.2.2 jruoho base->msl_class = i;
1284 1.6.2.2 jruoho base = vtw_next(ctl, base);
1285 1.6.2.2 jruoho }
1286 1.6.2.2 jruoho
1287 1.6.2.2 jruoho ctl[i].lim.v = base;
1288 1.6.2.2 jruoho base = vtw_next(ctl, base);
1289 1.6.2.2 jruoho ctl[i].nfree = class_n;
1290 1.6.2.2 jruoho }
1291 1.6.2.2 jruoho
1292 1.6.2.2 jruoho vtw_debug_init();
1293 1.6.2.2 jruoho }
1294 1.6.2.2 jruoho
1295 1.6.2.2 jruoho /*!\brief map class to TCP MSL
1296 1.6.2.2 jruoho */
1297 1.6.2.2 jruoho static inline uint32_t
1298 1.6.2.2 jruoho class_to_msl(int class)
1299 1.6.2.2 jruoho {
1300 1.6.2.2 jruoho switch (class) {
1301 1.6.2.2 jruoho case 0:
1302 1.6.2.2 jruoho case 1:
1303 1.6.2.2 jruoho return tcp_msl_remote ? tcp_msl_remote : (TCPTV_MSL >> 0);
1304 1.6.2.2 jruoho case 2:
1305 1.6.2.2 jruoho return tcp_msl_local ? tcp_msl_local : (TCPTV_MSL >> 1);
1306 1.6.2.2 jruoho default:
1307 1.6.2.2 jruoho return tcp_msl_loop ? tcp_msl_loop : (TCPTV_MSL >> 2);
1308 1.6.2.2 jruoho }
1309 1.6.2.2 jruoho }
1310 1.6.2.2 jruoho
1311 1.6.2.2 jruoho /*!\brief map TCP MSL to class
1312 1.6.2.2 jruoho */
1313 1.6.2.2 jruoho static inline uint32_t
1314 1.6.2.2 jruoho msl_to_class(int msl)
1315 1.6.2.2 jruoho {
1316 1.6.2.2 jruoho if (tcp_msl_enable) {
1317 1.6.2.2 jruoho if (msl <= (tcp_msl_loop ? tcp_msl_loop : (TCPTV_MSL >> 2)))
1318 1.6.2.2 jruoho return 1+2;
1319 1.6.2.2 jruoho if (msl <= (tcp_msl_local ? tcp_msl_local : (TCPTV_MSL >> 1)))
1320 1.6.2.2 jruoho return 1+1;
1321 1.6.2.2 jruoho return 1;
1322 1.6.2.2 jruoho }
1323 1.6.2.2 jruoho return 0;
1324 1.6.2.2 jruoho }
1325 1.6.2.2 jruoho
1326 1.6.2.2 jruoho /*!\brief allocate a vtw entry
1327 1.6.2.2 jruoho */
1328 1.6.2.2 jruoho static inline vtw_t *
1329 1.6.2.2 jruoho vtw_alloc(vtw_ctl_t *ctl)
1330 1.6.2.2 jruoho {
1331 1.6.2.2 jruoho vtw_t *vtw = 0;
1332 1.6.2.2 jruoho int stuck = 0;
1333 1.6.2.2 jruoho int avail = ctl ? (ctl->nalloc + ctl->nfree) : 0;
1334 1.6.2.2 jruoho int msl;
1335 1.6.2.2 jruoho
1336 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
1337 1.6.2.2 jruoho
1338 1.6.2.2 jruoho /* If no resources, we will not get far.
1339 1.6.2.2 jruoho */
1340 1.6.2.2 jruoho if (!ctl || !ctl->base.v4 || avail <= 0)
1341 1.6.2.2 jruoho return 0;
1342 1.6.2.2 jruoho
1343 1.6.2.2 jruoho /* Obtain a free one.
1344 1.6.2.2 jruoho */
1345 1.6.2.2 jruoho while (!ctl->nfree) {
1346 1.6.2.2 jruoho vtw_age(ctl, 0);
1347 1.6.2.2 jruoho
1348 1.6.2.2 jruoho if (++stuck > avail) {
1349 1.6.2.2 jruoho /* When in transition between
1350 1.6.2.2 jruoho * schemes (classless, classed) we
1351 1.6.2.2 jruoho * can be stuck having to await the
1352 1.6.2.2 jruoho * expiration of cross-allocated entries.
1353 1.6.2.2 jruoho *
1354 1.6.2.2 jruoho * Returning zero means we will fall back to the
1355 1.6.2.2 jruoho * traditional TIME_WAIT handling, except in the
1356 1.6.2.2 jruoho * case of a re-shed, in which case we cannot
1357 1.6.2.2 jruoho * perform the reshecd, but will retain the extant
1358 1.6.2.2 jruoho * entry.
1359 1.6.2.2 jruoho */
1360 1.6.2.2 jruoho db_trace(KTR_VTW
1361 1.6.2.2 jruoho , (ctl, "vtw:!none free in class %x %x/%x"
1362 1.6.2.2 jruoho , ctl->clidx
1363 1.6.2.2 jruoho , ctl->nalloc, ctl->nfree));
1364 1.6.2.2 jruoho
1365 1.6.2.2 jruoho return 0;
1366 1.6.2.2 jruoho }
1367 1.6.2.2 jruoho }
1368 1.6.2.2 jruoho
1369 1.6.2.2 jruoho vtw = ctl->alloc.v;
1370 1.6.2.2 jruoho
1371 1.6.2.2 jruoho if (vtw->msl_class != ctl->clidx) {
1372 1.6.2.2 jruoho /* Usurping rules:
1373 1.6.2.2 jruoho * 0 -> {1,2,3} or {1,2,3} -> 0
1374 1.6.2.2 jruoho */
1375 1.6.2.2 jruoho KASSERT(!vtw->msl_class || !ctl->clidx);
1376 1.6.2.2 jruoho
1377 1.6.2.2 jruoho if (vtw->hashed || vtw->expire.tv_sec) {
1378 1.6.2.2 jruoho /* As this is owned by some other class,
1379 1.6.2.2 jruoho * we must wait for it to expire it.
1380 1.6.2.2 jruoho * This will only happen on class/classless
1381 1.6.2.2 jruoho * transitions, which are guaranteed to progress
1382 1.6.2.2 jruoho * to completion in small finite time, barring bugs.
1383 1.6.2.2 jruoho */
1384 1.6.2.2 jruoho db_trace(KTR_VTW
1385 1.6.2.2 jruoho , (ctl, "vtw:!%p class %x!=%x %x:%x%s"
1386 1.6.2.2 jruoho , vtw, vtw->msl_class, ctl->clidx
1387 1.6.2.2 jruoho , vtw->expire.tv_sec
1388 1.6.2.2 jruoho , vtw->expire.tv_usec
1389 1.6.2.2 jruoho , vtw->hashed ? " hashed" : ""));
1390 1.6.2.2 jruoho
1391 1.6.2.2 jruoho return 0;
1392 1.6.2.2 jruoho }
1393 1.6.2.2 jruoho
1394 1.6.2.2 jruoho db_trace(KTR_VTW
1395 1.6.2.2 jruoho , (ctl, "vtw:!%p usurped from %x to %x"
1396 1.6.2.2 jruoho , vtw, vtw->msl_class, ctl->clidx));
1397 1.6.2.2 jruoho
1398 1.6.2.2 jruoho vtw->msl_class = ctl->clidx;
1399 1.6.2.2 jruoho }
1400 1.6.2.2 jruoho
1401 1.6.2.2 jruoho if (vtw_alive(vtw)) {
1402 1.6.2.2 jruoho KASSERT(0 && "next free not free");
1403 1.6.2.2 jruoho return 0;
1404 1.6.2.2 jruoho }
1405 1.6.2.2 jruoho
1406 1.6.2.2 jruoho /* Advance allocation poiter.
1407 1.6.2.2 jruoho */
1408 1.6.2.2 jruoho ctl->alloc.v = vtw_next(ctl, vtw);
1409 1.6.2.2 jruoho
1410 1.6.2.2 jruoho --ctl->nfree;
1411 1.6.2.2 jruoho ++ctl->nalloc;
1412 1.6.2.2 jruoho
1413 1.6.2.2 jruoho msl = (2 * class_to_msl(ctl->clidx) * 1000) / PR_SLOWHZ; // msec
1414 1.6.2.2 jruoho
1415 1.6.2.2 jruoho /* mark expiration
1416 1.6.2.2 jruoho */
1417 1.6.2.2 jruoho getmicrouptime(&vtw->expire);
1418 1.6.2.2 jruoho
1419 1.6.2.2 jruoho /* Move expiration into the future.
1420 1.6.2.2 jruoho */
1421 1.6.2.2 jruoho vtw->expire.tv_sec += msl / 1000;
1422 1.6.2.2 jruoho vtw->expire.tv_usec += 1000 * (msl % 1000);
1423 1.6.2.2 jruoho
1424 1.6.2.2 jruoho while (vtw->expire.tv_usec >= 1000*1000) {
1425 1.6.2.2 jruoho vtw->expire.tv_usec -= 1000*1000;
1426 1.6.2.2 jruoho vtw->expire.tv_sec += 1;
1427 1.6.2.2 jruoho }
1428 1.6.2.2 jruoho
1429 1.6.2.2 jruoho if (!ctl->oldest.v)
1430 1.6.2.2 jruoho ctl->oldest.v = vtw;
1431 1.6.2.2 jruoho
1432 1.6.2.2 jruoho return vtw;
1433 1.6.2.2 jruoho }
1434 1.6.2.2 jruoho
1435 1.6.2.2 jruoho /*!\brief expiration
1436 1.6.2.2 jruoho */
1437 1.6.2.2 jruoho static int
1438 1.6.2.2 jruoho vtw_age(vtw_ctl_t *ctl, struct timeval *_when)
1439 1.6.2.2 jruoho {
1440 1.6.2.2 jruoho vtw_t *vtw;
1441 1.6.2.2 jruoho struct timeval then, *when = _when;
1442 1.6.2.2 jruoho int maxtries = 0;
1443 1.6.2.2 jruoho
1444 1.6.2.2 jruoho if (!ctl->oldest.v) {
1445 1.6.2.2 jruoho KASSERT(!ctl->nalloc);
1446 1.6.2.2 jruoho return 0;
1447 1.6.2.2 jruoho }
1448 1.6.2.2 jruoho
1449 1.6.2.2 jruoho for (vtw = ctl->oldest.v; vtw && ctl->nalloc; ) {
1450 1.6.2.2 jruoho if (++maxtries > ctl->nalloc)
1451 1.6.2.2 jruoho break;
1452 1.6.2.2 jruoho
1453 1.6.2.2 jruoho if (vtw->msl_class != ctl->clidx) {
1454 1.6.2.2 jruoho db_trace(KTR_VTW
1455 1.6.2.2 jruoho , (vtw, "vtw:!age class mismatch %x != %x"
1456 1.6.2.2 jruoho , vtw->msl_class, ctl->clidx));
1457 1.6.2.2 jruoho /* XXXX
1458 1.6.2.2 jruoho * See if the appropriate action is to skip to the next.
1459 1.6.2.2 jruoho * XXXX
1460 1.6.2.2 jruoho */
1461 1.6.2.2 jruoho ctl->oldest.v = vtw = vtw_next(ctl, vtw);
1462 1.6.2.2 jruoho continue;
1463 1.6.2.2 jruoho }
1464 1.6.2.2 jruoho if (!when) {
1465 1.6.2.2 jruoho /* Latch oldest timeval if none specified.
1466 1.6.2.2 jruoho */
1467 1.6.2.2 jruoho then = vtw->expire;
1468 1.6.2.2 jruoho when = &then;
1469 1.6.2.2 jruoho }
1470 1.6.2.2 jruoho
1471 1.6.2.2 jruoho if (!timercmp(&vtw->expire, when, <=))
1472 1.6.2.2 jruoho break;
1473 1.6.2.2 jruoho
1474 1.6.2.2 jruoho db_trace(KTR_VTW
1475 1.6.2.2 jruoho , (vtw, "vtw: expire %x %8.8x:%8.8x %x/%x"
1476 1.6.2.2 jruoho , ctl->clidx
1477 1.6.2.2 jruoho , vtw->expire.tv_sec
1478 1.6.2.2 jruoho , vtw->expire.tv_usec
1479 1.6.2.2 jruoho , ctl->nalloc
1480 1.6.2.2 jruoho , ctl->nfree));
1481 1.6.2.2 jruoho
1482 1.6.2.2 jruoho if (!_when)
1483 1.6.2.2 jruoho ++vtw_stats.kill;
1484 1.6.2.2 jruoho
1485 1.6.2.2 jruoho vtw_del(ctl, vtw);
1486 1.6.2.2 jruoho vtw = ctl->oldest.v;
1487 1.6.2.2 jruoho }
1488 1.6.2.2 jruoho
1489 1.6.2.2 jruoho return ctl->nalloc; // # remaining allocated
1490 1.6.2.2 jruoho }
1491 1.6.2.2 jruoho
1492 1.6.2.2 jruoho static callout_t vtw_cs;
1493 1.6.2.2 jruoho
1494 1.6.2.2 jruoho /*!\brief notice the passage of time.
1495 1.6.2.2 jruoho * It seems to be getting faster. What happened to the year?
1496 1.6.2.2 jruoho */
1497 1.6.2.2 jruoho static void
1498 1.6.2.2 jruoho vtw_tick(void *arg)
1499 1.6.2.2 jruoho {
1500 1.6.2.2 jruoho struct timeval now;
1501 1.6.2.2 jruoho int i, cnt = 0;
1502 1.6.2.2 jruoho
1503 1.6.2.2 jruoho getmicrouptime(&now);
1504 1.6.2.2 jruoho
1505 1.6.2.2 jruoho db_trace(KTR_VTW, (arg, "vtk: tick - now %8.8x:%8.8x"
1506 1.6.2.2 jruoho , now.tv_sec, now.tv_usec));
1507 1.6.2.2 jruoho
1508 1.6.2.2 jruoho mutex_enter(softnet_lock);
1509 1.6.2.2 jruoho
1510 1.6.2.2 jruoho for (i = 0; i < VTW_NCLASS; ++i) {
1511 1.6.2.2 jruoho cnt += vtw_age(&vtw_tcpv4[i], &now);
1512 1.6.2.2 jruoho cnt += vtw_age(&vtw_tcpv6[i], &now);
1513 1.6.2.2 jruoho }
1514 1.6.2.2 jruoho
1515 1.6.2.2 jruoho /* Keep ticks coming while we need them.
1516 1.6.2.2 jruoho */
1517 1.6.2.2 jruoho if (cnt)
1518 1.6.2.2 jruoho callout_schedule(&vtw_cs, hz / 5);
1519 1.6.2.2 jruoho else {
1520 1.6.2.2 jruoho tcp_vtw_was_enabled = 0;
1521 1.6.2.2 jruoho tcbtable.vestige = 0;
1522 1.6.2.2 jruoho }
1523 1.6.2.2 jruoho mutex_exit(softnet_lock);
1524 1.6.2.2 jruoho }
1525 1.6.2.2 jruoho
1526 1.6.2.2 jruoho /* in_pcblookup_ports assist for handling vestigial entries.
1527 1.6.2.2 jruoho */
1528 1.6.2.2 jruoho static void *
1529 1.6.2.2 jruoho tcp_init_ports_v4(struct in_addr addr, u_int port, int wild)
1530 1.6.2.2 jruoho {
1531 1.6.2.2 jruoho struct tcp_ports_iterator *it = &tcp_ports_iterator_v4;
1532 1.6.2.2 jruoho
1533 1.6.2.2 jruoho bzero(it, sizeof (*it));
1534 1.6.2.2 jruoho
1535 1.6.2.2 jruoho /* Note: the reference to vtw_tcpv4[0] is fine.
1536 1.6.2.2 jruoho * We do not need per-class iteration. We just
1537 1.6.2.2 jruoho * need to get to the fat, and there is one
1538 1.6.2.2 jruoho * shared fat.
1539 1.6.2.2 jruoho */
1540 1.6.2.2 jruoho if (vtw_tcpv4[0].fat) {
1541 1.6.2.2 jruoho it->addr.v4 = addr;
1542 1.6.2.2 jruoho it->port = port;
1543 1.6.2.2 jruoho it->wild = !!wild;
1544 1.6.2.2 jruoho it->ctl = &vtw_tcpv4[0];
1545 1.6.2.2 jruoho
1546 1.6.2.2 jruoho ++vtw_stats.look[1];
1547 1.6.2.2 jruoho }
1548 1.6.2.2 jruoho
1549 1.6.2.2 jruoho return it;
1550 1.6.2.2 jruoho }
1551 1.6.2.2 jruoho
1552 1.6.2.2 jruoho /*!\brief export an IPv4 vtw.
1553 1.6.2.2 jruoho */
1554 1.6.2.2 jruoho static int
1555 1.6.2.2 jruoho vtw_export_v4(vtw_ctl_t *ctl, vtw_t *vtw, vestigial_inpcb_t *res)
1556 1.6.2.2 jruoho {
1557 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
1558 1.6.2.2 jruoho
1559 1.6.2.2 jruoho bzero(res, sizeof (*res));
1560 1.6.2.2 jruoho
1561 1.6.2.2 jruoho if (ctl && vtw) {
1562 1.6.2.2 jruoho if (!ctl->clidx && vtw->msl_class)
1563 1.6.2.2 jruoho ctl += vtw->msl_class;
1564 1.6.2.2 jruoho else
1565 1.6.2.2 jruoho KASSERT(ctl->clidx == vtw->msl_class);
1566 1.6.2.2 jruoho
1567 1.6.2.2 jruoho res->valid = 1;
1568 1.6.2.2 jruoho res->v4 = 1;
1569 1.6.2.2 jruoho
1570 1.6.2.2 jruoho res->faddr.v4.s_addr = v4->faddr;
1571 1.6.2.2 jruoho res->laddr.v4.s_addr = v4->laddr;
1572 1.6.2.2 jruoho res->fport = v4->fport;
1573 1.6.2.2 jruoho res->lport = v4->lport;
1574 1.6.2.2 jruoho res->vtw = vtw; // netlock held over call(s)
1575 1.6.2.2 jruoho res->ctl = ctl;
1576 1.6.2.2 jruoho res->reuse_addr = vtw->reuse_addr;
1577 1.6.2.2 jruoho res->reuse_port = vtw->reuse_port;
1578 1.6.2.2 jruoho res->snd_nxt = vtw->snd_nxt;
1579 1.6.2.2 jruoho res->rcv_nxt = vtw->rcv_nxt;
1580 1.6.2.2 jruoho res->rcv_wnd = vtw->rcv_wnd;
1581 1.6.2.2 jruoho res->uid = vtw->uid;
1582 1.6.2.2 jruoho }
1583 1.6.2.2 jruoho
1584 1.6.2.2 jruoho return res->valid;
1585 1.6.2.2 jruoho }
1586 1.6.2.2 jruoho
1587 1.6.2.2 jruoho /*!\brief return next port in the port iterator. yowza.
1588 1.6.2.2 jruoho */
1589 1.6.2.2 jruoho static int
1590 1.6.2.2 jruoho tcp_next_port_v4(void *arg, struct vestigial_inpcb *res)
1591 1.6.2.2 jruoho {
1592 1.6.2.2 jruoho struct tcp_ports_iterator *it = arg;
1593 1.6.2.2 jruoho vtw_t *vtw = 0;
1594 1.6.2.2 jruoho
1595 1.6.2.2 jruoho if (it->ctl)
1596 1.6.2.2 jruoho vtw = vtw_next_port_v4(it);
1597 1.6.2.2 jruoho
1598 1.6.2.2 jruoho if (!vtw)
1599 1.6.2.2 jruoho it->ctl = 0;
1600 1.6.2.2 jruoho
1601 1.6.2.2 jruoho return vtw_export_v4(it->ctl, vtw, res);
1602 1.6.2.2 jruoho }
1603 1.6.2.2 jruoho
1604 1.6.2.2 jruoho static int
1605 1.6.2.2 jruoho tcp_lookup_v4(struct in_addr faddr, uint16_t fport,
1606 1.6.2.2 jruoho struct in_addr laddr, uint16_t lport,
1607 1.6.2.2 jruoho struct vestigial_inpcb *res)
1608 1.6.2.2 jruoho {
1609 1.6.2.2 jruoho vtw_t *vtw;
1610 1.6.2.2 jruoho vtw_ctl_t *ctl;
1611 1.6.2.2 jruoho
1612 1.6.2.2 jruoho
1613 1.6.2.2 jruoho db_trace(KTR_VTW
1614 1.6.2.2 jruoho , (res, "vtw: lookup %A:%P %A:%P"
1615 1.6.2.2 jruoho , faddr, fport
1616 1.6.2.2 jruoho , laddr, lport));
1617 1.6.2.2 jruoho
1618 1.6.2.2 jruoho vtw = vtw_lookup_hash_v4((ctl = &vtw_tcpv4[0])
1619 1.6.2.2 jruoho , faddr.s_addr, fport
1620 1.6.2.2 jruoho , laddr.s_addr, lport, 0);
1621 1.6.2.2 jruoho
1622 1.6.2.2 jruoho return vtw_export_v4(ctl, vtw, res);
1623 1.6.2.2 jruoho }
1624 1.6.2.2 jruoho
1625 1.6.2.2 jruoho /* in_pcblookup_ports assist for handling vestigial entries.
1626 1.6.2.2 jruoho */
1627 1.6.2.2 jruoho static void *
1628 1.6.2.2 jruoho tcp_init_ports_v6(const struct in6_addr *addr, u_int port, int wild)
1629 1.6.2.2 jruoho {
1630 1.6.2.2 jruoho struct tcp_ports_iterator *it = &tcp_ports_iterator_v6;
1631 1.6.2.2 jruoho
1632 1.6.2.2 jruoho bzero(it, sizeof (*it));
1633 1.6.2.2 jruoho
1634 1.6.2.2 jruoho /* Note: the reference to vtw_tcpv6[0] is fine.
1635 1.6.2.2 jruoho * We do not need per-class iteration. We just
1636 1.6.2.2 jruoho * need to get to the fat, and there is one
1637 1.6.2.2 jruoho * shared fat.
1638 1.6.2.2 jruoho */
1639 1.6.2.2 jruoho if (vtw_tcpv6[0].fat) {
1640 1.6.2.2 jruoho it->addr.v6 = *addr;
1641 1.6.2.2 jruoho it->port = port;
1642 1.6.2.2 jruoho it->wild = !!wild;
1643 1.6.2.2 jruoho it->ctl = &vtw_tcpv6[0];
1644 1.6.2.2 jruoho
1645 1.6.2.2 jruoho ++vtw_stats.look[1];
1646 1.6.2.2 jruoho }
1647 1.6.2.2 jruoho
1648 1.6.2.2 jruoho return it;
1649 1.6.2.2 jruoho }
1650 1.6.2.2 jruoho
1651 1.6.2.2 jruoho /*!\brief export an IPv6 vtw.
1652 1.6.2.2 jruoho */
1653 1.6.2.2 jruoho static int
1654 1.6.2.2 jruoho vtw_export_v6(vtw_ctl_t *ctl, vtw_t *vtw, vestigial_inpcb_t *res)
1655 1.6.2.2 jruoho {
1656 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
1657 1.6.2.2 jruoho
1658 1.6.2.2 jruoho bzero(res, sizeof (*res));
1659 1.6.2.2 jruoho
1660 1.6.2.2 jruoho if (ctl && vtw) {
1661 1.6.2.2 jruoho if (!ctl->clidx && vtw->msl_class)
1662 1.6.2.2 jruoho ctl += vtw->msl_class;
1663 1.6.2.2 jruoho else
1664 1.6.2.2 jruoho KASSERT(ctl->clidx == vtw->msl_class);
1665 1.6.2.2 jruoho
1666 1.6.2.2 jruoho res->valid = 1;
1667 1.6.2.2 jruoho res->v4 = 0;
1668 1.6.2.2 jruoho
1669 1.6.2.2 jruoho res->faddr.v6 = v6->faddr;
1670 1.6.2.2 jruoho res->laddr.v6 = v6->laddr;
1671 1.6.2.2 jruoho res->fport = v6->fport;
1672 1.6.2.2 jruoho res->lport = v6->lport;
1673 1.6.2.2 jruoho res->vtw = vtw; // netlock held over call(s)
1674 1.6.2.2 jruoho res->ctl = ctl;
1675 1.6.2.2 jruoho
1676 1.6.2.2 jruoho res->v6only = vtw->v6only;
1677 1.6.2.2 jruoho res->reuse_addr = vtw->reuse_addr;
1678 1.6.2.2 jruoho res->reuse_port = vtw->reuse_port;
1679 1.6.2.2 jruoho
1680 1.6.2.2 jruoho res->snd_nxt = vtw->snd_nxt;
1681 1.6.2.2 jruoho res->rcv_nxt = vtw->rcv_nxt;
1682 1.6.2.2 jruoho res->rcv_wnd = vtw->rcv_wnd;
1683 1.6.2.2 jruoho res->uid = vtw->uid;
1684 1.6.2.2 jruoho }
1685 1.6.2.2 jruoho
1686 1.6.2.2 jruoho return res->valid;
1687 1.6.2.2 jruoho }
1688 1.6.2.2 jruoho
1689 1.6.2.2 jruoho static int
1690 1.6.2.2 jruoho tcp_next_port_v6(void *arg, struct vestigial_inpcb *res)
1691 1.6.2.2 jruoho {
1692 1.6.2.2 jruoho struct tcp_ports_iterator *it = arg;
1693 1.6.2.2 jruoho vtw_t *vtw = 0;
1694 1.6.2.2 jruoho
1695 1.6.2.2 jruoho if (it->ctl)
1696 1.6.2.2 jruoho vtw = vtw_next_port_v6(it);
1697 1.6.2.2 jruoho
1698 1.6.2.2 jruoho if (!vtw)
1699 1.6.2.2 jruoho it->ctl = 0;
1700 1.6.2.2 jruoho
1701 1.6.2.2 jruoho return vtw_export_v6(it->ctl, vtw, res);
1702 1.6.2.2 jruoho }
1703 1.6.2.2 jruoho
1704 1.6.2.2 jruoho static int
1705 1.6.2.2 jruoho tcp_lookup_v6(const struct in6_addr *faddr, uint16_t fport,
1706 1.6.2.2 jruoho const struct in6_addr *laddr, uint16_t lport,
1707 1.6.2.2 jruoho struct vestigial_inpcb *res)
1708 1.6.2.2 jruoho {
1709 1.6.2.2 jruoho vtw_ctl_t *ctl;
1710 1.6.2.2 jruoho vtw_t *vtw;
1711 1.6.2.2 jruoho
1712 1.6.2.2 jruoho db_trace(KTR_VTW
1713 1.6.2.2 jruoho , (res, "vtw: lookup %6A:%P %6A:%P"
1714 1.6.2.2 jruoho , db_store(faddr, sizeof (*faddr)), fport
1715 1.6.2.2 jruoho , db_store(laddr, sizeof (*laddr)), lport));
1716 1.6.2.2 jruoho
1717 1.6.2.2 jruoho vtw = vtw_lookup_hash_v6((ctl = &vtw_tcpv6[0])
1718 1.6.2.2 jruoho , faddr, fport
1719 1.6.2.2 jruoho , laddr, lport, 0);
1720 1.6.2.2 jruoho
1721 1.6.2.2 jruoho return vtw_export_v6(ctl, vtw, res);
1722 1.6.2.2 jruoho }
1723 1.6.2.2 jruoho
1724 1.6.2.2 jruoho static vestigial_hooks_t tcp_hooks = {
1725 1.6.2.2 jruoho .init_ports4 = tcp_init_ports_v4,
1726 1.6.2.2 jruoho .next_port4 = tcp_next_port_v4,
1727 1.6.2.2 jruoho .lookup4 = tcp_lookup_v4,
1728 1.6.2.2 jruoho .init_ports6 = tcp_init_ports_v6,
1729 1.6.2.2 jruoho .next_port6 = tcp_next_port_v6,
1730 1.6.2.2 jruoho .lookup6 = tcp_lookup_v6,
1731 1.6.2.2 jruoho };
1732 1.6.2.2 jruoho
1733 1.6.2.2 jruoho static bool
1734 1.6.2.2 jruoho vtw_select(int af, fatp_ctl_t **fatp, vtw_ctl_t **ctlp)
1735 1.6.2.2 jruoho {
1736 1.6.2.2 jruoho fatp_ctl_t *fat;
1737 1.6.2.2 jruoho vtw_ctl_t *ctl;
1738 1.6.2.2 jruoho
1739 1.6.2.2 jruoho switch (af) {
1740 1.6.2.2 jruoho case AF_INET:
1741 1.6.2.2 jruoho fat = &fat_tcpv4;
1742 1.6.2.2 jruoho ctl = &vtw_tcpv4[0];
1743 1.6.2.2 jruoho break;
1744 1.6.2.2 jruoho case AF_INET6:
1745 1.6.2.2 jruoho fat = &fat_tcpv6;
1746 1.6.2.2 jruoho ctl = &vtw_tcpv6[0];
1747 1.6.2.2 jruoho break;
1748 1.6.2.2 jruoho default:
1749 1.6.2.2 jruoho return false;
1750 1.6.2.2 jruoho }
1751 1.6.2.2 jruoho if (fatp != NULL)
1752 1.6.2.2 jruoho *fatp = fat;
1753 1.6.2.2 jruoho if (ctlp != NULL)
1754 1.6.2.2 jruoho *ctlp = ctl;
1755 1.6.2.2 jruoho return true;
1756 1.6.2.2 jruoho }
1757 1.6.2.2 jruoho
1758 1.6.2.2 jruoho /*!\brief initialize controlling instance
1759 1.6.2.2 jruoho */
1760 1.6.2.2 jruoho static int
1761 1.6.2.2 jruoho vtw_control_init(int af)
1762 1.6.2.2 jruoho {
1763 1.6.2.2 jruoho fatp_ctl_t *fat;
1764 1.6.2.2 jruoho vtw_ctl_t *ctl;
1765 1.6.2.2 jruoho fatp_t *fat_base;
1766 1.6.2.2 jruoho fatp_t **fat_hash;
1767 1.6.2.2 jruoho vtw_t *ctl_base_v;
1768 1.6.2.2 jruoho uint32_t n, m;
1769 1.6.2.2 jruoho size_t sz;
1770 1.6.2.2 jruoho
1771 1.6.2.2 jruoho KASSERT(powerof2(tcp_vtw_entries));
1772 1.6.2.2 jruoho
1773 1.6.2.2 jruoho if (!vtw_select(af, &fat, &ctl))
1774 1.6.2.2 jruoho return EAFNOSUPPORT;
1775 1.6.2.2 jruoho
1776 1.6.2.2 jruoho if (fat->hash != NULL) {
1777 1.6.2.2 jruoho KASSERT(fat->base != NULL && ctl->base.v != NULL);
1778 1.6.2.2 jruoho return 0;
1779 1.6.2.2 jruoho }
1780 1.6.2.2 jruoho
1781 1.6.2.2 jruoho /* Allocate 10% more capacity in the fat pointers.
1782 1.6.2.2 jruoho * We should only need ~#hash additional based on
1783 1.6.2.2 jruoho * how they age, but TIME_WAIT assassination could cause
1784 1.6.2.2 jruoho * sparse fat pointer utilisation.
1785 1.6.2.2 jruoho */
1786 1.6.2.2 jruoho m = 512;
1787 1.6.2.2 jruoho n = 2*m + (11 * (tcp_vtw_entries / fatp_ntags())) / 10;
1788 1.6.2.2 jruoho sz = (ctl->is_v4 ? sizeof(vtw_v4_t) : sizeof(vtw_v6_t));
1789 1.6.2.2 jruoho
1790 1.6.2.2 jruoho fat_hash = kmem_zalloc(2*m * sizeof(fatp_t *), KM_NOSLEEP);
1791 1.6.2.2 jruoho
1792 1.6.2.2 jruoho if (fat_hash == NULL) {
1793 1.6.2.2 jruoho printf("%s: could not allocate %zu bytes for "
1794 1.6.2.2 jruoho "hash anchors", __func__, 2*m * sizeof(fatp_t *));
1795 1.6.2.2 jruoho return ENOMEM;
1796 1.6.2.2 jruoho }
1797 1.6.2.2 jruoho
1798 1.6.2.2 jruoho fat_base = kmem_zalloc(2*n * sizeof(fatp_t), KM_NOSLEEP);
1799 1.6.2.2 jruoho
1800 1.6.2.2 jruoho if (fat_base == NULL) {
1801 1.6.2.2 jruoho kmem_free(fat_hash, 2*m * sizeof (fatp_t *));
1802 1.6.2.2 jruoho printf("%s: could not allocate %zu bytes for "
1803 1.6.2.2 jruoho "fatp_t array", __func__, 2*n * sizeof(fatp_t));
1804 1.6.2.2 jruoho return ENOMEM;
1805 1.6.2.2 jruoho }
1806 1.6.2.2 jruoho
1807 1.6.2.2 jruoho ctl_base_v = kmem_zalloc(tcp_vtw_entries * sz, KM_NOSLEEP);
1808 1.6.2.2 jruoho
1809 1.6.2.2 jruoho if (ctl_base_v == NULL) {
1810 1.6.2.2 jruoho kmem_free(fat_hash, 2*m * sizeof (fatp_t *));
1811 1.6.2.2 jruoho kmem_free(fat_base, 2*n * sizeof(fatp_t));
1812 1.6.2.2 jruoho printf("%s: could not allocate %zu bytes for "
1813 1.6.2.2 jruoho "vtw_t array", __func__, tcp_vtw_entries * sz);
1814 1.6.2.2 jruoho return ENOMEM;
1815 1.6.2.2 jruoho }
1816 1.6.2.2 jruoho
1817 1.6.2.2 jruoho fatp_init(fat, n, m, fat_base, fat_hash);
1818 1.6.2.2 jruoho
1819 1.6.2.2 jruoho vtw_init(fat, ctl, tcp_vtw_entries, ctl_base_v);
1820 1.6.2.2 jruoho
1821 1.6.2.2 jruoho return 0;
1822 1.6.2.2 jruoho }
1823 1.6.2.2 jruoho
1824 1.6.2.2 jruoho /*!\brief select controlling instance
1825 1.6.2.2 jruoho */
1826 1.6.2.2 jruoho static vtw_ctl_t *
1827 1.6.2.2 jruoho vtw_control(int af, uint32_t msl)
1828 1.6.2.2 jruoho {
1829 1.6.2.2 jruoho fatp_ctl_t *fat;
1830 1.6.2.2 jruoho vtw_ctl_t *ctl;
1831 1.6.2.2 jruoho int class = msl_to_class(msl);
1832 1.6.2.2 jruoho
1833 1.6.2.2 jruoho if (!vtw_select(af, &fat, &ctl))
1834 1.6.2.2 jruoho return NULL;
1835 1.6.2.2 jruoho
1836 1.6.2.2 jruoho if (!fat->base || !ctl->base.v)
1837 1.6.2.2 jruoho return NULL;
1838 1.6.2.2 jruoho
1839 1.6.2.2 jruoho if (!tcp_vtw_was_enabled) {
1840 1.6.2.2 jruoho /* This guarantees is timer ticks until we no longer need them.
1841 1.6.2.2 jruoho */
1842 1.6.2.2 jruoho tcp_vtw_was_enabled = 1;
1843 1.6.2.2 jruoho
1844 1.6.2.2 jruoho callout_schedule(&vtw_cs, hz / 5);
1845 1.6.2.2 jruoho
1846 1.6.2.2 jruoho tcbtable.vestige = &tcp_hooks;
1847 1.6.2.2 jruoho }
1848 1.6.2.2 jruoho
1849 1.6.2.2 jruoho return ctl + class;
1850 1.6.2.2 jruoho }
1851 1.6.2.2 jruoho
1852 1.6.2.2 jruoho /*!\brief add TCP pcb to vestigial timewait
1853 1.6.2.2 jruoho */
1854 1.6.2.2 jruoho int
1855 1.6.2.2 jruoho vtw_add(int af, struct tcpcb *tp)
1856 1.6.2.2 jruoho {
1857 1.6.2.2 jruoho int enable;
1858 1.6.2.2 jruoho vtw_ctl_t *ctl;
1859 1.6.2.2 jruoho vtw_t *vtw;
1860 1.6.2.2 jruoho
1861 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
1862 1.6.2.2 jruoho
1863 1.6.2.2 jruoho ctl = vtw_control(af, tp->t_msl);
1864 1.6.2.2 jruoho if (!ctl)
1865 1.6.2.2 jruoho return 0;
1866 1.6.2.2 jruoho
1867 1.6.2.2 jruoho enable = (af == AF_INET) ? tcp4_vtw_enable : tcp6_vtw_enable;
1868 1.6.2.2 jruoho
1869 1.6.2.2 jruoho vtw = vtw_alloc(ctl);
1870 1.6.2.2 jruoho
1871 1.6.2.2 jruoho if (vtw) {
1872 1.6.2.2 jruoho vtw->snd_nxt = tp->snd_nxt;
1873 1.6.2.2 jruoho vtw->rcv_nxt = tp->rcv_nxt;
1874 1.6.2.2 jruoho
1875 1.6.2.2 jruoho switch (af) {
1876 1.6.2.2 jruoho case AF_INET: {
1877 1.6.2.2 jruoho struct inpcb *inp = tp->t_inpcb;
1878 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
1879 1.6.2.2 jruoho
1880 1.6.2.2 jruoho v4->faddr = inp->inp_faddr.s_addr;
1881 1.6.2.2 jruoho v4->laddr = inp->inp_laddr.s_addr;
1882 1.6.2.2 jruoho v4->fport = inp->inp_fport;
1883 1.6.2.2 jruoho v4->lport = inp->inp_lport;
1884 1.6.2.2 jruoho
1885 1.6.2.2 jruoho vtw->reuse_port = !!(inp->inp_socket->so_options
1886 1.6.2.2 jruoho & SO_REUSEPORT);
1887 1.6.2.2 jruoho vtw->reuse_addr = !!(inp->inp_socket->so_options
1888 1.6.2.2 jruoho & SO_REUSEADDR);
1889 1.6.2.2 jruoho vtw->v6only = 0;
1890 1.6.2.2 jruoho vtw->uid = inp->inp_socket->so_uidinfo->ui_uid;
1891 1.6.2.2 jruoho
1892 1.6.2.2 jruoho vtw_inshash_v4(ctl, vtw);
1893 1.6.2.2 jruoho
1894 1.6.2.2 jruoho
1895 1.6.2.2 jruoho #ifdef VTW_DEBUG
1896 1.6.2.2 jruoho /* Immediate lookup (connected and port) to
1897 1.6.2.2 jruoho * ensure at least that works!
1898 1.6.2.2 jruoho */
1899 1.6.2.2 jruoho if (enable & 4) {
1900 1.6.2.2 jruoho KASSERT(vtw_lookup_hash_v4
1901 1.6.2.2 jruoho (ctl
1902 1.6.2.2 jruoho , inp->inp_faddr.s_addr, inp->inp_fport
1903 1.6.2.2 jruoho , inp->inp_laddr.s_addr, inp->inp_lport
1904 1.6.2.2 jruoho , 0)
1905 1.6.2.2 jruoho == vtw);
1906 1.6.2.2 jruoho KASSERT(vtw_lookup_hash_v4
1907 1.6.2.2 jruoho (ctl
1908 1.6.2.2 jruoho , inp->inp_faddr.s_addr, inp->inp_fport
1909 1.6.2.2 jruoho , inp->inp_laddr.s_addr, inp->inp_lport
1910 1.6.2.2 jruoho , 1));
1911 1.6.2.2 jruoho }
1912 1.6.2.2 jruoho /* Immediate port iterator functionality check: not wild
1913 1.6.2.2 jruoho */
1914 1.6.2.2 jruoho if (enable & 8) {
1915 1.6.2.2 jruoho struct tcp_ports_iterator *it;
1916 1.6.2.2 jruoho struct vestigial_inpcb res;
1917 1.6.2.2 jruoho int cnt = 0;
1918 1.6.2.2 jruoho
1919 1.6.2.2 jruoho it = tcp_init_ports_v4(inp->inp_laddr
1920 1.6.2.2 jruoho , inp->inp_lport, 0);
1921 1.6.2.2 jruoho
1922 1.6.2.2 jruoho while (tcp_next_port_v4(it, &res)) {
1923 1.6.2.2 jruoho ++cnt;
1924 1.6.2.2 jruoho }
1925 1.6.2.2 jruoho KASSERT(cnt);
1926 1.6.2.2 jruoho }
1927 1.6.2.2 jruoho /* Immediate port iterator functionality check: wild
1928 1.6.2.2 jruoho */
1929 1.6.2.2 jruoho if (enable & 16) {
1930 1.6.2.2 jruoho struct tcp_ports_iterator *it;
1931 1.6.2.2 jruoho struct vestigial_inpcb res;
1932 1.6.2.2 jruoho struct in_addr any;
1933 1.6.2.2 jruoho int cnt = 0;
1934 1.6.2.2 jruoho
1935 1.6.2.2 jruoho any.s_addr = htonl(INADDR_ANY);
1936 1.6.2.2 jruoho
1937 1.6.2.2 jruoho it = tcp_init_ports_v4(any, inp->inp_lport, 1);
1938 1.6.2.2 jruoho
1939 1.6.2.2 jruoho while (tcp_next_port_v4(it, &res)) {
1940 1.6.2.2 jruoho ++cnt;
1941 1.6.2.2 jruoho }
1942 1.6.2.2 jruoho KASSERT(cnt);
1943 1.6.2.2 jruoho }
1944 1.6.2.2 jruoho #endif /* VTW_DEBUG */
1945 1.6.2.2 jruoho break;
1946 1.6.2.2 jruoho }
1947 1.6.2.2 jruoho
1948 1.6.2.2 jruoho case AF_INET6: {
1949 1.6.2.2 jruoho struct in6pcb *inp = tp->t_in6pcb;
1950 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
1951 1.6.2.2 jruoho
1952 1.6.2.2 jruoho v6->faddr = inp->in6p_faddr;
1953 1.6.2.2 jruoho v6->laddr = inp->in6p_laddr;
1954 1.6.2.2 jruoho v6->fport = inp->in6p_fport;
1955 1.6.2.2 jruoho v6->lport = inp->in6p_lport;
1956 1.6.2.2 jruoho
1957 1.6.2.2 jruoho vtw->reuse_port = !!(inp->in6p_socket->so_options
1958 1.6.2.2 jruoho & SO_REUSEPORT);
1959 1.6.2.2 jruoho vtw->reuse_addr = !!(inp->in6p_socket->so_options
1960 1.6.2.2 jruoho & SO_REUSEADDR);
1961 1.6.2.2 jruoho vtw->v6only = !!(inp->in6p_flags
1962 1.6.2.2 jruoho & IN6P_IPV6_V6ONLY);
1963 1.6.2.2 jruoho vtw->uid = inp->in6p_socket->so_uidinfo->ui_uid;
1964 1.6.2.2 jruoho
1965 1.6.2.2 jruoho vtw_inshash_v6(ctl, vtw);
1966 1.6.2.2 jruoho #ifdef VTW_DEBUG
1967 1.6.2.2 jruoho /* Immediate lookup (connected and port) to
1968 1.6.2.2 jruoho * ensure at least that works!
1969 1.6.2.2 jruoho */
1970 1.6.2.2 jruoho if (enable & 4) {
1971 1.6.2.2 jruoho KASSERT(vtw_lookup_hash_v6(ctl
1972 1.6.2.2 jruoho , &inp->in6p_faddr, inp->in6p_fport
1973 1.6.2.2 jruoho , &inp->in6p_laddr, inp->in6p_lport
1974 1.6.2.2 jruoho , 0)
1975 1.6.2.2 jruoho == vtw);
1976 1.6.2.2 jruoho KASSERT(vtw_lookup_hash_v6
1977 1.6.2.2 jruoho (ctl
1978 1.6.2.2 jruoho , &inp->in6p_faddr, inp->in6p_fport
1979 1.6.2.2 jruoho , &inp->in6p_laddr, inp->in6p_lport
1980 1.6.2.2 jruoho , 1));
1981 1.6.2.2 jruoho }
1982 1.6.2.2 jruoho /* Immediate port iterator functionality check: not wild
1983 1.6.2.2 jruoho */
1984 1.6.2.2 jruoho if (enable & 8) {
1985 1.6.2.2 jruoho struct tcp_ports_iterator *it;
1986 1.6.2.2 jruoho struct vestigial_inpcb res;
1987 1.6.2.2 jruoho int cnt = 0;
1988 1.6.2.2 jruoho
1989 1.6.2.2 jruoho it = tcp_init_ports_v6(&inp->in6p_laddr
1990 1.6.2.2 jruoho , inp->in6p_lport, 0);
1991 1.6.2.2 jruoho
1992 1.6.2.2 jruoho while (tcp_next_port_v6(it, &res)) {
1993 1.6.2.2 jruoho ++cnt;
1994 1.6.2.2 jruoho }
1995 1.6.2.2 jruoho KASSERT(cnt);
1996 1.6.2.2 jruoho }
1997 1.6.2.2 jruoho /* Immediate port iterator functionality check: wild
1998 1.6.2.2 jruoho */
1999 1.6.2.2 jruoho if (enable & 16) {
2000 1.6.2.2 jruoho struct tcp_ports_iterator *it;
2001 1.6.2.2 jruoho struct vestigial_inpcb res;
2002 1.6.2.2 jruoho static struct in6_addr any = IN6ADDR_ANY_INIT;
2003 1.6.2.2 jruoho int cnt = 0;
2004 1.6.2.2 jruoho
2005 1.6.2.2 jruoho it = tcp_init_ports_v6(&any
2006 1.6.2.2 jruoho , inp->in6p_lport, 1);
2007 1.6.2.2 jruoho
2008 1.6.2.2 jruoho while (tcp_next_port_v6(it, &res)) {
2009 1.6.2.2 jruoho ++cnt;
2010 1.6.2.2 jruoho }
2011 1.6.2.2 jruoho KASSERT(cnt);
2012 1.6.2.2 jruoho }
2013 1.6.2.2 jruoho #endif /* VTW_DEBUG */
2014 1.6.2.2 jruoho break;
2015 1.6.2.2 jruoho }
2016 1.6.2.2 jruoho }
2017 1.6.2.2 jruoho
2018 1.6.2.2 jruoho tcp_canceltimers(tp);
2019 1.6.2.2 jruoho tp = tcp_close(tp);
2020 1.6.2.2 jruoho KASSERT(!tp);
2021 1.6.2.2 jruoho
2022 1.6.2.2 jruoho return 1;
2023 1.6.2.2 jruoho }
2024 1.6.2.2 jruoho
2025 1.6.2.2 jruoho return 0;
2026 1.6.2.2 jruoho }
2027 1.6.2.2 jruoho
2028 1.6.2.2 jruoho /*!\brief restart timer for vestigial time-wait entry
2029 1.6.2.2 jruoho */
2030 1.6.2.2 jruoho static void
2031 1.6.2.2 jruoho vtw_restart_v4(vestigial_inpcb_t *vp)
2032 1.6.2.2 jruoho {
2033 1.6.2.2 jruoho vtw_v4_t copy = *(vtw_v4_t*)vp->vtw;
2034 1.6.2.2 jruoho vtw_t *vtw;
2035 1.6.2.2 jruoho vtw_t *cp = ©.common;
2036 1.6.2.2 jruoho vtw_ctl_t *ctl;
2037 1.6.2.2 jruoho
2038 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
2039 1.6.2.2 jruoho
2040 1.6.2.2 jruoho db_trace(KTR_VTW
2041 1.6.2.2 jruoho , (vp->vtw, "vtw: restart %A:%P %A:%P"
2042 1.6.2.2 jruoho , vp->faddr.v4.s_addr, vp->fport
2043 1.6.2.2 jruoho , vp->laddr.v4.s_addr, vp->lport));
2044 1.6.2.2 jruoho
2045 1.6.2.2 jruoho /* Class might have changed, so have a squiz.
2046 1.6.2.2 jruoho */
2047 1.6.2.2 jruoho ctl = vtw_control(AF_INET, class_to_msl(cp->msl_class));
2048 1.6.2.2 jruoho vtw = vtw_alloc(ctl);
2049 1.6.2.2 jruoho
2050 1.6.2.2 jruoho if (vtw) {
2051 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
2052 1.6.2.2 jruoho
2053 1.6.2.2 jruoho /* Safe now to unhash the old entry
2054 1.6.2.2 jruoho */
2055 1.6.2.2 jruoho vtw_del(vp->ctl, vp->vtw);
2056 1.6.2.2 jruoho
2057 1.6.2.2 jruoho vtw->snd_nxt = cp->snd_nxt;
2058 1.6.2.2 jruoho vtw->rcv_nxt = cp->rcv_nxt;
2059 1.6.2.2 jruoho
2060 1.6.2.2 jruoho v4->faddr = copy.faddr;
2061 1.6.2.2 jruoho v4->laddr = copy.laddr;
2062 1.6.2.2 jruoho v4->fport = copy.fport;
2063 1.6.2.2 jruoho v4->lport = copy.lport;
2064 1.6.2.2 jruoho
2065 1.6.2.2 jruoho vtw->reuse_port = cp->reuse_port;
2066 1.6.2.2 jruoho vtw->reuse_addr = cp->reuse_addr;
2067 1.6.2.2 jruoho vtw->v6only = 0;
2068 1.6.2.2 jruoho vtw->uid = cp->uid;
2069 1.6.2.2 jruoho
2070 1.6.2.2 jruoho vtw_inshash_v4(ctl, vtw);
2071 1.6.2.2 jruoho }
2072 1.6.2.2 jruoho
2073 1.6.2.2 jruoho vp->valid = 0;
2074 1.6.2.2 jruoho }
2075 1.6.2.2 jruoho
2076 1.6.2.2 jruoho /*!\brief restart timer for vestigial time-wait entry
2077 1.6.2.2 jruoho */
2078 1.6.2.2 jruoho static void
2079 1.6.2.2 jruoho vtw_restart_v6(vestigial_inpcb_t *vp)
2080 1.6.2.2 jruoho {
2081 1.6.2.2 jruoho vtw_v6_t copy = *(vtw_v6_t*)vp->vtw;
2082 1.6.2.2 jruoho vtw_t *vtw;
2083 1.6.2.2 jruoho vtw_t *cp = ©.common;
2084 1.6.2.2 jruoho vtw_ctl_t *ctl;
2085 1.6.2.2 jruoho
2086 1.6.2.2 jruoho KASSERT(mutex_owned(softnet_lock));
2087 1.6.2.2 jruoho
2088 1.6.2.2 jruoho db_trace(KTR_VTW
2089 1.6.2.2 jruoho , (vp->vtw, "vtw: restart %6A:%P %6A:%P"
2090 1.6.2.2 jruoho , db_store(&vp->faddr.v6, sizeof (vp->faddr.v6))
2091 1.6.2.2 jruoho , vp->fport
2092 1.6.2.2 jruoho , db_store(&vp->laddr.v6, sizeof (vp->laddr.v6))
2093 1.6.2.2 jruoho , vp->lport));
2094 1.6.2.2 jruoho
2095 1.6.2.2 jruoho /* Class might have changed, so have a squiz.
2096 1.6.2.2 jruoho */
2097 1.6.2.2 jruoho ctl = vtw_control(AF_INET6, class_to_msl(cp->msl_class));
2098 1.6.2.2 jruoho vtw = vtw_alloc(ctl);
2099 1.6.2.2 jruoho
2100 1.6.2.2 jruoho if (vtw) {
2101 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
2102 1.6.2.2 jruoho
2103 1.6.2.2 jruoho /* Safe now to unhash the old entry
2104 1.6.2.2 jruoho */
2105 1.6.2.2 jruoho vtw_del(vp->ctl, vp->vtw);
2106 1.6.2.2 jruoho
2107 1.6.2.2 jruoho vtw->snd_nxt = cp->snd_nxt;
2108 1.6.2.2 jruoho vtw->rcv_nxt = cp->rcv_nxt;
2109 1.6.2.2 jruoho
2110 1.6.2.2 jruoho v6->faddr = copy.faddr;
2111 1.6.2.2 jruoho v6->laddr = copy.laddr;
2112 1.6.2.2 jruoho v6->fport = copy.fport;
2113 1.6.2.2 jruoho v6->lport = copy.lport;
2114 1.6.2.2 jruoho
2115 1.6.2.2 jruoho vtw->reuse_port = cp->reuse_port;
2116 1.6.2.2 jruoho vtw->reuse_addr = cp->reuse_addr;
2117 1.6.2.2 jruoho vtw->v6only = cp->v6only;
2118 1.6.2.2 jruoho vtw->uid = cp->uid;
2119 1.6.2.2 jruoho
2120 1.6.2.2 jruoho vtw_inshash_v6(ctl, vtw);
2121 1.6.2.2 jruoho }
2122 1.6.2.2 jruoho
2123 1.6.2.2 jruoho vp->valid = 0;
2124 1.6.2.2 jruoho }
2125 1.6.2.2 jruoho
2126 1.6.2.2 jruoho /*!\brief restart timer for vestigial time-wait entry
2127 1.6.2.2 jruoho */
2128 1.6.2.2 jruoho void
2129 1.6.2.2 jruoho vtw_restart(vestigial_inpcb_t *vp)
2130 1.6.2.2 jruoho {
2131 1.6.2.2 jruoho if (!vp || !vp->valid)
2132 1.6.2.2 jruoho return;
2133 1.6.2.2 jruoho
2134 1.6.2.2 jruoho if (vp->v4)
2135 1.6.2.2 jruoho vtw_restart_v4(vp);
2136 1.6.2.2 jruoho else
2137 1.6.2.2 jruoho vtw_restart_v6(vp);
2138 1.6.2.2 jruoho }
2139 1.6.2.2 jruoho
2140 1.6.2.2 jruoho int
2141 1.6.2.2 jruoho vtw_earlyinit(void)
2142 1.6.2.2 jruoho {
2143 1.6.2.2 jruoho int i, rc;
2144 1.6.2.2 jruoho
2145 1.6.2.2 jruoho callout_init(&vtw_cs, 0);
2146 1.6.2.2 jruoho callout_setfunc(&vtw_cs, vtw_tick, 0);
2147 1.6.2.2 jruoho
2148 1.6.2.2 jruoho for (i = 0; i < VTW_NCLASS; ++i) {
2149 1.6.2.2 jruoho vtw_tcpv4[i].is_v4 = 1;
2150 1.6.2.2 jruoho vtw_tcpv6[i].is_v6 = 1;
2151 1.6.2.2 jruoho }
2152 1.6.2.2 jruoho
2153 1.6.2.2 jruoho if ((rc = vtw_control_init(AF_INET)) != 0 ||
2154 1.6.2.2 jruoho (rc = vtw_control_init(AF_INET6)) != 0)
2155 1.6.2.2 jruoho return rc;
2156 1.6.2.2 jruoho
2157 1.6.2.2 jruoho return 0;
2158 1.6.2.2 jruoho }
2159 1.6.2.2 jruoho
2160 1.6.2.2 jruoho #ifdef VTW_DEBUG
2161 1.6.2.2 jruoho #include <sys/syscallargs.h>
2162 1.6.2.2 jruoho #include <sys/sysctl.h>
2163 1.6.2.2 jruoho
2164 1.6.2.2 jruoho /*!\brief add lalp, fafp entries for debug
2165 1.6.2.2 jruoho */
2166 1.6.2.2 jruoho int
2167 1.6.2.2 jruoho vtw_debug_add(int af, sin_either_t *la, sin_either_t *fa, int msl, int class)
2168 1.6.2.2 jruoho {
2169 1.6.2.2 jruoho vtw_ctl_t *ctl;
2170 1.6.2.2 jruoho vtw_t *vtw;
2171 1.6.2.2 jruoho
2172 1.6.2.2 jruoho ctl = vtw_control(af, msl ? msl : class_to_msl(class));
2173 1.6.2.2 jruoho if (!ctl)
2174 1.6.2.2 jruoho return 0;
2175 1.6.2.2 jruoho
2176 1.6.2.2 jruoho vtw = vtw_alloc(ctl);
2177 1.6.2.2 jruoho
2178 1.6.2.2 jruoho if (vtw) {
2179 1.6.2.2 jruoho vtw->snd_nxt = 0;
2180 1.6.2.2 jruoho vtw->rcv_nxt = 0;
2181 1.6.2.2 jruoho
2182 1.6.2.2 jruoho switch (af) {
2183 1.6.2.2 jruoho case AF_INET: {
2184 1.6.2.2 jruoho vtw_v4_t *v4 = (void*)vtw;
2185 1.6.2.2 jruoho
2186 1.6.2.2 jruoho v4->faddr = fa->sin_addr.v4.s_addr;
2187 1.6.2.2 jruoho v4->laddr = la->sin_addr.v4.s_addr;
2188 1.6.2.2 jruoho v4->fport = fa->sin_port;
2189 1.6.2.2 jruoho v4->lport = la->sin_port;
2190 1.6.2.2 jruoho
2191 1.6.2.2 jruoho vtw->reuse_port = 1;
2192 1.6.2.2 jruoho vtw->reuse_addr = 1;
2193 1.6.2.2 jruoho vtw->v6only = 0;
2194 1.6.2.2 jruoho vtw->uid = 0;
2195 1.6.2.2 jruoho
2196 1.6.2.2 jruoho vtw_inshash_v4(ctl, vtw);
2197 1.6.2.2 jruoho break;
2198 1.6.2.2 jruoho }
2199 1.6.2.2 jruoho
2200 1.6.2.2 jruoho case AF_INET6: {
2201 1.6.2.2 jruoho vtw_v6_t *v6 = (void*)vtw;
2202 1.6.2.2 jruoho
2203 1.6.2.2 jruoho v6->faddr = fa->sin_addr.v6;
2204 1.6.2.2 jruoho v6->laddr = la->sin_addr.v6;
2205 1.6.2.2 jruoho
2206 1.6.2.2 jruoho v6->fport = fa->sin_port;
2207 1.6.2.2 jruoho v6->lport = la->sin_port;
2208 1.6.2.2 jruoho
2209 1.6.2.2 jruoho vtw->reuse_port = 1;
2210 1.6.2.2 jruoho vtw->reuse_addr = 1;
2211 1.6.2.2 jruoho vtw->v6only = 0;
2212 1.6.2.2 jruoho vtw->uid = 0;
2213 1.6.2.2 jruoho
2214 1.6.2.2 jruoho vtw_inshash_v6(ctl, vtw);
2215 1.6.2.2 jruoho break;
2216 1.6.2.2 jruoho }
2217 1.6.2.2 jruoho
2218 1.6.2.2 jruoho default:
2219 1.6.2.2 jruoho break;
2220 1.6.2.2 jruoho }
2221 1.6.2.2 jruoho
2222 1.6.2.2 jruoho return 1;
2223 1.6.2.2 jruoho }
2224 1.6.2.2 jruoho
2225 1.6.2.2 jruoho return 0;
2226 1.6.2.2 jruoho }
2227 1.6.2.2 jruoho
2228 1.6.2.2 jruoho static int vtw_syscall = 0;
2229 1.6.2.2 jruoho
2230 1.6.2.2 jruoho static int
2231 1.6.2.2 jruoho vtw_debug_process(vtw_sysargs_t *ap)
2232 1.6.2.2 jruoho {
2233 1.6.2.2 jruoho struct vestigial_inpcb vestige;
2234 1.6.2.2 jruoho int rc = 0;
2235 1.6.2.2 jruoho
2236 1.6.2.2 jruoho mutex_enter(softnet_lock);
2237 1.6.2.2 jruoho
2238 1.6.2.2 jruoho switch (ap->op) {
2239 1.6.2.2 jruoho case 0: // insert
2240 1.6.2.2 jruoho vtw_debug_add(ap->la.sin_family
2241 1.6.2.2 jruoho , &ap->la
2242 1.6.2.2 jruoho , &ap->fa
2243 1.6.2.2 jruoho , TCPTV_MSL
2244 1.6.2.2 jruoho , 0);
2245 1.6.2.2 jruoho break;
2246 1.6.2.2 jruoho
2247 1.6.2.2 jruoho case 1: // lookup
2248 1.6.2.2 jruoho case 2: // restart
2249 1.6.2.2 jruoho switch (ap->la.sin_family) {
2250 1.6.2.2 jruoho case AF_INET:
2251 1.6.2.2 jruoho if (tcp_lookup_v4(ap->fa.sin_addr.v4, ap->fa.sin_port,
2252 1.6.2.2 jruoho ap->la.sin_addr.v4, ap->la.sin_port,
2253 1.6.2.2 jruoho &vestige)) {
2254 1.6.2.2 jruoho if (ap->op == 2) {
2255 1.6.2.2 jruoho vtw_restart(&vestige);
2256 1.6.2.2 jruoho }
2257 1.6.2.2 jruoho rc = 0;
2258 1.6.2.2 jruoho } else
2259 1.6.2.2 jruoho rc = ESRCH;
2260 1.6.2.2 jruoho break;
2261 1.6.2.2 jruoho
2262 1.6.2.2 jruoho case AF_INET6:
2263 1.6.2.2 jruoho if (tcp_lookup_v6(&ap->fa.sin_addr.v6, ap->fa.sin_port,
2264 1.6.2.2 jruoho &ap->la.sin_addr.v6, ap->la.sin_port,
2265 1.6.2.2 jruoho &vestige)) {
2266 1.6.2.2 jruoho if (ap->op == 2) {
2267 1.6.2.2 jruoho vtw_restart(&vestige);
2268 1.6.2.2 jruoho }
2269 1.6.2.2 jruoho rc = 0;
2270 1.6.2.2 jruoho } else
2271 1.6.2.2 jruoho rc = ESRCH;
2272 1.6.2.2 jruoho break;
2273 1.6.2.2 jruoho default:
2274 1.6.2.2 jruoho rc = EINVAL;
2275 1.6.2.2 jruoho }
2276 1.6.2.2 jruoho break;
2277 1.6.2.2 jruoho
2278 1.6.2.2 jruoho default:
2279 1.6.2.2 jruoho rc = EINVAL;
2280 1.6.2.2 jruoho }
2281 1.6.2.2 jruoho
2282 1.6.2.2 jruoho mutex_exit(softnet_lock);
2283 1.6.2.2 jruoho return rc;
2284 1.6.2.2 jruoho }
2285 1.6.2.2 jruoho
2286 1.6.2.2 jruoho struct sys_vtw_args {
2287 1.6.2.2 jruoho syscallarg(const vtw_sysargs_t *) req;
2288 1.6.2.2 jruoho syscallarg(size_t) len;
2289 1.6.2.2 jruoho };
2290 1.6.2.2 jruoho
2291 1.6.2.2 jruoho static int
2292 1.6.2.2 jruoho vtw_sys(struct lwp *l, const void *_, register_t *retval)
2293 1.6.2.2 jruoho {
2294 1.6.2.2 jruoho const struct sys_vtw_args *uap = _;
2295 1.6.2.2 jruoho void *buf;
2296 1.6.2.2 jruoho int rc;
2297 1.6.2.2 jruoho size_t len = SCARG(uap, len);
2298 1.6.2.2 jruoho
2299 1.6.2.2 jruoho if (len != sizeof (vtw_sysargs_t))
2300 1.6.2.2 jruoho return EINVAL;
2301 1.6.2.2 jruoho
2302 1.6.2.2 jruoho buf = kmem_alloc(len, KM_SLEEP);
2303 1.6.2.2 jruoho if (!buf)
2304 1.6.2.2 jruoho return ENOMEM;
2305 1.6.2.2 jruoho
2306 1.6.2.2 jruoho rc = copyin(SCARG(uap, req), buf, len);
2307 1.6.2.2 jruoho if (!rc) {
2308 1.6.2.2 jruoho rc = vtw_debug_process(buf);
2309 1.6.2.2 jruoho }
2310 1.6.2.2 jruoho kmem_free(buf, len);
2311 1.6.2.2 jruoho
2312 1.6.2.2 jruoho return rc;
2313 1.6.2.2 jruoho }
2314 1.6.2.2 jruoho
2315 1.6.2.2 jruoho static void
2316 1.6.2.2 jruoho vtw_sanity_check(void)
2317 1.6.2.2 jruoho {
2318 1.6.2.2 jruoho vtw_ctl_t *ctl;
2319 1.6.2.2 jruoho vtw_t *vtw;
2320 1.6.2.2 jruoho int i;
2321 1.6.2.2 jruoho int n;
2322 1.6.2.2 jruoho
2323 1.6.2.2 jruoho for (i = 0; i < VTW_NCLASS; ++i) {
2324 1.6.2.2 jruoho ctl = &vtw_tcpv4[i];
2325 1.6.2.2 jruoho
2326 1.6.2.2 jruoho if (!ctl->base.v || ctl->nalloc)
2327 1.6.2.2 jruoho continue;
2328 1.6.2.2 jruoho
2329 1.6.2.2 jruoho for (n = 0, vtw = ctl->base.v; ; ) {
2330 1.6.2.2 jruoho ++n;
2331 1.6.2.2 jruoho vtw = vtw_next(ctl, vtw);
2332 1.6.2.2 jruoho if (vtw == ctl->base.v)
2333 1.6.2.2 jruoho break;
2334 1.6.2.2 jruoho }
2335 1.6.2.2 jruoho db_trace(KTR_VTW
2336 1.6.2.2 jruoho , (ctl, "sanity: class %x n %x nfree %x"
2337 1.6.2.2 jruoho , i, n, ctl->nfree));
2338 1.6.2.2 jruoho
2339 1.6.2.2 jruoho KASSERT(n == ctl->nfree);
2340 1.6.2.2 jruoho }
2341 1.6.2.2 jruoho
2342 1.6.2.2 jruoho for (i = 0; i < VTW_NCLASS; ++i) {
2343 1.6.2.2 jruoho ctl = &vtw_tcpv6[i];
2344 1.6.2.2 jruoho
2345 1.6.2.2 jruoho if (!ctl->base.v || ctl->nalloc)
2346 1.6.2.2 jruoho continue;
2347 1.6.2.2 jruoho
2348 1.6.2.2 jruoho for (n = 0, vtw = ctl->base.v; ; ) {
2349 1.6.2.2 jruoho ++n;
2350 1.6.2.2 jruoho vtw = vtw_next(ctl, vtw);
2351 1.6.2.2 jruoho if (vtw == ctl->base.v)
2352 1.6.2.2 jruoho break;
2353 1.6.2.2 jruoho }
2354 1.6.2.2 jruoho db_trace(KTR_VTW
2355 1.6.2.2 jruoho , (ctl, "sanity: class %x n %x nfree %x"
2356 1.6.2.2 jruoho , i, n, ctl->nfree));
2357 1.6.2.2 jruoho KASSERT(n == ctl->nfree);
2358 1.6.2.2 jruoho }
2359 1.6.2.2 jruoho }
2360 1.6.2.2 jruoho
2361 1.6.2.2 jruoho /*!\brief Initialise debug support.
2362 1.6.2.2 jruoho */
2363 1.6.2.2 jruoho static void
2364 1.6.2.2 jruoho vtw_debug_init(void)
2365 1.6.2.2 jruoho {
2366 1.6.2.2 jruoho int i;
2367 1.6.2.2 jruoho
2368 1.6.2.2 jruoho vtw_sanity_check();
2369 1.6.2.2 jruoho
2370 1.6.2.2 jruoho if (vtw_syscall)
2371 1.6.2.2 jruoho return;
2372 1.6.2.2 jruoho
2373 1.6.2.2 jruoho for (i = 511; i; --i) {
2374 1.6.2.2 jruoho if (sysent[i].sy_call == sys_nosys) {
2375 1.6.2.2 jruoho sysent[i].sy_call = vtw_sys;
2376 1.6.2.2 jruoho sysent[i].sy_narg = 2;
2377 1.6.2.2 jruoho sysent[i].sy_argsize = sizeof (struct sys_vtw_args);
2378 1.6.2.2 jruoho sysent[i].sy_flags = 0;
2379 1.6.2.2 jruoho
2380 1.6.2.2 jruoho vtw_syscall = i;
2381 1.6.2.2 jruoho break;
2382 1.6.2.2 jruoho }
2383 1.6.2.2 jruoho }
2384 1.6.2.2 jruoho if (i) {
2385 1.6.2.2 jruoho const struct sysctlnode *node;
2386 1.6.2.2 jruoho uint32_t flags;
2387 1.6.2.2 jruoho
2388 1.6.2.2 jruoho flags = sysctl_root.sysctl_flags;
2389 1.6.2.2 jruoho
2390 1.6.2.2 jruoho sysctl_root.sysctl_flags |= CTLFLAG_READWRITE;
2391 1.6.2.2 jruoho sysctl_root.sysctl_flags &= ~CTLFLAG_PERMANENT;
2392 1.6.2.2 jruoho
2393 1.6.2.2 jruoho sysctl_createv(0, 0, 0, &node,
2394 1.6.2.2 jruoho CTLFLAG_PERMANENT, CTLTYPE_NODE,
2395 1.6.2.2 jruoho "koff",
2396 1.6.2.2 jruoho SYSCTL_DESCR("Kernel Obscure Feature Finder"),
2397 1.6.2.2 jruoho 0, 0, 0, 0, CTL_CREATE, CTL_EOL);
2398 1.6.2.2 jruoho
2399 1.6.2.2 jruoho if (!node) {
2400 1.6.2.2 jruoho sysctl_createv(0, 0, 0, &node,
2401 1.6.2.2 jruoho CTLFLAG_PERMANENT, CTLTYPE_NODE,
2402 1.6.2.2 jruoho "koffka",
2403 1.6.2.2 jruoho SYSCTL_DESCR("The Real(tm) Kernel"
2404 1.6.2.2 jruoho " Obscure Feature Finder"),
2405 1.6.2.2 jruoho 0, 0, 0, 0, CTL_CREATE, CTL_EOL);
2406 1.6.2.2 jruoho }
2407 1.6.2.2 jruoho if (node) {
2408 1.6.2.2 jruoho sysctl_createv(0, 0, 0, 0,
2409 1.6.2.2 jruoho CTLFLAG_PERMANENT|CTLFLAG_READONLY,
2410 1.6.2.2 jruoho CTLTYPE_INT, "vtw_debug_syscall",
2411 1.6.2.2 jruoho SYSCTL_DESCR("vtw debug"
2412 1.6.2.2 jruoho " system call number"),
2413 1.6.2.2 jruoho 0, 0, &vtw_syscall, 0, node->sysctl_num,
2414 1.6.2.2 jruoho CTL_CREATE, CTL_EOL);
2415 1.6.2.2 jruoho }
2416 1.6.2.2 jruoho sysctl_root.sysctl_flags = flags;
2417 1.6.2.2 jruoho }
2418 1.6.2.2 jruoho }
2419 1.6.2.2 jruoho #else /* !VTW_DEBUG */
2420 1.6.2.2 jruoho static void
2421 1.6.2.2 jruoho vtw_debug_init(void)
2422 1.6.2.2 jruoho {
2423 1.6.2.2 jruoho return;
2424 1.6.2.2 jruoho }
2425 1.6.2.2 jruoho #endif /* !VTW_DEBUG */
2426