1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 288ff5695SSUZUKI Shinsuke /* $KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 4caf43b02SWarner Losh /*- 582cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 682cd038dSYoshinobu Inoue * All rights reserved. 782cd038dSYoshinobu Inoue * 882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 1082cd038dSYoshinobu Inoue * are met: 1182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1682cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1882cd038dSYoshinobu Inoue * without specific prior written permission. 1982cd038dSYoshinobu Inoue * 2082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3082cd038dSYoshinobu Inoue * SUCH DAMAGE. 3182cd038dSYoshinobu Inoue */ 3282cd038dSYoshinobu Inoue 33caf43b02SWarner Losh /*- 3482cd038dSYoshinobu Inoue * Copyright 1994, 1995 Massachusetts Institute of Technology 3582cd038dSYoshinobu Inoue * 3682cd038dSYoshinobu Inoue * Permission to use, copy, modify, and distribute this software and 3782cd038dSYoshinobu Inoue * its documentation for any purpose and without fee is hereby 3882cd038dSYoshinobu Inoue * granted, provided that both the above copyright notice and this 3982cd038dSYoshinobu Inoue * permission notice appear in all copies, that both the above 4082cd038dSYoshinobu Inoue * copyright notice and this permission notice appear in all 4182cd038dSYoshinobu Inoue * supporting documentation, and that the name of M.I.T. not be used 4282cd038dSYoshinobu Inoue * in advertising or publicity pertaining to distribution of the 4382cd038dSYoshinobu Inoue * software without specific, written prior permission. M.I.T. makes 4482cd038dSYoshinobu Inoue * no representations about the suitability of this software for any 4582cd038dSYoshinobu Inoue * purpose. It is provided "as is" without express or implied 4682cd038dSYoshinobu Inoue * warranty. 4782cd038dSYoshinobu Inoue * 4882cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 4982cd038dSYoshinobu Inoue * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 5082cd038dSYoshinobu Inoue * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 5182cd038dSYoshinobu Inoue * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 5282cd038dSYoshinobu Inoue * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 5382cd038dSYoshinobu Inoue * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 5482cd038dSYoshinobu Inoue * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 5582cd038dSYoshinobu Inoue * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 5682cd038dSYoshinobu Inoue * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 5782cd038dSYoshinobu Inoue * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 5882cd038dSYoshinobu Inoue * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5982cd038dSYoshinobu Inoue * SUCH DAMAGE. 6082cd038dSYoshinobu Inoue * 6182cd038dSYoshinobu Inoue */ 6282cd038dSYoshinobu Inoue 6382cd038dSYoshinobu Inoue /* 6482cd038dSYoshinobu Inoue * This code does two things necessary for the enhanced TCP metrics to 6582cd038dSYoshinobu Inoue * function in a useful manner: 6682cd038dSYoshinobu Inoue * 1) It marks all non-host routes as `cloning', thus ensuring that 6782cd038dSYoshinobu Inoue * every actual reference to such a route actually gets turned 6882cd038dSYoshinobu Inoue * into a reference to a host route to the specific destination 6982cd038dSYoshinobu Inoue * requested. 7082cd038dSYoshinobu Inoue * 2) When such routes lose all their references, it arranges for them 7182cd038dSYoshinobu Inoue * to be deleted in some random collection of circumstances, so that 7282cd038dSYoshinobu Inoue * a large quantity of stale routing data is not kept in kernel memory 7382cd038dSYoshinobu Inoue * indefinitely. See in6_rtqtimo() below for the exact mechanism. 7482cd038dSYoshinobu Inoue */ 7582cd038dSYoshinobu Inoue 7682cd038dSYoshinobu Inoue #include <sys/param.h> 7782cd038dSYoshinobu Inoue #include <sys/systm.h> 7882cd038dSYoshinobu Inoue #include <sys/kernel.h> 7982cd038dSYoshinobu Inoue #include <sys/sysctl.h> 8082cd038dSYoshinobu Inoue #include <sys/queue.h> 8182cd038dSYoshinobu Inoue #include <sys/socket.h> 8282cd038dSYoshinobu Inoue #include <sys/socketvar.h> 8382cd038dSYoshinobu Inoue #include <sys/mbuf.h> 8482cd038dSYoshinobu Inoue #include <sys/syslog.h> 85d1dd20beSSam Leffler #include <sys/callout.h> 8682cd038dSYoshinobu Inoue 8782cd038dSYoshinobu Inoue #include <net/if.h> 8882cd038dSYoshinobu Inoue #include <net/route.h> 8982cd038dSYoshinobu Inoue #include <netinet/in.h> 9082cd038dSYoshinobu Inoue #include <netinet/ip_var.h> 9182cd038dSYoshinobu Inoue #include <netinet/in_var.h> 9282cd038dSYoshinobu Inoue 93686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 9482cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 9582cd038dSYoshinobu Inoue 96686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h> 9731b3783cSHajimu UMEMOTO #include <netinet6/nd6.h> 9882cd038dSYoshinobu Inoue 9982cd038dSYoshinobu Inoue #include <netinet/tcp.h> 10082cd038dSYoshinobu Inoue #include <netinet/tcp_seq.h> 10182cd038dSYoshinobu Inoue #include <netinet/tcp_timer.h> 10282cd038dSYoshinobu Inoue #include <netinet/tcp_var.h> 10382cd038dSYoshinobu Inoue 10482cd038dSYoshinobu Inoue extern int in6_inithead __P((void **head, int off)); 10582cd038dSYoshinobu Inoue 10682cd038dSYoshinobu Inoue #define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ 10782cd038dSYoshinobu Inoue 10882cd038dSYoshinobu Inoue /* 10982cd038dSYoshinobu Inoue * Do what we need to do when inserting a route. 11082cd038dSYoshinobu Inoue */ 11182cd038dSYoshinobu Inoue static struct radix_node * 11282cd038dSYoshinobu Inoue in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, 11382cd038dSYoshinobu Inoue struct radix_node *treenodes) 11482cd038dSYoshinobu Inoue { 11582cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)treenodes; 11682cd038dSYoshinobu Inoue struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); 11782cd038dSYoshinobu Inoue struct radix_node *ret; 11882cd038dSYoshinobu Inoue 11982cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 12082cd038dSYoshinobu Inoue rt->rt_flags |= RTF_MULTICAST; 12182cd038dSYoshinobu Inoue 12282cd038dSYoshinobu Inoue /* 12382cd038dSYoshinobu Inoue * A little bit of help for both IPv6 output and input: 12482cd038dSYoshinobu Inoue * For local addresses, we make sure that RTF_LOCAL is set, 12582cd038dSYoshinobu Inoue * with the thought that this might one day be used to speed up 12682cd038dSYoshinobu Inoue * ip_input(). 12782cd038dSYoshinobu Inoue * 12882cd038dSYoshinobu Inoue * We also mark routes to multicast addresses as such, because 12982cd038dSYoshinobu Inoue * it's easy to do and might be useful (but this is much more 13082cd038dSYoshinobu Inoue * dubious since it's so easy to inspect the address). (This 13182cd038dSYoshinobu Inoue * is done above.) 13282cd038dSYoshinobu Inoue * 13382cd038dSYoshinobu Inoue * XXX 13482cd038dSYoshinobu Inoue * should elaborate the code. 13582cd038dSYoshinobu Inoue */ 13682cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_HOST) { 13782cd038dSYoshinobu Inoue if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr) 13882cd038dSYoshinobu Inoue ->sin6_addr, 13982cd038dSYoshinobu Inoue &sin6->sin6_addr)) { 14082cd038dSYoshinobu Inoue rt->rt_flags |= RTF_LOCAL; 14182cd038dSYoshinobu Inoue } 14282cd038dSYoshinobu Inoue } 14382cd038dSYoshinobu Inoue 14497d8d152SAndre Oppermann if (!rt->rt_rmx.rmx_mtu && rt->rt_ifp) 14531b3783cSHajimu UMEMOTO rt->rt_rmx.rmx_mtu = IN6_LINKMTU(rt->rt_ifp); 14682cd038dSYoshinobu Inoue 14782cd038dSYoshinobu Inoue ret = rn_addroute(v_arg, n_arg, head, treenodes); 14882cd038dSYoshinobu Inoue if (ret == NULL && rt->rt_flags & RTF_HOST) { 14982cd038dSYoshinobu Inoue struct rtentry *rt2; 15082cd038dSYoshinobu Inoue /* 15182cd038dSYoshinobu Inoue * We are trying to add a host route, but can't. 15282cd038dSYoshinobu Inoue * Find out if it is because of an 15382cd038dSYoshinobu Inoue * ARP entry and delete it if so. 15482cd038dSYoshinobu Inoue */ 15526d02ca7SAndre Oppermann rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING); 15682cd038dSYoshinobu Inoue if (rt2) { 15782cd038dSYoshinobu Inoue if (rt2->rt_flags & RTF_LLINFO && 15882cd038dSYoshinobu Inoue rt2->rt_flags & RTF_HOST && 15982cd038dSYoshinobu Inoue rt2->rt_gateway && 16082cd038dSYoshinobu Inoue rt2->rt_gateway->sa_family == AF_LINK) { 1619c63e9dbSSam Leffler rtexpunge(rt2); 1629c63e9dbSSam Leffler RTFREE_LOCKED(rt2); 16382cd038dSYoshinobu Inoue ret = rn_addroute(v_arg, n_arg, head, 16482cd038dSYoshinobu Inoue treenodes); 1659c63e9dbSSam Leffler } else 166d1dd20beSSam Leffler RTFREE_LOCKED(rt2); 16782cd038dSYoshinobu Inoue } 16882cd038dSYoshinobu Inoue } else if (ret == NULL && rt->rt_flags & RTF_CLONING) { 16982cd038dSYoshinobu Inoue struct rtentry *rt2; 17082cd038dSYoshinobu Inoue /* 17182cd038dSYoshinobu Inoue * We are trying to add a net route, but can't. 17282cd038dSYoshinobu Inoue * The following case should be allowed, so we'll make a 17382cd038dSYoshinobu Inoue * special check for this: 17482cd038dSYoshinobu Inoue * Two IPv6 addresses with the same prefix is assigned 17582cd038dSYoshinobu Inoue * to a single interrface. 17682cd038dSYoshinobu Inoue * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1) 17782cd038dSYoshinobu Inoue * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2) 17882cd038dSYoshinobu Inoue * In this case, (*1) and (*2) want to add the same 17982cd038dSYoshinobu Inoue * net route entry, 3ffe:0501:: -> if0. 18082cd038dSYoshinobu Inoue * This case should not raise an error. 18182cd038dSYoshinobu Inoue */ 18226d02ca7SAndre Oppermann rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING); 18382cd038dSYoshinobu Inoue if (rt2) { 18482cd038dSYoshinobu Inoue if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY)) 18582cd038dSYoshinobu Inoue == RTF_CLONING 18682cd038dSYoshinobu Inoue && rt2->rt_gateway 18782cd038dSYoshinobu Inoue && rt2->rt_gateway->sa_family == AF_LINK 18882cd038dSYoshinobu Inoue && rt2->rt_ifp == rt->rt_ifp) { 18982cd038dSYoshinobu Inoue ret = rt2->rt_nodes; 19082cd038dSYoshinobu Inoue } 191d1dd20beSSam Leffler RTFREE_LOCKED(rt2); 19282cd038dSYoshinobu Inoue } 19382cd038dSYoshinobu Inoue } 19482cd038dSYoshinobu Inoue return ret; 19582cd038dSYoshinobu Inoue } 19682cd038dSYoshinobu Inoue 19782cd038dSYoshinobu Inoue /* 19882cd038dSYoshinobu Inoue * This code is the inverse of in6_clsroute: on first reference, if we 19982cd038dSYoshinobu Inoue * were managing the route, stop doing so and set the expiration timer 20082cd038dSYoshinobu Inoue * back off again. 20182cd038dSYoshinobu Inoue */ 20282cd038dSYoshinobu Inoue static struct radix_node * 20382cd038dSYoshinobu Inoue in6_matroute(void *v_arg, struct radix_node_head *head) 20482cd038dSYoshinobu Inoue { 20582cd038dSYoshinobu Inoue struct radix_node *rn = rn_match(v_arg, head); 20682cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 20782cd038dSYoshinobu Inoue 20882cd038dSYoshinobu Inoue if (rt && rt->rt_refcnt == 0) { /* this is first reference */ 20982cd038dSYoshinobu Inoue if (rt->rt_flags & RTPRF_OURS) { 21082cd038dSYoshinobu Inoue rt->rt_flags &= ~RTPRF_OURS; 21182cd038dSYoshinobu Inoue rt->rt_rmx.rmx_expire = 0; 21282cd038dSYoshinobu Inoue } 21382cd038dSYoshinobu Inoue } 21482cd038dSYoshinobu Inoue return rn; 21582cd038dSYoshinobu Inoue } 21682cd038dSYoshinobu Inoue 2177ee982bcSJun-ichiro itojun Hagino SYSCTL_DECL(_net_inet6_ip6); 2187ee982bcSJun-ichiro itojun Hagino 21982cd038dSYoshinobu Inoue static int rtq_reallyold = 60*60; 22082cd038dSYoshinobu Inoue /* one hour is ``really old'' */ 2217ee982bcSJun-ichiro itojun Hagino SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTEXPIRE, rtexpire, 22282cd038dSYoshinobu Inoue CTLFLAG_RW, &rtq_reallyold , 0, ""); 22382cd038dSYoshinobu Inoue 22482cd038dSYoshinobu Inoue static int rtq_minreallyold = 10; 22582cd038dSYoshinobu Inoue /* never automatically crank down to less */ 2267ee982bcSJun-ichiro itojun Hagino SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMINEXPIRE, rtminexpire, 22782cd038dSYoshinobu Inoue CTLFLAG_RW, &rtq_minreallyold , 0, ""); 22882cd038dSYoshinobu Inoue 22982cd038dSYoshinobu Inoue static int rtq_toomany = 128; 23082cd038dSYoshinobu Inoue /* 128 cached routes is ``too many'' */ 2317ee982bcSJun-ichiro itojun Hagino SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RTMAXCACHE, rtmaxcache, 23282cd038dSYoshinobu Inoue CTLFLAG_RW, &rtq_toomany , 0, ""); 23382cd038dSYoshinobu Inoue 23482cd038dSYoshinobu Inoue 23582cd038dSYoshinobu Inoue /* 23682cd038dSYoshinobu Inoue * On last reference drop, mark the route as belong to us so that it can be 23782cd038dSYoshinobu Inoue * timed out. 23882cd038dSYoshinobu Inoue */ 23982cd038dSYoshinobu Inoue static void 24082cd038dSYoshinobu Inoue in6_clsroute(struct radix_node *rn, struct radix_node_head *head) 24182cd038dSYoshinobu Inoue { 24282cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 24382cd038dSYoshinobu Inoue 244d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 245d1dd20beSSam Leffler 24682cd038dSYoshinobu Inoue if (!(rt->rt_flags & RTF_UP)) 24782cd038dSYoshinobu Inoue return; /* prophylactic measures */ 24882cd038dSYoshinobu Inoue 24982cd038dSYoshinobu Inoue if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) 25082cd038dSYoshinobu Inoue return; 25182cd038dSYoshinobu Inoue 252956b0b65SJeffrey Hsu if ((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) != RTF_WASCLONED) 25382cd038dSYoshinobu Inoue return; 25482cd038dSYoshinobu Inoue 25582cd038dSYoshinobu Inoue /* 25682cd038dSYoshinobu Inoue * As requested by David Greenman: 25782cd038dSYoshinobu Inoue * If rtq_reallyold is 0, just delete the route without 25882cd038dSYoshinobu Inoue * waiting for a timeout cycle to kill it. 25982cd038dSYoshinobu Inoue */ 26082cd038dSYoshinobu Inoue if (rtq_reallyold != 0) { 26182cd038dSYoshinobu Inoue rt->rt_flags |= RTPRF_OURS; 26282cd038dSYoshinobu Inoue rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; 26382cd038dSYoshinobu Inoue } else { 2649c63e9dbSSam Leffler rtexpunge(rt); 26582cd038dSYoshinobu Inoue } 26682cd038dSYoshinobu Inoue } 26782cd038dSYoshinobu Inoue 26882cd038dSYoshinobu Inoue struct rtqk_arg { 26982cd038dSYoshinobu Inoue struct radix_node_head *rnh; 27082cd038dSYoshinobu Inoue int mode; 27182cd038dSYoshinobu Inoue int updating; 27282cd038dSYoshinobu Inoue int draining; 27382cd038dSYoshinobu Inoue int killed; 27482cd038dSYoshinobu Inoue int found; 27582cd038dSYoshinobu Inoue time_t nextstop; 27682cd038dSYoshinobu Inoue }; 27782cd038dSYoshinobu Inoue 27882cd038dSYoshinobu Inoue /* 27982cd038dSYoshinobu Inoue * Get rid of old routes. When draining, this deletes everything, even when 28082cd038dSYoshinobu Inoue * the timeout is not expired yet. When updating, this makes sure that 28182cd038dSYoshinobu Inoue * nothing has a timeout longer than the current value of rtq_reallyold. 28282cd038dSYoshinobu Inoue */ 28382cd038dSYoshinobu Inoue static int 28482cd038dSYoshinobu Inoue in6_rtqkill(struct radix_node *rn, void *rock) 28582cd038dSYoshinobu Inoue { 28682cd038dSYoshinobu Inoue struct rtqk_arg *ap = rock; 28782cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 28882cd038dSYoshinobu Inoue int err; 28982cd038dSYoshinobu Inoue 29082cd038dSYoshinobu Inoue if (rt->rt_flags & RTPRF_OURS) { 29182cd038dSYoshinobu Inoue ap->found++; 29282cd038dSYoshinobu Inoue 29382cd038dSYoshinobu Inoue if (ap->draining || rt->rt_rmx.rmx_expire <= time_second) { 29482cd038dSYoshinobu Inoue if (rt->rt_refcnt > 0) 29582cd038dSYoshinobu Inoue panic("rtqkill route really not free"); 29682cd038dSYoshinobu Inoue 29782cd038dSYoshinobu Inoue err = rtrequest(RTM_DELETE, 29882cd038dSYoshinobu Inoue (struct sockaddr *)rt_key(rt), 29982cd038dSYoshinobu Inoue rt->rt_gateway, rt_mask(rt), 30082cd038dSYoshinobu Inoue rt->rt_flags, 0); 30182cd038dSYoshinobu Inoue if (err) { 30282cd038dSYoshinobu Inoue log(LOG_WARNING, "in6_rtqkill: error %d", err); 30382cd038dSYoshinobu Inoue } else { 30482cd038dSYoshinobu Inoue ap->killed++; 30582cd038dSYoshinobu Inoue } 30682cd038dSYoshinobu Inoue } else { 30782cd038dSYoshinobu Inoue if (ap->updating 30882cd038dSYoshinobu Inoue && (rt->rt_rmx.rmx_expire - time_second 30982cd038dSYoshinobu Inoue > rtq_reallyold)) { 31082cd038dSYoshinobu Inoue rt->rt_rmx.rmx_expire = time_second 31182cd038dSYoshinobu Inoue + rtq_reallyold; 31282cd038dSYoshinobu Inoue } 31382cd038dSYoshinobu Inoue ap->nextstop = lmin(ap->nextstop, 31482cd038dSYoshinobu Inoue rt->rt_rmx.rmx_expire); 31582cd038dSYoshinobu Inoue } 31682cd038dSYoshinobu Inoue } 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue return 0; 31982cd038dSYoshinobu Inoue } 32082cd038dSYoshinobu Inoue 32182cd038dSYoshinobu Inoue #define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ 32282cd038dSYoshinobu Inoue static int rtq_timeout = RTQ_TIMEOUT; 323d1dd20beSSam Leffler static struct callout rtq_timer; 32482cd038dSYoshinobu Inoue 32582cd038dSYoshinobu Inoue static void 32682cd038dSYoshinobu Inoue in6_rtqtimo(void *rock) 32782cd038dSYoshinobu Inoue { 32882cd038dSYoshinobu Inoue struct radix_node_head *rnh = rock; 32982cd038dSYoshinobu Inoue struct rtqk_arg arg; 33082cd038dSYoshinobu Inoue struct timeval atv; 33182cd038dSYoshinobu Inoue static time_t last_adjusted_timeout = 0; 33282cd038dSYoshinobu Inoue 33382cd038dSYoshinobu Inoue arg.found = arg.killed = 0; 33482cd038dSYoshinobu Inoue arg.rnh = rnh; 33582cd038dSYoshinobu Inoue arg.nextstop = time_second + rtq_timeout; 33682cd038dSYoshinobu Inoue arg.draining = arg.updating = 0; 337956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 33882cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 339956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 34082cd038dSYoshinobu Inoue 34182cd038dSYoshinobu Inoue /* 34282cd038dSYoshinobu Inoue * Attempt to be somewhat dynamic about this: 34382cd038dSYoshinobu Inoue * If there are ``too many'' routes sitting around taking up space, 34482cd038dSYoshinobu Inoue * then crank down the timeout, and see if we can't make some more 34582cd038dSYoshinobu Inoue * go away. However, we make sure that we will never adjust more 34682cd038dSYoshinobu Inoue * than once in rtq_timeout seconds, to keep from cranking down too 34782cd038dSYoshinobu Inoue * hard. 34882cd038dSYoshinobu Inoue */ 34982cd038dSYoshinobu Inoue if ((arg.found - arg.killed > rtq_toomany) 35082cd038dSYoshinobu Inoue && (time_second - last_adjusted_timeout >= rtq_timeout) 35182cd038dSYoshinobu Inoue && rtq_reallyold > rtq_minreallyold) { 35282cd038dSYoshinobu Inoue rtq_reallyold = 2*rtq_reallyold / 3; 35382cd038dSYoshinobu Inoue if (rtq_reallyold < rtq_minreallyold) { 35482cd038dSYoshinobu Inoue rtq_reallyold = rtq_minreallyold; 35582cd038dSYoshinobu Inoue } 35682cd038dSYoshinobu Inoue 35782cd038dSYoshinobu Inoue last_adjusted_timeout = time_second; 35882cd038dSYoshinobu Inoue #ifdef DIAGNOSTIC 35982cd038dSYoshinobu Inoue log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold to %d", 36082cd038dSYoshinobu Inoue rtq_reallyold); 36182cd038dSYoshinobu Inoue #endif 36282cd038dSYoshinobu Inoue arg.found = arg.killed = 0; 36382cd038dSYoshinobu Inoue arg.updating = 1; 364956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 36582cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 366956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 36782cd038dSYoshinobu Inoue } 36882cd038dSYoshinobu Inoue 36982cd038dSYoshinobu Inoue atv.tv_usec = 0; 3706f9e3ebfSSUZUKI Shinsuke atv.tv_sec = arg.nextstop - time_second; 371d1dd20beSSam Leffler callout_reset(&rtq_timer, tvtohz(&atv), in6_rtqtimo, rock); 37282cd038dSYoshinobu Inoue } 37382cd038dSYoshinobu Inoue 37482cd038dSYoshinobu Inoue /* 37582cd038dSYoshinobu Inoue * Age old PMTUs. 37682cd038dSYoshinobu Inoue */ 37782cd038dSYoshinobu Inoue struct mtuex_arg { 37882cd038dSYoshinobu Inoue struct radix_node_head *rnh; 37982cd038dSYoshinobu Inoue time_t nextstop; 38082cd038dSYoshinobu Inoue }; 381d1dd20beSSam Leffler static struct callout rtq_mtutimer; 38282cd038dSYoshinobu Inoue 38382cd038dSYoshinobu Inoue static int 38482cd038dSYoshinobu Inoue in6_mtuexpire(struct radix_node *rn, void *rock) 38582cd038dSYoshinobu Inoue { 38682cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 38782cd038dSYoshinobu Inoue struct mtuex_arg *ap = rock; 38882cd038dSYoshinobu Inoue 38982cd038dSYoshinobu Inoue /* sanity */ 39082cd038dSYoshinobu Inoue if (!rt) 39182cd038dSYoshinobu Inoue panic("rt == NULL in in6_mtuexpire"); 39282cd038dSYoshinobu Inoue 39382cd038dSYoshinobu Inoue if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) { 39482cd038dSYoshinobu Inoue if (rt->rt_rmx.rmx_expire <= time_second) { 39582cd038dSYoshinobu Inoue rt->rt_flags |= RTF_PROBEMTU; 39682cd038dSYoshinobu Inoue } else { 39782cd038dSYoshinobu Inoue ap->nextstop = lmin(ap->nextstop, 39882cd038dSYoshinobu Inoue rt->rt_rmx.rmx_expire); 39982cd038dSYoshinobu Inoue } 40082cd038dSYoshinobu Inoue } 40182cd038dSYoshinobu Inoue 40282cd038dSYoshinobu Inoue return 0; 40382cd038dSYoshinobu Inoue } 40482cd038dSYoshinobu Inoue 40582cd038dSYoshinobu Inoue #define MTUTIMO_DEFAULT (60*1) 40682cd038dSYoshinobu Inoue 40782cd038dSYoshinobu Inoue static void 40882cd038dSYoshinobu Inoue in6_mtutimo(void *rock) 40982cd038dSYoshinobu Inoue { 41082cd038dSYoshinobu Inoue struct radix_node_head *rnh = rock; 41182cd038dSYoshinobu Inoue struct mtuex_arg arg; 41282cd038dSYoshinobu Inoue struct timeval atv; 41382cd038dSYoshinobu Inoue 41482cd038dSYoshinobu Inoue arg.rnh = rnh; 41582cd038dSYoshinobu Inoue arg.nextstop = time_second + MTUTIMO_DEFAULT; 416956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 41782cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, in6_mtuexpire, &arg); 418956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 41982cd038dSYoshinobu Inoue 42082cd038dSYoshinobu Inoue atv.tv_usec = 0; 4216f9e3ebfSSUZUKI Shinsuke atv.tv_sec = arg.nextstop - time_second; 4226f9e3ebfSSUZUKI Shinsuke if (atv.tv_sec < 0) { 42382cd038dSYoshinobu Inoue printf("invalid mtu expiration time on routing table\n"); 4246f9e3ebfSSUZUKI Shinsuke arg.nextstop = 30; /* last resort */ 42582cd038dSYoshinobu Inoue } 426d1dd20beSSam Leffler callout_reset(&rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock); 42782cd038dSYoshinobu Inoue } 42882cd038dSYoshinobu Inoue 429686cdd19SJun-ichiro itojun Hagino #if 0 430686cdd19SJun-ichiro itojun Hagino void 431686cdd19SJun-ichiro itojun Hagino in6_rtqdrain() 432686cdd19SJun-ichiro itojun Hagino { 433686cdd19SJun-ichiro itojun Hagino struct radix_node_head *rnh = rt_tables[AF_INET6]; 434686cdd19SJun-ichiro itojun Hagino struct rtqk_arg arg; 435d1dd20beSSam Leffler 436686cdd19SJun-ichiro itojun Hagino arg.found = arg.killed = 0; 437686cdd19SJun-ichiro itojun Hagino arg.rnh = rnh; 438686cdd19SJun-ichiro itojun Hagino arg.nextstop = 0; 439686cdd19SJun-ichiro itojun Hagino arg.draining = 1; 440686cdd19SJun-ichiro itojun Hagino arg.updating = 0; 441956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 442686cdd19SJun-ichiro itojun Hagino rnh->rnh_walktree(rnh, in6_rtqkill, &arg); 443956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 444686cdd19SJun-ichiro itojun Hagino } 445686cdd19SJun-ichiro itojun Hagino #endif 446686cdd19SJun-ichiro itojun Hagino 44782cd038dSYoshinobu Inoue /* 44882cd038dSYoshinobu Inoue * Initialize our routing tree. 44982cd038dSYoshinobu Inoue */ 45082cd038dSYoshinobu Inoue int 45182cd038dSYoshinobu Inoue in6_inithead(void **head, int off) 45282cd038dSYoshinobu Inoue { 45382cd038dSYoshinobu Inoue struct radix_node_head *rnh; 45482cd038dSYoshinobu Inoue 45582cd038dSYoshinobu Inoue if (!rn_inithead(head, off)) 45682cd038dSYoshinobu Inoue return 0; 45782cd038dSYoshinobu Inoue 45882cd038dSYoshinobu Inoue if (head != (void **)&rt_tables[AF_INET6]) /* BOGUS! */ 45982cd038dSYoshinobu Inoue return 1; /* only do this for the real routing table */ 46082cd038dSYoshinobu Inoue 46182cd038dSYoshinobu Inoue rnh = *head; 46282cd038dSYoshinobu Inoue rnh->rnh_addaddr = in6_addroute; 46382cd038dSYoshinobu Inoue rnh->rnh_matchaddr = in6_matroute; 46482cd038dSYoshinobu Inoue rnh->rnh_close = in6_clsroute; 465d1dd20beSSam Leffler callout_init(&rtq_timer, CALLOUT_MPSAFE); 46682cd038dSYoshinobu Inoue in6_rtqtimo(rnh); /* kick off timeout first time */ 467d1dd20beSSam Leffler callout_init(&rtq_mtutimer, CALLOUT_MPSAFE); 46882cd038dSYoshinobu Inoue in6_mtutimo(rnh); /* kick off timeout first time */ 46982cd038dSYoshinobu Inoue return 1; 47082cd038dSYoshinobu Inoue } 471