in6_rmx.c revision 120727
162587Sitojun/* $FreeBSD: head/sys/netinet6/in6_rmx.c 120727 2003-10-04 03:44:50Z sam $ */ 295023Ssuz/* $KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $ */ 362587Sitojun 453541Sshin/* 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 3353541Sshin/* 3453541Sshin * Copyright 1994, 1995 Massachusetts Institute of Technology 3553541Sshin * 3653541Sshin * Permission to use, copy, modify, and distribute this software and 3753541Sshin * its documentation for any purpose and without fee is hereby 3853541Sshin * granted, provided that both the above copyright notice and this 3953541Sshin * permission notice appear in all copies, that both the above 4053541Sshin * copyright notice and this permission notice appear in all 4153541Sshin * supporting documentation, and that the name of M.I.T. not be used 4253541Sshin * in advertising or publicity pertaining to distribution of the 4353541Sshin * software without specific, written prior permission. M.I.T. makes 4453541Sshin * no representations about the suitability of this software for any 4553541Sshin * purpose. It is provided "as is" without express or implied 4653541Sshin * warranty. 4753541Sshin * 4853541Sshin * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 4953541Sshin * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 5053541Sshin * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 5153541Sshin * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 5253541Sshin * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 5353541Sshin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 5453541Sshin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 5553541Sshin * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 5653541Sshin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 5753541Sshin * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 5853541Sshin * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5953541Sshin * SUCH DAMAGE. 6053541Sshin * 6153541Sshin */ 6253541Sshin 6353541Sshin/* 6453541Sshin * This code does two things necessary for the enhanced TCP metrics to 6553541Sshin * function in a useful manner: 6653541Sshin * 1) It marks all non-host routes as `cloning', thus ensuring that 6753541Sshin * every actual reference to such a route actually gets turned 6853541Sshin * into a reference to a host route to the specific destination 6953541Sshin * requested. 7053541Sshin * 2) When such routes lose all their references, it arranges for them 7153541Sshin * to be deleted in some random collection of circumstances, so that 7253541Sshin * a large quantity of stale routing data is not kept in kernel memory 7353541Sshin * indefinitely. See in6_rtqtimo() below for the exact mechanism. 7453541Sshin */ 7553541Sshin 7653541Sshin#include <sys/param.h> 7753541Sshin#include <sys/systm.h> 7853541Sshin#include <sys/kernel.h> 7953541Sshin#include <sys/sysctl.h> 8053541Sshin#include <sys/queue.h> 8153541Sshin#include <sys/socket.h> 8253541Sshin#include <sys/socketvar.h> 8353541Sshin#include <sys/mbuf.h> 8453541Sshin#include <sys/syslog.h> 85120727Ssam#include <sys/callout.h> 8653541Sshin 8753541Sshin#include <net/if.h> 8853541Sshin#include <net/route.h> 8953541Sshin#include <netinet/in.h> 9053541Sshin#include <netinet/ip_var.h> 9153541Sshin#include <netinet/in_var.h> 9253541Sshin 9362587Sitojun#include <netinet/ip6.h> 9453541Sshin#include <netinet6/ip6_var.h> 9553541Sshin 9662587Sitojun#include <netinet/icmp6.h> 9753541Sshin 9853541Sshin#include <netinet/tcp.h> 9953541Sshin#include <netinet/tcp_seq.h> 10053541Sshin#include <netinet/tcp_timer.h> 10153541Sshin#include <netinet/tcp_var.h> 10253541Sshin 10353541Sshinextern int in6_inithead __P((void **head, int off)); 10453541Sshin 10562587Sitojun#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ 10653541Sshin 10753541Sshin/* 10853541Sshin * Do what we need to do when inserting a route. 10953541Sshin */ 11053541Sshinstatic struct radix_node * 11153541Sshinin6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, 11262587Sitojun struct radix_node *treenodes) 11353541Sshin{ 11453541Sshin struct rtentry *rt = (struct rtentry *)treenodes; 11553541Sshin struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); 11653541Sshin struct radix_node *ret; 11753541Sshin 11853541Sshin /* 11953541Sshin * For IPv6, all unicast non-host routes are automatically cloning. 12053541Sshin */ 12153541Sshin if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 12253541Sshin rt->rt_flags |= RTF_MULTICAST; 12353541Sshin 12453541Sshin if (!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { 12553541Sshin rt->rt_flags |= RTF_PRCLONING; 12653541Sshin } 12753541Sshin 12853541Sshin /* 12953541Sshin * A little bit of help for both IPv6 output and input: 13053541Sshin * For local addresses, we make sure that RTF_LOCAL is set, 13153541Sshin * with the thought that this might one day be used to speed up 13253541Sshin * ip_input(). 13353541Sshin * 13453541Sshin * We also mark routes to multicast addresses as such, because 13553541Sshin * it's easy to do and might be useful (but this is much more 13653541Sshin * dubious since it's so easy to inspect the address). (This 13753541Sshin * is done above.) 13853541Sshin * 13953541Sshin * XXX 14053541Sshin * should elaborate the code. 14153541Sshin */ 14253541Sshin if (rt->rt_flags & RTF_HOST) { 14353541Sshin if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr) 14453541Sshin ->sin6_addr, 14553541Sshin &sin6->sin6_addr)) { 14653541Sshin rt->rt_flags |= RTF_LOCAL; 14753541Sshin } 14853541Sshin } 14953541Sshin 15053541Sshin if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) 15153541Sshin && rt->rt_ifp) 15253541Sshin rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 15353541Sshin 15453541Sshin ret = rn_addroute(v_arg, n_arg, head, treenodes); 15553541Sshin if (ret == NULL && rt->rt_flags & RTF_HOST) { 15653541Sshin struct rtentry *rt2; 15753541Sshin /* 15853541Sshin * We are trying to add a host route, but can't. 15953541Sshin * Find out if it is because of an 16053541Sshin * ARP entry and delete it if so. 16153541Sshin */ 16253541Sshin rt2 = rtalloc1((struct sockaddr *)sin6, 0, 16353541Sshin RTF_CLONING | RTF_PRCLONING); 16453541Sshin if (rt2) { 16553541Sshin if (rt2->rt_flags & RTF_LLINFO && 16653541Sshin rt2->rt_flags & RTF_HOST && 16753541Sshin rt2->rt_gateway && 16853541Sshin rt2->rt_gateway->sa_family == AF_LINK) { 169120727Ssam /* NB: must unlock to avoid recursion */ 170120727Ssam RT_UNLOCK(rt2); 17153541Sshin rtrequest(RTM_DELETE, 17253541Sshin (struct sockaddr *)rt_key(rt2), 17353541Sshin rt2->rt_gateway, 17453541Sshin rt_mask(rt2), rt2->rt_flags, 0); 17553541Sshin ret = rn_addroute(v_arg, n_arg, head, 17653541Sshin treenodes); 177120727Ssam RT_LOCK(rt2); 17853541Sshin } 179120727Ssam RTFREE_LOCKED(rt2); 18053541Sshin } 18153541Sshin } else if (ret == NULL && rt->rt_flags & RTF_CLONING) { 18253541Sshin struct rtentry *rt2; 18353541Sshin /* 18453541Sshin * We are trying to add a net route, but can't. 18553541Sshin * The following case should be allowed, so we'll make a 18653541Sshin * special check for this: 18753541Sshin * Two IPv6 addresses with the same prefix is assigned 18853541Sshin * to a single interrface. 18953541Sshin * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1) 19053541Sshin * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2) 19153541Sshin * In this case, (*1) and (*2) want to add the same 19253541Sshin * net route entry, 3ffe:0501:: -> if0. 19353541Sshin * This case should not raise an error. 19453541Sshin */ 19553541Sshin rt2 = rtalloc1((struct sockaddr *)sin6, 0, 19653541Sshin RTF_CLONING | RTF_PRCLONING); 19753541Sshin if (rt2) { 19853541Sshin if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY)) 19953541Sshin == RTF_CLONING 20053541Sshin && rt2->rt_gateway 20153541Sshin && rt2->rt_gateway->sa_family == AF_LINK 20253541Sshin && rt2->rt_ifp == rt->rt_ifp) { 20353541Sshin ret = rt2->rt_nodes; 20453541Sshin } 205120727Ssam RTFREE_LOCKED(rt2); 20653541Sshin } 20753541Sshin } 20853541Sshin return ret; 20953541Sshin} 21053541Sshin 21153541Sshin/* 21253541Sshin * This code is the inverse of in6_clsroute: on first reference, if we 21353541Sshin * were managing the route, stop doing so and set the expiration timer 21453541Sshin * back off again. 21553541Sshin */ 21653541Sshinstatic struct radix_node * 21753541Sshinin6_matroute(void *v_arg, struct radix_node_head *head) 21853541Sshin{ 21953541Sshin struct radix_node *rn = rn_match(v_arg, head); 22053541Sshin struct rtentry *rt = (struct rtentry *)rn; 22153541Sshin 22253541Sshin if (rt && rt->rt_refcnt == 0) { /* this is first reference */ 22353541Sshin if (rt->rt_flags & RTPRF_OURS) { 22453541Sshin rt->rt_flags &= ~RTPRF_OURS; 22553541Sshin rt->rt_rmx.rmx_expire = 0; 22653541Sshin } 22753541Sshin } 22853541Sshin return rn; 22953541Sshin} 23053541Sshin 23162604SitojunSYSCTL_DECL(_net_inet6_ip6); 23262604Sitojun 23353541Sshinstatic int rtq_reallyold = 60*60; 23453541Sshin /* one hour is ``really old'' */ 23562604SitojunSYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTEXPIRE, rtexpire, 23653541Sshin CTLFLAG_RW, &rtq_reallyold , 0, ""); 23753541Sshin 23853541Sshinstatic int rtq_minreallyold = 10; 23953541Sshin /* never automatically crank down to less */ 24062604SitojunSYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMINEXPIRE, rtminexpire, 24153541Sshin CTLFLAG_RW, &rtq_minreallyold , 0, ""); 24253541Sshin 24353541Sshinstatic int rtq_toomany = 128; 24453541Sshin /* 128 cached routes is ``too many'' */ 24562604SitojunSYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMAXCACHE, rtmaxcache, 24653541Sshin CTLFLAG_RW, &rtq_toomany , 0, ""); 24753541Sshin 24853541Sshin 24953541Sshin/* 25053541Sshin * On last reference drop, mark the route as belong to us so that it can be 25153541Sshin * timed out. 25253541Sshin */ 25353541Sshinstatic void 25453541Sshinin6_clsroute(struct radix_node *rn, struct radix_node_head *head) 25553541Sshin{ 25653541Sshin struct rtentry *rt = (struct rtentry *)rn; 25753541Sshin 258120727Ssam RT_LOCK_ASSERT(rt); 259120727Ssam 26053541Sshin if (!(rt->rt_flags & RTF_UP)) 26153541Sshin return; /* prophylactic measures */ 26253541Sshin 26353541Sshin if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) 26453541Sshin return; 26553541Sshin 266108250Shsu if ((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) != RTF_WASCLONED) 26753541Sshin return; 26853541Sshin 26953541Sshin /* 27053541Sshin * As requested by David Greenman: 27153541Sshin * If rtq_reallyold is 0, just delete the route without 27253541Sshin * waiting for a timeout cycle to kill it. 27353541Sshin */ 27453541Sshin if (rtq_reallyold != 0) { 27553541Sshin rt->rt_flags |= RTPRF_OURS; 27653541Sshin rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; 27753541Sshin } else { 278120727Ssam /* NB: must unlock to avoid recursion */ 279120727Ssam RT_UNLOCK(rt); 28053541Sshin rtrequest(RTM_DELETE, 28153541Sshin (struct sockaddr *)rt_key(rt), 28253541Sshin rt->rt_gateway, rt_mask(rt), 28353541Sshin rt->rt_flags, 0); 284120727Ssam RT_LOCK(rt); 28553541Sshin } 28653541Sshin} 28753541Sshin 28853541Sshinstruct rtqk_arg { 28953541Sshin struct radix_node_head *rnh; 29053541Sshin int mode; 29153541Sshin int updating; 29253541Sshin int draining; 29353541Sshin int killed; 29453541Sshin int found; 29553541Sshin time_t nextstop; 29653541Sshin}; 29753541Sshin 29853541Sshin/* 29953541Sshin * Get rid of old routes. When draining, this deletes everything, even when 30053541Sshin * the timeout is not expired yet. When updating, this makes sure that 30153541Sshin * nothing has a timeout longer than the current value of rtq_reallyold. 30253541Sshin */ 30353541Sshinstatic int 30453541Sshinin6_rtqkill(struct radix_node *rn, void *rock) 30553541Sshin{ 30653541Sshin struct rtqk_arg *ap = rock; 30753541Sshin struct rtentry *rt = (struct rtentry *)rn; 30853541Sshin int err; 30953541Sshin 31053541Sshin if (rt->rt_flags & RTPRF_OURS) { 31153541Sshin ap->found++; 31253541Sshin 31353541Sshin if (ap->draining || rt->rt_rmx.rmx_expire <= time_second) { 31453541Sshin if (rt->rt_refcnt > 0) 31553541Sshin panic("rtqkill route really not free"); 31653541Sshin 31753541Sshin err = rtrequest(RTM_DELETE, 31853541Sshin (struct sockaddr *)rt_key(rt), 31953541Sshin rt->rt_gateway, rt_mask(rt), 32053541Sshin rt->rt_flags, 0); 32153541Sshin if (err) { 32253541Sshin log(LOG_WARNING, "in6_rtqkill: error %d", err); 32353541Sshin } else { 32453541Sshin ap->killed++; 32553541Sshin } 32653541Sshin } else { 32753541Sshin if (ap->updating 32853541Sshin && (rt->rt_rmx.rmx_expire - time_second 32953541Sshin > rtq_reallyold)) { 33053541Sshin rt->rt_rmx.rmx_expire = time_second 33153541Sshin + rtq_reallyold; 33253541Sshin } 33353541Sshin ap->nextstop = lmin(ap->nextstop, 33453541Sshin rt->rt_rmx.rmx_expire); 33553541Sshin } 33653541Sshin } 33753541Sshin 33853541Sshin return 0; 33953541Sshin} 34053541Sshin 34153541Sshin#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ 34253541Sshinstatic int rtq_timeout = RTQ_TIMEOUT; 343120727Ssamstatic struct callout rtq_timer; 34453541Sshin 34553541Sshinstatic void 34653541Sshinin6_rtqtimo(void *rock) 34753541Sshin{ 34853541Sshin struct radix_node_head *rnh = rock; 34953541Sshin struct rtqk_arg arg; 35053541Sshin struct timeval atv; 35153541Sshin static time_t last_adjusted_timeout = 0; 35253541Sshin 35353541Sshin arg.found = arg.killed = 0; 35453541Sshin arg.rnh = rnh; 35553541Sshin arg.nextstop = time_second + rtq_timeout; 35653541Sshin arg.draining = arg.updating = 0; 357108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 35853541Sshin rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 359108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 36053541Sshin 36153541Sshin /* 36253541Sshin * Attempt to be somewhat dynamic about this: 36353541Sshin * If there are ``too many'' routes sitting around taking up space, 36453541Sshin * then crank down the timeout, and see if we can't make some more 36553541Sshin * go away. However, we make sure that we will never adjust more 36653541Sshin * than once in rtq_timeout seconds, to keep from cranking down too 36753541Sshin * hard. 36853541Sshin */ 36953541Sshin if ((arg.found - arg.killed > rtq_toomany) 37053541Sshin && (time_second - last_adjusted_timeout >= rtq_timeout) 37153541Sshin && rtq_reallyold > rtq_minreallyold) { 37253541Sshin rtq_reallyold = 2*rtq_reallyold / 3; 37353541Sshin if (rtq_reallyold < rtq_minreallyold) { 37453541Sshin rtq_reallyold = rtq_minreallyold; 37553541Sshin } 37653541Sshin 37753541Sshin last_adjusted_timeout = time_second; 37853541Sshin#ifdef DIAGNOSTIC 37953541Sshin log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold to %d", 38053541Sshin rtq_reallyold); 38153541Sshin#endif 38253541Sshin arg.found = arg.killed = 0; 38353541Sshin arg.updating = 1; 384108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 38553541Sshin rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 386108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 38753541Sshin } 38853541Sshin 38953541Sshin atv.tv_usec = 0; 39053541Sshin atv.tv_sec = arg.nextstop; 391120727Ssam callout_reset(&rtq_timer, tvtohz(&atv), in6_rtqtimo, rock); 39253541Sshin} 39353541Sshin 39453541Sshin/* 39553541Sshin * Age old PMTUs. 39653541Sshin */ 39753541Sshinstruct mtuex_arg { 39853541Sshin struct radix_node_head *rnh; 39953541Sshin time_t nextstop; 40053541Sshin}; 401120727Ssamstatic struct callout rtq_mtutimer; 40253541Sshin 40353541Sshinstatic int 40453541Sshinin6_mtuexpire(struct radix_node *rn, void *rock) 40553541Sshin{ 40653541Sshin struct rtentry *rt = (struct rtentry *)rn; 40753541Sshin struct mtuex_arg *ap = rock; 40853541Sshin 40953541Sshin /* sanity */ 41053541Sshin if (!rt) 41153541Sshin panic("rt == NULL in in6_mtuexpire"); 41253541Sshin 41353541Sshin if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) { 41453541Sshin if (rt->rt_rmx.rmx_expire <= time_second) { 41553541Sshin rt->rt_flags |= RTF_PROBEMTU; 41653541Sshin } else { 41753541Sshin ap->nextstop = lmin(ap->nextstop, 41853541Sshin rt->rt_rmx.rmx_expire); 41953541Sshin } 42053541Sshin } 42153541Sshin 42253541Sshin return 0; 42353541Sshin} 42453541Sshin 42553541Sshin#define MTUTIMO_DEFAULT (60*1) 42653541Sshin 42753541Sshinstatic void 42853541Sshinin6_mtutimo(void *rock) 42953541Sshin{ 43053541Sshin struct radix_node_head *rnh = rock; 43153541Sshin struct mtuex_arg arg; 43253541Sshin struct timeval atv; 43353541Sshin 43453541Sshin arg.rnh = rnh; 43553541Sshin arg.nextstop = time_second + MTUTIMO_DEFAULT; 436108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 43753541Sshin rnh->rnh_walktree(rnh, in6_mtuexpire, &arg); 438108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 43953541Sshin 44053541Sshin atv.tv_usec = 0; 44153541Sshin atv.tv_sec = arg.nextstop; 44253541Sshin if (atv.tv_sec < time_second) { 44353541Sshin printf("invalid mtu expiration time on routing table\n"); 44495023Ssuz arg.nextstop = time_second + 30; /* last resort */ 44553541Sshin } 446120727Ssam callout_reset(&rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock); 44753541Sshin} 44853541Sshin 44962587Sitojun#if 0 45062587Sitojunvoid 45162587Sitojunin6_rtqdrain() 45262587Sitojun{ 45362587Sitojun struct radix_node_head *rnh = rt_tables[AF_INET6]; 45462587Sitojun struct rtqk_arg arg; 455120727Ssam 45662587Sitojun arg.found = arg.killed = 0; 45762587Sitojun arg.rnh = rnh; 45862587Sitojun arg.nextstop = 0; 45962587Sitojun arg.draining = 1; 46062587Sitojun arg.updating = 0; 461108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 46262587Sitojun rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 463108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 46462587Sitojun} 46562587Sitojun#endif 46662587Sitojun 46753541Sshin/* 46853541Sshin * Initialize our routing tree. 46953541Sshin */ 47053541Sshinint 47153541Sshinin6_inithead(void **head, int off) 47253541Sshin{ 47353541Sshin struct radix_node_head *rnh; 47453541Sshin 47553541Sshin if (!rn_inithead(head, off)) 47653541Sshin return 0; 47753541Sshin 47853541Sshin if (head != (void **)&rt_tables[AF_INET6]) /* BOGUS! */ 47953541Sshin return 1; /* only do this for the real routing table */ 48053541Sshin 48153541Sshin rnh = *head; 48253541Sshin rnh->rnh_addaddr = in6_addroute; 48353541Sshin rnh->rnh_matchaddr = in6_matroute; 48453541Sshin rnh->rnh_close = in6_clsroute; 485120727Ssam callout_init(&rtq_timer, CALLOUT_MPSAFE); 48653541Sshin in6_rtqtimo(rnh); /* kick off timeout first time */ 487120727Ssam callout_init(&rtq_mtutimer, CALLOUT_MPSAFE); 48853541Sshin in6_mtutimo(rnh); /* kick off timeout first time */ 48953541Sshin return 1; 49053541Sshin} 491