Annotation of src/sys/net/route.c, Revision 1.164
1.164 ! ozaki-r 1: /* $NetBSD: route.c,v 1.163 2016/04/25 14:30:42 ozaki-r Exp $ */
1.18 kml 2:
3: /*-
1.106 ad 4: * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
1.18 kml 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
9: * NASA Ames Research Center.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
1.11 cgd 32:
1.1 cgd 33: /*
1.25 itojun 34: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
35: * All rights reserved.
1.65 perry 36: *
1.25 itojun 37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
45: * 3. Neither the name of the project nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
1.65 perry 48: *
1.25 itojun 49: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: */
61:
62: /*
1.10 mycroft 63: * Copyright (c) 1980, 1986, 1991, 1993
64: * The Regents of the University of California. All rights reserved.
1.1 cgd 65: *
66: * Redistribution and use in source and binary forms, with or without
67: * modification, are permitted provided that the following conditions
68: * are met:
69: * 1. Redistributions of source code must retain the above copyright
70: * notice, this list of conditions and the following disclaimer.
71: * 2. Redistributions in binary form must reproduce the above copyright
72: * notice, this list of conditions and the following disclaimer in the
73: * documentation and/or other materials provided with the distribution.
1.58 agc 74: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 75: * may be used to endorse or promote products derived from this software
76: * without specific prior written permission.
77: *
78: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88: * SUCH DAMAGE.
89: *
1.17 christos 90: * @(#)route.c 8.3 (Berkeley) 1/9/95
1.1 cgd 91: */
1.50 lukem 92:
1.149 pooka 93: #ifdef _KERNEL_OPT
1.136 roy 94: #include "opt_inet.h"
1.90 dyoung 95: #include "opt_route.h"
1.149 pooka 96: #endif
1.90 dyoung 97:
1.50 lukem 98: #include <sys/cdefs.h>
1.164 ! ozaki-r 99: __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.163 2016/04/25 14:30:42 ozaki-r Exp $");
1.2 cgd 100:
1.5 mycroft 101: #include <sys/param.h>
1.140 ozaki-r 102: #ifdef RTFLUSH_DEBUG
1.90 dyoung 103: #include <sys/sysctl.h>
1.140 ozaki-r 104: #endif
1.5 mycroft 105: #include <sys/systm.h>
1.35 thorpej 106: #include <sys/callout.h>
1.5 mycroft 107: #include <sys/proc.h>
108: #include <sys/mbuf.h>
109: #include <sys/socket.h>
110: #include <sys/socketvar.h>
111: #include <sys/domain.h>
112: #include <sys/protosw.h>
1.18 kml 113: #include <sys/kernel.h>
1.5 mycroft 114: #include <sys/ioctl.h>
1.22 thorpej 115: #include <sys/pool.h>
1.119 elad 116: #include <sys/kauth.h>
1.1 cgd 117:
1.5 mycroft 118: #include <net/if.h>
1.114 dyoung 119: #include <net/if_dl.h>
1.5 mycroft 120: #include <net/route.h>
1.1 cgd 121:
1.5 mycroft 122: #include <netinet/in.h>
123: #include <netinet/in_var.h>
1.1 cgd 124:
1.90 dyoung 125: #ifdef RTFLUSH_DEBUG
126: #define rtcache_debug() __predict_false(_rtcache_debug)
127: #else /* RTFLUSH_DEBUG */
128: #define rtcache_debug() 0
129: #endif /* RTFLUSH_DEBUG */
1.5 mycroft 130:
1.155 ozaki-r 131: struct rtstat rtstat;
1.1 cgd 132:
1.155 ozaki-r 133: static int rttrash; /* routes not in table but not freed */
1.1 cgd 134:
1.155 ozaki-r 135: static struct pool rtentry_pool;
136: static struct pool rttimer_pool;
1.22 thorpej 137:
1.155 ozaki-r 138: static struct callout rt_timer_ch; /* callout for rt_timer_timer() */
1.35 thorpej 139:
1.90 dyoung 140: #ifdef RTFLUSH_DEBUG
141: static int _rtcache_debug = 0;
142: #endif /* RTFLUSH_DEBUG */
143:
1.119 elad 144: static kauth_listener_t route_listener;
145:
1.60 matt 146: static int rtdeletemsg(struct rtentry *);
1.144 ozaki-r 147: static void rtflushall(int);
1.40 itojun 148:
1.141 ozaki-r 149: static void rt_maskedcopy(const struct sockaddr *,
150: struct sockaddr *, const struct sockaddr *);
151:
1.144 ozaki-r 152: static void rtcache_clear(struct route *);
153: static void rtcache_invalidate(struct dom_rtlist *);
154:
1.162 ozaki-r 155: #ifdef DDB
156: static void db_print_sa(const struct sockaddr *);
157: static void db_print_ifa(struct ifaddr *);
158: static int db_show_rtentry(struct rtentry *, void *);
159: #endif
160:
1.90 dyoung 161: #ifdef RTFLUSH_DEBUG
1.118 pooka 162: static void sysctl_net_rtcache_setup(struct sysctllog **);
163: static void
164: sysctl_net_rtcache_setup(struct sysctllog **clog)
1.90 dyoung 165: {
166: const struct sysctlnode *rnode;
167:
168: if (sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT,
169: CTLTYPE_NODE,
170: "rtcache", SYSCTL_DESCR("Route cache related settings"),
1.128 pooka 171: NULL, 0, NULL, 0, CTL_NET, CTL_CREATE, CTL_EOL) != 0)
1.90 dyoung 172: return;
173: if (sysctl_createv(clog, 0, &rnode, &rnode,
174: CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
175: "debug", SYSCTL_DESCR("Debug route caches"),
176: NULL, 0, &_rtcache_debug, 0, CTL_CREATE, CTL_EOL) != 0)
177: return;
178: }
179: #endif /* RTFLUSH_DEBUG */
180:
1.144 ozaki-r 181: static inline void
182: rt_destroy(struct rtentry *rt)
183: {
184: if (rt->_rt_key != NULL)
185: sockaddr_free(rt->_rt_key);
186: if (rt->rt_gateway != NULL)
187: sockaddr_free(rt->rt_gateway);
188: if (rt_gettag(rt) != NULL)
189: sockaddr_free(rt_gettag(rt));
190: rt->_rt_key = rt->rt_gateway = rt->rt_tag = NULL;
191: }
192:
193: static inline const struct sockaddr *
194: rt_setkey(struct rtentry *rt, const struct sockaddr *key, int flags)
195: {
196: if (rt->_rt_key == key)
197: goto out;
198:
199: if (rt->_rt_key != NULL)
200: sockaddr_free(rt->_rt_key);
201: rt->_rt_key = sockaddr_dup(key, flags);
202: out:
203: rt->rt_nodes->rn_key = (const char *)rt->_rt_key;
204: return rt->_rt_key;
205: }
206:
1.81 joerg 207: struct ifaddr *
208: rt_get_ifa(struct rtentry *rt)
209: {
210: struct ifaddr *ifa;
211:
212: if ((ifa = rt->rt_ifa) == NULL)
213: return ifa;
214: else if (ifa->ifa_getifa == NULL)
215: return ifa;
216: #if 0
217: else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno)
218: return ifa;
219: #endif
220: else {
1.94 dyoung 221: ifa = (*ifa->ifa_getifa)(ifa, rt_getkey(rt));
1.145 roy 222: if (ifa == NULL)
223: return NULL;
1.81 joerg 224: rt_replace_ifa(rt, ifa);
225: return ifa;
226: }
227: }
228:
1.80 joerg 229: static void
230: rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa)
231: {
232: rt->rt_ifa = ifa;
233: if (ifa->ifa_seqno != NULL)
234: rt->rt_ifa_seqno = *ifa->ifa_seqno;
235: }
236:
1.116 roy 237: /*
238: * Is this route the connected route for the ifa?
239: */
240: static int
241: rt_ifa_connected(const struct rtentry *rt, const struct ifaddr *ifa)
242: {
243: const struct sockaddr *key, *dst, *odst;
244: struct sockaddr_storage maskeddst;
245:
246: key = rt_getkey(rt);
247: dst = rt->rt_flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
248: if (dst == NULL ||
249: dst->sa_family != key->sa_family ||
250: dst->sa_len != key->sa_len)
251: return 0;
252: if ((rt->rt_flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
253: odst = dst;
254: dst = (struct sockaddr *)&maskeddst;
255: rt_maskedcopy(odst, (struct sockaddr *)&maskeddst,
256: ifa->ifa_netmask);
257: }
258: return (memcmp(dst, key, dst->sa_len) == 0);
259: }
260:
1.80 joerg 261: void
262: rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa)
263: {
1.116 roy 264: if (rt->rt_ifa &&
265: rt->rt_ifa != ifa &&
266: rt->rt_ifa->ifa_flags & IFA_ROUTE &&
267: rt_ifa_connected(rt, rt->rt_ifa))
268: {
269: RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
270: "replace deleted IFA_ROUTE\n",
271: (void *)rt->_rt_key, (void *)rt->rt_ifa);
272: rt->rt_ifa->ifa_flags &= ~IFA_ROUTE;
273: if (rt_ifa_connected(rt, ifa)) {
274: RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
275: "replace added IFA_ROUTE\n",
276: (void *)rt->_rt_key, (void *)ifa);
277: ifa->ifa_flags |= IFA_ROUTE;
278: }
279: }
280:
1.133 rmind 281: ifaref(ifa);
282: ifafree(rt->rt_ifa);
1.80 joerg 283: rt_set_ifa1(rt, ifa);
284: }
285:
286: static void
287: rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa)
288: {
1.133 rmind 289: ifaref(ifa);
1.80 joerg 290: rt_set_ifa1(rt, ifa);
291: }
292:
1.119 elad 293: static int
294: route_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
295: void *arg0, void *arg1, void *arg2, void *arg3)
296: {
297: struct rt_msghdr *rtm;
298: int result;
299:
300: result = KAUTH_RESULT_DEFER;
301: rtm = arg1;
302:
1.120 elad 303: if (action != KAUTH_NETWORK_ROUTE)
304: return result;
305:
1.119 elad 306: if (rtm->rtm_type == RTM_GET)
307: result = KAUTH_RESULT_ALLOW;
308:
309: return result;
310: }
311:
1.9 mycroft 312: void
1.124 matt 313: rt_init(void)
1.1 cgd 314: {
1.22 thorpej 315:
1.118 pooka 316: #ifdef RTFLUSH_DEBUG
317: sysctl_net_rtcache_setup(NULL);
318: #endif
319:
1.113 pooka 320: pool_init(&rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl",
321: NULL, IPL_SOFTNET);
322: pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",
323: NULL, IPL_SOFTNET);
324:
1.10 mycroft 325: rn_init(); /* initialize all zeroes, all ones, mask table */
1.125 dyoung 326: rtbl_init();
1.119 elad 327:
328: route_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
329: route_listener_cb, NULL);
1.1 cgd 330: }
331:
1.144 ozaki-r 332: static void
1.82 dyoung 333: rtflushall(int family)
334: {
1.90 dyoung 335: struct domain *dom;
336:
337: if (rtcache_debug())
338: printf("%s: enter\n", __func__);
339:
340: if ((dom = pffinddomain(family)) == NULL)
341: return;
1.82 dyoung 342:
1.105 dyoung 343: rtcache_invalidate(&dom->dom_rtcache);
1.82 dyoung 344: }
345:
1.131 rmind 346: static void
1.82 dyoung 347: rtcache(struct route *ro)
348: {
1.90 dyoung 349: struct domain *dom;
1.82 dyoung 350:
1.114 dyoung 351: rtcache_invariants(ro);
1.99 dyoung 352: KASSERT(ro->_ro_rt != NULL);
1.105 dyoung 353: KASSERT(ro->ro_invalid == false);
1.90 dyoung 354: KASSERT(rtcache_getdst(ro) != NULL);
1.82 dyoung 355:
1.90 dyoung 356: if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL)
357: return;
358:
359: LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next);
1.114 dyoung 360: rtcache_invariants(ro);
1.82 dyoung 361: }
362:
1.158 ozaki-r 363: #ifdef RT_DEBUG
364: static void
365: dump_rt(const struct rtentry *rt)
366: {
367: char buf[512];
368:
369: aprint_normal("rt: ");
370: aprint_normal("p=%p ", rt);
371: if (rt->_rt_key == NULL) {
372: aprint_normal("dst=(NULL) ");
373: } else {
374: sockaddr_format(rt->_rt_key, buf, sizeof(buf));
375: aprint_normal("dst=%s ", buf);
376: }
377: if (rt->rt_gateway == NULL) {
378: aprint_normal("gw=(NULL) ");
379: } else {
380: sockaddr_format(rt->_rt_key, buf, sizeof(buf));
381: aprint_normal("gw=%s ", buf);
382: }
383: aprint_normal("flags=%x ", rt->rt_flags);
384: if (rt->rt_ifp == NULL) {
385: aprint_normal("if=(NULL) ");
386: } else {
387: aprint_normal("if=%s ", rt->rt_ifp->if_xname);
388: }
389: aprint_normal("\n");
390: }
391: #endif /* RT_DEBUG */
392:
1.1 cgd 393: /*
1.146 ozaki-r 394: * Packet routing routines. If success, refcnt of a returned rtentry
395: * will be incremented. The caller has to rtfree it by itself.
1.1 cgd 396: */
397: struct rtentry *
1.60 matt 398: rtalloc1(const struct sockaddr *dst, int report)
1.1 cgd 399: {
1.158 ozaki-r 400: rtbl_t *rtbl;
1.36 augustss 401: struct rtentry *rt;
1.159 christos 402: int s;
1.1 cgd 403:
1.159 christos 404: s = splsoftnet();
1.158 ozaki-r 405: rtbl = rt_gettable(dst->sa_family);
1.159 christos 406: if (rtbl == NULL)
1.158 ozaki-r 407: goto miss;
408:
409: rt = rt_matchaddr(rtbl, dst);
1.159 christos 410: if (rt == NULL)
1.158 ozaki-r 411: goto miss;
1.159 christos 412:
1.158 ozaki-r 413: rt->rt_refcnt++;
414:
1.159 christos 415: splx(s);
416: return rt;
1.158 ozaki-r 417: miss:
1.159 christos 418: rtstat.rts_unreach++;
1.158 ozaki-r 419: if (report) {
1.159 christos 420: struct rt_addrinfo info;
421:
1.160 christos 422: memset(&info, 0, sizeof(info));
1.158 ozaki-r 423: info.rti_info[RTAX_DST] = dst;
1.159 christos 424: rt_missmsg(RTM_MISS, &info, 0, 0);
1.1 cgd 425: }
426: splx(s);
1.159 christos 427: return NULL;
1.1 cgd 428: }
429:
1.151 ozaki-r 430: #ifdef DEBUG
431: /*
432: * Check the following constraint for each rtcache:
433: * if a rtcache holds a rtentry, the rtentry's refcnt is more than zero,
434: * i.e., the rtentry should be referenced at least by the rtcache.
435: */
436: static void
437: rtcache_check_rtrefcnt(int family)
438: {
439: struct domain *dom = pffinddomain(family);
440: struct route *ro;
441:
442: if (dom == NULL)
443: return;
444:
445: LIST_FOREACH(ro, &dom->dom_rtcache, ro_rtcache_next)
446: KDASSERT(ro->_ro_rt == NULL || ro->_ro_rt->rt_refcnt > 0);
447: }
448: #endif
449:
1.9 mycroft 450: void
1.60 matt 451: rtfree(struct rtentry *rt)
1.1 cgd 452: {
1.36 augustss 453: struct ifaddr *ifa;
1.10 mycroft 454:
1.132 rmind 455: KASSERT(rt != NULL);
456: KASSERT(rt->rt_refcnt > 0);
457:
1.1 cgd 458: rt->rt_refcnt--;
1.151 ozaki-r 459: #ifdef DEBUG
460: if (rt_getkey(rt) != NULL)
461: rtcache_check_rtrefcnt(rt_getkey(rt)->sa_family);
462: #endif
1.132 rmind 463: if (rt->rt_refcnt == 0 && (rt->rt_flags & RTF_UP) == 0) {
1.125 dyoung 464: rt_assert_inactive(rt);
1.10 mycroft 465: rttrash--;
1.54 itojun 466: rt_timer_remove_all(rt, 0);
1.10 mycroft 467: ifa = rt->rt_ifa;
1.78 dyoung 468: rt->rt_ifa = NULL;
1.133 rmind 469: ifafree(ifa);
1.78 dyoung 470: rt->rt_ifp = NULL;
1.94 dyoung 471: rt_destroy(rt);
1.22 thorpej 472: pool_put(&rtentry_pool, rt);
1.1 cgd 473: }
474: }
475:
476: /*
477: * Force a routing table entry to the specified
478: * destination to go through the given gateway.
479: * Normally called as a result of a routing redirect
480: * message from the network layer.
481: *
1.13 mycroft 482: * N.B.: must be called at splsoftnet
1.1 cgd 483: */
1.14 christos 484: void
1.60 matt 485: rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
486: const struct sockaddr *netmask, int flags, const struct sockaddr *src,
487: struct rtentry **rtp)
1.1 cgd 488: {
1.36 augustss 489: struct rtentry *rt;
1.1 cgd 490: int error = 0;
1.121 dyoung 491: uint64_t *stat = NULL;
1.10 mycroft 492: struct rt_addrinfo info;
493: struct ifaddr *ifa;
1.1 cgd 494:
495: /* verify the gateway is directly reachable */
1.68 christos 496: if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
1.1 cgd 497: error = ENETUNREACH;
1.8 cgd 498: goto out;
1.1 cgd 499: }
500: rt = rtalloc1(dst, 0);
501: /*
502: * If the redirect isn't from our current router for this dst,
503: * it's either old or wrong. If it redirects us to ourselves,
504: * we have a routing loop, perhaps as a result of an interface
505: * going down recently.
506: */
1.10 mycroft 507: if (!(flags & RTF_DONE) && rt &&
1.115 yamt 508: (sockaddr_cmp(src, rt->rt_gateway) != 0 || rt->rt_ifa != ifa))
1.1 cgd 509: error = EINVAL;
510: else if (ifa_ifwithaddr(gateway))
511: error = EHOSTUNREACH;
512: if (error)
513: goto done;
514: /*
515: * Create a new entry if we just got back a wildcard entry
1.33 soren 516: * or the lookup failed. This is necessary for hosts
1.1 cgd 517: * which use routing redirects generated by smart gateways
518: * to dynamically build the routing tables.
519: */
1.95 dyoung 520: if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
1.1 cgd 521: goto create;
522: /*
523: * Don't listen to the redirect if it's
1.65 perry 524: * for a route to an interface.
1.1 cgd 525: */
526: if (rt->rt_flags & RTF_GATEWAY) {
527: if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
528: /*
529: * Changing from route to net => route to host.
530: * Create new route, rather than smashing route to net.
531: */
532: create:
1.95 dyoung 533: if (rt != NULL)
1.39 itojun 534: rtfree(rt);
1.1 cgd 535: flags |= RTF_GATEWAY | RTF_DYNAMIC;
1.122 kefren 536: memset(&info, 0, sizeof(info));
1.39 itojun 537: info.rti_info[RTAX_DST] = dst;
538: info.rti_info[RTAX_GATEWAY] = gateway;
539: info.rti_info[RTAX_NETMASK] = netmask;
540: info.rti_ifa = ifa;
541: info.rti_flags = flags;
542: rt = NULL;
543: error = rtrequest1(RTM_ADD, &info, &rt);
544: if (rt != NULL)
545: flags = rt->rt_flags;
1.1 cgd 546: stat = &rtstat.rts_dynamic;
547: } else {
548: /*
549: * Smash the current notion of the gateway to
550: * this destination. Should check about netmask!!!
551: */
1.164 ! ozaki-r 552: error = rt_setgate(rt, gateway);
! 553: if (error == 0) {
! 554: rt->rt_flags |= RTF_MODIFIED;
! 555: flags |= RTF_MODIFIED;
! 556: }
1.10 mycroft 557: stat = &rtstat.rts_newgateway;
1.1 cgd 558: }
559: } else
560: error = EHOSTUNREACH;
561: done:
562: if (rt) {
1.95 dyoung 563: if (rtp != NULL && !error)
1.1 cgd 564: *rtp = rt;
565: else
566: rtfree(rt);
567: }
1.8 cgd 568: out:
1.1 cgd 569: if (error)
570: rtstat.rts_badredirect++;
1.8 cgd 571: else if (stat != NULL)
572: (*stat)++;
1.95 dyoung 573: memset(&info, 0, sizeof(info));
1.10 mycroft 574: info.rti_info[RTAX_DST] = dst;
575: info.rti_info[RTAX_GATEWAY] = gateway;
576: info.rti_info[RTAX_NETMASK] = netmask;
577: info.rti_info[RTAX_AUTHOR] = src;
578: rt_missmsg(RTM_REDIRECT, &info, flags, error);
1.1 cgd 579: }
580:
581: /*
1.146 ozaki-r 582: * Delete a route and generate a message.
583: * It doesn't free a passed rt.
1.40 itojun 584: */
585: static int
1.60 matt 586: rtdeletemsg(struct rtentry *rt)
1.40 itojun 587: {
588: int error;
589: struct rt_addrinfo info;
590:
591: /*
592: * Request the new route so that the entry is not actually
593: * deleted. That will allow the information being reported to
594: * be accurate (and consistent with route_output()).
595: */
1.95 dyoung 596: memset(&info, 0, sizeof(info));
1.94 dyoung 597: info.rti_info[RTAX_DST] = rt_getkey(rt);
1.40 itojun 598: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
599: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
600: info.rti_flags = rt->rt_flags;
1.157 ozaki-r 601: error = rtrequest1(RTM_DELETE, &info, NULL);
1.40 itojun 602:
603: rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
604:
1.95 dyoung 605: return error;
1.40 itojun 606: }
607:
1.1 cgd 608: struct ifaddr *
1.60 matt 609: ifa_ifwithroute(int flags, const struct sockaddr *dst,
610: const struct sockaddr *gateway)
1.1 cgd 611: {
1.36 augustss 612: struct ifaddr *ifa;
1.1 cgd 613: if ((flags & RTF_GATEWAY) == 0) {
614: /*
615: * If we are adding a route to an interface,
616: * and the interface is a pt to pt link
617: * we should search for the destination
618: * as our clue to the interface. Otherwise
619: * we can use the local address.
620: */
1.68 christos 621: ifa = NULL;
1.127 christos 622: if ((flags & RTF_HOST) && gateway->sa_family != AF_LINK)
1.1 cgd 623: ifa = ifa_ifwithdstaddr(dst);
1.68 christos 624: if (ifa == NULL)
1.1 cgd 625: ifa = ifa_ifwithaddr(gateway);
626: } else {
627: /*
628: * If we are adding a route to a remote net
629: * or host, the gateway may still be on the
630: * other end of a pt to pt link.
631: */
632: ifa = ifa_ifwithdstaddr(gateway);
633: }
1.68 christos 634: if (ifa == NULL)
1.1 cgd 635: ifa = ifa_ifwithnet(gateway);
1.68 christos 636: if (ifa == NULL) {
1.1 cgd 637: struct rtentry *rt = rtalloc1(dst, 0);
1.68 christos 638: if (rt == NULL)
639: return NULL;
1.146 ozaki-r 640: ifa = rt->rt_ifa;
641: rtfree(rt);
642: if (ifa == NULL)
1.68 christos 643: return NULL;
1.1 cgd 644: }
645: if (ifa->ifa_addr->sa_family != dst->sa_family) {
1.10 mycroft 646: struct ifaddr *oifa = ifa;
1.1 cgd 647: ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
1.127 christos 648: if (ifa == NULL)
1.1 cgd 649: ifa = oifa;
650: }
1.95 dyoung 651: return ifa;
1.1 cgd 652: }
653:
1.146 ozaki-r 654: /*
655: * If it suceeds and ret_nrt isn't NULL, refcnt of ret_nrt is incremented.
656: * The caller has to rtfree it by itself.
657: */
1.9 mycroft 658: int
1.60 matt 659: rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway,
660: const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
1.1 cgd 661: {
1.39 itojun 662: struct rt_addrinfo info;
663:
1.44 thorpej 664: memset(&info, 0, sizeof(info));
1.39 itojun 665: info.rti_flags = flags;
666: info.rti_info[RTAX_DST] = dst;
667: info.rti_info[RTAX_GATEWAY] = gateway;
668: info.rti_info[RTAX_NETMASK] = netmask;
669: return rtrequest1(req, &info, ret_nrt);
670: }
671:
1.146 ozaki-r 672: /*
673: * It's a utility function to add/remove a route to/from the routing table
674: * and tell user processes the addition/removal on success.
675: */
676: int
677: rtrequest_newmsg(const int req, const struct sockaddr *dst,
678: const struct sockaddr *gateway, const struct sockaddr *netmask,
679: const int flags)
680: {
681: int error;
682: struct rtentry *ret_nrt = NULL;
683:
684: KASSERT(req == RTM_ADD || req == RTM_DELETE);
685:
686: error = rtrequest(req, dst, gateway, netmask, flags, &ret_nrt);
687: if (error != 0)
688: return error;
689:
690: KASSERT(ret_nrt != NULL);
691:
692: rt_newmsg(req, ret_nrt); /* tell user process */
693: rtfree(ret_nrt);
694:
695: return 0;
696: }
697:
1.39 itojun 698: int
1.60 matt 699: rt_getifa(struct rt_addrinfo *info)
1.39 itojun 700: {
701: struct ifaddr *ifa;
1.68 christos 702: const struct sockaddr *dst = info->rti_info[RTAX_DST];
703: const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
704: const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
705: const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
706: int flags = info->rti_flags;
1.39 itojun 707:
708: /*
709: * ifp may be specified by sockaddr_dl when protocol address
710: * is ambiguous
711: */
712: if (info->rti_ifp == NULL && ifpaddr != NULL
713: && ifpaddr->sa_family == AF_LINK &&
1.101 dyoung 714: (ifa = ifa_ifwithnet(ifpaddr)) != NULL)
1.39 itojun 715: info->rti_ifp = ifa->ifa_ifp;
716: if (info->rti_ifa == NULL && ifaaddr != NULL)
717: info->rti_ifa = ifa_ifwithaddr(ifaaddr);
718: if (info->rti_ifa == NULL) {
1.59 matt 719: const struct sockaddr *sa;
1.39 itojun 720:
721: sa = ifaaddr != NULL ? ifaaddr :
722: (gateway != NULL ? gateway : dst);
723: if (sa != NULL && info->rti_ifp != NULL)
724: info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
725: else if (dst != NULL && gateway != NULL)
726: info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
727: else if (sa != NULL)
728: info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
729: }
1.74 dyoung 730: if ((ifa = info->rti_ifa) == NULL)
731: return ENETUNREACH;
1.145 roy 732: if (ifa->ifa_getifa != NULL) {
1.74 dyoung 733: info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
1.145 roy 734: if (ifa == NULL)
735: return ENETUNREACH;
736: }
1.74 dyoung 737: if (info->rti_ifp == NULL)
738: info->rti_ifp = ifa->ifa_ifp;
739: return 0;
1.39 itojun 740: }
741:
1.146 ozaki-r 742: /*
743: * If it suceeds and ret_nrt isn't NULL, refcnt of ret_nrt is incremented.
744: * The caller has to rtfree it by itself.
745: */
1.39 itojun 746: int
1.60 matt 747: rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
1.39 itojun 748: {
1.60 matt 749: int s = splsoftnet();
1.125 dyoung 750: int error = 0, rc;
1.158 ozaki-r 751: struct rtentry *rt;
1.125 dyoung 752: rtbl_t *rtbl;
1.122 kefren 753: struct ifaddr *ifa, *ifa2;
1.94 dyoung 754: struct sockaddr_storage maskeddst;
1.68 christos 755: const struct sockaddr *dst = info->rti_info[RTAX_DST];
756: const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
757: const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
758: int flags = info->rti_flags;
1.1 cgd 759: #define senderr(x) { error = x ; goto bad; }
760:
1.125 dyoung 761: if ((rtbl = rt_gettable(dst->sa_family)) == NULL)
1.1 cgd 762: senderr(ESRCH);
763: if (flags & RTF_HOST)
1.68 christos 764: netmask = NULL;
1.1 cgd 765: switch (req) {
766: case RTM_DELETE:
1.63 christos 767: if (netmask) {
1.94 dyoung 768: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
769: netmask);
770: dst = (struct sockaddr *)&maskeddst;
1.63 christos 771: }
1.125 dyoung 772: if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.41 itojun 773: senderr(ESRCH);
1.125 dyoung 774: if ((rt = rt_deladdr(rtbl, dst, netmask)) == NULL)
1.1 cgd 775: senderr(ESRCH);
1.10 mycroft 776: if (rt->rt_gwroute) {
1.131 rmind 777: rtfree(rt->rt_gwroute);
1.68 christos 778: rt->rt_gwroute = NULL;
1.48 itojun 779: }
1.28 erh 780: rt->rt_flags &= ~RTF_UP;
1.116 roy 781: if ((ifa = rt->rt_ifa)) {
782: if (ifa->ifa_flags & IFA_ROUTE &&
783: rt_ifa_connected(rt, ifa)) {
784: RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
785: "deleted IFA_ROUTE\n",
786: (void *)rt->_rt_key, (void *)ifa);
787: ifa->ifa_flags &= ~IFA_ROUTE;
788: }
789: if (ifa->ifa_rtrequest)
790: ifa->ifa_rtrequest(RTM_DELETE, rt, info);
791: }
1.1 cgd 792: rttrash++;
1.146 ozaki-r 793: if (ret_nrt) {
1.10 mycroft 794: *ret_nrt = rt;
1.146 ozaki-r 795: rt->rt_refcnt++;
796: } else if (rt->rt_refcnt <= 0) {
797: /* Adjust the refcount */
1.10 mycroft 798: rt->rt_refcnt++;
1.1 cgd 799: rtfree(rt);
1.10 mycroft 800: }
1.1 cgd 801: break;
802:
803: case RTM_ADD:
1.68 christos 804: if (info->rti_ifa == NULL && (error = rt_getifa(info)))
1.39 itojun 805: senderr(error);
806: ifa = info->rti_ifa;
1.22 thorpej 807: rt = pool_get(&rtentry_pool, PR_NOWAIT);
1.68 christos 808: if (rt == NULL)
1.1 cgd 809: senderr(ENOBUFS);
1.109 dyoung 810: memset(rt, 0, sizeof(*rt));
1.10 mycroft 811: rt->rt_flags = RTF_UP | flags;
1.18 kml 812: LIST_INIT(&rt->rt_timer);
1.163 ozaki-r 813:
1.110 dyoung 814: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 815: if (netmask) {
1.94 dyoung 816: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
817: netmask);
1.96 dyoung 818: rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT);
1.94 dyoung 819: } else {
1.96 dyoung 820: rt_setkey(rt, dst, M_NOWAIT);
1.94 dyoung 821: }
1.163 ozaki-r 822: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
823: if (rt_getkey(rt) == NULL ||
824: rt_setgate(rt, gateway) != 0) {
825: pool_put(&rtentry_pool, rt);
826: senderr(ENOBUFS);
827: }
828:
1.74 dyoung 829: rt_set_ifa(rt, ifa);
1.164 ! ozaki-r 830: if (info->rti_info[RTAX_TAG] != NULL) {
! 831: const struct sockaddr *tag;
! 832: tag = rt_settag(rt, info->rti_info[RTAX_TAG]);
! 833: if (tag == NULL)
! 834: senderr(ENOBUFS);
! 835: }
1.110 dyoung 836: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.122 kefren 837: if (info->rti_info[RTAX_IFP] != NULL &&
838: (ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP])) != NULL &&
839: ifa2->ifa_ifp != NULL)
840: rt->rt_ifp = ifa2->ifa_ifp;
841: else
842: rt->rt_ifp = ifa->ifa_ifp;
1.110 dyoung 843: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125 dyoung 844: rc = rt_addaddr(rtbl, rt, netmask);
1.110 dyoung 845: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125 dyoung 846: if (rc != 0) {
1.133 rmind 847: ifafree(ifa);
1.40 itojun 848: if (rt->rt_gwroute)
849: rtfree(rt->rt_gwroute);
1.94 dyoung 850: rt_destroy(rt);
1.40 itojun 851: pool_put(&rtentry_pool, rt);
1.125 dyoung 852: senderr(rc);
1.27 matt 853: }
1.110 dyoung 854: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 855: if (ifa->ifa_rtrequest)
1.39 itojun 856: ifa->ifa_rtrequest(req, rt, info);
1.110 dyoung 857: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 858: if (ret_nrt) {
859: *ret_nrt = rt;
860: rt->rt_refcnt++;
1.41 itojun 861: }
1.82 dyoung 862: rtflushall(dst->sa_family);
1.1 cgd 863: break;
1.92 dyoung 864: case RTM_GET:
1.94 dyoung 865: if (netmask != NULL) {
866: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
867: netmask);
868: dst = (struct sockaddr *)&maskeddst;
869: }
1.125 dyoung 870: if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.92 dyoung 871: senderr(ESRCH);
872: if (ret_nrt != NULL) {
873: *ret_nrt = rt;
874: rt->rt_refcnt++;
875: }
876: break;
1.1 cgd 877: }
878: bad:
879: splx(s);
1.95 dyoung 880: return error;
1.1 cgd 881: }
882:
1.10 mycroft 883: int
1.94 dyoung 884: rt_setgate(struct rtentry *rt, const struct sockaddr *gate)
1.10 mycroft 885: {
1.94 dyoung 886: KASSERT(rt != rt->rt_gwroute);
887:
888: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 889: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 890:
1.10 mycroft 891: if (rt->rt_gwroute) {
1.131 rmind 892: rtfree(rt->rt_gwroute);
1.68 christos 893: rt->rt_gwroute = NULL;
1.10 mycroft 894: }
1.94 dyoung 895: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 896: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 897: if (rt->rt_gateway != NULL)
898: sockaddr_free(rt->rt_gateway);
899: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 900: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.134 christos 901: if ((rt->rt_gateway = sockaddr_dup(gate, M_ZERO | M_NOWAIT)) == NULL)
1.94 dyoung 902: return ENOMEM;
903: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 904: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 905:
1.10 mycroft 906: if (rt->rt_flags & RTF_GATEWAY) {
1.94 dyoung 907: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 908: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10 mycroft 909: rt->rt_gwroute = rtalloc1(gate, 1);
1.27 matt 910: /*
911: * If we switched gateways, grab the MTU from the new
1.47 itojun 912: * gateway route if the current MTU, if the current MTU is
913: * greater than the MTU of gateway.
914: * Note that, if the MTU of gateway is 0, we will reset the
915: * MTU of the route to run PMTUD again from scratch. XXX
1.27 matt 916: */
1.94 dyoung 917: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 918: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.27 matt 919: if (rt->rt_gwroute
920: && !(rt->rt_rmx.rmx_locks & RTV_MTU)
1.47 itojun 921: && rt->rt_rmx.rmx_mtu
922: && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
1.27 matt 923: rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
924: }
1.10 mycroft 925: }
1.94 dyoung 926: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 927: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10 mycroft 928: return 0;
929: }
930:
1.141 ozaki-r 931: static void
1.60 matt 932: rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
933: const struct sockaddr *netmask)
1.1 cgd 934: {
1.94 dyoung 935: const char *netmaskp = &netmask->sa_data[0],
936: *srcp = &src->sa_data[0];
937: char *dstp = &dst->sa_data[0];
1.126 christos 938: const char *maskend = (char *)dst + MIN(netmask->sa_len, src->sa_len);
939: const char *srcend = (char *)dst + src->sa_len;
1.94 dyoung 940:
941: dst->sa_len = src->sa_len;
942: dst->sa_family = src->sa_family;
943:
944: while (dstp < maskend)
945: *dstp++ = *srcp++ & *netmaskp++;
946: if (dstp < srcend)
947: memset(dstp, 0, (size_t)(srcend - dstp));
1.1 cgd 948: }
1.10 mycroft 949:
1.1 cgd 950: /*
1.135 roy 951: * Inform the routing socket of a route change.
952: */
953: void
1.154 ozaki-r 954: rt_newmsg(const int cmd, const struct rtentry *rt)
1.135 roy 955: {
956: struct rt_addrinfo info;
957:
958: memset((void *)&info, 0, sizeof(info));
959: info.rti_info[RTAX_DST] = rt_getkey(rt);
960: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
961: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
962: if (rt->rt_ifp) {
963: info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr;
964: info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
965: }
966:
967: rt_missmsg(cmd, &info, rt->rt_flags, 0);
968: }
969:
970: /*
1.29 sommerfe 971: * Set up or tear down a routing table entry, normally
1.1 cgd 972: * for an interface.
973: */
1.9 mycroft 974: int
1.60 matt 975: rtinit(struct ifaddr *ifa, int cmd, int flags)
1.1 cgd 976: {
1.36 augustss 977: struct rtentry *rt;
978: struct sockaddr *dst, *odst;
1.94 dyoung 979: struct sockaddr_storage maskeddst;
1.68 christos 980: struct rtentry *nrt = NULL;
1.1 cgd 981: int error;
1.39 itojun 982: struct rt_addrinfo info;
1.1 cgd 983:
984: dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
985: if (cmd == RTM_DELETE) {
986: if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1.29 sommerfe 987: /* Delete subnet route for this interface */
988: odst = dst;
1.94 dyoung 989: dst = (struct sockaddr *)&maskeddst;
1.29 sommerfe 990: rt_maskedcopy(odst, dst, ifa->ifa_netmask);
1.1 cgd 991: }
1.14 christos 992: if ((rt = rtalloc1(dst, 0)) != NULL) {
1.146 ozaki-r 993: if (rt->rt_ifa != ifa) {
994: rtfree(rt);
1.85 dyoung 995: return (flags & RTF_HOST) ? EHOSTUNREACH
996: : ENETUNREACH;
1.146 ozaki-r 997: }
998: rtfree(rt);
1.1 cgd 999: }
1000: }
1.44 thorpej 1001: memset(&info, 0, sizeof(info));
1.39 itojun 1002: info.rti_ifa = ifa;
1003: info.rti_flags = flags | ifa->ifa_flags;
1004: info.rti_info[RTAX_DST] = dst;
1005: info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
1.158 ozaki-r 1006:
1.39 itojun 1007: /*
1008: * XXX here, it seems that we are assuming that ifa_netmask is NULL
1009: * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate
1010: * variable) when RTF_HOST is 1. still not sure if i can safely
1011: * change it to meet bsdi4 behavior.
1012: */
1.114 dyoung 1013: if (cmd != RTM_LLINFO_UPD)
1014: info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1015: error = rtrequest1((cmd == RTM_LLINFO_UPD) ? RTM_GET : cmd, &info,
1016: &nrt);
1.153 ozaki-r 1017: if (error != 0)
1.146 ozaki-r 1018: return error;
1019:
1.153 ozaki-r 1020: rt = nrt;
1.146 ozaki-r 1021: switch (cmd) {
1.114 dyoung 1022: case RTM_DELETE:
1.146 ozaki-r 1023: rt_newmsg(cmd, rt);
1.114 dyoung 1024: break;
1025: case RTM_LLINFO_UPD:
1026: if (cmd == RTM_LLINFO_UPD && ifa->ifa_rtrequest != NULL)
1027: ifa->ifa_rtrequest(RTM_LLINFO_UPD, rt, &info);
1.146 ozaki-r 1028: rt_newmsg(RTM_CHANGE, rt);
1.114 dyoung 1029: break;
1030: case RTM_ADD:
1.10 mycroft 1031: if (rt->rt_ifa != ifa) {
1.17 christos 1032: printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
1033: rt->rt_ifa);
1.114 dyoung 1034: if (rt->rt_ifa->ifa_rtrequest != NULL) {
1035: rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
1036: &info);
1037: }
1.74 dyoung 1038: rt_replace_ifa(rt, ifa);
1.10 mycroft 1039: rt->rt_ifp = ifa->ifa_ifp;
1.114 dyoung 1040: if (ifa->ifa_rtrequest != NULL)
1041: ifa->ifa_rtrequest(RTM_ADD, rt, &info);
1.10 mycroft 1042: }
1.146 ozaki-r 1043: rt_newmsg(cmd, rt);
1.114 dyoung 1044: break;
1.1 cgd 1045: }
1.147 ozaki-r 1046: rtfree(rt);
1.85 dyoung 1047: return error;
1.18 kml 1048: }
1049:
1.136 roy 1050: /*
1051: * Create a local route entry for the address.
1052: * Announce the addition of the address and the route to the routing socket.
1053: */
1054: int
1055: rt_ifa_addlocal(struct ifaddr *ifa)
1056: {
1057: struct rtentry *rt;
1058: int e;
1059:
1060: /* If there is no loopback entry, allocate one. */
1061: rt = rtalloc1(ifa->ifa_addr, 0);
1.158 ozaki-r 1062: #ifdef RT_DEBUG
1063: if (rt != NULL)
1064: dump_rt(rt);
1065: #endif
1.136 roy 1066: if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
1067: (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
1.152 roy 1068: {
1069: struct rt_addrinfo info;
1070: struct rtentry *nrt;
1071:
1072: memset(&info, 0, sizeof(info));
1073: info.rti_flags = RTF_HOST | RTF_LOCAL;
1074: if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)))
1.158 ozaki-r 1075: info.rti_flags |= RTF_LLDATA;
1.152 roy 1076: info.rti_info[RTAX_DST] = ifa->ifa_addr;
1077: info.rti_info[RTAX_GATEWAY] =
1078: (const struct sockaddr *)ifa->ifa_ifp->if_sadl;
1079: info.rti_ifa = ifa;
1080: nrt = NULL;
1081: e = rtrequest1(RTM_ADD, &info, &nrt);
1082: if (nrt && ifa != nrt->rt_ifa)
1083: rt_replace_ifa(nrt, ifa);
1084: rt_newaddrmsg(RTM_ADD, ifa, e, nrt);
1.158 ozaki-r 1085: if (nrt != NULL) {
1086: #ifdef RT_DEBUG
1087: dump_rt(nrt);
1088: #endif
1.152 roy 1089: rtfree(nrt);
1.158 ozaki-r 1090: }
1.152 roy 1091: } else {
1.136 roy 1092: e = 0;
1093: rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1094: }
1095: if (rt != NULL)
1.146 ozaki-r 1096: rtfree(rt);
1.136 roy 1097: return e;
1098: }
1099:
1100: /*
1101: * Remove the local route entry for the address.
1102: * Announce the removal of the address and the route to the routing socket.
1103: */
1104: int
1105: rt_ifa_remlocal(struct ifaddr *ifa, struct ifaddr *alt_ifa)
1106: {
1107: struct rtentry *rt;
1108: int e = 0;
1109:
1110: rt = rtalloc1(ifa->ifa_addr, 0);
1111:
1112: /*
1113: * Before deleting, check if a corresponding loopbacked
1114: * host route surely exists. With this check, we can avoid
1115: * deleting an interface direct route whose destination is
1116: * the same as the address being removed. This can happen
1117: * when removing a subnet-router anycast address on an
1118: * interface attached to a shared medium.
1119: */
1120: if (rt != NULL &&
1121: (rt->rt_flags & RTF_HOST) &&
1122: (rt->rt_ifp->if_flags & IFF_LOOPBACK))
1123: {
1124: /* If we cannot replace the route's ifaddr with the equivalent
1125: * ifaddr of another interface, I believe it is safest to
1126: * delete the route.
1127: */
1.152 roy 1128: if (alt_ifa == NULL) {
1129: e = rtdeletemsg(rt);
1130: rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
1131: } else {
1.136 roy 1132: rt_replace_ifa(rt, alt_ifa);
1133: rt_newmsg(RTM_CHANGE, rt);
1134: }
1135: } else
1136: rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
1137: if (rt != NULL)
1.146 ozaki-r 1138: rtfree(rt);
1.136 roy 1139: return e;
1140: }
1141:
1.18 kml 1142: /*
1143: * Route timer routines. These routes allow functions to be called
1144: * for various routes at any time. This is useful in supporting
1145: * path MTU discovery and redirect route deletion.
1146: *
1147: * This is similar to some BSDI internal functions, but it provides
1148: * for multiple queues for efficiency's sake...
1149: */
1150:
1151: LIST_HEAD(, rttimer_queue) rttimer_queue_head;
1152: static int rt_init_done = 0;
1153:
1.65 perry 1154: /*
1.18 kml 1155: * Some subtle order problems with domain initialization mean that
1156: * we cannot count on this being run from rt_init before various
1157: * protocol initializations are done. Therefore, we make sure
1158: * that this is run when the first queue is added...
1159: */
1160:
1.65 perry 1161: void
1.60 matt 1162: rt_timer_init(void)
1.18 kml 1163: {
1164: assert(rt_init_done == 0);
1165:
1166: LIST_INIT(&rttimer_queue_head);
1.93 ad 1167: callout_init(&rt_timer_ch, 0);
1.35 thorpej 1168: callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.18 kml 1169: rt_init_done = 1;
1170: }
1171:
1172: struct rttimer_queue *
1.60 matt 1173: rt_timer_queue_create(u_int timeout)
1.18 kml 1174: {
1175: struct rttimer_queue *rtq;
1176:
1177: if (rt_init_done == 0)
1178: rt_timer_init();
1179:
1180: R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
1181: if (rtq == NULL)
1.85 dyoung 1182: return NULL;
1.109 dyoung 1183: memset(rtq, 0, sizeof(*rtq));
1.18 kml 1184:
1185: rtq->rtq_timeout = timeout;
1.24 thorpej 1186: TAILQ_INIT(&rtq->rtq_head);
1.18 kml 1187: LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
1188:
1.85 dyoung 1189: return rtq;
1.18 kml 1190: }
1191:
1192: void
1.60 matt 1193: rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
1.18 kml 1194: {
1.24 thorpej 1195:
1.18 kml 1196: rtq->rtq_timeout = timeout;
1197: }
1198:
1199: void
1.60 matt 1200: rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy)
1.18 kml 1201: {
1.24 thorpej 1202: struct rttimer *r;
1.18 kml 1203:
1.24 thorpej 1204: while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
1.18 kml 1205: LIST_REMOVE(r, rtt_link);
1.24 thorpej 1206: TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1207: if (destroy)
1.156 ozaki-r 1208: (*r->rtt_func)(r->rtt_rt, r);
1.150 ozaki-r 1209: rtfree(r->rtt_rt);
1.22 thorpej 1210: pool_put(&rttimer_pool, r);
1.37 itojun 1211: if (rtq->rtq_count > 0)
1212: rtq->rtq_count--;
1213: else
1.55 itojun 1214: printf("rt_timer_queue_remove_all: "
1215: "rtq_count reached 0\n");
1.18 kml 1216: }
1.55 itojun 1217: }
1218:
1219: void
1.60 matt 1220: rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy)
1.55 itojun 1221: {
1222:
1223: rt_timer_queue_remove_all(rtq, destroy);
1.18 kml 1224:
1225: LIST_REMOVE(rtq, rtq_link);
1.22 thorpej 1226:
1227: /*
1228: * Caller is responsible for freeing the rttimer_queue structure.
1229: */
1.18 kml 1230: }
1231:
1.37 itojun 1232: unsigned long
1.60 matt 1233: rt_timer_count(struct rttimer_queue *rtq)
1.37 itojun 1234: {
1235: return rtq->rtq_count;
1236: }
1237:
1.65 perry 1238: void
1.60 matt 1239: rt_timer_remove_all(struct rtentry *rt, int destroy)
1.18 kml 1240: {
1.24 thorpej 1241: struct rttimer *r;
1.18 kml 1242:
1.24 thorpej 1243: while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
1.18 kml 1244: LIST_REMOVE(r, rtt_link);
1.24 thorpej 1245: TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1.54 itojun 1246: if (destroy)
1.156 ozaki-r 1247: (*r->rtt_func)(r->rtt_rt, r);
1.37 itojun 1248: if (r->rtt_queue->rtq_count > 0)
1249: r->rtt_queue->rtq_count--;
1250: else
1251: printf("rt_timer_remove_all: rtq_count reached 0\n");
1.150 ozaki-r 1252: rtfree(r->rtt_rt);
1.38 itojun 1253: pool_put(&rttimer_pool, r);
1.18 kml 1254: }
1255: }
1256:
1.65 perry 1257: int
1.60 matt 1258: rt_timer_add(struct rtentry *rt,
1259: void (*func)(struct rtentry *, struct rttimer *),
1260: struct rttimer_queue *queue)
1.18 kml 1261: {
1.24 thorpej 1262: struct rttimer *r;
1.18 kml 1263:
1.156 ozaki-r 1264: KASSERT(func != NULL);
1.24 thorpej 1265: /*
1266: * If there's already a timer with this action, destroy it before
1267: * we add a new one.
1268: */
1.85 dyoung 1269: LIST_FOREACH(r, &rt->rt_timer, rtt_link) {
1270: if (r->rtt_func == func)
1271: break;
1272: }
1273: if (r != NULL) {
1274: LIST_REMOVE(r, rtt_link);
1275: TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1276: if (r->rtt_queue->rtq_count > 0)
1277: r->rtt_queue->rtq_count--;
1278: else
1279: printf("rt_timer_add: rtq_count reached 0\n");
1.150 ozaki-r 1280: rtfree(r->rtt_rt);
1.85 dyoung 1281: } else {
1282: r = pool_get(&rttimer_pool, PR_NOWAIT);
1283: if (r == NULL)
1284: return ENOBUFS;
1.18 kml 1285: }
1286:
1.85 dyoung 1287: memset(r, 0, sizeof(*r));
1.24 thorpej 1288:
1.150 ozaki-r 1289: rt->rt_refcnt++;
1.24 thorpej 1290: r->rtt_rt = rt;
1.70 kardel 1291: r->rtt_time = time_uptime;
1.24 thorpej 1292: r->rtt_func = func;
1293: r->rtt_queue = queue;
1294: LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
1295: TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1.37 itojun 1296: r->rtt_queue->rtq_count++;
1.65 perry 1297:
1.95 dyoung 1298: return 0;
1.18 kml 1299: }
1300:
1301: /* ARGSUSED */
1302: void
1.76 christos 1303: rt_timer_timer(void *arg)
1.18 kml 1304: {
1.24 thorpej 1305: struct rttimer_queue *rtq;
1306: struct rttimer *r;
1307: int s;
1.21 kml 1308:
1.24 thorpej 1309: s = splsoftnet();
1.85 dyoung 1310: LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) {
1.24 thorpej 1311: while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1.70 kardel 1312: (r->rtt_time + rtq->rtq_timeout) < time_uptime) {
1.24 thorpej 1313: LIST_REMOVE(r, rtt_link);
1314: TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1.156 ozaki-r 1315: (*r->rtt_func)(r->rtt_rt, r);
1.150 ozaki-r 1316: rtfree(r->rtt_rt);
1.24 thorpej 1317: pool_put(&rttimer_pool, r);
1.37 itojun 1318: if (rtq->rtq_count > 0)
1319: rtq->rtq_count--;
1320: else
1321: printf("rt_timer_timer: rtq_count reached 0\n");
1.18 kml 1322: }
1323: }
1.24 thorpej 1324: splx(s);
1.18 kml 1325:
1.35 thorpej 1326: callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.1 cgd 1327: }
1.83 joerg 1328:
1.102 dyoung 1329: static struct rtentry *
1.84 joerg 1330: _rtcache_init(struct route *ro, int flag)
1331: {
1.114 dyoung 1332: rtcache_invariants(ro);
1.99 dyoung 1333: KASSERT(ro->_ro_rt == NULL);
1.84 joerg 1334:
1.90 dyoung 1335: if (rtcache_getdst(ro) == NULL)
1.102 dyoung 1336: return NULL;
1.105 dyoung 1337: ro->ro_invalid = false;
1338: if ((ro->_ro_rt = rtalloc1(rtcache_getdst(ro), flag)) != NULL)
1339: rtcache(ro);
1.103 dyoung 1340:
1.114 dyoung 1341: rtcache_invariants(ro);
1.102 dyoung 1342: return ro->_ro_rt;
1.84 joerg 1343: }
1344:
1.102 dyoung 1345: struct rtentry *
1.83 joerg 1346: rtcache_init(struct route *ro)
1347: {
1.102 dyoung 1348: return _rtcache_init(ro, 1);
1.83 joerg 1349: }
1350:
1.102 dyoung 1351: struct rtentry *
1.83 joerg 1352: rtcache_init_noclone(struct route *ro)
1353: {
1.102 dyoung 1354: return _rtcache_init(ro, 0);
1.83 joerg 1355: }
1.90 dyoung 1356:
1.102 dyoung 1357: struct rtentry *
1.90 dyoung 1358: rtcache_update(struct route *ro, int clone)
1359: {
1360: rtcache_clear(ro);
1.102 dyoung 1361: return _rtcache_init(ro, clone);
1.90 dyoung 1362: }
1.83 joerg 1363:
1364: void
1.90 dyoung 1365: rtcache_copy(struct route *new_ro, const struct route *old_ro)
1.83 joerg 1366: {
1.103 dyoung 1367: struct rtentry *rt;
1368:
1369: KASSERT(new_ro != old_ro);
1.114 dyoung 1370: rtcache_invariants(new_ro);
1371: rtcache_invariants(old_ro);
1.103 dyoung 1372:
1.104 dyoung 1373: if ((rt = rtcache_validate(old_ro)) != NULL)
1.103 dyoung 1374: rt->rt_refcnt++;
1375:
1.90 dyoung 1376: if (rtcache_getdst(old_ro) == NULL ||
1377: rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0)
1378: return;
1.103 dyoung 1379:
1.105 dyoung 1380: new_ro->ro_invalid = false;
1.103 dyoung 1381: if ((new_ro->_ro_rt = rt) != NULL)
1.86 dyoung 1382: rtcache(new_ro);
1.114 dyoung 1383: rtcache_invariants(new_ro);
1.83 joerg 1384: }
1385:
1.105 dyoung 1386: static struct dom_rtlist invalid_routes = LIST_HEAD_INITIALIZER(dom_rtlist);
1387:
1.144 ozaki-r 1388: static void
1.105 dyoung 1389: rtcache_invalidate(struct dom_rtlist *rtlist)
1.83 joerg 1390: {
1.105 dyoung 1391: struct route *ro;
1.99 dyoung 1392:
1.105 dyoung 1393: while ((ro = LIST_FIRST(rtlist)) != NULL) {
1.114 dyoung 1394: rtcache_invariants(ro);
1.105 dyoung 1395: KASSERT(ro->_ro_rt != NULL);
1396: ro->ro_invalid = true;
1.99 dyoung 1397: LIST_REMOVE(ro, ro_rtcache_next);
1.105 dyoung 1398: LIST_INSERT_HEAD(&invalid_routes, ro, ro_rtcache_next);
1.114 dyoung 1399: rtcache_invariants(ro);
1.84 joerg 1400: }
1.105 dyoung 1401: }
1402:
1.144 ozaki-r 1403: static void
1.105 dyoung 1404: rtcache_clear(struct route *ro)
1405: {
1.114 dyoung 1406: rtcache_invariants(ro);
1.105 dyoung 1407: if (ro->_ro_rt == NULL)
1408: return;
1409:
1410: LIST_REMOVE(ro, ro_rtcache_next);
1411:
1.131 rmind 1412: rtfree(ro->_ro_rt);
1.105 dyoung 1413: ro->_ro_rt = NULL;
1.114 dyoung 1414: ro->ro_invalid = false;
1415: rtcache_invariants(ro);
1.83 joerg 1416: }
1417:
1.90 dyoung 1418: struct rtentry *
1.91 dyoung 1419: rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone,
1420: int *hitp)
1.90 dyoung 1421: {
1422: const struct sockaddr *odst;
1.104 dyoung 1423: struct rtentry *rt = NULL;
1.90 dyoung 1424:
1425: odst = rtcache_getdst(ro);
1.138 ozaki-r 1426: if (odst == NULL)
1427: goto miss;
1.90 dyoung 1428:
1.138 ozaki-r 1429: if (sockaddr_cmp(odst, dst) != 0) {
1.90 dyoung 1430: rtcache_free(ro);
1.138 ozaki-r 1431: goto miss;
1432: }
1433:
1434: rt = rtcache_validate(ro);
1435: if (rt == NULL) {
1.91 dyoung 1436: rtcache_clear(ro);
1.138 ozaki-r 1437: goto miss;
1438: }
1439:
1440: *hitp = 1;
1441: rtcache_invariants(ro);
1.90 dyoung 1442:
1.138 ozaki-r 1443: return rt;
1444: miss:
1445: *hitp = 0;
1446: if (rtcache_setdst(ro, dst) == 0)
1447: rt = _rtcache_init(ro, clone);
1.90 dyoung 1448:
1.114 dyoung 1449: rtcache_invariants(ro);
1450:
1.104 dyoung 1451: return rt;
1.90 dyoung 1452: }
1453:
1.83 joerg 1454: void
1.86 dyoung 1455: rtcache_free(struct route *ro)
1456: {
1457: rtcache_clear(ro);
1458: if (ro->ro_sa != NULL) {
1459: sockaddr_free(ro->ro_sa);
1460: ro->ro_sa = NULL;
1461: }
1.114 dyoung 1462: rtcache_invariants(ro);
1.86 dyoung 1463: }
1464:
1.90 dyoung 1465: int
1466: rtcache_setdst(struct route *ro, const struct sockaddr *sa)
1.83 joerg 1467: {
1.90 dyoung 1468: KASSERT(sa != NULL);
1469:
1.114 dyoung 1470: rtcache_invariants(ro);
1.142 ozaki-r 1471: if (ro->ro_sa != NULL) {
1472: if (ro->ro_sa->sa_family == sa->sa_family) {
1473: rtcache_clear(ro);
1474: sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa);
1.143 ozaki-r 1475: rtcache_invariants(ro);
1476: return 0;
1.114 dyoung 1477: }
1.143 ozaki-r 1478: /* free ro_sa, wrong family */
1479: rtcache_free(ro);
1.142 ozaki-r 1480: }
1.90 dyoung 1481:
1.107 dyoung 1482: KASSERT(ro->_ro_rt == NULL);
1483:
1.134 christos 1484: if ((ro->ro_sa = sockaddr_dup(sa, M_ZERO | M_NOWAIT)) == NULL) {
1.114 dyoung 1485: rtcache_invariants(ro);
1.90 dyoung 1486: return ENOMEM;
1.107 dyoung 1487: }
1.114 dyoung 1488: rtcache_invariants(ro);
1.90 dyoung 1489: return 0;
1.83 joerg 1490: }
1.92 dyoung 1491:
1.123 kefren 1492: const struct sockaddr *
1493: rt_settag(struct rtentry *rt, const struct sockaddr *tag)
1494: {
1495: if (rt->rt_tag != tag) {
1496: if (rt->rt_tag != NULL)
1497: sockaddr_free(rt->rt_tag);
1.134 christos 1498: rt->rt_tag = sockaddr_dup(tag, M_ZERO | M_NOWAIT);
1.123 kefren 1499: }
1500: return rt->rt_tag;
1501: }
1502:
1503: struct sockaddr *
1504: rt_gettag(struct rtentry *rt)
1505: {
1506: return rt->rt_tag;
1507: }
1.162 ozaki-r 1508:
1509: #ifdef DDB
1510:
1511: #include <machine/db_machdep.h>
1512: #include <ddb/db_interface.h>
1513: #include <ddb/db_output.h>
1514:
1515: #define rt_expire rt_rmx.rmx_expire
1516:
1517: static void
1518: db_print_sa(const struct sockaddr *sa)
1519: {
1520: int len;
1521: const u_char *p;
1522:
1523: if (sa == NULL) {
1524: db_printf("[NULL]");
1525: return;
1526: }
1527:
1528: p = (const u_char *)sa;
1529: len = sa->sa_len;
1530: db_printf("[");
1531: while (len > 0) {
1532: db_printf("%d", *p);
1533: p++; len--;
1534: if (len) db_printf(",");
1535: }
1536: db_printf("]\n");
1537: }
1538:
1539: static void
1540: db_print_ifa(struct ifaddr *ifa)
1541: {
1542: if (ifa == NULL)
1543: return;
1544: db_printf(" ifa_addr=");
1545: db_print_sa(ifa->ifa_addr);
1546: db_printf(" ifa_dsta=");
1547: db_print_sa(ifa->ifa_dstaddr);
1548: db_printf(" ifa_mask=");
1549: db_print_sa(ifa->ifa_netmask);
1550: db_printf(" flags=0x%x,refcnt=%d,metric=%d\n",
1551: ifa->ifa_flags,
1552: ifa->ifa_refcnt,
1553: ifa->ifa_metric);
1554: }
1555:
1556: /*
1557: * Function to pass to rt_walktree().
1558: * Return non-zero error to abort walk.
1559: */
1560: static int
1561: db_show_rtentry(struct rtentry *rt, void *w)
1562: {
1563: db_printf("rtentry=%p", rt);
1564:
1565: db_printf(" flags=0x%x refcnt=%d use=%"PRId64" expire=%"PRId64"\n",
1566: rt->rt_flags, rt->rt_refcnt,
1567: rt->rt_use, (uint64_t)rt->rt_expire);
1568:
1569: db_printf(" key="); db_print_sa(rt_getkey(rt));
1570: db_printf(" mask="); db_print_sa(rt_mask(rt));
1571: db_printf(" gw="); db_print_sa(rt->rt_gateway);
1572:
1573: db_printf(" ifp=%p ", rt->rt_ifp);
1574: if (rt->rt_ifp)
1575: db_printf("(%s)", rt->rt_ifp->if_xname);
1576: else
1577: db_printf("(NULL)");
1578:
1579: db_printf(" ifa=%p\n", rt->rt_ifa);
1580: db_print_ifa(rt->rt_ifa);
1581:
1582: db_printf(" gwroute=%p llinfo=%p\n",
1583: rt->rt_gwroute, rt->rt_llinfo);
1584:
1585: return 0;
1586: }
1587:
1588: /*
1589: * Function to print all the route trees.
1590: * Use this from ddb: "show routes"
1591: */
1592: void
1593: db_show_routes(db_expr_t addr, bool have_addr,
1594: db_expr_t count, const char *modif)
1595: {
1596: rt_walktree(AF_INET, db_show_rtentry, NULL);
1597: }
1598: #endif
CVSweb <webmaster@jp.NetBSD.org>