|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright 1994, 1995 Massachusetts Institute of Technology ! 24: * ! 25: * Permission to use, copy, modify, and distribute this software and ! 26: * its documentation for any purpose and without fee is hereby ! 27: * granted, provided that both the above copyright notice and this ! 28: * permission notice appear in all copies, that both the above ! 29: * copyright notice and this permission notice appear in all ! 30: * supporting documentation, and that the name of M.I.T. not be used ! 31: * in advertising or publicity pertaining to distribution of the ! 32: * software without specific, written prior permission. M.I.T. makes ! 33: * no representations about the suitability of this software for any ! 34: * purpose. It is provided "as is" without express or implied ! 35: * warranty. ! 36: * ! 37: * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS ! 38: * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, ! 39: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ! 40: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT ! 41: * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ! 42: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ! 43: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ! 44: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ! 45: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ! 46: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ! 47: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 48: * SUCH DAMAGE. ! 49: * ! 50: */ ! 51: ! 52: /* ! 53: * This code does two things necessary for the enhanced TCP metrics to ! 54: * function in a useful manner: ! 55: * 1) It marks all non-host routes as `cloning', thus ensuring that ! 56: * every actual reference to such a route actually gets turned ! 57: * into a reference to a host route to the specific destination ! 58: * requested. ! 59: * 2) When such routes lose all their references, it arranges for them ! 60: * to be deleted in some random collection of circumstances, so that ! 61: * a large quantity of stale routing data is not kept in kernel memory ! 62: * indefinitely. See in_rtqtimo() below for the exact mechanism. ! 63: */ ! 64: ! 65: #include <sys/param.h> ! 66: #include <sys/systm.h> ! 67: #include <sys/kernel.h> ! 68: #include <sys/sysctl.h> ! 69: #include <sys/socket.h> ! 70: #include <sys/mbuf.h> ! 71: #include <sys/syslog.h> ! 72: ! 73: #include <net/if.h> ! 74: #include <net/route.h> ! 75: #include <netinet/in.h> ! 76: #include <netinet/in_var.h> ! 77: ! 78: extern int in_inithead __P((void **head, int off)); ! 79: ! 80: #define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */ ! 81: ! 82: /* ! 83: * Do what we need to do when inserting a route. ! 84: */ ! 85: static struct radix_node * ! 86: in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, ! 87: struct radix_node *treenodes) ! 88: { ! 89: struct rtentry *rt = (struct rtentry *)treenodes; ! 90: struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); ! 91: struct radix_node *ret; ! 92: ! 93: /* ! 94: * For IP, all unicast non-host routes are automatically cloning. ! 95: */ ! 96: if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) ! 97: rt->rt_flags |= RTF_MULTICAST; ! 98: ! 99: if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { ! 100: rt->rt_flags |= RTF_PRCLONING; ! 101: } ! 102: ! 103: /* ! 104: * A little bit of help for both IP output and input: ! 105: * For host routes, we make sure that RTF_BROADCAST ! 106: * is set for anything that looks like a broadcast address. ! 107: * This way, we can avoid an expensive call to in_broadcast() ! 108: * in ip_output() most of the time (because the route passed ! 109: * to ip_output() is almost always a host route). ! 110: * ! 111: * We also do the same for local addresses, with the thought ! 112: * that this might one day be used to speed up ip_input(). ! 113: * ! 114: * We also mark routes to multicast addresses as such, because ! 115: * it's easy to do and might be useful (but this is much more ! 116: * dubious since it's so easy to inspect the address). (This ! 117: * is done above.) ! 118: */ ! 119: if (rt->rt_flags & RTF_HOST) { ! 120: if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { ! 121: rt->rt_flags |= RTF_BROADCAST; ! 122: } else { ! 123: #define satosin(sa) ((struct sockaddr_in *)sa) ! 124: if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr ! 125: == sin->sin_addr.s_addr) ! 126: rt->rt_flags |= RTF_LOCAL; ! 127: #undef satosin ! 128: } ! 129: } ! 130: ! 131: if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) ! 132: && rt->rt_ifp) ! 133: rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; ! 134: ! 135: ret = rn_addroute(v_arg, n_arg, head, treenodes); ! 136: if (ret == NULL && rt->rt_flags & RTF_HOST) { ! 137: struct rtentry *rt2; ! 138: /* ! 139: * We are trying to add a host route, but can't. ! 140: * Find out if it is because of an ! 141: * ARP entry and delete it if so. ! 142: */ ! 143: rt2 = rtalloc1((struct sockaddr *)sin, 0, ! 144: RTF_CLONING | RTF_PRCLONING); ! 145: if (rt2) { ! 146: if (rt2->rt_flags & RTF_LLINFO && ! 147: rt2->rt_flags & RTF_HOST && ! 148: rt2->rt_gateway && ! 149: rt2->rt_gateway->sa_family == AF_LINK) { ! 150: rtrequest(RTM_DELETE, ! 151: (struct sockaddr *)rt_key(rt2), ! 152: rt2->rt_gateway, ! 153: rt_mask(rt2), rt2->rt_flags, 0); ! 154: ret = rn_addroute(v_arg, n_arg, head, ! 155: treenodes); ! 156: } ! 157: RTFREE(rt2); ! 158: } ! 159: } ! 160: return ret; ! 161: } ! 162: ! 163: /* ! 164: * This code is the inverse of in_clsroute: on first reference, if we ! 165: * were managing the route, stop doing so and set the expiration timer ! 166: * back off again. ! 167: */ ! 168: static struct radix_node * ! 169: in_matroute(void *v_arg, struct radix_node_head *head) ! 170: { ! 171: struct radix_node *rn = rn_match(v_arg, head); ! 172: struct rtentry *rt = (struct rtentry *)rn; ! 173: ! 174: if(rt && rt->rt_refcnt == 0) { /* this is first reference */ ! 175: if(rt->rt_flags & RTPRF_OURS) { ! 176: rt->rt_flags &= ~RTPRF_OURS; ! 177: rt->rt_rmx.rmx_expire = 0; ! 178: } ! 179: } ! 180: return rn; ! 181: } ! 182: ! 183: static int rtq_reallyold = 60*60; ! 184: /* one hour is ``really old'' */ ! 185: SYSCTL_INT(_net_inet_ip, IPCTL_RTEXPIRE, rtexpire, ! 186: CTLFLAG_RW, &rtq_reallyold , 0, ""); ! 187: ! 188: static int rtq_minreallyold = 10; ! 189: /* never automatically crank down to less */ ! 190: SYSCTL_INT(_net_inet_ip, IPCTL_RTMINEXPIRE, rtminexpire, ! 191: CTLFLAG_RW, &rtq_minreallyold , 0, ""); ! 192: ! 193: static int rtq_toomany = 128; ! 194: /* 128 cached routes is ``too many'' */ ! 195: SYSCTL_INT(_net_inet_ip, IPCTL_RTMAXCACHE, rtmaxcache, ! 196: CTLFLAG_RW, &rtq_toomany , 0, ""); ! 197: ! 198: ! 199: /* ! 200: * On last reference drop, mark the route as belong to us so that it can be ! 201: * timed out. ! 202: */ ! 203: static void ! 204: in_clsroute(struct radix_node *rn, struct radix_node_head *head) ! 205: { ! 206: struct rtentry *rt = (struct rtentry *)rn; ! 207: ! 208: if(!(rt->rt_flags & RTF_UP)) ! 209: return; /* prophylactic measures */ ! 210: ! 211: if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) ! 212: return; ! 213: ! 214: if((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) ! 215: != RTF_WASCLONED) ! 216: return; ! 217: ! 218: /* ! 219: * As requested by David Greenman: ! 220: * If rtq_reallyold is 0, just delete the route without ! 221: * waiting for a timeout cycle to kill it. ! 222: */ ! 223: if(rtq_reallyold != 0) { ! 224: rt->rt_flags |= RTPRF_OURS; ! 225: rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; ! 226: } else { ! 227: rtrequest(RTM_DELETE, ! 228: (struct sockaddr *)rt_key(rt), ! 229: rt->rt_gateway, rt_mask(rt), ! 230: rt->rt_flags, 0); ! 231: } ! 232: } ! 233: ! 234: struct rtqk_arg { ! 235: struct radix_node_head *rnh; ! 236: int draining; ! 237: int killed; ! 238: int found; ! 239: int updating; ! 240: time_t nextstop; ! 241: }; ! 242: ! 243: /* ! 244: * Get rid of old routes. When draining, this deletes everything, even when ! 245: * the timeout is not expired yet. When updating, this makes sure that ! 246: * nothing has a timeout longer than the current value of rtq_reallyold. ! 247: */ ! 248: static int ! 249: in_rtqkill(struct radix_node *rn, void *rock) ! 250: { ! 251: struct rtqk_arg *ap = rock; ! 252: struct rtentry *rt = (struct rtentry *)rn; ! 253: int err; ! 254: ! 255: if(rt->rt_flags & RTPRF_OURS) { ! 256: ap->found++; ! 257: ! 258: if(ap->draining || rt->rt_rmx.rmx_expire <= time_second) { ! 259: if(rt->rt_refcnt > 0) ! 260: panic("rtqkill route really not free"); ! 261: ! 262: err = rtrequest(RTM_DELETE, ! 263: (struct sockaddr *)rt_key(rt), ! 264: rt->rt_gateway, rt_mask(rt), ! 265: rt->rt_flags, 0); ! 266: if(err) { ! 267: log(LOG_WARNING, "in_rtqkill: error %d\n", err); ! 268: } else { ! 269: ap->killed++; ! 270: } ! 271: } else { ! 272: if(ap->updating ! 273: && (rt->rt_rmx.rmx_expire - time_second ! 274: > rtq_reallyold)) { ! 275: rt->rt_rmx.rmx_expire = time_second ! 276: + rtq_reallyold; ! 277: } ! 278: ap->nextstop = lmin(ap->nextstop, ! 279: rt->rt_rmx.rmx_expire); ! 280: } ! 281: } ! 282: ! 283: return 0; ! 284: } ! 285: ! 286: #define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ ! 287: static int rtq_timeout = RTQ_TIMEOUT; ! 288: ! 289: static void ! 290: in_rtqtimo(void *rock) ! 291: { ! 292: struct radix_node_head *rnh = rock; ! 293: struct rtqk_arg arg; ! 294: struct timeval atv; ! 295: static time_t last_adjusted_timeout = 0; ! 296: int s; ! 297: ! 298: arg.found = arg.killed = 0; ! 299: arg.rnh = rnh; ! 300: arg.nextstop = time_second + rtq_timeout; ! 301: arg.draining = arg.updating = 0; ! 302: s = splnet(); ! 303: rnh->rnh_walktree(rnh, in_rtqkill, &arg); ! 304: splx(s); ! 305: ! 306: /* ! 307: * Attempt to be somewhat dynamic about this: ! 308: * If there are ``too many'' routes sitting around taking up space, ! 309: * then crank down the timeout, and see if we can't make some more ! 310: * go away. However, we make sure that we will never adjust more ! 311: * than once in rtq_timeout seconds, to keep from cranking down too ! 312: * hard. ! 313: */ ! 314: if((arg.found - arg.killed > rtq_toomany) ! 315: && (time_second - last_adjusted_timeout >= rtq_timeout) ! 316: && rtq_reallyold > rtq_minreallyold) { ! 317: rtq_reallyold = 2*rtq_reallyold / 3; ! 318: if(rtq_reallyold < rtq_minreallyold) { ! 319: rtq_reallyold = rtq_minreallyold; ! 320: } ! 321: ! 322: last_adjusted_timeout = time_second; ! 323: #if DIAGNOSTIC ! 324: log(LOG_DEBUG, "in_rtqtimo: adjusted rtq_reallyold to %d\n", ! 325: rtq_reallyold); ! 326: #endif ! 327: arg.found = arg.killed = 0; ! 328: arg.updating = 1; ! 329: s = splnet(); ! 330: rnh->rnh_walktree(rnh, in_rtqkill, &arg); ! 331: splx(s); ! 332: } ! 333: ! 334: atv.tv_usec = 0; ! 335: atv.tv_sec = arg.nextstop - time_second; ! 336: timeout(in_rtqtimo, rock, tvtohz(&atv)); ! 337: } ! 338: ! 339: void ! 340: in_rtqdrain(void) ! 341: { ! 342: struct radix_node_head *rnh = rt_tables[AF_INET]; ! 343: struct rtqk_arg arg; ! 344: int s; ! 345: arg.found = arg.killed = 0; ! 346: arg.rnh = rnh; ! 347: arg.nextstop = 0; ! 348: arg.draining = 1; ! 349: arg.updating = 0; ! 350: s = splnet(); ! 351: rnh->rnh_walktree(rnh, in_rtqkill, &arg); ! 352: splx(s); ! 353: } ! 354: ! 355: /* ! 356: * Initialize our routing tree. ! 357: */ ! 358: int ! 359: in_inithead(void **head, int off) ! 360: { ! 361: struct radix_node_head *rnh; ! 362: ! 363: if (*head) ! 364: return 1; ! 365: ! 366: if(!rn_inithead(head, off)) ! 367: return 0; ! 368: ! 369: if(head != (void **)&rt_tables[AF_INET]) /* BOGUS! */ ! 370: return 1; /* only do this for the real routing table */ ! 371: ! 372: rnh = *head; ! 373: rnh->rnh_addaddr = in_addroute; ! 374: rnh->rnh_matchaddr = in_matroute; ! 375: rnh->rnh_close = in_clsroute; ! 376: in_rtqtimo(rnh); /* kick off timeout first time */ ! 377: return 1; ! 378: } ! 379: ! 380: ! 381: /* ! 382: * This zaps old routes when the interface goes down. ! 383: * Currently it doesn't delete static routes; there are ! 384: * arguments one could make for both behaviors. For the moment, ! 385: * we will adopt the Principle of Least Surprise and leave them ! 386: * alone (with the knowledge that this will not be enough for some ! 387: * people). The ones we really want to get rid of are things like ARP ! 388: * entries, since the user might down the interface, walk over to a completely ! 389: * different network, and plug back in. ! 390: */ ! 391: struct in_ifadown_arg { ! 392: struct radix_node_head *rnh; ! 393: struct ifaddr *ifa; ! 394: }; ! 395: ! 396: static int ! 397: in_ifadownkill(struct radix_node *rn, void *xap) ! 398: { ! 399: struct in_ifadown_arg *ap = xap; ! 400: struct rtentry *rt = (struct rtentry *)rn; ! 401: int err; ! 402: ! 403: if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) { ! 404: /* ! 405: * We need to disable the automatic prune that happens ! 406: * in this case in rtrequest() because it will blow ! 407: * away the pointers that rn_walktree() needs in order ! 408: * continue our descent. We will end up deleting all ! 409: * the routes that rtrequest() would have in any case, ! 410: * so that behavior is not needed there. ! 411: */ ! 412: rt->rt_flags &= ~RTF_PRCLONING; ! 413: err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), ! 414: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); ! 415: if (err) { ! 416: log(LOG_WARNING, "in_ifadownkill: error %d\n", err); ! 417: } ! 418: } ! 419: return 0; ! 420: } ! 421: ! 422: int ! 423: in_ifadown(struct ifaddr *ifa) ! 424: { ! 425: struct in_ifadown_arg arg; ! 426: struct radix_node_head *rnh; ! 427: ! 428: if (ifa->ifa_addr->sa_family != AF_INET) ! 429: return 1; ! 430: ! 431: arg.rnh = rnh = rt_tables[AF_INET]; ! 432: arg.ifa = ifa; ! 433: rnh->rnh_walktree(rnh, in_ifadownkill, &arg); ! 434: ifa->ifa_flags &= ~IFA_ROUTE; ! 435: return 0; ! 436: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.