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