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_mpath.h" 36 #include "opt_route.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/socket.h> 42 #include <sys/sysctl.h> 43 #include <sys/syslog.h> 44 #include <sys/kernel.h> 45 #include <sys/lock.h> 46 #include <sys/rmlock.h> 47 48 #include <net/if.h> 49 #include <net/if_var.h> 50 #include <net/if_dl.h> 51 #include <net/route.h> 52 #include <net/route/route_ctl.h> 53 #include <net/route/route_var.h> 54 #include <net/route/nhop.h> 55 #include <net/vnet.h> 56 57 #include <netinet/in.h> 58 59 /* 60 * Control interface address fib propagation. 61 * By default, interface address routes are added to the fib of the interface. 62 * Once set to non-zero, adds interface address route to all fibs. 63 */ 64 VNET_DEFINE(u_int, rt_add_addr_allfibs) = 0; 65 SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, 66 &VNET_NAME(rt_add_addr_allfibs), 0, ""); 67 68 /* 69 * Set up a routing table entry, normally 70 * for an interface. 71 */ 72 static inline int 73 rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 74 { 75 RIB_RLOCK_TRACKER; 76 struct epoch_tracker et; 77 struct sockaddr *dst; 78 struct sockaddr *netmask; 79 struct rib_cmd_info rc; 80 struct rt_addrinfo info; 81 int error = 0; 82 int startfib, endfib; 83 struct sockaddr_storage ss; 84 int didwork = 0; 85 int a_failure = 0; 86 struct sockaddr_dl_short sdl; 87 struct rib_head *rnh; 88 89 if (flags & RTF_HOST) { 90 dst = ifa->ifa_dstaddr; 91 netmask = NULL; 92 } else { 93 dst = ifa->ifa_addr; 94 netmask = ifa->ifa_netmask; 95 } 96 if (dst->sa_len == 0) 97 return(EINVAL); 98 switch (dst->sa_family) { 99 case AF_INET6: 100 case AF_INET: 101 /* We support multiple FIBs. */ 102 break; 103 default: 104 fibnum = RT_DEFAULT_FIB; 105 break; 106 } 107 if (fibnum == RT_ALL_FIBS) { 108 if (V_rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) 109 startfib = endfib = ifa->ifa_ifp->if_fib; 110 else { 111 startfib = 0; 112 endfib = rt_numfibs - 1; 113 } 114 } else { 115 KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 116 startfib = fibnum; 117 endfib = fibnum; 118 } 119 120 /* 121 * If it's a delete, check that if it exists, 122 * it's on the correct interface or we might scrub 123 * a route to another ifa which would 124 * be confusing at best and possibly worse. 125 */ 126 if (cmd == RTM_DELETE) { 127 /* 128 * It's a delete, so it should already exist.. 129 * If it's a net, mask off the host bits 130 * (Assuming we have a mask) 131 * XXX this is kinda inet specific.. 132 */ 133 if (netmask != NULL) { 134 rt_maskedcopy(dst, (struct sockaddr *)&ss, netmask); 135 dst = (struct sockaddr *)&ss; 136 } 137 } 138 bzero(&sdl, sizeof(struct sockaddr_dl_short)); 139 sdl.sdl_family = AF_LINK; 140 sdl.sdl_len = sizeof(struct sockaddr_dl_short); 141 sdl.sdl_type = ifa->ifa_ifp->if_type; 142 sdl.sdl_index = ifa->ifa_ifp->if_index; 143 /* 144 * Now go through all the requested tables (fibs) and do the 145 * requested action. Realistically, this will either be fib 0 146 * for protocols that don't do multiple tables or all the 147 * tables for those that do. 148 */ 149 for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 150 if (cmd == RTM_DELETE) { 151 struct radix_node *rn; 152 /* 153 * Look up an rtentry that is in the routing tree and 154 * contains the correct info. 155 */ 156 rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 157 if (rnh == NULL) 158 /* this table doesn't exist but others might */ 159 continue; 160 RIB_RLOCK(rnh); 161 rn = rnh->rnh_lookup(dst, netmask, &rnh->head); 162 error = (rn == NULL || 163 (rn->rn_flags & RNF_ROOT) || 164 RNTORT(rn)->rt_nhop->nh_ifa != ifa); 165 RIB_RUNLOCK(rnh); 166 if (error) { 167 /* this is only an error if bad on ALL tables */ 168 continue; 169 } 170 } 171 /* 172 * Do the actual request 173 */ 174 bzero((caddr_t)&info, sizeof(info)); 175 info.rti_ifa = ifa; 176 info.rti_flags = flags | 177 (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; 178 info.rti_info[RTAX_DST] = dst; 179 info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; 180 info.rti_info[RTAX_NETMASK] = netmask; 181 NET_EPOCH_ENTER(et); 182 error = rib_action(fibnum, cmd, &info, &rc); 183 if (error == 0 && rc.rc_rt != NULL) { 184 /* 185 * notify any listening routing agents of the change 186 */ 187 188 /* TODO: interface routes/aliases */ 189 rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum); 190 didwork = 1; 191 } 192 NET_EPOCH_EXIT(et); 193 if (error) 194 a_failure = error; 195 } 196 if (cmd == RTM_DELETE) { 197 if (didwork) { 198 error = 0; 199 } else { 200 /* we only give an error if it wasn't in any table */ 201 error = ((flags & RTF_HOST) ? 202 EHOSTUNREACH : ENETUNREACH); 203 } 204 } else { 205 if (a_failure) { 206 /* return an error if any of them failed */ 207 error = a_failure; 208 } 209 } 210 return (error); 211 } 212 213 /* 214 * Set up a routing table entry, normally 215 * for an interface. 216 */ 217 int 218 rtinit(struct ifaddr *ifa, int cmd, int flags) 219 { 220 struct sockaddr *dst; 221 int fib = RT_DEFAULT_FIB; 222 223 if (flags & RTF_HOST) { 224 dst = ifa->ifa_dstaddr; 225 } else { 226 dst = ifa->ifa_addr; 227 } 228 229 switch (dst->sa_family) { 230 case AF_INET6: 231 case AF_INET: 232 /* We do support multiple FIBs. */ 233 fib = RT_ALL_FIBS; 234 break; 235 } 236 return (rtinit1(ifa, cmd, flags, fib)); 237 } 238 239 static int 240 ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, 241 struct sockaddr *ia) 242 { 243 struct rib_cmd_info rc; 244 struct epoch_tracker et; 245 int error; 246 struct rt_addrinfo info; 247 struct sockaddr_dl null_sdl; 248 struct ifnet *ifp; 249 struct ifaddr *rti_ifa = NULL; 250 251 ifp = ifa->ifa_ifp; 252 253 NET_EPOCH_ENTER(et); 254 bzero(&info, sizeof(info)); 255 if (cmd != RTM_DELETE) 256 info.rti_ifp = V_loif; 257 if (cmd == RTM_ADD) { 258 /* explicitly specify (loopback) ifa */ 259 if (info.rti_ifp != NULL) { 260 rti_ifa = ifaof_ifpforaddr(ifa->ifa_addr, info.rti_ifp); 261 if (rti_ifa != NULL) 262 ifa_ref(rti_ifa); 263 info.rti_ifa = rti_ifa; 264 } 265 } 266 info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC | RTF_PINNED; 267 info.rti_info[RTAX_DST] = ia; 268 info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; 269 link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type); 270 271 error = rib_action(ifp->if_fib, cmd, &info, &rc); 272 NET_EPOCH_EXIT(et); 273 274 if (rti_ifa != NULL) 275 ifa_free(rti_ifa); 276 277 if (error == 0 || 278 (cmd == RTM_ADD && error == EEXIST) || 279 (cmd == RTM_DELETE && (error == ENOENT || error == ESRCH))) 280 return (error); 281 282 log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n", 283 __func__, otype, if_name(ifp), error); 284 285 return (error); 286 } 287 288 int 289 ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) 290 { 291 292 return (ifa_maintain_loopback_route(RTM_ADD, "insertion", ifa, ia)); 293 } 294 295 int 296 ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) 297 { 298 299 return (ifa_maintain_loopback_route(RTM_DELETE, "deletion", ifa, ia)); 300 } 301 302 int 303 ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) 304 { 305 306 return (ifa_maintain_loopback_route(RTM_CHANGE, "switch", ifa, ia)); 307 } 308 309 310