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