xref: /freebsd/sys/netinet6/in6_rmx.c (revision 51369649b03ece2aed3eb61b0c8214b9aa5b2fa2)
1caf43b02SWarner Losh /*-
2*51369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*51369649SPedro F. Giffuni  *
482cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
582cd038dSYoshinobu Inoue  * All rights reserved.
682cd038dSYoshinobu Inoue  *
782cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
882cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
982cd038dSYoshinobu Inoue  * are met:
1082cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1282cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1382cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1482cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1582cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1682cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1782cd038dSYoshinobu Inoue  *    without specific prior written permission.
1882cd038dSYoshinobu Inoue  *
1982cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2082cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2182cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2282cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2382cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2482cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2582cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2682cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2782cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2882cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2982cd038dSYoshinobu Inoue  * SUCH DAMAGE.
30b48287a3SDavid E. O'Brien  *
31b48287a3SDavid E. O'Brien  *	$KAME: in6_rmx.c,v 1.11 2001/07/26 06:53:16 jinmei Exp $
3282cd038dSYoshinobu Inoue  */
3382cd038dSYoshinobu Inoue 
34caf43b02SWarner Losh /*-
3582cd038dSYoshinobu Inoue  * Copyright 1994, 1995 Massachusetts Institute of Technology
3682cd038dSYoshinobu Inoue  *
3782cd038dSYoshinobu Inoue  * Permission to use, copy, modify, and distribute this software and
3882cd038dSYoshinobu Inoue  * its documentation for any purpose and without fee is hereby
3982cd038dSYoshinobu Inoue  * granted, provided that both the above copyright notice and this
4082cd038dSYoshinobu Inoue  * permission notice appear in all copies, that both the above
4182cd038dSYoshinobu Inoue  * copyright notice and this permission notice appear in all
4282cd038dSYoshinobu Inoue  * supporting documentation, and that the name of M.I.T. not be used
4382cd038dSYoshinobu Inoue  * in advertising or publicity pertaining to distribution of the
4482cd038dSYoshinobu Inoue  * software without specific, written prior permission.  M.I.T. makes
4582cd038dSYoshinobu Inoue  * no representations about the suitability of this software for any
4682cd038dSYoshinobu Inoue  * purpose.  It is provided "as is" without express or implied
4782cd038dSYoshinobu Inoue  * warranty.
4882cd038dSYoshinobu Inoue  *
4982cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
5082cd038dSYoshinobu Inoue  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
5182cd038dSYoshinobu Inoue  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5282cd038dSYoshinobu Inoue  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
5382cd038dSYoshinobu Inoue  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5482cd038dSYoshinobu Inoue  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5582cd038dSYoshinobu Inoue  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
5682cd038dSYoshinobu Inoue  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5782cd038dSYoshinobu Inoue  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5882cd038dSYoshinobu Inoue  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
5982cd038dSYoshinobu Inoue  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6082cd038dSYoshinobu Inoue  * SUCH DAMAGE.
6182cd038dSYoshinobu Inoue  *
6282cd038dSYoshinobu Inoue  */
6382cd038dSYoshinobu Inoue 
64b48287a3SDavid E. O'Brien #include <sys/cdefs.h>
65b48287a3SDavid E. O'Brien __FBSDID("$FreeBSD$");
66b48287a3SDavid E. O'Brien 
6782cd038dSYoshinobu Inoue #include <sys/param.h>
6882cd038dSYoshinobu Inoue #include <sys/systm.h>
6982cd038dSYoshinobu Inoue #include <sys/kernel.h>
70609ff41fSWarner Losh #include <sys/lock.h>
7182cd038dSYoshinobu Inoue #include <sys/queue.h>
7282cd038dSYoshinobu Inoue #include <sys/socket.h>
7382cd038dSYoshinobu Inoue #include <sys/socketvar.h>
7482cd038dSYoshinobu Inoue #include <sys/mbuf.h>
753120b9d4SKip Macy #include <sys/rwlock.h>
7682cd038dSYoshinobu Inoue #include <sys/syslog.h>
77d1dd20beSSam Leffler #include <sys/callout.h>
7882cd038dSYoshinobu Inoue 
7982cd038dSYoshinobu Inoue #include <net/if.h>
8076039bc8SGleb Smirnoff #include <net/if_var.h>
810c88be04SBjoern A. Zeeb #include <net/route.h>
8261eee0e2SAlexander V. Chernikov #include <net/route_var.h>
834b79449eSBjoern A. Zeeb 
8482cd038dSYoshinobu Inoue #include <netinet/in.h>
8582cd038dSYoshinobu Inoue #include <netinet/ip_var.h>
8682cd038dSYoshinobu Inoue #include <netinet/in_var.h>
8782cd038dSYoshinobu Inoue 
88686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
8982cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
9082cd038dSYoshinobu Inoue 
91686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h>
9231b3783cSHajimu UMEMOTO #include <netinet6/nd6.h>
9382cd038dSYoshinobu Inoue 
9482cd038dSYoshinobu Inoue #include <netinet/tcp.h>
9582cd038dSYoshinobu Inoue #include <netinet/tcp_seq.h>
9682cd038dSYoshinobu Inoue #include <netinet/tcp_timer.h>
9782cd038dSYoshinobu Inoue #include <netinet/tcp_var.h>
9882cd038dSYoshinobu Inoue 
999233d8f3SDavid E. O'Brien extern int	in6_inithead(void **head, int off);
100bc29160dSMarko Zec #ifdef VIMAGE
101bc29160dSMarko Zec extern int	in6_detachhead(void **head, int off);
102bc29160dSMarko Zec #endif
10382cd038dSYoshinobu Inoue 
10482cd038dSYoshinobu Inoue /*
10582cd038dSYoshinobu Inoue  * Do what we need to do when inserting a route.
10682cd038dSYoshinobu Inoue  */
10782cd038dSYoshinobu Inoue static struct radix_node *
10861eee0e2SAlexander V. Chernikov in6_addroute(void *v_arg, void *n_arg, struct radix_head *head,
10982cd038dSYoshinobu Inoue     struct radix_node *treenodes)
11082cd038dSYoshinobu Inoue {
11182cd038dSYoshinobu Inoue 	struct rtentry *rt = (struct rtentry *)treenodes;
11282cd038dSYoshinobu Inoue 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt);
11382cd038dSYoshinobu Inoue 
11482cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
11582cd038dSYoshinobu Inoue 		rt->rt_flags |= RTF_MULTICAST;
11682cd038dSYoshinobu Inoue 
11782cd038dSYoshinobu Inoue 	/*
11882cd038dSYoshinobu Inoue 	 * A little bit of help for both IPv6 output and input:
11982cd038dSYoshinobu Inoue 	 *   For local addresses, we make sure that RTF_LOCAL is set,
12082cd038dSYoshinobu Inoue 	 *   with the thought that this might one day be used to speed up
12182cd038dSYoshinobu Inoue 	 *   ip_input().
12282cd038dSYoshinobu Inoue 	 *
12382cd038dSYoshinobu Inoue 	 * We also mark routes to multicast addresses as such, because
12482cd038dSYoshinobu Inoue 	 * it's easy to do and might be useful (but this is much more
12582cd038dSYoshinobu Inoue 	 * dubious since it's so easy to inspect the address).  (This
12682cd038dSYoshinobu Inoue 	 * is done above.)
12782cd038dSYoshinobu Inoue 	 *
12882cd038dSYoshinobu Inoue 	 * XXX
12982cd038dSYoshinobu Inoue 	 * should elaborate the code.
13082cd038dSYoshinobu Inoue 	 */
13182cd038dSYoshinobu Inoue 	if (rt->rt_flags & RTF_HOST) {
13282cd038dSYoshinobu Inoue 		if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr)
13382cd038dSYoshinobu Inoue 					->sin6_addr,
13482cd038dSYoshinobu Inoue 				       &sin6->sin6_addr)) {
13582cd038dSYoshinobu Inoue 			rt->rt_flags |= RTF_LOCAL;
13682cd038dSYoshinobu Inoue 		}
13782cd038dSYoshinobu Inoue 	}
13882cd038dSYoshinobu Inoue 
1391a75e3b2SAlexander V. Chernikov 	if (rt->rt_ifp != NULL) {
1401a75e3b2SAlexander V. Chernikov 
1411a75e3b2SAlexander V. Chernikov 		/*
1421a75e3b2SAlexander V. Chernikov 		 * Check route MTU:
1431a75e3b2SAlexander V. Chernikov 		 * inherit interface MTU if not set or
1441a75e3b2SAlexander V. Chernikov 		 * check if MTU is too large.
1451a75e3b2SAlexander V. Chernikov 		 */
1461a75e3b2SAlexander V. Chernikov 		if (rt->rt_mtu == 0) {
147e3a7aa6fSGleb Smirnoff 			rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
1481a75e3b2SAlexander V. Chernikov 		} else if (rt->rt_mtu > IN6_LINKMTU(rt->rt_ifp))
1491a75e3b2SAlexander V. Chernikov 			rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
1501a75e3b2SAlexander V. Chernikov 	}
15182cd038dSYoshinobu Inoue 
1525dba456cSAlexander V. Chernikov 	return (rn_addroute(v_arg, n_arg, head, treenodes));
15382cd038dSYoshinobu Inoue }
15482cd038dSYoshinobu Inoue 
15582cd038dSYoshinobu Inoue /*
15682cd038dSYoshinobu Inoue  * Age old PMTUs.
15782cd038dSYoshinobu Inoue  */
15882cd038dSYoshinobu Inoue struct mtuex_arg {
15961eee0e2SAlexander V. Chernikov 	struct rib_head *rnh;
16082cd038dSYoshinobu Inoue 	time_t nextstop;
16182cd038dSYoshinobu Inoue };
1623e288e62SDimitry Andric static VNET_DEFINE(struct callout, rtq_mtutimer);
1631e77c105SRobert Watson #define	V_rtq_mtutimer			VNET(rtq_mtutimer)
16482cd038dSYoshinobu Inoue 
16582cd038dSYoshinobu Inoue static int
1664bdf0b6aSAlexander V. Chernikov in6_mtuexpire(struct rtentry *rt, void *rock)
16782cd038dSYoshinobu Inoue {
16882cd038dSYoshinobu Inoue 	struct mtuex_arg *ap = rock;
16982cd038dSYoshinobu Inoue 
170e3a7aa6fSGleb Smirnoff 	if (rt->rt_expire && !(rt->rt_flags & RTF_PROBEMTU)) {
171e3a7aa6fSGleb Smirnoff 		if (rt->rt_expire <= time_uptime) {
17282cd038dSYoshinobu Inoue 			rt->rt_flags |= RTF_PROBEMTU;
17382cd038dSYoshinobu Inoue 		} else {
174e3a7aa6fSGleb Smirnoff 			ap->nextstop = lmin(ap->nextstop, rt->rt_expire);
17582cd038dSYoshinobu Inoue 		}
17682cd038dSYoshinobu Inoue 	}
17782cd038dSYoshinobu Inoue 
1784bdf0b6aSAlexander V. Chernikov 	return (0);
17982cd038dSYoshinobu Inoue }
18082cd038dSYoshinobu Inoue 
18182cd038dSYoshinobu Inoue #define	MTUTIMO_DEFAULT	(60*1)
18282cd038dSYoshinobu Inoue 
18382cd038dSYoshinobu Inoue static void
18461eee0e2SAlexander V. Chernikov in6_mtutimo_setwa(struct rib_head *rnh, uint32_t fibum, int af,
1852caee4beSAlexander V. Chernikov     void *_arg)
18682cd038dSYoshinobu Inoue {
1874bdf0b6aSAlexander V. Chernikov 	struct mtuex_arg *arg;
18882cd038dSYoshinobu Inoue 
1894bdf0b6aSAlexander V. Chernikov 	arg = (struct mtuex_arg *)_arg;
1904bdf0b6aSAlexander V. Chernikov 
1914bdf0b6aSAlexander V. Chernikov 	arg->rnh = rnh;
19282cd038dSYoshinobu Inoue }
19381d5d46bSBjoern A. Zeeb 
19481d5d46bSBjoern A. Zeeb static void
19581d5d46bSBjoern A. Zeeb in6_mtutimo(void *rock)
19681d5d46bSBjoern A. Zeeb {
19781d5d46bSBjoern A. Zeeb 	CURVNET_SET_QUIET((struct vnet *) rock);
19881d5d46bSBjoern A. Zeeb 	struct timeval atv;
1994bdf0b6aSAlexander V. Chernikov 	struct mtuex_arg arg;
20081d5d46bSBjoern A. Zeeb 
2012caee4beSAlexander V. Chernikov 	rt_foreach_fib_walk(AF_INET6, in6_mtutimo_setwa, in6_mtuexpire, &arg);
20281d5d46bSBjoern A. Zeeb 
20381d5d46bSBjoern A. Zeeb 	atv.tv_sec = MTUTIMO_DEFAULT;
20481d5d46bSBjoern A. Zeeb 	atv.tv_usec = 0;
205603724d3SBjoern A. Zeeb 	callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
2068b615593SMarko Zec 	CURVNET_RESTORE();
20782cd038dSYoshinobu Inoue }
20882cd038dSYoshinobu Inoue 
20982cd038dSYoshinobu Inoue /*
21082cd038dSYoshinobu Inoue  * Initialize our routing tree.
21182cd038dSYoshinobu Inoue  */
21281d5d46bSBjoern A. Zeeb static VNET_DEFINE(int, _in6_rt_was_here);
21381d5d46bSBjoern A. Zeeb #define	V__in6_rt_was_here	VNET(_in6_rt_was_here)
21481d5d46bSBjoern A. Zeeb 
21582cd038dSYoshinobu Inoue int
21682cd038dSYoshinobu Inoue in6_inithead(void **head, int off)
21782cd038dSYoshinobu Inoue {
21861eee0e2SAlexander V. Chernikov 	struct rib_head *rh;
21982cd038dSYoshinobu Inoue 
22061eee0e2SAlexander V. Chernikov 	rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3);
22161eee0e2SAlexander V. Chernikov 	if (rh == NULL)
2229f25cbe4SAlexander V. Chernikov 		return (0);
22382cd038dSYoshinobu Inoue 
22461eee0e2SAlexander V. Chernikov 	rh->rnh_addaddr = in6_addroute;
22561eee0e2SAlexander V. Chernikov 	*head = (void *)rh;
22681d5d46bSBjoern A. Zeeb 
22781d5d46bSBjoern A. Zeeb 	if (V__in6_rt_was_here == 0) {
228fd90e2edSJung-uk Kim 		callout_init(&V_rtq_mtutimer, 1);
22921ca7b57SMarko Zec 		in6_mtutimo(curvnet);	/* kick off timeout first time */
23081d5d46bSBjoern A. Zeeb 		V__in6_rt_was_here = 1;
23181d5d46bSBjoern A. Zeeb 	}
23281d5d46bSBjoern A. Zeeb 
2339f25cbe4SAlexander V. Chernikov 	return (1);
23482cd038dSYoshinobu Inoue }
235bc29160dSMarko Zec 
236bc29160dSMarko Zec #ifdef VIMAGE
237bc29160dSMarko Zec int
238bc29160dSMarko Zec in6_detachhead(void **head, int off)
239bc29160dSMarko Zec {
240bc29160dSMarko Zec 
241bc29160dSMarko Zec 	callout_drain(&V_rtq_mtutimer);
242a5243af2SBjoern A. Zeeb 	rt_table_destroy((struct rib_head *)(*head));
243a5243af2SBjoern A. Zeeb 
244a5243af2SBjoern A. Zeeb 	return (1);
245bc29160dSMarko Zec }
246bc29160dSMarko Zec #endif
247db566a23SBjoern A. Zeeb 
248db566a23SBjoern A. Zeeb /*
249db566a23SBjoern A. Zeeb  * Extended API for IPv6 FIB support.
250db566a23SBjoern A. Zeeb  */
251db566a23SBjoern A. Zeeb void
252db566a23SBjoern A. Zeeb in6_rtredirect(struct sockaddr *dst, struct sockaddr *gw, struct sockaddr *nm,
253db566a23SBjoern A. Zeeb     int flags, struct sockaddr *src, u_int fibnum)
254db566a23SBjoern A. Zeeb {
255db566a23SBjoern A. Zeeb 
256db566a23SBjoern A. Zeeb 	rtredirect_fib(dst, gw, nm, flags, src, fibnum);
257db566a23SBjoern A. Zeeb }
258db566a23SBjoern A. Zeeb 
259db566a23SBjoern A. Zeeb int
260db566a23SBjoern A. Zeeb in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw,
261db566a23SBjoern A. Zeeb     struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum)
262db566a23SBjoern A. Zeeb {
263db566a23SBjoern A. Zeeb 
264db566a23SBjoern A. Zeeb 	return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum));
265db566a23SBjoern A. Zeeb }
266db566a23SBjoern A. Zeeb 
267db566a23SBjoern A. Zeeb void
268db566a23SBjoern A. Zeeb in6_rtalloc(struct route_in6 *ro, u_int fibnum)
269db566a23SBjoern A. Zeeb {
270db566a23SBjoern A. Zeeb 
271db566a23SBjoern A. Zeeb 	rtalloc_ign_fib((struct route *)ro, 0ul, fibnum);
272db566a23SBjoern A. Zeeb }
273db566a23SBjoern A. Zeeb 
274db566a23SBjoern A. Zeeb void
275db566a23SBjoern A. Zeeb in6_rtalloc_ign(struct route_in6 *ro, u_long ignflags, u_int fibnum)
276db566a23SBjoern A. Zeeb {
277db566a23SBjoern A. Zeeb 
278db566a23SBjoern A. Zeeb 	rtalloc_ign_fib((struct route *)ro, ignflags, fibnum);
279db566a23SBjoern A. Zeeb }
280db566a23SBjoern A. Zeeb 
281db566a23SBjoern A. Zeeb struct rtentry *
282db566a23SBjoern A. Zeeb in6_rtalloc1(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)
283db566a23SBjoern A. Zeeb {
284db566a23SBjoern A. Zeeb 
285db566a23SBjoern A. Zeeb 	return (rtalloc1_fib(dst, report, ignflags, fibnum));
286db566a23SBjoern A. Zeeb }
287