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 * $Id: in_rmx.c,v 1.28 1997/02/13 19:46:41 wollman Exp $ 30 */ 31 32 /* 33 * This code does two things necessary for the enhanced TCP metrics to 34 * function in a useful manner: 35 * 1) It marks all non-host routes as `cloning', thus ensuring that 36 * every actual reference to such a route actually gets turned 37 * into a reference to a host route to the specific destination 38 * requested. 39 * 2) When such routes lose all their references, it arranges for them 40 * to be deleted in some random collection of circumstances, so that 41 * a large quantity of stale routing data is not kept in kernel memory 42 * indefinitely. See in_rtqtimo() below for the exact mechanism. 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/sysctl.h> 49 #include <sys/queue.h> 50 #include <sys/socket.h> 51 #include <sys/socketvar.h> 52 #include <sys/mbuf.h> 53 #include <sys/syslog.h> 54 55 #include <net/if.h> 56 #include <net/route.h> 57 #include <netinet/in.h> 58 #include <netinet/in_systm.h> 59 #include <netinet/in_var.h> 60 61 #include <netinet/ip.h> 62 #include <netinet/ip_var.h> 63 64 #include <netinet/tcp.h> 65 #include <netinet/tcp_seq.h> 66 #include <netinet/tcp_timer.h> 67 #include <netinet/tcp_var.h> 68 69 extern int in_inithead __P((void **head, int off)); 70 71 #define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ 72 73 /* 74 * Do what we need to do when inserting a route. 75 */ 76 static struct radix_node * 77 in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, 78 struct radix_node *treenodes) 79 { 80 struct rtentry *rt = (struct rtentry *)treenodes; 81 struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); 82 struct radix_node *ret; 83 84 /* 85 * For IP, all unicast non-host routes are automatically cloning. 86 */ 87 if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 88 rt->rt_flags |= RTF_MULTICAST; 89 90 if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { 91 rt->rt_flags |= RTF_PRCLONING; 92 } 93 94 /* 95 * A little bit of help for both IP output and input: 96 * For host routes, we make sure that RTF_BROADCAST 97 * is set for anything that looks like a broadcast address. 98 * This way, we can avoid an expensive call to in_broadcast() 99 * in ip_output() most of the time (because the route passed 100 * to ip_output() is almost always a host route). 101 * 102 * We also do the same for local addresses, with the thought 103 * that this might one day be used to speed up ip_input(). 104 * 105 * We also mark routes to multicast addresses as such, because 106 * it's easy to do and might be useful (but this is much more 107 * dubious since it's so easy to inspect the address). (This 108 * is done above.) 109 */ 110 if (rt->rt_flags & RTF_HOST) { 111 if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { 112 rt->rt_flags |= RTF_BROADCAST; 113 } else { 114 #define satosin(sa) ((struct sockaddr_in *)sa) 115 if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr 116 == sin->sin_addr.s_addr) 117 rt->rt_flags |= RTF_LOCAL; 118 #undef satosin 119 } 120 } 121 122 if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) 123 && rt->rt_ifp) 124 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 125 126 ret = rn_addroute(v_arg, n_arg, head, treenodes); 127 if (ret == NULL && rt->rt_flags & RTF_HOST) { 128 struct rtentry *rt2; 129 /* 130 * We are trying to add a host route, but can't. 131 * Find out if it is because of an 132 * ARP entry and delete it if so. 133 */ 134 rt2 = rtalloc1((struct sockaddr *)sin, 0, 135 RTF_CLONING | RTF_PRCLONING); 136 if (rt2) { 137 if (rt2->rt_flags & RTF_LLINFO && 138 rt2->rt_flags & RTF_HOST && 139 rt2->rt_gateway && 140 rt2->rt_gateway->sa_family == AF_LINK) { 141 rtrequest(RTM_DELETE, 142 (struct sockaddr *)rt_key(rt2), 143 rt2->rt_gateway, 144 rt_mask(rt2), rt2->rt_flags, 0); 145 ret = rn_addroute(v_arg, n_arg, head, 146 treenodes); 147 } 148 RTFREE(rt2); 149 } 150 } 151 return ret; 152 } 153 154 /* 155 * This code is the inverse of in_clsroute: on first reference, if we 156 * were managing the route, stop doing so and set the expiration timer 157 * back off again. 158 */ 159 static struct radix_node * 160 in_matroute(void *v_arg, struct radix_node_head *head) 161 { 162 struct radix_node *rn = rn_match(v_arg, head); 163 struct rtentry *rt = (struct rtentry *)rn; 164 165 if(rt && rt->rt_refcnt == 0) { /* this is first reference */ 166 if(rt->rt_flags & RTPRF_OURS) { 167 rt->rt_flags &= ~RTPRF_OURS; 168 rt->rt_rmx.rmx_expire = 0; 169 } 170 } 171 return rn; 172 } 173 174 static int rtq_reallyold = 60*60; 175 /* one hour is ``really old'' */ 176 SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, 177 CTLFLAG_RW, &rtq_reallyold , 0, ""); 178 179 static int rtq_minreallyold = 10; 180 /* never automatically crank down to less */ 181 SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, 182 CTLFLAG_RW, &rtq_minreallyold , 0, ""); 183 184 static int rtq_toomany = 128; 185 /* 128 cached routes is ``too many'' */ 186 SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, 187 CTLFLAG_RW, &rtq_toomany , 0, ""); 188 189 190 /* 191 * On last reference drop, mark the route as belong to us so that it can be 192 * timed out. 193 */ 194 static void 195 in_clsroute(struct radix_node *rn, struct radix_node_head *head) 196 { 197 struct rtentry *rt = (struct rtentry *)rn; 198 199 if(!(rt->rt_flags & RTF_UP)) 200 return; /* prophylactic measures */ 201 202 if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) 203 return; 204 205 if((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) 206 != RTF_WASCLONED) 207 return; 208 209 /* 210 * As requested by David Greenman: 211 * If rtq_reallyold is 0, just delete the route without 212 * waiting for a timeout cycle to kill it. 213 */ 214 if(rtq_reallyold != 0) { 215 rt->rt_flags |= RTPRF_OURS; 216 rt->rt_rmx.rmx_expire = time.tv_sec + rtq_reallyold; 217 } else { 218 rtrequest(RTM_DELETE, 219 (struct sockaddr *)rt_key(rt), 220 rt->rt_gateway, rt_mask(rt), 221 rt->rt_flags, 0); 222 } 223 } 224 225 struct rtqk_arg { 226 struct radix_node_head *rnh; 227 int draining; 228 int killed; 229 int found; 230 int updating; 231 time_t nextstop; 232 }; 233 234 /* 235 * Get rid of old routes. When draining, this deletes everything, even when 236 * the timeout is not expired yet. When updating, this makes sure that 237 * nothing has a timeout longer than the current value of rtq_reallyold. 238 */ 239 static int 240 in_rtqkill(struct radix_node *rn, void *rock) 241 { 242 struct rtqk_arg *ap = rock; 243 struct rtentry *rt = (struct rtentry *)rn; 244 int err; 245 246 if(rt->rt_flags & RTPRF_OURS) { 247 ap->found++; 248 249 if(ap->draining || rt->rt_rmx.rmx_expire <= time.tv_sec) { 250 if(rt->rt_refcnt > 0) 251 panic("rtqkill route really not free"); 252 253 err = rtrequest(RTM_DELETE, 254 (struct sockaddr *)rt_key(rt), 255 rt->rt_gateway, rt_mask(rt), 256 rt->rt_flags, 0); 257 if(err) { 258 log(LOG_WARNING, "in_rtqkill: error %d\n", err); 259 } else { 260 ap->killed++; 261 } 262 } else { 263 if(ap->updating 264 && (rt->rt_rmx.rmx_expire - time.tv_sec 265 > rtq_reallyold)) { 266 rt->rt_rmx.rmx_expire = time.tv_sec 267 + rtq_reallyold; 268 } 269 ap->nextstop = lmin(ap->nextstop, 270 rt->rt_rmx.rmx_expire); 271 } 272 } 273 274 return 0; 275 } 276 277 #define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ 278 static int rtq_timeout = RTQ_TIMEOUT; 279 280 static void 281 in_rtqtimo(void *rock) 282 { 283 struct radix_node_head *rnh = rock; 284 struct rtqk_arg arg; 285 struct timeval atv; 286 static time_t last_adjusted_timeout = 0; 287 int s; 288 289 arg.found = arg.killed = 0; 290 arg.rnh = rnh; 291 arg.nextstop = time.tv_sec + rtq_timeout; 292 arg.draining = arg.updating = 0; 293 s = splnet(); 294 rnh->rnh_walktree(rnh, in_rtqkill, &arg); 295 splx(s); 296 297 /* 298 * Attempt to be somewhat dynamic about this: 299 * If there are ``too many'' routes sitting around taking up space, 300 * then crank down the timeout, and see if we can't make some more 301 * go away. However, we make sure that we will never adjust more 302 * than once in rtq_timeout seconds, to keep from cranking down too 303 * hard. 304 */ 305 if((arg.found - arg.killed > rtq_toomany) 306 && (time.tv_sec - last_adjusted_timeout >= rtq_timeout) 307 && rtq_reallyold > rtq_minreallyold) { 308 rtq_reallyold = 2*rtq_reallyold / 3; 309 if(rtq_reallyold < rtq_minreallyold) { 310 rtq_reallyold = rtq_minreallyold; 311 } 312 313 last_adjusted_timeout = time.tv_sec; 314 #ifdef DIAGNOSTIC 315 log(LOG_DEBUG, "in_rtqtimo: adjusted rtq_reallyold to %d\n", 316 rtq_reallyold); 317 #endif 318 arg.found = arg.killed = 0; 319 arg.updating = 1; 320 s = splnet(); 321 rnh->rnh_walktree(rnh, in_rtqkill, &arg); 322 splx(s); 323 } 324 325 atv.tv_usec = 0; 326 atv.tv_sec = arg.nextstop; 327 timeout(in_rtqtimo, rock, hzto(&atv)); 328 } 329 330 void 331 in_rtqdrain(void) 332 { 333 struct radix_node_head *rnh = rt_tables[AF_INET]; 334 struct rtqk_arg arg; 335 int s; 336 arg.found = arg.killed = 0; 337 arg.rnh = rnh; 338 arg.nextstop = 0; 339 arg.draining = 1; 340 arg.updating = 0; 341 s = splnet(); 342 rnh->rnh_walktree(rnh, in_rtqkill, &arg); 343 splx(s); 344 } 345 346 /* 347 * Initialize our routing tree. 348 */ 349 int 350 in_inithead(void **head, int off) 351 { 352 struct radix_node_head *rnh; 353 354 if(!rn_inithead(head, off)) 355 return 0; 356 357 if(head != (void **)&rt_tables[AF_INET]) /* BOGUS! */ 358 return 1; /* only do this for the real routing table */ 359 360 rnh = *head; 361 rnh->rnh_addaddr = in_addroute; 362 rnh->rnh_matchaddr = in_matroute; 363 rnh->rnh_close = in_clsroute; 364 in_rtqtimo(rnh); /* kick off timeout first time */ 365 return 1; 366 } 367 368 369 /* 370 * This zaps old routes when the interface goes down. 371 * Currently it doesn't delete static routes; there are 372 * arguments one could make for both behaviors. For the moment, 373 * we will adopt the Principle of Least Surprise and leave them 374 * alone (with the knowledge that this will not be enough for some 375 * people). The ones we really want to get rid of are things like ARP 376 * entries, since the user might down the interface, walk over to a completely 377 * different network, and plug back in. 378 */ 379 struct in_ifadown_arg { 380 struct radix_node_head *rnh; 381 struct ifaddr *ifa; 382 }; 383 384 static int 385 in_ifadownkill(struct radix_node *rn, void *xap) 386 { 387 struct in_ifadown_arg *ap = xap; 388 struct rtentry *rt = (struct rtentry *)rn; 389 int err; 390 391 if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) { 392 err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), 393 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); 394 if (err) { 395 log(LOG_WARNING, "in_ifadownkill: error %d\n", err); 396 } 397 } 398 return 0; 399 } 400 401 int 402 in_ifadown(struct ifaddr *ifa) 403 { 404 struct in_ifadown_arg arg; 405 struct radix_node_head *rnh; 406 407 if (ifa->ifa_addr->sa_family != AF_INET) 408 return 1; 409 410 arg.rnh = rnh = rt_tables[AF_INET]; 411 arg.ifa = ifa; 412 rnh->rnh_walktree(rnh, in_ifadownkill, &arg); 413 ifa->ifa_flags &= ~IFA_ROUTE; 414 return 0; 415 } 416