xref: /freebsd/sys/netinet/in_rmx.c (revision 4684d3cbcb0d3d8378d378e42fe1489afb0a9fd5)
1c398230bSWarner Losh /*-
2ea80aed1SGarrett Wollman  * Copyright 1994, 1995 Massachusetts Institute of Technology
3d4a8d8f2SGarrett Wollman  *
4ea80aed1SGarrett Wollman  * Permission to use, copy, modify, and distribute this software and
5ea80aed1SGarrett Wollman  * its documentation for any purpose and without fee is hereby
6ea80aed1SGarrett Wollman  * granted, provided that both the above copyright notice and this
7ea80aed1SGarrett Wollman  * permission notice appear in all copies, that both the above
8ea80aed1SGarrett Wollman  * copyright notice and this permission notice appear in all
9ea80aed1SGarrett Wollman  * supporting documentation, and that the name of M.I.T. not be used
10ea80aed1SGarrett Wollman  * in advertising or publicity pertaining to distribution of the
11ea80aed1SGarrett Wollman  * software without specific, written prior permission.  M.I.T. makes
12ea80aed1SGarrett Wollman  * no representations about the suitability of this software for any
13ea80aed1SGarrett Wollman  * purpose.  It is provided "as is" without express or implied
14ea80aed1SGarrett Wollman  * warranty.
15d4a8d8f2SGarrett Wollman  *
16ea80aed1SGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17ea80aed1SGarrett Wollman  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18ea80aed1SGarrett Wollman  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19ea80aed1SGarrett Wollman  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20ea80aed1SGarrett Wollman  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21ea80aed1SGarrett Wollman  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22ea80aed1SGarrett Wollman  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23ea80aed1SGarrett Wollman  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24ea80aed1SGarrett Wollman  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25ea80aed1SGarrett Wollman  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26ea80aed1SGarrett Wollman  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27ea80aed1SGarrett Wollman  * SUCH DAMAGE.
28d4a8d8f2SGarrett Wollman  */
29d4a8d8f2SGarrett Wollman 
304b421e2dSMike Silbersack #include <sys/cdefs.h>
314b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
324b421e2dSMike Silbersack 
33*4684d3cbSAlexander V. Chernikov #include "opt_mpath.h"
34*4684d3cbSAlexander V. Chernikov 
35d4a8d8f2SGarrett Wollman #include <sys/param.h>
36d4a8d8f2SGarrett Wollman #include <sys/systm.h>
37d4a8d8f2SGarrett Wollman #include <sys/kernel.h>
3898163b98SPoul-Henning Kamp #include <sys/sysctl.h>
39d4a8d8f2SGarrett Wollman #include <sys/socket.h>
40d4a8d8f2SGarrett Wollman #include <sys/mbuf.h>
41d4a8d8f2SGarrett Wollman 
42d4a8d8f2SGarrett Wollman #include <net/if.h>
4376039bc8SGleb Smirnoff #include <net/if_var.h>
44d4a8d8f2SGarrett Wollman #include <net/route.h>
4561eee0e2SAlexander V. Chernikov #include <net/route_var.h>
46530c0060SRobert Watson #include <net/vnet.h>
474b79449eSBjoern A. Zeeb 
48d4a8d8f2SGarrett Wollman #include <netinet/in.h>
49d4a8d8f2SGarrett Wollman #include <netinet/in_var.h>
503c2824b9SAlexander V. Chernikov #include <netinet/ip.h>
513c2824b9SAlexander V. Chernikov #include <netinet/ip_icmp.h>
521e3d5af0SRuslan Ermilov #include <netinet/ip_var.h>
53d4a8d8f2SGarrett Wollman 
54ead85fe4SAlexander V. Chernikov extern int	in_inithead(void **head, int off, u_int fibnum);
55bc29160dSMarko Zec #ifdef VIMAGE
56bc29160dSMarko Zec extern int	in_detachhead(void **head, int off);
57bc29160dSMarko Zec #endif
58ce7609a4SBruce Evans 
59d4a8d8f2SGarrett Wollman /*
60d4a8d8f2SGarrett Wollman  * Do what we need to do when inserting a route.
61d4a8d8f2SGarrett Wollman  */
62d4a8d8f2SGarrett Wollman static struct radix_node *
6361eee0e2SAlexander V. Chernikov in_addroute(void *v_arg, void *n_arg, struct radix_head *head,
64d4a8d8f2SGarrett Wollman     struct radix_node *treenodes)
65d4a8d8f2SGarrett Wollman {
66d4a8d8f2SGarrett Wollman 	struct rtentry *rt = (struct rtentry *)treenodes;
67dd224982SGarrett Wollman 	struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt);
68d4a8d8f2SGarrett Wollman 
69d4a8d8f2SGarrett Wollman 	/*
709f9b3dc4SGarrett Wollman 	 * A little bit of help for both IP output and input:
719f9b3dc4SGarrett Wollman 	 *   For host routes, we make sure that RTF_BROADCAST
729f9b3dc4SGarrett Wollman 	 *   is set for anything that looks like a broadcast address.
739f9b3dc4SGarrett Wollman 	 *   This way, we can avoid an expensive call to in_broadcast()
749f9b3dc4SGarrett Wollman 	 *   in ip_output() most of the time (because the route passed
759f9b3dc4SGarrett Wollman 	 *   to ip_output() is almost always a host route).
769f9b3dc4SGarrett Wollman 	 *
779f9b3dc4SGarrett Wollman 	 *   We also do the same for local addresses, with the thought
789f9b3dc4SGarrett Wollman 	 *   that this might one day be used to speed up ip_input().
799f9b3dc4SGarrett Wollman 	 *
809f9b3dc4SGarrett Wollman 	 * We also mark routes to multicast addresses as such, because
819f9b3dc4SGarrett Wollman 	 * it's easy to do and might be useful (but this is much more
8226d02ca7SAndre Oppermann 	 * dubious since it's so easy to inspect the address).
839f9b3dc4SGarrett Wollman 	 */
849f9b3dc4SGarrett Wollman 	if (rt->rt_flags & RTF_HOST) {
85b8a6e03fSGleb Smirnoff 		struct epoch_tracker et;
86b8a6e03fSGleb Smirnoff 		bool bcast;
87b8a6e03fSGleb Smirnoff 
88b8a6e03fSGleb Smirnoff 		NET_EPOCH_ENTER(et);
89b8a6e03fSGleb Smirnoff 		bcast = in_broadcast(sin->sin_addr, rt->rt_ifp);
90b8a6e03fSGleb Smirnoff 		NET_EPOCH_EXIT(et);
91b8a6e03fSGleb Smirnoff 		if (bcast)
929f9b3dc4SGarrett Wollman 			rt->rt_flags |= RTF_BROADCAST;
93b8a6e03fSGleb Smirnoff 		else if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr ==
94b8a6e03fSGleb Smirnoff 		    sin->sin_addr.s_addr)
959f9b3dc4SGarrett Wollman 			rt->rt_flags |= RTF_LOCAL;
969f9b3dc4SGarrett Wollman 	}
9726d02ca7SAndre Oppermann 	if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
9826d02ca7SAndre Oppermann 		rt->rt_flags |= RTF_MULTICAST;
99d4a8d8f2SGarrett Wollman 
1001a75e3b2SAlexander V. Chernikov 	if (rt->rt_ifp != NULL) {
1011a75e3b2SAlexander V. Chernikov 
1021a75e3b2SAlexander V. Chernikov 		/*
1031a75e3b2SAlexander V. Chernikov 		 * Check route MTU:
1041a75e3b2SAlexander V. Chernikov 		 * inherit interface MTU if not set or
1051a75e3b2SAlexander V. Chernikov 		 * check if MTU is too large.
1061a75e3b2SAlexander V. Chernikov 		 */
1071a75e3b2SAlexander V. Chernikov 		if (rt->rt_mtu == 0) {
108e3a7aa6fSGleb Smirnoff 			rt->rt_mtu = rt->rt_ifp->if_mtu;
1091a75e3b2SAlexander V. Chernikov 		} else if (rt->rt_mtu > rt->rt_ifp->if_mtu)
1101a75e3b2SAlexander V. Chernikov 			rt->rt_mtu = rt->rt_ifp->if_mtu;
1111a75e3b2SAlexander V. Chernikov 	}
112dd224982SGarrett Wollman 
1136e6b3f7cSQing Li 	return (rn_addroute(v_arg, n_arg, head, treenodes));
114d4a8d8f2SGarrett Wollman }
115d4a8d8f2SGarrett Wollman 
1168b07e49aSJulian Elischer static int _in_rt_was_here;
117d4a8d8f2SGarrett Wollman /*
118d4a8d8f2SGarrett Wollman  * Initialize our routing tree.
119d4a8d8f2SGarrett Wollman  */
120d4a8d8f2SGarrett Wollman int
121ead85fe4SAlexander V. Chernikov in_inithead(void **head, int off, u_int fibnum)
122d4a8d8f2SGarrett Wollman {
12361eee0e2SAlexander V. Chernikov 	struct rib_head *rh;
124d4a8d8f2SGarrett Wollman 
125ead85fe4SAlexander V. Chernikov 	rh = rt_table_init(32, AF_INET, fibnum);
12661eee0e2SAlexander V. Chernikov 	if (rh == NULL)
12761eee0e2SAlexander V. Chernikov 		return (0);
128d4a8d8f2SGarrett Wollman 
12961eee0e2SAlexander V. Chernikov 	rh->rnh_addaddr = in_addroute;
130*4684d3cbSAlexander V. Chernikov #ifdef	RADIX_MPATH
131*4684d3cbSAlexander V. Chernikov 	rt_mpath_init_rnh(rh);
132*4684d3cbSAlexander V. Chernikov #endif
13361eee0e2SAlexander V. Chernikov 	*head = (void *)rh;
13431f0d081SAlexander V. Chernikov 
1358b07e49aSJulian Elischer 	if (_in_rt_was_here == 0 ) {
1368b07e49aSJulian Elischer 		_in_rt_was_here = 1;
1378b07e49aSJulian Elischer 	}
138d4a8d8f2SGarrett Wollman 	return 1;
139d4a8d8f2SGarrett Wollman }
140d4a8d8f2SGarrett Wollman 
141bc29160dSMarko Zec #ifdef VIMAGE
142bc29160dSMarko Zec int
143bc29160dSMarko Zec in_detachhead(void **head, int off)
144bc29160dSMarko Zec {
145bc29160dSMarko Zec 
146a5243af2SBjoern A. Zeeb 	rt_table_destroy((struct rib_head *)(*head));
147a5243af2SBjoern A. Zeeb 	return (1);
148bc29160dSMarko Zec }
149bc29160dSMarko Zec #endif
150bc29160dSMarko Zec 
15139191c8eSGarrett Wollman /*
15291854268SRuslan Ermilov  * This zaps old routes when the interface goes down or interface
15391854268SRuslan Ermilov  * address is deleted.  In the latter case, it deletes static routes
15491854268SRuslan Ermilov  * that point to this address.  If we don't do this, we may end up
15591854268SRuslan Ermilov  * using the old address in the future.  The ones we always want to
15691854268SRuslan Ermilov  * get rid of are things like ARP entries, since the user might down
15791854268SRuslan Ermilov  * the interface, walk over to a completely different network, and
15891854268SRuslan Ermilov  * plug back in.
15939191c8eSGarrett Wollman  */
16039191c8eSGarrett Wollman struct in_ifadown_arg {
16139191c8eSGarrett Wollman 	struct ifaddr *ifa;
16291854268SRuslan Ermilov 	int del;
16339191c8eSGarrett Wollman };
16439191c8eSGarrett Wollman 
16539191c8eSGarrett Wollman static int
166e8b0643eSAlexander V. Chernikov in_ifadownkill(const struct rtentry *rt, void *xap)
16739191c8eSGarrett Wollman {
16839191c8eSGarrett Wollman 	struct in_ifadown_arg *ap = xap;
16939191c8eSGarrett Wollman 
170e8b0643eSAlexander V. Chernikov 	if (rt->rt_ifa != ap->ifa)
1714579930dSBjoern A. Zeeb 		return (0);
17239191c8eSGarrett Wollman 
173e8b0643eSAlexander V. Chernikov 	if ((rt->rt_flags & RTF_STATIC) != 0 && ap->del == 0)
174e8b0643eSAlexander V. Chernikov 		return (0);
1754bdf0b6aSAlexander V. Chernikov 
176e8b0643eSAlexander V. Chernikov 	return (1);
1774bdf0b6aSAlexander V. Chernikov }
1784bdf0b6aSAlexander V. Chernikov 
179586904c2SGleb Smirnoff void
18091854268SRuslan Ermilov in_ifadown(struct ifaddr *ifa, int delete)
18139191c8eSGarrett Wollman {
18239191c8eSGarrett Wollman 	struct in_ifadown_arg arg;
18339191c8eSGarrett Wollman 
184586904c2SGleb Smirnoff 	KASSERT(ifa->ifa_addr->sa_family == AF_INET,
185586904c2SGleb Smirnoff 	    ("%s: wrong family", __func__));
18639191c8eSGarrett Wollman 
18739191c8eSGarrett Wollman 	arg.ifa = ifa;
18891854268SRuslan Ermilov 	arg.del = delete;
1894bdf0b6aSAlexander V. Chernikov 
190e8b0643eSAlexander V. Chernikov 	rt_foreach_fib_walk_del(AF_INET, in_ifadownkill, &arg);
191d1dd20beSSam Leffler 	ifa->ifa_flags &= ~IFA_ROUTE;		/* XXXlocking? */
1928b07e49aSJulian Elischer }
1938b07e49aSJulian Elischer 
1948b07e49aSJulian Elischer /*
1958b07e49aSJulian Elischer  * inet versions of rt functions. These have fib extensions and
1968b07e49aSJulian Elischer  * for now will just reference the _fib variants.
1978b07e49aSJulian Elischer  * eventually this order will be reversed,
1988b07e49aSJulian Elischer  */
1998b07e49aSJulian Elischer void
2008b07e49aSJulian Elischer in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)
2018b07e49aSJulian Elischer {
2028b07e49aSJulian Elischer 	rtalloc_ign_fib(ro, ignflags, fibnum);
2038b07e49aSJulian Elischer }
2048b07e49aSJulian Elischer 
205