xref: /freebsd/sys/net/route/route_ifaddrs.c (revision a1b59379)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1986, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)route.c	8.3.1.1 (Berkeley) 2/23/95
32  * $FreeBSD$
33  */
34 
35 #include "opt_route.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
42 #include <sys/syslog.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/rmlock.h>
46 
47 #include <net/if.h>
48 #include <net/if_var.h>
49 #include <net/if_dl.h>
50 #include <net/route.h>
51 #include <net/route/route_ctl.h>
52 #include <net/route/route_var.h>
53 #include <net/route/nhop.h>
54 #include <net/vnet.h>
55 
56 #include <netinet/in.h>
57 
58 /*
59  * Control interface address fib propagation.
60  * By default, interface address routes are added to the fib of the interface.
61  * Once set to non-zero, adds interface address route to all fibs.
62  */
63 VNET_DEFINE(u_int, rt_add_addr_allfibs) = 0;
64 SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET,
65     &VNET_NAME(rt_add_addr_allfibs), 0, "");
66 
67 static void
68 report_operation(uint32_t fibnum, struct rib_cmd_info *rc)
69 {
70 	struct nhop_object *nh;
71 
72 	if (rc->rc_cmd == RTM_DELETE)
73 		nh = nhop_select(rc->rc_nh_old, 0);
74 	else
75 		nh = nhop_select(rc->rc_nh_new, 0);
76 	rt_routemsg(rc->rc_cmd, rc->rc_rt, nh, fibnum);
77 }
78 
79 int
80 rib_add_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen,
81     struct route_nhop_data *rnd, int op_flags)
82 {
83 	struct rib_cmd_info rc = {};
84 
85 	NET_EPOCH_ASSERT();
86 
87 	int error = rib_add_route_px(fibnum, dst, plen, rnd, op_flags, &rc);
88 	if (error != 0)
89 		return (error);
90 	report_operation(fibnum, &rc);
91 
92 	if (V_rt_add_addr_allfibs != 0) {
93 		for (int i = 0; i < V_rt_numfibs; i++) {
94 			if (i == fibnum)
95 				continue;
96 			struct rib_head *rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
97 			/* Don't care much about the errors in non-primary fib */
98 			if (rnh != NULL) {
99 				if (rib_copy_route(rc.rc_rt, rnd, rnh, &rc) == 0)
100 					report_operation(i, &rc);
101 			}
102 		}
103 	}
104 
105 	return (error);
106 }
107 
108 int
109 rib_del_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen,
110     rib_filter_f_t *filter_func, void *filter_arg, int op_flags)
111 {
112 	struct rib_cmd_info rc = {};
113 
114 	NET_EPOCH_ASSERT();
115 
116 	int error = rib_del_route_px(fibnum, dst, plen, filter_func, filter_arg,
117 	    op_flags, &rc);
118 	if (error != 0)
119 		return (error);
120 	report_operation(fibnum, &rc);
121 
122 	if (V_rt_add_addr_allfibs != 0) {
123 		for (int i = 0; i < V_rt_numfibs; i++) {
124 			if (i == fibnum)
125 				continue;
126 			/* Don't care much about the errors in non-primary fib */
127 			if (rib_del_route_px(fibnum, dst, plen, filter_func, filter_arg,
128 			    op_flags, &rc) == 0)
129 				report_operation(i, &rc);
130 		}
131 	}
132 
133 	return (error);
134 }
135 
136 static int
137 add_loopback_route_flags(struct ifaddr *ifa, struct sockaddr *ia, int op_flags)
138 {
139 	struct rib_cmd_info rc;
140 	int error;
141 
142 	NET_EPOCH_ASSERT();
143 
144 	struct ifnet *ifp = ifa->ifa_ifp;
145 	struct nhop_object *nh = nhop_alloc(ifp->if_fib, ia->sa_family);
146 	struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT };
147 	if (nh == NULL)
148 		return (ENOMEM);
149 
150 	nhop_set_direct_gw(nh, ifp);
151 	nhop_set_transmit_ifp(nh, V_loif);
152 	nhop_set_src(nh, ifaof_ifpforaddr(ifa->ifa_addr, ifp));
153 	nhop_set_pinned(nh, true);
154 	nhop_set_rtflags(nh, RTF_STATIC);
155 	nhop_set_pxtype_flag(nh, NHF_HOST);
156 	rnd.rnd_nhop = nhop_get_nhop(nh, &error);
157 	if (error != 0)
158 		return (error);
159 	error = rib_add_route_px(ifp->if_fib, ia, -1, &rnd, op_flags, &rc);
160 
161 	if (error != 0)
162 		log(LOG_DEBUG, "%s: failed to update interface %s route: %u\n",
163 		    __func__, if_name(ifp), error);
164 
165 	return (error);
166 }
167 
168 int
169 ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
170 {
171 	struct epoch_tracker et;
172 
173 	NET_EPOCH_ENTER(et);
174 	int error = add_loopback_route_flags(ifa, ia, RTM_F_CREATE | RTM_F_FORCE);
175 	NET_EPOCH_EXIT(et);
176 
177 	return (error);
178 }
179 
180 int
181 ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
182 {
183 	struct epoch_tracker et;
184 
185 	NET_EPOCH_ENTER(et);
186 	int error = add_loopback_route_flags(ifa, ia, RTM_F_REPLACE | RTM_F_FORCE);
187 	NET_EPOCH_EXIT(et);
188 
189 	return (error);
190 }
191 
192 int
193 ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
194 {
195 	struct ifnet *ifp = ifa->ifa_ifp;
196 	struct sockaddr_dl link_sdl;
197 	struct sockaddr *gw = (struct sockaddr *)&link_sdl;
198 	struct rib_cmd_info rc;
199 	struct epoch_tracker et;
200 	int error;
201 
202 	NET_EPOCH_ENTER(et);
203 
204 	link_init_sdl(ifp, gw, ifp->if_type);
205 	error = rib_del_route_px_gw(ifp->if_fib, ia, -1, gw, RTM_F_FORCE, &rc);
206 
207 	NET_EPOCH_EXIT(et);
208 
209 	if (error != 0)
210 		log(LOG_DEBUG, "%s: failed to delete interface %s route: %u\n",
211 		    __func__,  if_name(ifp), error);
212 
213 	return (error);
214 }
215 
216 static bool
217 match_kernel_route(const struct rtentry *rt, struct nhop_object *nh)
218 {
219 	if (!NH_IS_NHGRP(nh) && (nhop_get_rtflags(nh) & RTF_PINNED) &&
220 	    nh->nh_aifp->if_fib == nhop_get_fibnum(nh))
221 		return (true);
222 	return (false);
223 }
224 
225 static int
226 pick_kernel_route(struct rtentry *rt, void *arg)
227 {
228 	struct nhop_object *nh = rt->rt_nhop;
229 	struct rib_head *rh_dst = (struct rib_head *)arg;
230 
231 	if (match_kernel_route(rt, nh)) {
232 		struct rib_cmd_info rc = {};
233 		struct route_nhop_data rnd = {
234 			.rnd_nhop = nh,
235 			.rnd_weight = rt->rt_weight,
236 		};
237 		rib_copy_route(rt, &rnd, rh_dst, &rc);
238 	}
239 	return (0);
240 }
241 
242 /*
243  * Tries to copy kernel routes matching pattern from @rh_src to @rh_dst.
244  *
245  * Note: as this function acquires locks for both @rh_src and @rh_dst,
246  *  it needs to be called under RTABLES_LOCK() to avoid deadlocking
247  * with multiple ribs.
248  */
249 void
250 rib_copy_kernel_routes(struct rib_head *rh_src, struct rib_head *rh_dst)
251 {
252 	struct epoch_tracker et;
253 
254 	if (V_rt_add_addr_allfibs == 0)
255 		return;
256 
257 	NET_EPOCH_ENTER(et);
258 	rib_walk_ext_internal(rh_src, false, pick_kernel_route, NULL, rh_dst);
259 	NET_EPOCH_EXIT(et);
260 }
261 
262