Deleted Added
full compact
in6_rmx.c (191816) in6_rmx.c (193232)
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $
30 */
31
32/*-
33 * Copyright 1994, 1995 Massachusetts Institute of Technology
34 *
35 * Permission to use, copy, modify, and distribute this software and
36 * its documentation for any purpose and without fee is hereby
37 * granted, provided that both the above copyright notice and this
38 * permission notice appear in all copies, that both the above
39 * copyright notice and this permission notice appear in all
40 * supporting documentation, and that the name of M.I.T. not be used
41 * in advertising or publicity pertaining to distribution of the
42 * software without specific, written prior permission. M.I.T. makes
43 * no representations about the suitability of this software for any
44 * purpose. It is provided "as is" without express or implied
45 * warranty.
46 *
47 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
48 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
49 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
51 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 */
61
62/*
63 * This code does two things necessary for the enhanced TCP metrics to
64 * function in a useful manner:
65 * 1) It marks all non-host routes as `cloning', thus ensuring that
66 * every actual reference to such a route actually gets turned
67 * into a reference to a host route to the specific destination
68 * requested.
69 * 2) When such routes lose all their references, it arranges for them
70 * to be deleted in some random collection of circumstances, so that
71 * a large quantity of stale routing data is not kept in kernel memory
72 * indefinitely. See in6_rtqtimo() below for the exact mechanism.
73 */
74
75#include <sys/cdefs.h>
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $
30 */
31
32/*-
33 * Copyright 1994, 1995 Massachusetts Institute of Technology
34 *
35 * Permission to use, copy, modify, and distribute this software and
36 * its documentation for any purpose and without fee is hereby
37 * granted, provided that both the above copyright notice and this
38 * permission notice appear in all copies, that both the above
39 * copyright notice and this permission notice appear in all
40 * supporting documentation, and that the name of M.I.T. not be used
41 * in advertising or publicity pertaining to distribution of the
42 * software without specific, written prior permission. M.I.T. makes
43 * no representations about the suitability of this software for any
44 * purpose. It is provided "as is" without express or implied
45 * warranty.
46 *
47 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
48 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
49 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
51 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 */
61
62/*
63 * This code does two things necessary for the enhanced TCP metrics to
64 * function in a useful manner:
65 * 1) It marks all non-host routes as `cloning', thus ensuring that
66 * every actual reference to such a route actually gets turned
67 * into a reference to a host route to the specific destination
68 * requested.
69 * 2) When such routes lose all their references, it arranges for them
70 * to be deleted in some random collection of circumstances, so that
71 * a large quantity of stale routing data is not kept in kernel memory
72 * indefinitely. See in6_rtqtimo() below for the exact mechanism.
73 */
74
75#include <sys/cdefs.h>
76__FBSDID("$FreeBSD: head/sys/netinet6/in6_rmx.c 191816 2009-05-05 10:56:12Z zec $");
76__FBSDID("$FreeBSD: head/sys/netinet6/in6_rmx.c 193232 2009-06-01 15:49:42Z bz $");
77
78#include "opt_route.h"
79
80#include <sys/param.h>
81#include <sys/systm.h>
82#include <sys/kernel.h>
83#include <sys/lock.h>
84#include <sys/sysctl.h>
85#include <sys/queue.h>
86#include <sys/socket.h>
87#include <sys/socketvar.h>
88#include <sys/mbuf.h>
89#include <sys/rwlock.h>
90#include <sys/syslog.h>
91#include <sys/callout.h>
92#include <sys/vimage.h>
93
94#include <net/if.h>
95#include <net/route.h>
96#include <net/vnet.h>
97
98#include <netinet/in.h>
99#include <netinet/ip_var.h>
100#include <netinet/in_var.h>
101
102#include <netinet/ip6.h>
103#include <netinet6/ip6_var.h>
104
105#include <netinet/icmp6.h>
106#include <netinet6/nd6.h>
107#include <netinet6/vinet6.h>
108
109#include <netinet/tcp.h>
110#include <netinet/tcp_seq.h>
111#include <netinet/tcp_timer.h>
112#include <netinet/tcp_var.h>
113
114extern int in6_inithead(void **head, int off);
115
116#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
117
118/*
119 * Do what we need to do when inserting a route.
120 */
121static struct radix_node *
122in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
123 struct radix_node *treenodes)
124{
125 struct rtentry *rt = (struct rtentry *)treenodes;
126 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
127 struct radix_node *ret;
128
129 RADIX_NODE_HEAD_WLOCK_ASSERT(head);
130 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
131 rt->rt_flags |= RTF_MULTICAST;
132
133 /*
134 * A little bit of help for both IPv6 output and input:
135 * For local addresses, we make sure that RTF_LOCAL is set,
136 * with the thought that this might one day be used to speed up
137 * ip_input().
138 *
139 * We also mark routes to multicast addresses as such, because
140 * it's easy to do and might be useful (but this is much more
141 * dubious since it's so easy to inspect the address). (This
142 * is done above.)
143 *
144 * XXX
145 * should elaborate the code.
146 */
147 if (rt->rt_flags & RTF_HOST) {
148 if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr)
149 ->sin6_addr,
150 &sin6->sin6_addr)) {
151 rt->rt_flags |= RTF_LOCAL;
152 }
153 }
154
155 if (!rt->rt_rmx.rmx_mtu && rt->rt_ifp)
156 rt->rt_rmx.rmx_mtu = IN6_LINKMTU(rt->rt_ifp);
157
158 ret = rn_addroute(v_arg, n_arg, head, treenodes);
159 if (ret == NULL) {
160 struct rtentry *rt2;
161 /*
162 * We are trying to add a net route, but can't.
163 * The following case should be allowed, so we'll make a
164 * special check for this:
165 * Two IPv6 addresses with the same prefix is assigned
166 * to a single interrface.
167 * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1)
168 * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2)
169 * In this case, (*1) and (*2) want to add the same
170 * net route entry, 3ffe:0501:: -> if0.
171 * This case should not raise an error.
172 */
173 rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
174 if (rt2) {
175 if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
176 && rt2->rt_gateway
177 && rt2->rt_gateway->sa_family == AF_LINK
178 && rt2->rt_ifp == rt->rt_ifp) {
179 ret = rt2->rt_nodes;
180 }
181 RTFREE_LOCKED(rt2);
182 }
183 }
184 return (ret);
185}
186
187/*
188 * This code is the inverse of in6_clsroute: on first reference, if we
189 * were managing the route, stop doing so and set the expiration timer
190 * back off again.
191 */
192static struct radix_node *
193in6_matroute(void *v_arg, struct radix_node_head *head)
194{
195 struct radix_node *rn = rn_match(v_arg, head);
196 struct rtentry *rt = (struct rtentry *)rn;
197
198 if (rt && rt->rt_refcnt == 0) { /* this is first reference */
199 if (rt->rt_flags & RTPRF_OURS) {
200 rt->rt_flags &= ~RTPRF_OURS;
201 rt->rt_rmx.rmx_expire = 0;
202 }
203 }
204 return rn;
205}
206
207SYSCTL_DECL(_net_inet6_ip6);
208
209#ifdef VIMAGE_GLOBALS
210static int rtq_reallyold6;
211static int rtq_minreallyold6;
212static int rtq_toomany6;
213#endif
214
215SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTEXPIRE,
216 rtexpire, CTLFLAG_RW, rtq_reallyold6 , 0, "");
217
218SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTMINEXPIRE,
219 rtminexpire, CTLFLAG_RW, rtq_minreallyold6 , 0, "");
220
221SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTMAXCACHE,
222 rtmaxcache, CTLFLAG_RW, rtq_toomany6 , 0, "");
223
224
225
226struct rtqk_arg {
227 struct radix_node_head *rnh;
228 int mode;
229 int updating;
230 int draining;
231 int killed;
232 int found;
233 time_t nextstop;
234};
235
236/*
237 * Get rid of old routes. When draining, this deletes everything, even when
238 * the timeout is not expired yet. When updating, this makes sure that
239 * nothing has a timeout longer than the current value of rtq_reallyold6.
240 */
241static int
242in6_rtqkill(struct radix_node *rn, void *rock)
243{
244 INIT_VNET_INET6(curvnet);
245 struct rtqk_arg *ap = rock;
246 struct rtentry *rt = (struct rtentry *)rn;
247 int err;
248
249 RADIX_NODE_HEAD_WLOCK_ASSERT(ap->rnh);
250
251 if (rt->rt_flags & RTPRF_OURS) {
252 ap->found++;
253
254 if (ap->draining || rt->rt_rmx.rmx_expire <= time_uptime) {
255 if (rt->rt_refcnt > 0)
256 panic("rtqkill route really not free");
257
258 err = rtrequest(RTM_DELETE,
259 (struct sockaddr *)rt_key(rt),
260 rt->rt_gateway, rt_mask(rt),
261 rt->rt_flags|RTF_RNH_LOCKED, 0);
262 if (err) {
263 log(LOG_WARNING, "in6_rtqkill: error %d", err);
264 } else {
265 ap->killed++;
266 }
267 } else {
268 if (ap->updating
269 && (rt->rt_rmx.rmx_expire - time_uptime
270 > V_rtq_reallyold6)) {
271 rt->rt_rmx.rmx_expire = time_uptime
272 + V_rtq_reallyold6;
273 }
274 ap->nextstop = lmin(ap->nextstop,
275 rt->rt_rmx.rmx_expire);
276 }
277 }
278
279 return 0;
280}
281
282#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */
283#ifdef VIMAGE_GLOBALS
284static int rtq_timeout6;
285static struct callout rtq_timer6;
286#endif
287
288static void
289in6_rtqtimo(void *rock)
290{
291 CURVNET_SET_QUIET((struct vnet *) rock);
77
78#include "opt_route.h"
79
80#include <sys/param.h>
81#include <sys/systm.h>
82#include <sys/kernel.h>
83#include <sys/lock.h>
84#include <sys/sysctl.h>
85#include <sys/queue.h>
86#include <sys/socket.h>
87#include <sys/socketvar.h>
88#include <sys/mbuf.h>
89#include <sys/rwlock.h>
90#include <sys/syslog.h>
91#include <sys/callout.h>
92#include <sys/vimage.h>
93
94#include <net/if.h>
95#include <net/route.h>
96#include <net/vnet.h>
97
98#include <netinet/in.h>
99#include <netinet/ip_var.h>
100#include <netinet/in_var.h>
101
102#include <netinet/ip6.h>
103#include <netinet6/ip6_var.h>
104
105#include <netinet/icmp6.h>
106#include <netinet6/nd6.h>
107#include <netinet6/vinet6.h>
108
109#include <netinet/tcp.h>
110#include <netinet/tcp_seq.h>
111#include <netinet/tcp_timer.h>
112#include <netinet/tcp_var.h>
113
114extern int in6_inithead(void **head, int off);
115
116#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
117
118/*
119 * Do what we need to do when inserting a route.
120 */
121static struct radix_node *
122in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
123 struct radix_node *treenodes)
124{
125 struct rtentry *rt = (struct rtentry *)treenodes;
126 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
127 struct radix_node *ret;
128
129 RADIX_NODE_HEAD_WLOCK_ASSERT(head);
130 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
131 rt->rt_flags |= RTF_MULTICAST;
132
133 /*
134 * A little bit of help for both IPv6 output and input:
135 * For local addresses, we make sure that RTF_LOCAL is set,
136 * with the thought that this might one day be used to speed up
137 * ip_input().
138 *
139 * We also mark routes to multicast addresses as such, because
140 * it's easy to do and might be useful (but this is much more
141 * dubious since it's so easy to inspect the address). (This
142 * is done above.)
143 *
144 * XXX
145 * should elaborate the code.
146 */
147 if (rt->rt_flags & RTF_HOST) {
148 if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr)
149 ->sin6_addr,
150 &sin6->sin6_addr)) {
151 rt->rt_flags |= RTF_LOCAL;
152 }
153 }
154
155 if (!rt->rt_rmx.rmx_mtu && rt->rt_ifp)
156 rt->rt_rmx.rmx_mtu = IN6_LINKMTU(rt->rt_ifp);
157
158 ret = rn_addroute(v_arg, n_arg, head, treenodes);
159 if (ret == NULL) {
160 struct rtentry *rt2;
161 /*
162 * We are trying to add a net route, but can't.
163 * The following case should be allowed, so we'll make a
164 * special check for this:
165 * Two IPv6 addresses with the same prefix is assigned
166 * to a single interrface.
167 * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1)
168 * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2)
169 * In this case, (*1) and (*2) want to add the same
170 * net route entry, 3ffe:0501:: -> if0.
171 * This case should not raise an error.
172 */
173 rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
174 if (rt2) {
175 if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
176 && rt2->rt_gateway
177 && rt2->rt_gateway->sa_family == AF_LINK
178 && rt2->rt_ifp == rt->rt_ifp) {
179 ret = rt2->rt_nodes;
180 }
181 RTFREE_LOCKED(rt2);
182 }
183 }
184 return (ret);
185}
186
187/*
188 * This code is the inverse of in6_clsroute: on first reference, if we
189 * were managing the route, stop doing so and set the expiration timer
190 * back off again.
191 */
192static struct radix_node *
193in6_matroute(void *v_arg, struct radix_node_head *head)
194{
195 struct radix_node *rn = rn_match(v_arg, head);
196 struct rtentry *rt = (struct rtentry *)rn;
197
198 if (rt && rt->rt_refcnt == 0) { /* this is first reference */
199 if (rt->rt_flags & RTPRF_OURS) {
200 rt->rt_flags &= ~RTPRF_OURS;
201 rt->rt_rmx.rmx_expire = 0;
202 }
203 }
204 return rn;
205}
206
207SYSCTL_DECL(_net_inet6_ip6);
208
209#ifdef VIMAGE_GLOBALS
210static int rtq_reallyold6;
211static int rtq_minreallyold6;
212static int rtq_toomany6;
213#endif
214
215SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTEXPIRE,
216 rtexpire, CTLFLAG_RW, rtq_reallyold6 , 0, "");
217
218SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTMINEXPIRE,
219 rtminexpire, CTLFLAG_RW, rtq_minreallyold6 , 0, "");
220
221SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTMAXCACHE,
222 rtmaxcache, CTLFLAG_RW, rtq_toomany6 , 0, "");
223
224
225
226struct rtqk_arg {
227 struct radix_node_head *rnh;
228 int mode;
229 int updating;
230 int draining;
231 int killed;
232 int found;
233 time_t nextstop;
234};
235
236/*
237 * Get rid of old routes. When draining, this deletes everything, even when
238 * the timeout is not expired yet. When updating, this makes sure that
239 * nothing has a timeout longer than the current value of rtq_reallyold6.
240 */
241static int
242in6_rtqkill(struct radix_node *rn, void *rock)
243{
244 INIT_VNET_INET6(curvnet);
245 struct rtqk_arg *ap = rock;
246 struct rtentry *rt = (struct rtentry *)rn;
247 int err;
248
249 RADIX_NODE_HEAD_WLOCK_ASSERT(ap->rnh);
250
251 if (rt->rt_flags & RTPRF_OURS) {
252 ap->found++;
253
254 if (ap->draining || rt->rt_rmx.rmx_expire <= time_uptime) {
255 if (rt->rt_refcnt > 0)
256 panic("rtqkill route really not free");
257
258 err = rtrequest(RTM_DELETE,
259 (struct sockaddr *)rt_key(rt),
260 rt->rt_gateway, rt_mask(rt),
261 rt->rt_flags|RTF_RNH_LOCKED, 0);
262 if (err) {
263 log(LOG_WARNING, "in6_rtqkill: error %d", err);
264 } else {
265 ap->killed++;
266 }
267 } else {
268 if (ap->updating
269 && (rt->rt_rmx.rmx_expire - time_uptime
270 > V_rtq_reallyold6)) {
271 rt->rt_rmx.rmx_expire = time_uptime
272 + V_rtq_reallyold6;
273 }
274 ap->nextstop = lmin(ap->nextstop,
275 rt->rt_rmx.rmx_expire);
276 }
277 }
278
279 return 0;
280}
281
282#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */
283#ifdef VIMAGE_GLOBALS
284static int rtq_timeout6;
285static struct callout rtq_timer6;
286#endif
287
288static void
289in6_rtqtimo(void *rock)
290{
291 CURVNET_SET_QUIET((struct vnet *) rock);
292 INIT_VNET_NET(curvnet);
293 INIT_VNET_INET6(curvnet);
292 INIT_VNET_INET6(curvnet);
294 struct radix_node_head *rnh = V_rt_tables[0][AF_INET6];
293 struct radix_node_head *rnh;
295 struct rtqk_arg arg;
296 struct timeval atv;
297 static time_t last_adjusted_timeout = 0;
298
294 struct rtqk_arg arg;
295 struct timeval atv;
296 static time_t last_adjusted_timeout = 0;
297
298 rnh = rt_tables_get_rnh(0, AF_INET6);
299 if (rnh == NULL) {
300 CURVNET_RESTORE();
301 return;
302 }
299 arg.found = arg.killed = 0;
300 arg.rnh = rnh;
301 arg.nextstop = time_uptime + V_rtq_timeout6;
302 arg.draining = arg.updating = 0;
303 RADIX_NODE_HEAD_LOCK(rnh);
304 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
305 RADIX_NODE_HEAD_UNLOCK(rnh);
306
307 /*
308 * Attempt to be somewhat dynamic about this:
309 * If there are ``too many'' routes sitting around taking up space,
310 * then crank down the timeout, and see if we can't make some more
311 * go away. However, we make sure that we will never adjust more
312 * than once in rtq_timeout6 seconds, to keep from cranking down too
313 * hard.
314 */
315 if ((arg.found - arg.killed > V_rtq_toomany6)
316 && (time_uptime - last_adjusted_timeout >= V_rtq_timeout6)
317 && V_rtq_reallyold6 > V_rtq_minreallyold6) {
318 V_rtq_reallyold6 = 2*V_rtq_reallyold6 / 3;
319 if (V_rtq_reallyold6 < V_rtq_minreallyold6) {
320 V_rtq_reallyold6 = V_rtq_minreallyold6;
321 }
322
323 last_adjusted_timeout = time_uptime;
324#ifdef DIAGNOSTIC
325 log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold6 to %d",
326 V_rtq_reallyold6);
327#endif
328 arg.found = arg.killed = 0;
329 arg.updating = 1;
330 RADIX_NODE_HEAD_LOCK(rnh);
331 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
332 RADIX_NODE_HEAD_UNLOCK(rnh);
333 }
334
335 atv.tv_usec = 0;
336 atv.tv_sec = arg.nextstop - time_uptime;
337 callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
338 CURVNET_RESTORE();
339}
340
341/*
342 * Age old PMTUs.
343 */
344struct mtuex_arg {
345 struct radix_node_head *rnh;
346 time_t nextstop;
347};
348#ifdef VIMAGE_GLOBALS
349static struct callout rtq_mtutimer;
350#endif
351
352static int
353in6_mtuexpire(struct radix_node *rn, void *rock)
354{
355 struct rtentry *rt = (struct rtentry *)rn;
356 struct mtuex_arg *ap = rock;
357
358 /* sanity */
359 if (!rt)
360 panic("rt == NULL in in6_mtuexpire");
361
362 if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) {
363 if (rt->rt_rmx.rmx_expire <= time_uptime) {
364 rt->rt_flags |= RTF_PROBEMTU;
365 } else {
366 ap->nextstop = lmin(ap->nextstop,
367 rt->rt_rmx.rmx_expire);
368 }
369 }
370
371 return 0;
372}
373
374#define MTUTIMO_DEFAULT (60*1)
375
376static void
377in6_mtutimo(void *rock)
378{
379 CURVNET_SET_QUIET((struct vnet *) rock);
303 arg.found = arg.killed = 0;
304 arg.rnh = rnh;
305 arg.nextstop = time_uptime + V_rtq_timeout6;
306 arg.draining = arg.updating = 0;
307 RADIX_NODE_HEAD_LOCK(rnh);
308 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
309 RADIX_NODE_HEAD_UNLOCK(rnh);
310
311 /*
312 * Attempt to be somewhat dynamic about this:
313 * If there are ``too many'' routes sitting around taking up space,
314 * then crank down the timeout, and see if we can't make some more
315 * go away. However, we make sure that we will never adjust more
316 * than once in rtq_timeout6 seconds, to keep from cranking down too
317 * hard.
318 */
319 if ((arg.found - arg.killed > V_rtq_toomany6)
320 && (time_uptime - last_adjusted_timeout >= V_rtq_timeout6)
321 && V_rtq_reallyold6 > V_rtq_minreallyold6) {
322 V_rtq_reallyold6 = 2*V_rtq_reallyold6 / 3;
323 if (V_rtq_reallyold6 < V_rtq_minreallyold6) {
324 V_rtq_reallyold6 = V_rtq_minreallyold6;
325 }
326
327 last_adjusted_timeout = time_uptime;
328#ifdef DIAGNOSTIC
329 log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold6 to %d",
330 V_rtq_reallyold6);
331#endif
332 arg.found = arg.killed = 0;
333 arg.updating = 1;
334 RADIX_NODE_HEAD_LOCK(rnh);
335 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
336 RADIX_NODE_HEAD_UNLOCK(rnh);
337 }
338
339 atv.tv_usec = 0;
340 atv.tv_sec = arg.nextstop - time_uptime;
341 callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
342 CURVNET_RESTORE();
343}
344
345/*
346 * Age old PMTUs.
347 */
348struct mtuex_arg {
349 struct radix_node_head *rnh;
350 time_t nextstop;
351};
352#ifdef VIMAGE_GLOBALS
353static struct callout rtq_mtutimer;
354#endif
355
356static int
357in6_mtuexpire(struct radix_node *rn, void *rock)
358{
359 struct rtentry *rt = (struct rtentry *)rn;
360 struct mtuex_arg *ap = rock;
361
362 /* sanity */
363 if (!rt)
364 panic("rt == NULL in in6_mtuexpire");
365
366 if (rt->rt_rmx.rmx_expire && !(rt->rt_flags & RTF_PROBEMTU)) {
367 if (rt->rt_rmx.rmx_expire <= time_uptime) {
368 rt->rt_flags |= RTF_PROBEMTU;
369 } else {
370 ap->nextstop = lmin(ap->nextstop,
371 rt->rt_rmx.rmx_expire);
372 }
373 }
374
375 return 0;
376}
377
378#define MTUTIMO_DEFAULT (60*1)
379
380static void
381in6_mtutimo(void *rock)
382{
383 CURVNET_SET_QUIET((struct vnet *) rock);
380 INIT_VNET_NET(curvnet);
381 INIT_VNET_INET6(curvnet);
384 INIT_VNET_INET6(curvnet);
382 struct radix_node_head *rnh = V_rt_tables[0][AF_INET6];
385 struct radix_node_head *rnh;
383 struct mtuex_arg arg;
384 struct timeval atv;
385
386 struct mtuex_arg arg;
387 struct timeval atv;
388
389 rnh = rt_tables_get_rnh(0, AF_INET6);
390 if (rnh == NULL) {
391 CURVNET_RESTORE();
392 return;
393 }
386 arg.rnh = rnh;
387 arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
388 RADIX_NODE_HEAD_LOCK(rnh);
389 rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
390 RADIX_NODE_HEAD_UNLOCK(rnh);
391
392 atv.tv_usec = 0;
393 atv.tv_sec = arg.nextstop - time_uptime;
394 if (atv.tv_sec < 0) {
395 printf("invalid mtu expiration time on routing table\n");
396 arg.nextstop = time_uptime + 30; /* last resort */
397 atv.tv_sec = 30;
398 }
399 callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
400 CURVNET_RESTORE();
401}
402
403#if 0
404void
405in6_rtqdrain(void)
406{
407 INIT_VNET_NET(curvnet);
394 arg.rnh = rnh;
395 arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
396 RADIX_NODE_HEAD_LOCK(rnh);
397 rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
398 RADIX_NODE_HEAD_UNLOCK(rnh);
399
400 atv.tv_usec = 0;
401 atv.tv_sec = arg.nextstop - time_uptime;
402 if (atv.tv_sec < 0) {
403 printf("invalid mtu expiration time on routing table\n");
404 arg.nextstop = time_uptime + 30; /* last resort */
405 atv.tv_sec = 30;
406 }
407 callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
408 CURVNET_RESTORE();
409}
410
411#if 0
412void
413in6_rtqdrain(void)
414{
415 INIT_VNET_NET(curvnet);
408 struct radix_node_head *rnh = V_rt_tables[0][AF_INET6];
416 struct radix_node_head *rnh;
409 struct rtqk_arg arg;
410
417 struct rtqk_arg arg;
418
419 rnh = rt_tables_get_rnh(0, AF_INET6);
420 if (rnh == NULL)
421 panic("%s: rnh == NULL", __func__);
411 arg.found = arg.killed = 0;
412 arg.rnh = rnh;
413 arg.nextstop = 0;
414 arg.draining = 1;
415 arg.updating = 0;
416 RADIX_NODE_HEAD_LOCK(rnh);
417 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
418 RADIX_NODE_HEAD_UNLOCK(rnh);
419}
420#endif
421
422/*
423 * Initialize our routing tree.
424 * XXX MRT When off == 0, we are being called from vfs_export.c
425 * so just set up their table and leave. (we know what the correct
426 * value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
427 * see also comments in in_inithead() vfs_export.c and domain.h
428 */
429int
430in6_inithead(void **head, int off)
431{
422 arg.found = arg.killed = 0;
423 arg.rnh = rnh;
424 arg.nextstop = 0;
425 arg.draining = 1;
426 arg.updating = 0;
427 RADIX_NODE_HEAD_LOCK(rnh);
428 rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
429 RADIX_NODE_HEAD_UNLOCK(rnh);
430}
431#endif
432
433/*
434 * Initialize our routing tree.
435 * XXX MRT When off == 0, we are being called from vfs_export.c
436 * so just set up their table and leave. (we know what the correct
437 * value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
438 * see also comments in in_inithead() vfs_export.c and domain.h
439 */
440int
441in6_inithead(void **head, int off)
442{
432#ifdef INVARIANTS
433 INIT_VNET_NET(curvnet);
434#endif
435 INIT_VNET_INET6(curvnet);
436 struct radix_node_head *rnh;
437
438 if (!rn_inithead(head, offsetof(struct sockaddr_in6, sin6_addr) << 3))
439 return 0; /* See above */
440
441 if (off == 0) /* See above */
442 return 1; /* only do the rest for the real thing */
443
444 V_rtq_reallyold6 = 60*60; /* one hour is ``really old'' */
445 V_rtq_minreallyold6 = 10; /* never automatically crank down to less */
446 V_rtq_toomany6 = 128; /* 128 cached routes is ``too many'' */
447 V_rtq_timeout6 = RTQ_TIMEOUT;
448
449 rnh = *head;
443 INIT_VNET_INET6(curvnet);
444 struct radix_node_head *rnh;
445
446 if (!rn_inithead(head, offsetof(struct sockaddr_in6, sin6_addr) << 3))
447 return 0; /* See above */
448
449 if (off == 0) /* See above */
450 return 1; /* only do the rest for the real thing */
451
452 V_rtq_reallyold6 = 60*60; /* one hour is ``really old'' */
453 V_rtq_minreallyold6 = 10; /* never automatically crank down to less */
454 V_rtq_toomany6 = 128; /* 128 cached routes is ``too many'' */
455 V_rtq_timeout6 = RTQ_TIMEOUT;
456
457 rnh = *head;
450 KASSERT(rnh == V_rt_tables[0][AF_INET6], ("rnh?"));
458 KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
451 rnh->rnh_addaddr = in6_addroute;
452 rnh->rnh_matchaddr = in6_matroute;
453 callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
454 callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
455 in6_rtqtimo(curvnet); /* kick off timeout first time */
456 in6_mtutimo(curvnet); /* kick off timeout first time */
457 return 1;
458}
459 rnh->rnh_addaddr = in6_addroute;
460 rnh->rnh_matchaddr = in6_matroute;
461 callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
462 callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
463 in6_rtqtimo(curvnet); /* kick off timeout first time */
464 in6_mtutimo(curvnet); /* kick off timeout first time */
465 return 1;
466}