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