]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/in6_rmx.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_rmx.c
CommitLineData
2d21ac55 1/*
d1ecb069 2 * Copyright (c) 2003-2009 Apple Inc. All rights reserved.
2d21ac55
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
9bccf70c
A
29/* $FreeBSD: src/sys/netinet6/in6_rmx.c,v 1.1.2.2 2001/07/03 11:01:52 ume Exp $ */
30/* $KAME: in6_rmx.c,v 1.10 2001/05/24 05:44:58 itojun Exp $ */
1c79356b
A
31
32/*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61/*
62 * Copyright 1994, 1995 Massachusetts Institute of Technology
63 *
64 * Permission to use, copy, modify, and distribute this software and
65 * its documentation for any purpose and without fee is hereby
66 * granted, provided that both the above copyright notice and this
67 * permission notice appear in all copies, that both the above
68 * copyright notice and this permission notice appear in all
69 * supporting documentation, and that the name of M.I.T. not be used
70 * in advertising or publicity pertaining to distribution of the
71 * software without specific, written prior permission. M.I.T. makes
72 * no representations about the suitability of this software for any
73 * purpose. It is provided "as is" without express or implied
74 * warranty.
75 *
76 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
77 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
78 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
79 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
80 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
81 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
82 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
83 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
84 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
85 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
86 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87 * SUCH DAMAGE.
88 *
89 */
90
91/*
92 * This code does two things necessary for the enhanced TCP metrics to
93 * function in a useful manner:
94 * 1) It marks all non-host routes as `cloning', thus ensuring that
95 * every actual reference to such a route actually gets turned
96 * into a reference to a host route to the specific destination
97 * requested.
98 * 2) When such routes lose all their references, it arranges for them
99 * to be deleted in some random collection of circumstances, so that
100 * a large quantity of stale routing data is not kept in kernel memory
101 * indefinitely. See in6_rtqtimo() below for the exact mechanism.
102 */
103
104#include <sys/param.h>
105#include <sys/systm.h>
106#include <sys/kernel.h>
107#include <sys/sysctl.h>
108#include <kern/queue.h>
109#include <sys/socket.h>
110#include <sys/socketvar.h>
111#include <sys/mbuf.h>
112#include <sys/syslog.h>
91447636 113#include <kern/lock.h>
1c79356b
A
114
115#include <net/if.h>
116#include <net/route.h>
117#include <netinet/in.h>
1c79356b 118#include <netinet/ip_var.h>
1c79356b
A
119#include <netinet/in_var.h>
120
121#include <netinet/ip6.h>
122#include <netinet6/ip6_var.h>
123
124#include <netinet/icmp6.h>
125
1c79356b
A
126#include <netinet/tcp.h>
127#include <netinet/tcp_seq.h>
128#include <netinet/tcp_timer.h>
129#include <netinet/tcp_var.h>
1c79356b 130
91447636
A
131extern int in6_inithead(void **head, int off);
132static void in6_rtqtimo(void *rock);
133static void in6_mtutimo(void *rock);
2d21ac55 134extern int tvtohz(struct timeval *);
1c79356b 135
c910b4d9
A
136static struct radix_node *in6_matroute_args(void *, struct radix_node_head *,
137 rn_matchf_t *, void *);
138
1c79356b
A
139#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
140
b0d623f7
A
141/*
142 * Accessed by in6_addroute(), in6_deleteroute() and in6_rtqkill(), during
143 * which the routing lock (rnh_lock) is held and thus protects the variable.
144 */
145static int in6dynroutes;
146
1c79356b
A
147/*
148 * Do what we need to do when inserting a route.
149 */
150static struct radix_node *
151in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
152 struct radix_node *treenodes)
153{
154 struct rtentry *rt = (struct rtentry *)treenodes;
155 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
156 struct radix_node *ret;
157
b0d623f7
A
158 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
159 RT_LOCK_ASSERT_HELD(rt);
160
161 /*
162 * If this is a dynamic route (which is created via Redirect) and
163 * we already have the maximum acceptable number of such route entries,
164 * reject creating a new one. We could initiate garbage collection to
165 * make available space right now, but the benefit would probably not
166 * be worth the cleaning overhead; we only have to endure a slightly
167 * suboptimal path even without the redirecbted route.
168 */
169 if ((rt->rt_flags & RTF_DYNAMIC) != 0 &&
170 ip6_maxdynroutes >= 0 && in6dynroutes >= ip6_maxdynroutes)
171 return (NULL);
172
1c79356b
A
173 /*
174 * For IPv6, all unicast non-host routes are automatically cloning.
175 */
176 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
177 rt->rt_flags |= RTF_MULTICAST;
178
179 if (!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) {
180 rt->rt_flags |= RTF_PRCLONING;
181 }
182
183 /*
184 * A little bit of help for both IPv6 output and input:
185 * For local addresses, we make sure that RTF_LOCAL is set,
186 * with the thought that this might one day be used to speed up
187 * ip_input().
188 *
189 * We also mark routes to multicast addresses as such, because
190 * it's easy to do and might be useful (but this is much more
191 * dubious since it's so easy to inspect the address). (This
192 * is done above.)
193 *
194 * XXX
195 * should elaborate the code.
196 */
197 if (rt->rt_flags & RTF_HOST) {
198 if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr)
199 ->sin6_addr,
200 &sin6->sin6_addr)) {
201 rt->rt_flags |= RTF_LOCAL;
202 }
203 }
204
1c79356b
A
205 if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)
206 && rt->rt_ifp)
207 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
208
209 ret = rn_addroute(v_arg, n_arg, head, treenodes);
b0d623f7 210 if (ret == NULL && (rt->rt_flags & RTF_HOST)) {
1c79356b
A
211 struct rtentry *rt2;
212 /*
213 * We are trying to add a host route, but can't.
214 * Find out if it is because of an
215 * ARP entry and delete it if so.
216 */
91447636 217 rt2 = rtalloc1_locked((struct sockaddr *)sin6, 0,
1c79356b
A
218 RTF_CLONING | RTF_PRCLONING);
219 if (rt2) {
b0d623f7
A
220 RT_LOCK(rt2);
221 if ((rt2->rt_flags & RTF_LLINFO) &&
222 (rt2->rt_flags & RTF_HOST) &&
223 rt2->rt_gateway != NULL &&
224 rt2->rt_gateway->sa_family == AF_LINK) {
225 /*
226 * Safe to drop rt_lock and use rt_key,
227 * rt_gateway, since holding rnh_lock here
228 * prevents another thread from calling
229 * rt_setgate() on this route.
230 */
231 RT_UNLOCK(rt2);
232 (void) rtrequest_locked(RTM_DELETE, rt_key(rt2),
233 rt2->rt_gateway, rt_mask(rt2),
234 rt2->rt_flags, 0);
1c79356b
A
235 ret = rn_addroute(v_arg, n_arg, head,
236 treenodes);
b0d623f7
A
237 } else {
238 RT_UNLOCK(rt2);
1c79356b 239 }
91447636 240 rtfree_locked(rt2);
1c79356b 241 }
b0d623f7 242 } else if (ret == NULL && (rt->rt_flags & RTF_CLONING)) {
1c79356b
A
243 struct rtentry *rt2;
244 /*
245 * We are trying to add a net route, but can't.
246 * The following case should be allowed, so we'll make a
247 * special check for this:
248 * Two IPv6 addresses with the same prefix is assigned
249 * to a single interrface.
250 * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1)
251 * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2)
252 * In this case, (*1) and (*2) want to add the same
253 * net route entry, 3ffe:0501:: -> if0.
254 * This case should not raise an error.
255 */
91447636 256 rt2 = rtalloc1_locked((struct sockaddr *)sin6, 0,
1c79356b
A
257 RTF_CLONING | RTF_PRCLONING);
258 if (rt2) {
b0d623f7 259 RT_LOCK(rt2);
1c79356b
A
260 if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY))
261 == RTF_CLONING
262 && rt2->rt_gateway
263 && rt2->rt_gateway->sa_family == AF_LINK
264 && rt2->rt_ifp == rt->rt_ifp) {
265 ret = rt2->rt_nodes;
266 }
b0d623f7 267 RT_UNLOCK(rt2);
91447636 268 rtfree_locked(rt2);
1c79356b
A
269 }
270 }
b0d623f7
A
271
272 if (ret != NULL && (rt->rt_flags & RTF_DYNAMIC) != 0)
273 in6dynroutes++;
274
1c79356b
A
275 return ret;
276}
277
b0d623f7
A
278static struct radix_node *
279in6_deleteroute(void * v_arg, void *netmask_arg, struct radix_node_head *head)
280{
281 struct radix_node *rn;
282
283 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
284
285 rn = rn_delete(v_arg, netmask_arg, head);
286 if (rn != NULL) {
287 struct rtentry *rt = (struct rtentry *)rn;
288 RT_LOCK_SPIN(rt);
289 if ((rt->rt_flags & RTF_DYNAMIC) != 0)
290 in6dynroutes--;
291 RT_UNLOCK(rt);
292 }
293
294 return (rn);
295}
296
c910b4d9
A
297/*
298 * Similar to in6_matroute_args except without the leaf-matching parameters.
299 */
300static struct radix_node *
301in6_matroute(void *v_arg, struct radix_node_head *head)
302{
303 return (in6_matroute_args(v_arg, head, NULL, NULL));
304}
305
1c79356b
A
306/*
307 * This code is the inverse of in6_clsroute: on first reference, if we
308 * were managing the route, stop doing so and set the expiration timer
309 * back off again.
310 */
311static struct radix_node *
c910b4d9
A
312in6_matroute_args(void *v_arg, struct radix_node_head *head,
313 rn_matchf_t *f, void *w)
1c79356b 314{
c910b4d9 315 struct radix_node *rn = rn_match_args(v_arg, head, f, w);
1c79356b
A
316 struct rtentry *rt = (struct rtentry *)rn;
317
b0d623f7
A
318 /* This is first reference? */
319 if (rt != NULL) {
320 RT_LOCK_SPIN(rt);
321 if (rt->rt_refcnt == 0 && (rt->rt_flags & RTPRF_OURS)) {
1c79356b
A
322 rt->rt_flags &= ~RTPRF_OURS;
323 rt->rt_rmx.rmx_expire = 0;
324 }
b0d623f7 325 RT_UNLOCK(rt);
1c79356b 326 }
c910b4d9 327 return (rn);
1c79356b
A
328}
329
9bccf70c
A
330SYSCTL_DECL(_net_inet6_ip6);
331
1c79356b
A
332static int rtq_reallyold = 60*60;
333 /* one hour is ``really old'' */
9bccf70c
A
334SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTEXPIRE, rtexpire,
335 CTLFLAG_RW, &rtq_reallyold , 0, "");
b0d623f7 336
1c79356b
A
337static int rtq_minreallyold = 10;
338 /* never automatically crank down to less */
9bccf70c
A
339SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMINEXPIRE, rtminexpire,
340 CTLFLAG_RW, &rtq_minreallyold , 0, "");
b0d623f7 341
1c79356b
A
342static int rtq_toomany = 128;
343 /* 128 cached routes is ``too many'' */
9bccf70c
A
344SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMAXCACHE, rtmaxcache,
345 CTLFLAG_RW, &rtq_toomany , 0, "");
b0d623f7 346
1c79356b
A
347
348/*
349 * On last reference drop, mark the route as belong to us so that it can be
350 * timed out.
351 */
352static void
2d21ac55 353in6_clsroute(struct radix_node *rn, __unused struct radix_node_head *head)
1c79356b
A
354{
355 struct rtentry *rt = (struct rtentry *)rn;
356
b0d623f7
A
357 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
358 RT_LOCK_ASSERT_HELD(rt);
359
1c79356b
A
360 if (!(rt->rt_flags & RTF_UP))
361 return; /* prophylactic measures */
362
363 if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST)
364 return;
365
b0d623f7
A
366 if (rt->rt_flags & RTPRF_OURS)
367 return;
368
369 if (!(rt->rt_flags & (RTF_WASCLONED | RTF_DYNAMIC)))
1c79356b
A
370 return;
371
372 /*
2d21ac55
A
373 * Delete the route immediately if RTF_DELCLONE is set or
374 * if route caching is disabled (rtq_reallyold set to 0).
375 * Otherwise, let it expire and be deleted by in6_rtqkill().
1c79356b 376 */
2d21ac55
A
377 if ((rt->rt_flags & RTF_DELCLONE) || rtq_reallyold == 0) {
378 /*
379 * Delete the route from the radix tree but since we are
380 * called when the route's reference count is 0, don't
381 * deallocate it until we return from this routine by
382 * telling rtrequest that we're interested in it.
b0d623f7
A
383 * Safe to drop rt_lock and use rt_key, rt_gateway,
384 * since holding rnh_lock here prevents another thread
385 * from calling rt_setgate() on this route.
2d21ac55 386 */
b0d623f7
A
387 RT_UNLOCK(rt);
388 if (rtrequest_locked(RTM_DELETE, rt_key(rt),
2d21ac55
A
389 rt->rt_gateway, rt_mask(rt), rt->rt_flags, &rt) == 0) {
390 /* Now let the caller free it */
b0d623f7
A
391 RT_LOCK(rt);
392 RT_REMREF_LOCKED(rt);
393 } else {
394 RT_LOCK(rt);
2d21ac55
A
395 }
396 } else {
397 struct timeval timenow;
398
399 getmicrotime(&timenow);
1c79356b 400 rt->rt_flags |= RTPRF_OURS;
d1ecb069
A
401 rt->rt_rmx.rmx_expire =
402 rt_expiry(rt, timenow.tv_sec, rtq_reallyold);
1c79356b
A
403 }
404}
405
406struct rtqk_arg {
407 struct radix_node_head *rnh;
408 int mode;
409 int updating;
410 int draining;
411 int killed;
412 int found;
413 time_t nextstop;
414};
415
416/*
417 * Get rid of old routes. When draining, this deletes everything, even when
b0d623f7
A
418 * the timeout is not expired yet. This also applies if the route is dynamic
419 * and there are sufficiently large number of such routes (more than a half of
420 * maximum). When updating, this makes sure that nothing has a timeout longer
421 * than the current value of rtq_reallyold.
1c79356b
A
422 */
423static int
424in6_rtqkill(struct radix_node *rn, void *rock)
425{
426 struct rtqk_arg *ap = rock;
427 struct rtentry *rt = (struct rtentry *)rn;
428 int err;
91447636
A
429 struct timeval timenow;
430
431 getmicrotime(&timenow);
b0d623f7 432 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
2d21ac55 433
b0d623f7 434 RT_LOCK(rt);
1c79356b
A
435 if (rt->rt_flags & RTPRF_OURS) {
436 ap->found++;
437
b0d623f7
A
438 if (ap->draining || rt->rt_rmx.rmx_expire <= timenow.tv_sec ||
439 ((rt->rt_flags & RTF_DYNAMIC) != 0 &&
440 ip6_maxdynroutes >= 0 &&
441 in6dynroutes > ip6_maxdynroutes / 2)) {
1c79356b
A
442 if (rt->rt_refcnt > 0)
443 panic("rtqkill route really not free");
444
b0d623f7
A
445 /*
446 * Delete this route since we're done with it;
447 * the route may be freed afterwards, so we
448 * can no longer refer to 'rt' upon returning
449 * from rtrequest(). Safe to drop rt_lock and
450 * use rt_key, rt_gateway, since holding rnh_lock
451 * here prevents another thread from calling
452 * rt_setgate() on this route.
453 */
454 RT_UNLOCK(rt);
455 err = rtrequest_locked(RTM_DELETE, rt_key(rt),
456 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1c79356b
A
457 if (err) {
458 log(LOG_WARNING, "in6_rtqkill: error %d", err);
459 } else {
460 ap->killed++;
461 }
462 } else {
d1ecb069
A
463 if (ap->updating &&
464 (unsigned)(rt->rt_rmx.rmx_expire - timenow.tv_sec) >
465 rt_expiry(rt, 0, rtq_reallyold)) {
466 rt->rt_rmx.rmx_expire = rt_expiry(rt,
467 timenow.tv_sec, rtq_reallyold);
1c79356b
A
468 }
469 ap->nextstop = lmin(ap->nextstop,
470 rt->rt_rmx.rmx_expire);
b0d623f7 471 RT_UNLOCK(rt);
1c79356b 472 }
b0d623f7
A
473 } else {
474 RT_UNLOCK(rt);
1c79356b
A
475 }
476
477 return 0;
478}
479
480#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */
481static int rtq_timeout = RTQ_TIMEOUT;
482
483static void
484in6_rtqtimo(void *rock)
485{
486 struct radix_node_head *rnh = rock;
487 struct rtqk_arg arg;
488 struct timeval atv;
489 static time_t last_adjusted_timeout = 0;
91447636
A
490 struct timeval timenow;
491
b0d623f7 492 lck_mtx_lock(rnh_lock);
2d21ac55 493 /* Get the timestamp after we acquire the lock for better accuracy */
91447636 494 getmicrotime(&timenow);
1c79356b
A
495
496 arg.found = arg.killed = 0;
497 arg.rnh = rnh;
91447636 498 arg.nextstop = timenow.tv_sec + rtq_timeout;
1c79356b 499 arg.draining = arg.updating = 0;
1c79356b 500 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
1c79356b
A
501
502 /*
503 * Attempt to be somewhat dynamic about this:
504 * If there are ``too many'' routes sitting around taking up space,
505 * then crank down the timeout, and see if we can't make some more
506 * go away. However, we make sure that we will never adjust more
507 * than once in rtq_timeout seconds, to keep from cranking down too
508 * hard.
509 */
510 if ((arg.found - arg.killed > rtq_toomany)
91447636 511 && (timenow.tv_sec - last_adjusted_timeout >= rtq_timeout)
1c79356b
A
512 && rtq_reallyold > rtq_minreallyold) {
513 rtq_reallyold = 2*rtq_reallyold / 3;
514 if (rtq_reallyold < rtq_minreallyold) {
515 rtq_reallyold = rtq_minreallyold;
516 }
517
91447636 518 last_adjusted_timeout = timenow.tv_sec;
1c79356b
A
519#if DIAGNOSTIC
520 log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold to %d",
521 rtq_reallyold);
522#endif
523 arg.found = arg.killed = 0;
524 arg.updating = 1;
1c79356b 525 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
1c79356b
A
526 }
527
528 atv.tv_usec = 0;
91447636 529 atv.tv_sec = arg.nextstop - timenow.tv_sec;
b0d623f7 530 lck_mtx_unlock(rnh_lock);
91447636 531 timeout(in6_rtqtimo, rock, tvtohz(&atv));
1c79356b
A
532}
533
534/*
535 * Age old PMTUs.
536 */
537struct mtuex_arg {
538 struct radix_node_head *rnh;
539 time_t nextstop;
540};
541
542static int
543in6_mtuexpire(struct radix_node *rn, void *rock)
544{
545 struct rtentry *rt = (struct rtentry *)rn;
546 struct mtuex_arg *ap = rock;
91447636
A
547 struct timeval timenow;
548
549 getmicrotime(&timenow);
1c79356b
A
550
551 /* sanity */
552 if (!rt)
553 panic("rt == NULL in in6_mtuexpire");
554
b0d623f7 555 RT_LOCK(rt);
1c79356b 556 if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) {
91447636 557 if (rt->rt_rmx.rmx_expire <= timenow.tv_sec) {
1c79356b
A
558 rt->rt_flags |= RTF_PROBEMTU;
559 } else {
560 ap->nextstop = lmin(ap->nextstop,
561 rt->rt_rmx.rmx_expire);
562 }
563 }
b0d623f7 564 RT_UNLOCK(rt);
1c79356b
A
565
566 return 0;
567}
568
569#define MTUTIMO_DEFAULT (60*1)
570
571static void
572in6_mtutimo(void *rock)
573{
574 struct radix_node_head *rnh = rock;
575 struct mtuex_arg arg;
576 struct timeval atv;
91447636
A
577 struct timeval timenow;
578
579 getmicrotime(&timenow);
1c79356b
A
580
581 arg.rnh = rnh;
91447636 582 arg.nextstop = timenow.tv_sec + MTUTIMO_DEFAULT;
b0d623f7 583 lck_mtx_lock(rnh_lock);
1c79356b 584 rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
1c79356b
A
585
586 atv.tv_usec = 0;
587 atv.tv_sec = arg.nextstop;
91447636 588 if (atv.tv_sec < timenow.tv_sec) {
9bccf70c
A
589#if DIAGNOSTIC
590 log(LOG_DEBUG, "IPv6: invalid mtu expiration time on routing table\n");
591#endif
91447636 592 arg.nextstop = timenow.tv_sec + 30; /*last resort*/
1c79356b 593 }
91447636 594 atv.tv_sec -= timenow.tv_sec;
b0d623f7 595 lck_mtx_unlock(rnh_lock);
91447636 596 timeout(in6_mtutimo, rock, tvtohz(&atv));
1c79356b
A
597}
598
1c79356b
A
599void
600in6_rtqdrain()
601{
602 struct radix_node_head *rnh = rt_tables[AF_INET6];
603 struct rtqk_arg arg;
1c79356b
A
604 arg.found = arg.killed = 0;
605 arg.rnh = rnh;
606 arg.nextstop = 0;
607 arg.draining = 1;
608 arg.updating = 0;
d1ecb069 609 lck_mtx_lock(rnh_lock);
1c79356b 610 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
d1ecb069 611 lck_mtx_unlock(rnh_lock);
1c79356b 612}
1c79356b
A
613
614/*
615 * Initialize our routing tree.
616 */
617int
618in6_inithead(void **head, int off)
619{
620 struct radix_node_head *rnh;
621
622 if (!rn_inithead(head, off))
623 return 0;
624
625 if (head != (void **)&rt_tables[AF_INET6]) /* BOGUS! */
626 return 1; /* only do this for the real routing table */
627
628 rnh = *head;
629 rnh->rnh_addaddr = in6_addroute;
b0d623f7 630 rnh->rnh_deladdr = in6_deleteroute;
1c79356b 631 rnh->rnh_matchaddr = in6_matroute;
c910b4d9 632 rnh->rnh_matchaddr_args = in6_matroute_args;
1c79356b
A
633 rnh->rnh_close = in6_clsroute;
634 in6_rtqtimo(rnh); /* kick off timeout first time */
635 in6_mtutimo(rnh); /* kick off timeout first time */
636 return 1;
637}