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