in6_rmx.c revision 62587
152400Sbillf/*	$FreeBSD: head/sys/netinet6/in6_rmx.c 62587 2000-07-04 16:35:15Z itojun $	*/
252400Sbillf/*	$KAME: in6_rmx.c,v 1.7 2000/04/06 08:30:43 sumikawa Exp $	*/
352400Sbillf
452400Sbillf/*
552400Sbillf * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
652400Sbillf * All rights reserved.
752400Sbillf *
8124053Sdougb * Redistribution and use in source and binary forms, with or without
973651Sdougb * modification, are permitted provided that the following conditions
1052400Sbillf * are met:
1152495Sbillf * 1. Redistributions of source code must retain the above copyright
1252400Sbillf *    notice, this list of conditions and the following disclaimer.
1368507Sdougb * 2. Redistributions in binary form must reproduce the above copyright
1452400Sbillf *    notice, this list of conditions and the following disclaimer in the
1552400Sbillf *    documentation and/or other materials provided with the distribution.
1652533Sbillf * 3. Neither the name of the project nor the names of its contributors
1752400Sbillf *    may be used to endorse or promote products derived from this software
18114501Sdougb *    without specific prior written permission.
1967949Sdougb *
2052400Sbillf * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2152400Sbillf * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2252400Sbillf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2352400Sbillf * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2452400Sbillf * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2552400Sbillf * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2652400Sbillf * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2767949Sdougb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2891193Sdougb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2991193Sdougb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30114501Sdougb * SUCH DAMAGE.
3152400Sbillf */
3252400Sbillf
3352400Sbillf/*
3452400Sbillf * Copyright 1994, 1995 Massachusetts Institute of Technology
3552400Sbillf *
3667949Sdougb * Permission to use, copy, modify, and distribute this software and
3752400Sbillf * its documentation for any purpose and without fee is hereby
3852400Sbillf * granted, provided that both the above copyright notice and this
3952400Sbillf * permission notice appear in all copies, that both the above
4052400Sbillf * copyright notice and this permission notice appear in all
4152400Sbillf * supporting documentation, and that the name of M.I.T. not be used
4252400Sbillf * in advertising or publicity pertaining to distribution of the
4352400Sbillf * software without specific, written prior permission.  M.I.T. makes
4467859Sdougb * no representations about the suitability of this software for any
4567949Sdougb * purpose.  It is provided "as is" without express or implied
4652400Sbillf * warranty.
4752400Sbillf *
4858910Salfred * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
4958910Salfred * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
5058910Salfred * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5167850Sdougb * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
5267850Sdougb * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5367850Sdougb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5467850Sdougb * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
5567850Sdougb * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5667850Sdougb * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5767850Sdougb * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
5867850Sdougb * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5967850Sdougb * SUCH DAMAGE.
6067850Sdougb *
6167850Sdougb */
6267850Sdougb
6367949Sdougb/*
6467850Sdougb * This code does two things necessary for the enhanced TCP metrics to
6567850Sdougb * function in a useful manner:
6667850Sdougb *  1) It marks all non-host routes as `cloning', thus ensuring that
6767850Sdougb *     every actual reference to such a route actually gets turned
6867850Sdougb *     into a reference to a host route to the specific destination
6967850Sdougb *     requested.
7067850Sdougb *  2) When such routes lose all their references, it arranges for them
7167850Sdougb *     to be deleted in some random collection of circumstances, so that
7267859Sdougb *     a large quantity of stale routing data is not kept in kernel memory
7367859Sdougb *     indefinitely.  See in6_rtqtimo() below for the exact mechanism.
7458910Salfred */
7567850Sdougb
7667850Sdougb#include <sys/param.h>
7767850Sdougb#include <sys/systm.h>
7867850Sdougb#include <sys/kernel.h>
7967850Sdougb#include <sys/sysctl.h>
8067850Sdougb#include <sys/queue.h>
8167859Sdougb#include <sys/socket.h>
8267850Sdougb#include <sys/socketvar.h>
8367859Sdougb#include <sys/mbuf.h>
8467850Sdougb#include <sys/syslog.h>
8567850Sdougb
8667850Sdougb#include <net/if.h>
8767850Sdougb#include <net/route.h>
8867859Sdougb#include <netinet/in.h>
8967850Sdougb#include <netinet/ip_var.h>
9067850Sdougb#include <netinet/in_var.h>
9167850Sdougb
9267850Sdougb#include <netinet/ip6.h>
9367850Sdougb#include <netinet6/ip6_var.h>
9467850Sdougb
9567850Sdougb#include <netinet/icmp6.h>
9667850Sdougb
9767850Sdougb#include <netinet/tcp.h>
9867850Sdougb#include <netinet/tcp_seq.h>
9967850Sdougb#include <netinet/tcp_timer.h>
10067850Sdougb#include <netinet/tcp_var.h>
10167850Sdougb
10267850Sdougbextern int	in6_inithead __P((void **head, int off));
10358910Salfred
10458910Salfred#define RTPRF_OURS		RTF_PROTO3	/* set on routes we manage */
10558910Salfred
10658910Salfred/*
10758910Salfred * Do what we need to do when inserting a route.
10858910Salfred */
10967850Sdougbstatic struct radix_node *
11058910Salfredin6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
11177323Sdougb	    struct radix_node *treenodes)
11277323Sdougb{
11367949Sdougb	struct rtentry *rt = (struct rtentry *)treenodes;
11467850Sdougb	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
11590564Sdougb	struct radix_node *ret;
116109993Sdillon
117109993Sdillon	/*
118109993Sdillon	 * For IPv6, all unicast non-host routes are automatically cloning.
119109993Sdillon	 */
120109993Sdillon	if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
121110377Sdougb		rt->rt_flags |= RTF_MULTICAST;
122109993Sdillon
123109993Sdillon	if (!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) {
12467850Sdougb		rt->rt_flags |= RTF_PRCLONING;
12567850Sdougb	}
126109993Sdillon
12767850Sdougb	/*
12891193Sdougb	 * A little bit of help for both IPv6 output and input:
12967949Sdougb	 *   For local addresses, we make sure that RTF_LOCAL is set,
13067949Sdougb	 *   with the thought that this might one day be used to speed up
13167949Sdougb	 *   ip_input().
13267949Sdougb	 *
13367949Sdougb	 * We also mark routes to multicast addresses as such, because
13468507Sdougb	 * it's easy to do and might be useful (but this is much more
13567949Sdougb	 * dubious since it's so easy to inspect the address).  (This
13667949Sdougb	 * is done above.)
13767949Sdougb	 *
13867949Sdougb	 * XXX
13967949Sdougb	 * should elaborate the code.
14067949Sdougb	 */
14167949Sdougb	if (rt->rt_flags & RTF_HOST) {
14267949Sdougb		if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr)
14367949Sdougb					->sin6_addr,
14467949Sdougb				       &sin6->sin6_addr)) {
14567949Sdougb			rt->rt_flags |= RTF_LOCAL;
14667949Sdougb		}
14767850Sdougb	}
14867859Sdougb
14967850Sdougb	/*
15067850Sdougb	 * We also specify a send and receive pipe size for every
15167850Sdougb	 * route added, to help TCP a bit.  TCP doesn't actually
15267850Sdougb	 * want a true pipe size, which would be prohibitive in memory
15377326Sdougb	 * costs and is hard to compute anyway; it simply uses these
154109993Sdillon	 * values to size its buffers.  So, we fill them in with the
15567850Sdougb	 * same values that TCP would have used anyway, and allow the
15667850Sdougb	 * installing program or the link layer to override these values
15767850Sdougb	 * as it sees fit.  This will hopefully allow TCP more
15867850Sdougb	 * opportunities to save its ssthresh value.
15967850Sdougb	 */
16067859Sdougb	if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE))
16167859Sdougb		rt->rt_rmx.rmx_sendpipe = tcp_sendspace;
16267859Sdougb
16367850Sdougb	if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE))
16467850Sdougb		rt->rt_rmx.rmx_recvpipe = tcp_recvspace;
16567850Sdougb
16667850Sdougb	if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)
16767850Sdougb	    && rt->rt_ifp)
16867850Sdougb		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
16967850Sdougb
17067850Sdougb	ret = rn_addroute(v_arg, n_arg, head, treenodes);
17167850Sdougb	if (ret == NULL && rt->rt_flags & RTF_HOST) {
17267850Sdougb		struct rtentry *rt2;
17367850Sdougb		/*
17467850Sdougb		 * We are trying to add a host route, but can't.
17567850Sdougb		 * Find out if it is because of an
17667850Sdougb		 * ARP entry and delete it if so.
17767850Sdougb		 */
17867850Sdougb		rt2 = rtalloc1((struct sockaddr *)sin6, 0,
17967850Sdougb				RTF_CLONING | RTF_PRCLONING);
18067850Sdougb		if (rt2) {
18167850Sdougb			if (rt2->rt_flags & RTF_LLINFO &&
18267850Sdougb				rt2->rt_flags & RTF_HOST &&
18367850Sdougb				rt2->rt_gateway &&
18467850Sdougb				rt2->rt_gateway->sa_family == AF_LINK) {
18567850Sdougb				rtrequest(RTM_DELETE,
18667850Sdougb					  (struct sockaddr *)rt_key(rt2),
18767850Sdougb					  rt2->rt_gateway,
18867850Sdougb					  rt_mask(rt2), rt2->rt_flags, 0);
18967850Sdougb				ret = rn_addroute(v_arg, n_arg, head,
19067850Sdougb					treenodes);
19167850Sdougb			}
19267850Sdougb			RTFREE(rt2);
19367850Sdougb		}
19467850Sdougb	} else if (ret == NULL && rt->rt_flags & RTF_CLONING) {
19567850Sdougb		struct rtentry *rt2;
19667850Sdougb		/*
19767850Sdougb		 * We are trying to add a net route, but can't.
19867850Sdougb		 * The following case should be allowed, so we'll make a
19967850Sdougb		 * special check for this:
20067850Sdougb		 *	Two IPv6 addresses with the same prefix is assigned
20167850Sdougb		 *	to a single interrface.
20267850Sdougb		 *	# ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1)
20367850Sdougb		 *	# ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2)
20467850Sdougb		 *	In this case, (*1) and (*2) want to add the same
20567850Sdougb		 *	net route entry, 3ffe:0501:: -> if0.
20667859Sdougb		 *	This case should not raise an error.
20767850Sdougb		 */
20867850Sdougb		rt2 = rtalloc1((struct sockaddr *)sin6, 0,
20967850Sdougb				RTF_CLONING | RTF_PRCLONING);
21067850Sdougb		if (rt2) {
21167850Sdougb			if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY))
21267850Sdougb					== RTF_CLONING
21367850Sdougb			 && rt2->rt_gateway
21467850Sdougb			 && rt2->rt_gateway->sa_family == AF_LINK
21558910Salfred			 && rt2->rt_ifp == rt->rt_ifp) {
21658910Salfred				ret = rt2->rt_nodes;
21797960Sdougb			}
21897960Sdougb			RTFREE(rt2);
21997960Sdougb		}
22097960Sdougb	}
22197960Sdougb	return ret;
22297960Sdougb}
22352400Sbillf
22452400Sbillf/*
22552400Sbillf * This code is the inverse of in6_clsroute: on first reference, if we
22652400Sbillf * were managing the route, stop doing so and set the expiration timer
22773651Sdougb * back off again.
22873651Sdougb */
22973651Sdougbstatic struct radix_node *
23073651Sdougbin6_matroute(void *v_arg, struct radix_node_head *head)
23173651Sdougb{
23273651Sdougb	struct radix_node *rn = rn_match(v_arg, head);
23352400Sbillf	struct rtentry *rt = (struct rtentry *)rn;
23452400Sbillf
23567949Sdougb	if (rt && rt->rt_refcnt == 0) { /* this is first reference */
23652400Sbillf		if (rt->rt_flags & RTPRF_OURS) {
23752400Sbillf			rt->rt_flags &= ~RTPRF_OURS;
23852400Sbillf			rt->rt_rmx.rmx_expire = 0;
23952400Sbillf		}
24052400Sbillf	}
241114501Sdougb	return rn;
24252400Sbillf}
24352400Sbillf
24452400Sbillfstatic int rtq_reallyold = 60*60;
245110377Sdougb	/* one hour is ``really old'' */
24652400SbillfSYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire,
24752400Sbillf	CTLFLAG_RW, &rtq_reallyold , 0, "");
24852400Sbillf
24952400Sbillfstatic int rtq_minreallyold = 10;
25052400Sbillf	/* never automatically crank down to less */
25152400SbillfSYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire,
25252400Sbillf	CTLFLAG_RW, &rtq_minreallyold , 0, "");
25352400Sbillf
25452400Sbillfstatic int rtq_toomany = 128;
25552400Sbillf	/* 128 cached routes is ``too many'' */
25652400SbillfSYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache,
25752400Sbillf	CTLFLAG_RW, &rtq_toomany , 0, "");
25852400Sbillf
25952400Sbillf
26052400Sbillf/*
26152400Sbillf * On last reference drop, mark the route as belong to us so that it can be
26252400Sbillf * timed out.
26352400Sbillf */
26452400Sbillfstatic void
26552400Sbillfin6_clsroute(struct radix_node *rn, struct radix_node_head *head)
26652400Sbillf{
26767949Sdougb	struct rtentry *rt = (struct rtentry *)rn;
26867949Sdougb
26967949Sdougb	if (!(rt->rt_flags & RTF_UP))
27096045Sdougb		return;		/* prophylactic measures */
27196045Sdougb
27296045Sdougb	if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST)
273114501Sdougb		return;
274114501Sdougb
275114501Sdougb	if ((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS))
27691193Sdougb	   != RTF_WASCLONED)
27791193Sdougb		return;
27896045Sdougb
27996045Sdougb	/*
28091193Sdougb	 * As requested by David Greenman:
28152400Sbillf	 * If rtq_reallyold is 0, just delete the route without
28252400Sbillf	 * waiting for a timeout cycle to kill it.
28352400Sbillf	 */
28452400Sbillf	if (rtq_reallyold != 0) {
28552400Sbillf		rt->rt_flags |= RTPRF_OURS;
28652400Sbillf		rt->rt_rmx.rmx_expire = time_second + rtq_reallyold;
28752400Sbillf	} else {
28852400Sbillf		rtrequest(RTM_DELETE,
28952400Sbillf			  (struct sockaddr *)rt_key(rt),
29052400Sbillf			  rt->rt_gateway, rt_mask(rt),
29152400Sbillf			  rt->rt_flags, 0);
29252400Sbillf	}
29352400Sbillf}
29452400Sbillf
29552400Sbillfstruct rtqk_arg {
29667949Sdougb	struct radix_node_head *rnh;
29767949Sdougb	int mode;
29867949Sdougb	int updating;
29952400Sbillf	int draining;
30052400Sbillf	int killed;
30152400Sbillf	int found;
30252400Sbillf	time_t nextstop;
30352400Sbillf};
30452400Sbillf
30552400Sbillf/*
306114501Sdougb * Get rid of old routes.  When draining, this deletes everything, even when
307114501Sdougb * the timeout is not expired yet.  When updating, this makes sure that
308114501Sdougb * nothing has a timeout longer than the current value of rtq_reallyold.
309114501Sdougb */
310114501Sdougbstatic int
31152400Sbillfin6_rtqkill(struct radix_node *rn, void *rock)
31252400Sbillf{
31352400Sbillf	struct rtqk_arg *ap = rock;
31452400Sbillf	struct rtentry *rt = (struct rtentry *)rn;
31552400Sbillf	int err;
31652400Sbillf
31764467Sbrian	if (rt->rt_flags & RTPRF_OURS) {
31852400Sbillf		ap->found++;
31964467Sbrian
32067859Sdougb		if (ap->draining || rt->rt_rmx.rmx_expire <= time_second) {
32152400Sbillf			if (rt->rt_refcnt > 0)
32252400Sbillf				panic("rtqkill route really not free");
32364467Sbrian
32464467Sbrian			err = rtrequest(RTM_DELETE,
32552400Sbillf					(struct sockaddr *)rt_key(rt),
32652400Sbillf					rt->rt_gateway, rt_mask(rt),
32752400Sbillf					rt->rt_flags, 0);
32852400Sbillf			if (err) {
32952400Sbillf				log(LOG_WARNING, "in6_rtqkill: error %d", err);
33067859Sdougb			} else {
33167859Sdougb				ap->killed++;
33267859Sdougb			}
33352400Sbillf		} else {
33458910Salfred			if (ap->updating
33552400Sbillf			   && (rt->rt_rmx.rmx_expire - time_second
33652400Sbillf			       > rtq_reallyold)) {
33758910Salfred				rt->rt_rmx.rmx_expire = time_second
33864467Sbrian					+ rtq_reallyold;
33964467Sbrian			}
34064467Sbrian			ap->nextstop = lmin(ap->nextstop,
34158910Salfred					    rt->rt_rmx.rmx_expire);
34264467Sbrian		}
34364467Sbrian	}
34464467Sbrian
34564467Sbrian	return 0;
34664467Sbrian}
34764467Sbrian
34858910Salfred#define RTQ_TIMEOUT	60*10	/* run no less than once every ten minutes */
34952400Sbillfstatic int rtq_timeout = RTQ_TIMEOUT;
35060420Sbsd
35152400Sbillfstatic void
35252400Sbillfin6_rtqtimo(void *rock)
35358910Salfred{
35458910Salfred	struct radix_node_head *rnh = rock;
35558910Salfred	struct rtqk_arg arg;
35652400Sbillf	struct timeval atv;
35752400Sbillf	static time_t last_adjusted_timeout = 0;
35858910Salfred	int s;
35952400Sbillf
36052400Sbillf	arg.found = arg.killed = 0;
36152400Sbillf	arg.rnh = rnh;
36252400Sbillf	arg.nextstop = time_second + rtq_timeout;
36352400Sbillf	arg.draining = arg.updating = 0;
36452400Sbillf	s = splnet();
36552400Sbillf	rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
36652400Sbillf	splx(s);
36752400Sbillf
36852400Sbillf	/*
36952400Sbillf	 * Attempt to be somewhat dynamic about this:
37052400Sbillf	 * If there are ``too many'' routes sitting around taking up space,
37152400Sbillf	 * then crank down the timeout, and see if we can't make some more
37252400Sbillf	 * go away.  However, we make sure that we will never adjust more
37352400Sbillf	 * than once in rtq_timeout seconds, to keep from cranking down too
37452400Sbillf	 * hard.
37552400Sbillf	 */
37652400Sbillf	if ((arg.found - arg.killed > rtq_toomany)
37752400Sbillf	   && (time_second - last_adjusted_timeout >= rtq_timeout)
37852400Sbillf	   && rtq_reallyold > rtq_minreallyold) {
37952400Sbillf		rtq_reallyold = 2*rtq_reallyold / 3;
38052400Sbillf		if (rtq_reallyold < rtq_minreallyold) {
38196045Sdougb			rtq_reallyold = rtq_minreallyold;
38296045Sdougb		}
38396045Sdougb
384110377Sdougb		last_adjusted_timeout = time_second;
38596045Sdougb#ifdef DIAGNOSTIC
38696045Sdougb		log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold to %d",
38796045Sdougb		    rtq_reallyold);
38896045Sdougb#endif
38996045Sdougb		arg.found = arg.killed = 0;
39096045Sdougb		arg.updating = 1;
39196045Sdougb		s = splnet();
39296045Sdougb		rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
39396045Sdougb		splx(s);
39496045Sdougb	}
39596045Sdougb
39696045Sdougb	atv.tv_usec = 0;
39797380Sdougb	atv.tv_sec = arg.nextstop;
39897380Sdougb	timeout(in6_rtqtimo, rock, tvtohz(&atv));
39997380Sdougb}
40096045Sdougb
40196045Sdougb/*
40296045Sdougb * Age old PMTUs.
40396045Sdougb */
40496045Sdougbstruct mtuex_arg {
40573651Sdougb	struct radix_node_head *rnh;
40673651Sdougb	time_t nextstop;
40773651Sdougb};
40873651Sdougb
40999152Sdougbstatic int
410101362Sdougbin6_mtuexpire(struct radix_node *rn, void *rock)
411101362Sdougb{
412101362Sdougb	struct rtentry *rt = (struct rtentry *)rn;
41399152Sdougb	struct mtuex_arg *ap = rock;
41499152Sdougb
41552400Sbillf	/* sanity */
41652400Sbillf	if (!rt)
41752400Sbillf		panic("rt == NULL in in6_mtuexpire");
41852400Sbillf
41952400Sbillf	if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) {
42052400Sbillf		if (rt->rt_rmx.rmx_expire <= time_second) {
42152400Sbillf			rt->rt_flags |= RTF_PROBEMTU;
42252400Sbillf		} else {
42352400Sbillf			ap->nextstop = lmin(ap->nextstop,
42467859Sdougb					rt->rt_rmx.rmx_expire);
42552400Sbillf		}
42652400Sbillf	}
42752400Sbillf
42852400Sbillf	return 0;
42952400Sbillf}
43052400Sbillf
43152400Sbillf#define	MTUTIMO_DEFAULT	(60*1)
43252400Sbillf
43352400Sbillfstatic void
43452400Sbillfin6_mtutimo(void *rock)
43567859Sdougb{
43667859Sdougb	struct radix_node_head *rnh = rock;
43767859Sdougb	struct mtuex_arg arg;
43867859Sdougb	struct timeval atv;
43967859Sdougb	int s;
44067859Sdougb
44167859Sdougb	arg.rnh = rnh;
44267859Sdougb	arg.nextstop = time_second + MTUTIMO_DEFAULT;
44399152Sdougb	s = splnet();
44467859Sdougb	rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
44552400Sbillf	splx(s);
44667859Sdougb
44767859Sdougb	atv.tv_usec = 0;
44867859Sdougb	atv.tv_sec = arg.nextstop;
44967859Sdougb	if (atv.tv_sec < time_second) {
45067859Sdougb		printf("invalid mtu expiration time on routing table\n");
45167859Sdougb		arg.nextstop = time_second + 30;	/*last resort*/
45267859Sdougb	}
45367859Sdougb	timeout(in6_mtutimo, rock, tvtohz(&atv));
45467859Sdougb}
45567859Sdougb
45667859Sdougb#if 0
45767859Sdougbvoid
45867859Sdougbin6_rtqdrain()
45967859Sdougb{
46067859Sdougb	struct radix_node_head *rnh = rt_tables[AF_INET6];
46167859Sdougb	struct rtqk_arg arg;
46267859Sdougb	int s;
46367859Sdougb	arg.found = arg.killed = 0;
46467859Sdougb	arg.rnh = rnh;
46567859Sdougb	arg.nextstop = 0;
46652400Sbillf	arg.draining = 1;
46777323Sdougb	arg.updating = 0;
46877323Sdougb	s = splnet();
46952400Sbillf	rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
47052400Sbillf	splx(s);
47152400Sbillf}
47252400Sbillf#endif
47352400Sbillf
47452400Sbillf/*
47552400Sbillf * Initialize our routing tree.
47652400Sbillf */
47752400Sbillfint
47852400Sbillfin6_inithead(void **head, int off)
47952400Sbillf{
48052400Sbillf	struct radix_node_head *rnh;
48152400Sbillf
48252400Sbillf	if (!rn_inithead(head, off))
48352400Sbillf		return 0;
48452400Sbillf
48552400Sbillf	if (head != (void **)&rt_tables[AF_INET6]) /* BOGUS! */
48652400Sbillf		return 1;	/* only do this for the real routing table */
48752400Sbillf
48852400Sbillf	rnh = *head;
48952400Sbillf	rnh->rnh_addaddr = in6_addroute;
49052400Sbillf	rnh->rnh_matchaddr = in6_matroute;
49152400Sbillf	rnh->rnh_close = in6_clsroute;
49252400Sbillf	in6_rtqtimo(rnh);	/* kick off timeout first time */
49352400Sbillf	in6_mtutimo(rnh);	/* kick off timeout first time */
49452400Sbillf	return 1;
49552400Sbillf}
49697960Sdougb