1 /*- 2 * Copyright 1994, 1995 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include "opt_mpath.h" 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/sysctl.h> 39 #include <sys/socket.h> 40 #include <sys/mbuf.h> 41 42 #include <net/if.h> 43 #include <net/if_var.h> 44 #include <net/route.h> 45 #include <net/route_var.h> 46 #include <net/route/nhop.h> 47 #include <net/route/shared.h> 48 #include <net/vnet.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_var.h> 52 #include <netinet/ip.h> 53 #include <netinet/ip_icmp.h> 54 #include <netinet/ip_var.h> 55 56 extern int in_inithead(void **head, int off, u_int fibnum); 57 #ifdef VIMAGE 58 extern int in_detachhead(void **head, int off); 59 #endif 60 61 static int 62 rib4_preadd(u_int fibnum, const struct sockaddr *addr, const struct sockaddr *mask, 63 struct nhop_object *nh) 64 { 65 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; 66 uint16_t nh_type; 67 int rt_flags; 68 69 /* XXX: RTF_LOCAL && RTF_MULTICAST */ 70 71 rt_flags = nhop_get_rtflags(nh); 72 73 if (rt_flags & RTF_HOST) { 74 75 /* 76 * Backward compatibility: 77 * if the destination is broadcast, 78 * mark route as broadcast. 79 * This behavior was useful when route cloning 80 * was in place, so there was an explicit cloned 81 * route for every broadcasted address. 82 * Currently (2020-04) there is no kernel machinery 83 * to do route cloning, though someone might explicitly 84 * add these routes to support some cases with active-active 85 * load balancing. Given that, retain this support. 86 */ 87 if (in_broadcast(addr4->sin_addr, nh->nh_ifp)) { 88 rt_flags |= RTF_BROADCAST; 89 nhop_set_rtflags(nh, rt_flags); 90 nh->nh_flags |= NHF_BROADCAST; 91 } 92 } 93 94 /* 95 * Check route MTU: 96 * inherit interface MTU if not set or 97 * check if MTU is too large. 98 */ 99 if (nh->nh_mtu == 0) { 100 nh->nh_mtu = nh->nh_ifp->if_mtu; 101 } else if (nh->nh_mtu > nh->nh_ifp->if_mtu) 102 nh->nh_mtu = nh->nh_ifp->if_mtu; 103 104 /* Ensure that default route nhop has special flag */ 105 const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 106 if ((rt_flags & RTF_HOST) == 0 && mask4->sin_addr.s_addr == 0) 107 nh->nh_flags |= NHF_DEFAULT; 108 109 /* Set nhop type to basic per-AF nhop */ 110 if (nhop_get_type(nh) == 0) { 111 if (nh->nh_flags & NHF_GATEWAY) 112 nh_type = NH_TYPE_IPV4_ETHER_NHOP; 113 else 114 nh_type = NH_TYPE_IPV4_ETHER_RSLV; 115 116 nhop_set_type(nh, nh_type); 117 } 118 119 return (0); 120 } 121 122 /* 123 * Do what we need to do when inserting a route. 124 */ 125 static struct radix_node * 126 in_addroute(void *v_arg, void *n_arg, struct radix_head *head, 127 struct radix_node *treenodes) 128 { 129 struct rtentry *rt = (struct rtentry *)treenodes; 130 struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); 131 132 /* 133 * A little bit of help for both IP output and input: 134 * For host routes, we make sure that RTF_BROADCAST 135 * is set for anything that looks like a broadcast address. 136 * This way, we can avoid an expensive call to in_broadcast() 137 * in ip_output() most of the time (because the route passed 138 * to ip_output() is almost always a host route). 139 * 140 * We also do the same for local addresses, with the thought 141 * that this might one day be used to speed up ip_input(). 142 * 143 * We also mark routes to multicast addresses as such, because 144 * it's easy to do and might be useful (but this is much more 145 * dubious since it's so easy to inspect the address). 146 */ 147 if (rt->rt_flags & RTF_HOST) { 148 struct epoch_tracker et; 149 bool bcast; 150 151 NET_EPOCH_ENTER(et); 152 bcast = in_broadcast(sin->sin_addr, rt->rt_ifp); 153 NET_EPOCH_EXIT(et); 154 if (bcast) 155 rt->rt_flags |= RTF_BROADCAST; 156 else if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr == 157 sin->sin_addr.s_addr) 158 rt->rt_flags |= RTF_LOCAL; 159 } 160 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 161 rt->rt_flags |= RTF_MULTICAST; 162 163 if (rt->rt_ifp != NULL) { 164 165 /* 166 * Check route MTU: 167 * inherit interface MTU if not set or 168 * check if MTU is too large. 169 */ 170 if (rt->rt_mtu == 0) { 171 rt->rt_mtu = rt->rt_ifp->if_mtu; 172 } else if (rt->rt_mtu > rt->rt_ifp->if_mtu) 173 rt->rt_mtu = rt->rt_ifp->if_mtu; 174 } 175 176 return (rn_addroute(v_arg, n_arg, head, treenodes)); 177 } 178 179 static int _in_rt_was_here; 180 /* 181 * Initialize our routing tree. 182 */ 183 int 184 in_inithead(void **head, int off, u_int fibnum) 185 { 186 struct rib_head *rh; 187 188 rh = rt_table_init(32, AF_INET, fibnum); 189 if (rh == NULL) 190 return (0); 191 192 rh->rnh_preadd = rib4_preadd; 193 rh->rnh_addaddr = in_addroute; 194 #ifdef RADIX_MPATH 195 rt_mpath_init_rnh(rh); 196 #endif 197 *head = (void *)rh; 198 199 if (_in_rt_was_here == 0 ) { 200 _in_rt_was_here = 1; 201 } 202 return 1; 203 } 204 205 #ifdef VIMAGE 206 int 207 in_detachhead(void **head, int off) 208 { 209 210 rt_table_destroy((struct rib_head *)(*head)); 211 return (1); 212 } 213 #endif 214 215 /* 216 * This zaps old routes when the interface goes down or interface 217 * address is deleted. In the latter case, it deletes static routes 218 * that point to this address. If we don't do this, we may end up 219 * using the old address in the future. The ones we always want to 220 * get rid of are things like ARP entries, since the user might down 221 * the interface, walk over to a completely different network, and 222 * plug back in. 223 */ 224 struct in_ifadown_arg { 225 struct ifaddr *ifa; 226 int del; 227 }; 228 229 static int 230 in_ifadownkill(const struct rtentry *rt, void *xap) 231 { 232 struct in_ifadown_arg *ap = xap; 233 234 if (rt->rt_ifa != ap->ifa) 235 return (0); 236 237 if ((rt->rt_flags & RTF_STATIC) != 0 && ap->del == 0) 238 return (0); 239 240 return (1); 241 } 242 243 void 244 in_ifadown(struct ifaddr *ifa, int delete) 245 { 246 struct in_ifadown_arg arg; 247 248 KASSERT(ifa->ifa_addr->sa_family == AF_INET, 249 ("%s: wrong family", __func__)); 250 251 arg.ifa = ifa; 252 arg.del = delete; 253 254 rt_foreach_fib_walk_del(AF_INET, in_ifadownkill, &arg); 255 ifa->ifa_flags &= ~IFA_ROUTE; /* XXXlocking? */ 256 } 257 258 /* 259 * inet versions of rt functions. These have fib extensions and 260 * for now will just reference the _fib variants. 261 * eventually this order will be reversed, 262 */ 263 void 264 in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum) 265 { 266 rtalloc_ign_fib(ro, ignflags, fibnum); 267 } 268 269