Annotation of src/sys/net/route.c, Revision 1.162
1.162 ! ozaki-r 1: /* $NetBSD: route.c,v 1.161 2016/04/11 08:26:33 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.162 ! ozaki-r 99: __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.161 2016/04/11 08:26:33 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.10 mycroft 552: rt->rt_flags |= RTF_MODIFIED;
553: flags |= RTF_MODIFIED;
554: stat = &rtstat.rts_newgateway;
1.94 dyoung 555: rt_setgate(rt, gateway);
1.1 cgd 556: }
557: } else
558: error = EHOSTUNREACH;
559: done:
560: if (rt) {
1.95 dyoung 561: if (rtp != NULL && !error)
1.1 cgd 562: *rtp = rt;
563: else
564: rtfree(rt);
565: }
1.8 cgd 566: out:
1.1 cgd 567: if (error)
568: rtstat.rts_badredirect++;
1.8 cgd 569: else if (stat != NULL)
570: (*stat)++;
1.95 dyoung 571: memset(&info, 0, sizeof(info));
1.10 mycroft 572: info.rti_info[RTAX_DST] = dst;
573: info.rti_info[RTAX_GATEWAY] = gateway;
574: info.rti_info[RTAX_NETMASK] = netmask;
575: info.rti_info[RTAX_AUTHOR] = src;
576: rt_missmsg(RTM_REDIRECT, &info, flags, error);
1.1 cgd 577: }
578:
579: /*
1.146 ozaki-r 580: * Delete a route and generate a message.
581: * It doesn't free a passed rt.
1.40 itojun 582: */
583: static int
1.60 matt 584: rtdeletemsg(struct rtentry *rt)
1.40 itojun 585: {
586: int error;
587: struct rt_addrinfo info;
588:
589: /*
590: * Request the new route so that the entry is not actually
591: * deleted. That will allow the information being reported to
592: * be accurate (and consistent with route_output()).
593: */
1.95 dyoung 594: memset(&info, 0, sizeof(info));
1.94 dyoung 595: info.rti_info[RTAX_DST] = rt_getkey(rt);
1.40 itojun 596: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
597: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
598: info.rti_flags = rt->rt_flags;
1.157 ozaki-r 599: error = rtrequest1(RTM_DELETE, &info, NULL);
1.40 itojun 600:
601: rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
602:
1.95 dyoung 603: return error;
1.40 itojun 604: }
605:
1.1 cgd 606: struct ifaddr *
1.60 matt 607: ifa_ifwithroute(int flags, const struct sockaddr *dst,
608: const struct sockaddr *gateway)
1.1 cgd 609: {
1.36 augustss 610: struct ifaddr *ifa;
1.1 cgd 611: if ((flags & RTF_GATEWAY) == 0) {
612: /*
613: * If we are adding a route to an interface,
614: * and the interface is a pt to pt link
615: * we should search for the destination
616: * as our clue to the interface. Otherwise
617: * we can use the local address.
618: */
1.68 christos 619: ifa = NULL;
1.127 christos 620: if ((flags & RTF_HOST) && gateway->sa_family != AF_LINK)
1.1 cgd 621: ifa = ifa_ifwithdstaddr(dst);
1.68 christos 622: if (ifa == NULL)
1.1 cgd 623: ifa = ifa_ifwithaddr(gateway);
624: } else {
625: /*
626: * If we are adding a route to a remote net
627: * or host, the gateway may still be on the
628: * other end of a pt to pt link.
629: */
630: ifa = ifa_ifwithdstaddr(gateway);
631: }
1.68 christos 632: if (ifa == NULL)
1.1 cgd 633: ifa = ifa_ifwithnet(gateway);
1.68 christos 634: if (ifa == NULL) {
1.1 cgd 635: struct rtentry *rt = rtalloc1(dst, 0);
1.68 christos 636: if (rt == NULL)
637: return NULL;
1.146 ozaki-r 638: ifa = rt->rt_ifa;
639: rtfree(rt);
640: if (ifa == NULL)
1.68 christos 641: return NULL;
1.1 cgd 642: }
643: if (ifa->ifa_addr->sa_family != dst->sa_family) {
1.10 mycroft 644: struct ifaddr *oifa = ifa;
1.1 cgd 645: ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
1.127 christos 646: if (ifa == NULL)
1.1 cgd 647: ifa = oifa;
648: }
1.95 dyoung 649: return ifa;
1.1 cgd 650: }
651:
1.146 ozaki-r 652: /*
653: * If it suceeds and ret_nrt isn't NULL, refcnt of ret_nrt is incremented.
654: * The caller has to rtfree it by itself.
655: */
1.9 mycroft 656: int
1.60 matt 657: rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway,
658: const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
1.1 cgd 659: {
1.39 itojun 660: struct rt_addrinfo info;
661:
1.44 thorpej 662: memset(&info, 0, sizeof(info));
1.39 itojun 663: info.rti_flags = flags;
664: info.rti_info[RTAX_DST] = dst;
665: info.rti_info[RTAX_GATEWAY] = gateway;
666: info.rti_info[RTAX_NETMASK] = netmask;
667: return rtrequest1(req, &info, ret_nrt);
668: }
669:
1.146 ozaki-r 670: /*
671: * It's a utility function to add/remove a route to/from the routing table
672: * and tell user processes the addition/removal on success.
673: */
674: int
675: rtrequest_newmsg(const int req, const struct sockaddr *dst,
676: const struct sockaddr *gateway, const struct sockaddr *netmask,
677: const int flags)
678: {
679: int error;
680: struct rtentry *ret_nrt = NULL;
681:
682: KASSERT(req == RTM_ADD || req == RTM_DELETE);
683:
684: error = rtrequest(req, dst, gateway, netmask, flags, &ret_nrt);
685: if (error != 0)
686: return error;
687:
688: KASSERT(ret_nrt != NULL);
689:
690: rt_newmsg(req, ret_nrt); /* tell user process */
691: rtfree(ret_nrt);
692:
693: return 0;
694: }
695:
1.39 itojun 696: int
1.60 matt 697: rt_getifa(struct rt_addrinfo *info)
1.39 itojun 698: {
699: struct ifaddr *ifa;
1.68 christos 700: const struct sockaddr *dst = info->rti_info[RTAX_DST];
701: const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
702: const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
703: const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
704: int flags = info->rti_flags;
1.39 itojun 705:
706: /*
707: * ifp may be specified by sockaddr_dl when protocol address
708: * is ambiguous
709: */
710: if (info->rti_ifp == NULL && ifpaddr != NULL
711: && ifpaddr->sa_family == AF_LINK &&
1.101 dyoung 712: (ifa = ifa_ifwithnet(ifpaddr)) != NULL)
1.39 itojun 713: info->rti_ifp = ifa->ifa_ifp;
714: if (info->rti_ifa == NULL && ifaaddr != NULL)
715: info->rti_ifa = ifa_ifwithaddr(ifaaddr);
716: if (info->rti_ifa == NULL) {
1.59 matt 717: const struct sockaddr *sa;
1.39 itojun 718:
719: sa = ifaaddr != NULL ? ifaaddr :
720: (gateway != NULL ? gateway : dst);
721: if (sa != NULL && info->rti_ifp != NULL)
722: info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
723: else if (dst != NULL && gateway != NULL)
724: info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
725: else if (sa != NULL)
726: info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
727: }
1.74 dyoung 728: if ((ifa = info->rti_ifa) == NULL)
729: return ENETUNREACH;
1.145 roy 730: if (ifa->ifa_getifa != NULL) {
1.74 dyoung 731: info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
1.145 roy 732: if (ifa == NULL)
733: return ENETUNREACH;
734: }
1.74 dyoung 735: if (info->rti_ifp == NULL)
736: info->rti_ifp = ifa->ifa_ifp;
737: return 0;
1.39 itojun 738: }
739:
1.146 ozaki-r 740: /*
741: * If it suceeds and ret_nrt isn't NULL, refcnt of ret_nrt is incremented.
742: * The caller has to rtfree it by itself.
743: */
1.39 itojun 744: int
1.60 matt 745: rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
1.39 itojun 746: {
1.60 matt 747: int s = splsoftnet();
1.125 dyoung 748: int error = 0, rc;
1.158 ozaki-r 749: struct rtentry *rt;
1.125 dyoung 750: rtbl_t *rtbl;
1.122 kefren 751: struct ifaddr *ifa, *ifa2;
1.94 dyoung 752: struct sockaddr_storage maskeddst;
1.68 christos 753: const struct sockaddr *dst = info->rti_info[RTAX_DST];
754: const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
755: const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
756: int flags = info->rti_flags;
1.1 cgd 757: #define senderr(x) { error = x ; goto bad; }
758:
1.125 dyoung 759: if ((rtbl = rt_gettable(dst->sa_family)) == NULL)
1.1 cgd 760: senderr(ESRCH);
761: if (flags & RTF_HOST)
1.68 christos 762: netmask = NULL;
1.1 cgd 763: switch (req) {
764: case RTM_DELETE:
1.63 christos 765: if (netmask) {
1.94 dyoung 766: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
767: netmask);
768: dst = (struct sockaddr *)&maskeddst;
1.63 christos 769: }
1.125 dyoung 770: if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.41 itojun 771: senderr(ESRCH);
1.125 dyoung 772: if ((rt = rt_deladdr(rtbl, dst, netmask)) == NULL)
1.1 cgd 773: senderr(ESRCH);
1.10 mycroft 774: if (rt->rt_gwroute) {
1.131 rmind 775: rtfree(rt->rt_gwroute);
1.68 christos 776: rt->rt_gwroute = NULL;
1.48 itojun 777: }
1.28 erh 778: rt->rt_flags &= ~RTF_UP;
1.116 roy 779: if ((ifa = rt->rt_ifa)) {
780: if (ifa->ifa_flags & IFA_ROUTE &&
781: rt_ifa_connected(rt, ifa)) {
782: RT_DPRINTF("rt->_rt_key = %p, ifa = %p, "
783: "deleted IFA_ROUTE\n",
784: (void *)rt->_rt_key, (void *)ifa);
785: ifa->ifa_flags &= ~IFA_ROUTE;
786: }
787: if (ifa->ifa_rtrequest)
788: ifa->ifa_rtrequest(RTM_DELETE, rt, info);
789: }
1.1 cgd 790: rttrash++;
1.146 ozaki-r 791: if (ret_nrt) {
1.10 mycroft 792: *ret_nrt = rt;
1.146 ozaki-r 793: rt->rt_refcnt++;
794: } else if (rt->rt_refcnt <= 0) {
795: /* Adjust the refcount */
1.10 mycroft 796: rt->rt_refcnt++;
1.1 cgd 797: rtfree(rt);
1.10 mycroft 798: }
1.1 cgd 799: break;
800:
801: case RTM_ADD:
1.68 christos 802: if (info->rti_ifa == NULL && (error = rt_getifa(info)))
1.39 itojun 803: senderr(error);
804: ifa = info->rti_ifa;
1.22 thorpej 805: rt = pool_get(&rtentry_pool, PR_NOWAIT);
1.68 christos 806: if (rt == NULL)
1.1 cgd 807: senderr(ENOBUFS);
1.109 dyoung 808: memset(rt, 0, sizeof(*rt));
1.10 mycroft 809: rt->rt_flags = RTF_UP | flags;
1.18 kml 810: LIST_INIT(&rt->rt_timer);
1.110 dyoung 811: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.96 dyoung 812: if (rt_setkey(rt, dst, M_NOWAIT) == NULL ||
1.94 dyoung 813: rt_setgate(rt, gateway) != 0) {
1.22 thorpej 814: pool_put(&rtentry_pool, rt);
1.10 mycroft 815: senderr(ENOBUFS);
816: }
1.110 dyoung 817: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 818: if (netmask) {
1.94 dyoung 819: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
820: netmask);
1.96 dyoung 821: rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT);
1.110 dyoung 822: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 823: } else {
1.96 dyoung 824: rt_setkey(rt, dst, M_NOWAIT);
1.110 dyoung 825: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 826: }
1.74 dyoung 827: rt_set_ifa(rt, ifa);
1.123 kefren 828: if (info->rti_info[RTAX_TAG] != NULL)
829: rt_settag(rt, info->rti_info[RTAX_TAG]);
1.110 dyoung 830: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.122 kefren 831: if (info->rti_info[RTAX_IFP] != NULL &&
832: (ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP])) != NULL &&
833: ifa2->ifa_ifp != NULL)
834: rt->rt_ifp = ifa2->ifa_ifp;
835: else
836: rt->rt_ifp = ifa->ifa_ifp;
1.110 dyoung 837: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125 dyoung 838: rc = rt_addaddr(rtbl, rt, netmask);
1.110 dyoung 839: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.125 dyoung 840: if (rc != 0) {
1.133 rmind 841: ifafree(ifa);
1.40 itojun 842: if (rt->rt_gwroute)
843: rtfree(rt->rt_gwroute);
1.94 dyoung 844: rt_destroy(rt);
1.40 itojun 845: pool_put(&rtentry_pool, rt);
1.125 dyoung 846: senderr(rc);
1.27 matt 847: }
1.110 dyoung 848: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 849: if (ifa->ifa_rtrequest)
1.39 itojun 850: ifa->ifa_rtrequest(req, rt, info);
1.110 dyoung 851: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.1 cgd 852: if (ret_nrt) {
853: *ret_nrt = rt;
854: rt->rt_refcnt++;
1.41 itojun 855: }
1.82 dyoung 856: rtflushall(dst->sa_family);
1.1 cgd 857: break;
1.92 dyoung 858: case RTM_GET:
1.94 dyoung 859: if (netmask != NULL) {
860: rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
861: netmask);
862: dst = (struct sockaddr *)&maskeddst;
863: }
1.125 dyoung 864: if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL)
1.92 dyoung 865: senderr(ESRCH);
866: if (ret_nrt != NULL) {
867: *ret_nrt = rt;
868: rt->rt_refcnt++;
869: }
870: break;
1.1 cgd 871: }
872: bad:
873: splx(s);
1.95 dyoung 874: return error;
1.1 cgd 875: }
876:
1.10 mycroft 877: int
1.94 dyoung 878: rt_setgate(struct rtentry *rt, const struct sockaddr *gate)
1.10 mycroft 879: {
1.94 dyoung 880: KASSERT(rt != rt->rt_gwroute);
881:
882: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 883: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 884:
1.10 mycroft 885: if (rt->rt_gwroute) {
1.131 rmind 886: rtfree(rt->rt_gwroute);
1.68 christos 887: rt->rt_gwroute = NULL;
1.10 mycroft 888: }
1.94 dyoung 889: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 890: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 891: if (rt->rt_gateway != NULL)
892: sockaddr_free(rt->rt_gateway);
893: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 894: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.134 christos 895: if ((rt->rt_gateway = sockaddr_dup(gate, M_ZERO | M_NOWAIT)) == NULL)
1.94 dyoung 896: return ENOMEM;
897: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 898: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.94 dyoung 899:
1.10 mycroft 900: if (rt->rt_flags & RTF_GATEWAY) {
1.94 dyoung 901: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 902: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10 mycroft 903: rt->rt_gwroute = rtalloc1(gate, 1);
1.27 matt 904: /*
905: * If we switched gateways, grab the MTU from the new
1.47 itojun 906: * gateway route if the current MTU, if the current MTU is
907: * greater than the MTU of gateway.
908: * Note that, if the MTU of gateway is 0, we will reset the
909: * MTU of the route to run PMTUD again from scratch. XXX
1.27 matt 910: */
1.94 dyoung 911: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 912: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.27 matt 913: if (rt->rt_gwroute
914: && !(rt->rt_rmx.rmx_locks & RTV_MTU)
1.47 itojun 915: && rt->rt_rmx.rmx_mtu
916: && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
1.27 matt 917: rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
918: }
1.10 mycroft 919: }
1.94 dyoung 920: KASSERT(rt->_rt_key != NULL);
1.110 dyoung 921: RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
1.10 mycroft 922: return 0;
923: }
924:
1.141 ozaki-r 925: static void
1.60 matt 926: rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
927: const struct sockaddr *netmask)
1.1 cgd 928: {
1.94 dyoung 929: const char *netmaskp = &netmask->sa_data[0],
930: *srcp = &src->sa_data[0];
931: char *dstp = &dst->sa_data[0];
1.126 christos 932: const char *maskend = (char *)dst + MIN(netmask->sa_len, src->sa_len);
933: const char *srcend = (char *)dst + src->sa_len;
1.94 dyoung 934:
935: dst->sa_len = src->sa_len;
936: dst->sa_family = src->sa_family;
937:
938: while (dstp < maskend)
939: *dstp++ = *srcp++ & *netmaskp++;
940: if (dstp < srcend)
941: memset(dstp, 0, (size_t)(srcend - dstp));
1.1 cgd 942: }
1.10 mycroft 943:
1.1 cgd 944: /*
1.135 roy 945: * Inform the routing socket of a route change.
946: */
947: void
1.154 ozaki-r 948: rt_newmsg(const int cmd, const struct rtentry *rt)
1.135 roy 949: {
950: struct rt_addrinfo info;
951:
952: memset((void *)&info, 0, sizeof(info));
953: info.rti_info[RTAX_DST] = rt_getkey(rt);
954: info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
955: info.rti_info[RTAX_NETMASK] = rt_mask(rt);
956: if (rt->rt_ifp) {
957: info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr;
958: info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
959: }
960:
961: rt_missmsg(cmd, &info, rt->rt_flags, 0);
962: }
963:
964: /*
1.29 sommerfe 965: * Set up or tear down a routing table entry, normally
1.1 cgd 966: * for an interface.
967: */
1.9 mycroft 968: int
1.60 matt 969: rtinit(struct ifaddr *ifa, int cmd, int flags)
1.1 cgd 970: {
1.36 augustss 971: struct rtentry *rt;
972: struct sockaddr *dst, *odst;
1.94 dyoung 973: struct sockaddr_storage maskeddst;
1.68 christos 974: struct rtentry *nrt = NULL;
1.1 cgd 975: int error;
1.39 itojun 976: struct rt_addrinfo info;
1.1 cgd 977:
978: dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
979: if (cmd == RTM_DELETE) {
980: if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1.29 sommerfe 981: /* Delete subnet route for this interface */
982: odst = dst;
1.94 dyoung 983: dst = (struct sockaddr *)&maskeddst;
1.29 sommerfe 984: rt_maskedcopy(odst, dst, ifa->ifa_netmask);
1.1 cgd 985: }
1.14 christos 986: if ((rt = rtalloc1(dst, 0)) != NULL) {
1.146 ozaki-r 987: if (rt->rt_ifa != ifa) {
988: rtfree(rt);
1.85 dyoung 989: return (flags & RTF_HOST) ? EHOSTUNREACH
990: : ENETUNREACH;
1.146 ozaki-r 991: }
992: rtfree(rt);
1.1 cgd 993: }
994: }
1.44 thorpej 995: memset(&info, 0, sizeof(info));
1.39 itojun 996: info.rti_ifa = ifa;
997: info.rti_flags = flags | ifa->ifa_flags;
998: info.rti_info[RTAX_DST] = dst;
999: info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
1.158 ozaki-r 1000:
1.39 itojun 1001: /*
1002: * XXX here, it seems that we are assuming that ifa_netmask is NULL
1003: * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate
1004: * variable) when RTF_HOST is 1. still not sure if i can safely
1005: * change it to meet bsdi4 behavior.
1006: */
1.114 dyoung 1007: if (cmd != RTM_LLINFO_UPD)
1008: info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1009: error = rtrequest1((cmd == RTM_LLINFO_UPD) ? RTM_GET : cmd, &info,
1010: &nrt);
1.153 ozaki-r 1011: if (error != 0)
1.146 ozaki-r 1012: return error;
1013:
1.153 ozaki-r 1014: rt = nrt;
1.146 ozaki-r 1015: switch (cmd) {
1.114 dyoung 1016: case RTM_DELETE:
1.146 ozaki-r 1017: rt_newmsg(cmd, rt);
1.114 dyoung 1018: break;
1019: case RTM_LLINFO_UPD:
1020: if (cmd == RTM_LLINFO_UPD && ifa->ifa_rtrequest != NULL)
1021: ifa->ifa_rtrequest(RTM_LLINFO_UPD, rt, &info);
1.146 ozaki-r 1022: rt_newmsg(RTM_CHANGE, rt);
1.114 dyoung 1023: break;
1024: case RTM_ADD:
1.10 mycroft 1025: if (rt->rt_ifa != ifa) {
1.17 christos 1026: printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
1027: rt->rt_ifa);
1.114 dyoung 1028: if (rt->rt_ifa->ifa_rtrequest != NULL) {
1029: rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,
1030: &info);
1031: }
1.74 dyoung 1032: rt_replace_ifa(rt, ifa);
1.10 mycroft 1033: rt->rt_ifp = ifa->ifa_ifp;
1.114 dyoung 1034: if (ifa->ifa_rtrequest != NULL)
1035: ifa->ifa_rtrequest(RTM_ADD, rt, &info);
1.10 mycroft 1036: }
1.146 ozaki-r 1037: rt_newmsg(cmd, rt);
1.114 dyoung 1038: break;
1.1 cgd 1039: }
1.147 ozaki-r 1040: rtfree(rt);
1.85 dyoung 1041: return error;
1.18 kml 1042: }
1043:
1.136 roy 1044: /*
1045: * Create a local route entry for the address.
1046: * Announce the addition of the address and the route to the routing socket.
1047: */
1048: int
1049: rt_ifa_addlocal(struct ifaddr *ifa)
1050: {
1051: struct rtentry *rt;
1052: int e;
1053:
1054: /* If there is no loopback entry, allocate one. */
1055: rt = rtalloc1(ifa->ifa_addr, 0);
1.158 ozaki-r 1056: #ifdef RT_DEBUG
1057: if (rt != NULL)
1058: dump_rt(rt);
1059: #endif
1.136 roy 1060: if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
1061: (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
1.152 roy 1062: {
1063: struct rt_addrinfo info;
1064: struct rtentry *nrt;
1065:
1066: memset(&info, 0, sizeof(info));
1067: info.rti_flags = RTF_HOST | RTF_LOCAL;
1068: if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)))
1.158 ozaki-r 1069: info.rti_flags |= RTF_LLDATA;
1.152 roy 1070: info.rti_info[RTAX_DST] = ifa->ifa_addr;
1071: info.rti_info[RTAX_GATEWAY] =
1072: (const struct sockaddr *)ifa->ifa_ifp->if_sadl;
1073: info.rti_ifa = ifa;
1074: nrt = NULL;
1075: e = rtrequest1(RTM_ADD, &info, &nrt);
1076: if (nrt && ifa != nrt->rt_ifa)
1077: rt_replace_ifa(nrt, ifa);
1078: rt_newaddrmsg(RTM_ADD, ifa, e, nrt);
1.158 ozaki-r 1079: if (nrt != NULL) {
1080: #ifdef RT_DEBUG
1081: dump_rt(nrt);
1082: #endif
1.152 roy 1083: rtfree(nrt);
1.158 ozaki-r 1084: }
1.152 roy 1085: } else {
1.136 roy 1086: e = 0;
1087: rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1088: }
1089: if (rt != NULL)
1.146 ozaki-r 1090: rtfree(rt);
1.136 roy 1091: return e;
1092: }
1093:
1094: /*
1095: * Remove the local route entry for the address.
1096: * Announce the removal of the address and the route to the routing socket.
1097: */
1098: int
1099: rt_ifa_remlocal(struct ifaddr *ifa, struct ifaddr *alt_ifa)
1100: {
1101: struct rtentry *rt;
1102: int e = 0;
1103:
1104: rt = rtalloc1(ifa->ifa_addr, 0);
1105:
1106: /*
1107: * Before deleting, check if a corresponding loopbacked
1108: * host route surely exists. With this check, we can avoid
1109: * deleting an interface direct route whose destination is
1110: * the same as the address being removed. This can happen
1111: * when removing a subnet-router anycast address on an
1112: * interface attached to a shared medium.
1113: */
1114: if (rt != NULL &&
1115: (rt->rt_flags & RTF_HOST) &&
1116: (rt->rt_ifp->if_flags & IFF_LOOPBACK))
1117: {
1118: /* If we cannot replace the route's ifaddr with the equivalent
1119: * ifaddr of another interface, I believe it is safest to
1120: * delete the route.
1121: */
1.152 roy 1122: if (alt_ifa == NULL) {
1123: e = rtdeletemsg(rt);
1124: rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
1125: } else {
1.136 roy 1126: rt_replace_ifa(rt, alt_ifa);
1127: rt_newmsg(RTM_CHANGE, rt);
1128: }
1129: } else
1130: rt_newaddrmsg(RTM_DELADDR, ifa, 0, NULL);
1131: if (rt != NULL)
1.146 ozaki-r 1132: rtfree(rt);
1.136 roy 1133: return e;
1134: }
1135:
1.18 kml 1136: /*
1137: * Route timer routines. These routes allow functions to be called
1138: * for various routes at any time. This is useful in supporting
1139: * path MTU discovery and redirect route deletion.
1140: *
1141: * This is similar to some BSDI internal functions, but it provides
1142: * for multiple queues for efficiency's sake...
1143: */
1144:
1145: LIST_HEAD(, rttimer_queue) rttimer_queue_head;
1146: static int rt_init_done = 0;
1147:
1.65 perry 1148: /*
1.18 kml 1149: * Some subtle order problems with domain initialization mean that
1150: * we cannot count on this being run from rt_init before various
1151: * protocol initializations are done. Therefore, we make sure
1152: * that this is run when the first queue is added...
1153: */
1154:
1.65 perry 1155: void
1.60 matt 1156: rt_timer_init(void)
1.18 kml 1157: {
1158: assert(rt_init_done == 0);
1159:
1160: LIST_INIT(&rttimer_queue_head);
1.93 ad 1161: callout_init(&rt_timer_ch, 0);
1.35 thorpej 1162: callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.18 kml 1163: rt_init_done = 1;
1164: }
1165:
1166: struct rttimer_queue *
1.60 matt 1167: rt_timer_queue_create(u_int timeout)
1.18 kml 1168: {
1169: struct rttimer_queue *rtq;
1170:
1171: if (rt_init_done == 0)
1172: rt_timer_init();
1173:
1174: R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
1175: if (rtq == NULL)
1.85 dyoung 1176: return NULL;
1.109 dyoung 1177: memset(rtq, 0, sizeof(*rtq));
1.18 kml 1178:
1179: rtq->rtq_timeout = timeout;
1.24 thorpej 1180: TAILQ_INIT(&rtq->rtq_head);
1.18 kml 1181: LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
1182:
1.85 dyoung 1183: return rtq;
1.18 kml 1184: }
1185:
1186: void
1.60 matt 1187: rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
1.18 kml 1188: {
1.24 thorpej 1189:
1.18 kml 1190: rtq->rtq_timeout = timeout;
1191: }
1192:
1193: void
1.60 matt 1194: rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy)
1.18 kml 1195: {
1.24 thorpej 1196: struct rttimer *r;
1.18 kml 1197:
1.24 thorpej 1198: while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
1.18 kml 1199: LIST_REMOVE(r, rtt_link);
1.24 thorpej 1200: TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1201: if (destroy)
1.156 ozaki-r 1202: (*r->rtt_func)(r->rtt_rt, r);
1.150 ozaki-r 1203: rtfree(r->rtt_rt);
1.22 thorpej 1204: pool_put(&rttimer_pool, r);
1.37 itojun 1205: if (rtq->rtq_count > 0)
1206: rtq->rtq_count--;
1207: else
1.55 itojun 1208: printf("rt_timer_queue_remove_all: "
1209: "rtq_count reached 0\n");
1.18 kml 1210: }
1.55 itojun 1211: }
1212:
1213: void
1.60 matt 1214: rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy)
1.55 itojun 1215: {
1216:
1217: rt_timer_queue_remove_all(rtq, destroy);
1.18 kml 1218:
1219: LIST_REMOVE(rtq, rtq_link);
1.22 thorpej 1220:
1221: /*
1222: * Caller is responsible for freeing the rttimer_queue structure.
1223: */
1.18 kml 1224: }
1225:
1.37 itojun 1226: unsigned long
1.60 matt 1227: rt_timer_count(struct rttimer_queue *rtq)
1.37 itojun 1228: {
1229: return rtq->rtq_count;
1230: }
1231:
1.65 perry 1232: void
1.60 matt 1233: rt_timer_remove_all(struct rtentry *rt, int destroy)
1.18 kml 1234: {
1.24 thorpej 1235: struct rttimer *r;
1.18 kml 1236:
1.24 thorpej 1237: while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
1.18 kml 1238: LIST_REMOVE(r, rtt_link);
1.24 thorpej 1239: TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1.54 itojun 1240: if (destroy)
1.156 ozaki-r 1241: (*r->rtt_func)(r->rtt_rt, r);
1.37 itojun 1242: if (r->rtt_queue->rtq_count > 0)
1243: r->rtt_queue->rtq_count--;
1244: else
1245: printf("rt_timer_remove_all: rtq_count reached 0\n");
1.150 ozaki-r 1246: rtfree(r->rtt_rt);
1.38 itojun 1247: pool_put(&rttimer_pool, r);
1.18 kml 1248: }
1249: }
1250:
1.65 perry 1251: int
1.60 matt 1252: rt_timer_add(struct rtentry *rt,
1253: void (*func)(struct rtentry *, struct rttimer *),
1254: struct rttimer_queue *queue)
1.18 kml 1255: {
1.24 thorpej 1256: struct rttimer *r;
1.18 kml 1257:
1.156 ozaki-r 1258: KASSERT(func != NULL);
1.24 thorpej 1259: /*
1260: * If there's already a timer with this action, destroy it before
1261: * we add a new one.
1262: */
1.85 dyoung 1263: LIST_FOREACH(r, &rt->rt_timer, rtt_link) {
1264: if (r->rtt_func == func)
1265: break;
1266: }
1267: if (r != NULL) {
1268: LIST_REMOVE(r, rtt_link);
1269: TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1270: if (r->rtt_queue->rtq_count > 0)
1271: r->rtt_queue->rtq_count--;
1272: else
1273: printf("rt_timer_add: rtq_count reached 0\n");
1.150 ozaki-r 1274: rtfree(r->rtt_rt);
1.85 dyoung 1275: } else {
1276: r = pool_get(&rttimer_pool, PR_NOWAIT);
1277: if (r == NULL)
1278: return ENOBUFS;
1.18 kml 1279: }
1280:
1.85 dyoung 1281: memset(r, 0, sizeof(*r));
1.24 thorpej 1282:
1.150 ozaki-r 1283: rt->rt_refcnt++;
1.24 thorpej 1284: r->rtt_rt = rt;
1.70 kardel 1285: r->rtt_time = time_uptime;
1.24 thorpej 1286: r->rtt_func = func;
1287: r->rtt_queue = queue;
1288: LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
1289: TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1.37 itojun 1290: r->rtt_queue->rtq_count++;
1.65 perry 1291:
1.95 dyoung 1292: return 0;
1.18 kml 1293: }
1294:
1295: /* ARGSUSED */
1296: void
1.76 christos 1297: rt_timer_timer(void *arg)
1.18 kml 1298: {
1.24 thorpej 1299: struct rttimer_queue *rtq;
1300: struct rttimer *r;
1301: int s;
1.21 kml 1302:
1.24 thorpej 1303: s = splsoftnet();
1.85 dyoung 1304: LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) {
1.24 thorpej 1305: while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1.70 kardel 1306: (r->rtt_time + rtq->rtq_timeout) < time_uptime) {
1.24 thorpej 1307: LIST_REMOVE(r, rtt_link);
1308: TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1.156 ozaki-r 1309: (*r->rtt_func)(r->rtt_rt, r);
1.150 ozaki-r 1310: rtfree(r->rtt_rt);
1.24 thorpej 1311: pool_put(&rttimer_pool, r);
1.37 itojun 1312: if (rtq->rtq_count > 0)
1313: rtq->rtq_count--;
1314: else
1315: printf("rt_timer_timer: rtq_count reached 0\n");
1.18 kml 1316: }
1317: }
1.24 thorpej 1318: splx(s);
1.18 kml 1319:
1.35 thorpej 1320: callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1.1 cgd 1321: }
1.83 joerg 1322:
1.102 dyoung 1323: static struct rtentry *
1.84 joerg 1324: _rtcache_init(struct route *ro, int flag)
1325: {
1.114 dyoung 1326: rtcache_invariants(ro);
1.99 dyoung 1327: KASSERT(ro->_ro_rt == NULL);
1.84 joerg 1328:
1.90 dyoung 1329: if (rtcache_getdst(ro) == NULL)
1.102 dyoung 1330: return NULL;
1.105 dyoung 1331: ro->ro_invalid = false;
1332: if ((ro->_ro_rt = rtalloc1(rtcache_getdst(ro), flag)) != NULL)
1333: rtcache(ro);
1.103 dyoung 1334:
1.114 dyoung 1335: rtcache_invariants(ro);
1.102 dyoung 1336: return ro->_ro_rt;
1.84 joerg 1337: }
1338:
1.102 dyoung 1339: struct rtentry *
1.83 joerg 1340: rtcache_init(struct route *ro)
1341: {
1.102 dyoung 1342: return _rtcache_init(ro, 1);
1.83 joerg 1343: }
1344:
1.102 dyoung 1345: struct rtentry *
1.83 joerg 1346: rtcache_init_noclone(struct route *ro)
1347: {
1.102 dyoung 1348: return _rtcache_init(ro, 0);
1.83 joerg 1349: }
1.90 dyoung 1350:
1.102 dyoung 1351: struct rtentry *
1.90 dyoung 1352: rtcache_update(struct route *ro, int clone)
1353: {
1354: rtcache_clear(ro);
1.102 dyoung 1355: return _rtcache_init(ro, clone);
1.90 dyoung 1356: }
1.83 joerg 1357:
1358: void
1.90 dyoung 1359: rtcache_copy(struct route *new_ro, const struct route *old_ro)
1.83 joerg 1360: {
1.103 dyoung 1361: struct rtentry *rt;
1362:
1363: KASSERT(new_ro != old_ro);
1.114 dyoung 1364: rtcache_invariants(new_ro);
1365: rtcache_invariants(old_ro);
1.103 dyoung 1366:
1.104 dyoung 1367: if ((rt = rtcache_validate(old_ro)) != NULL)
1.103 dyoung 1368: rt->rt_refcnt++;
1369:
1.90 dyoung 1370: if (rtcache_getdst(old_ro) == NULL ||
1371: rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0)
1372: return;
1.103 dyoung 1373:
1.105 dyoung 1374: new_ro->ro_invalid = false;
1.103 dyoung 1375: if ((new_ro->_ro_rt = rt) != NULL)
1.86 dyoung 1376: rtcache(new_ro);
1.114 dyoung 1377: rtcache_invariants(new_ro);
1.83 joerg 1378: }
1379:
1.105 dyoung 1380: static struct dom_rtlist invalid_routes = LIST_HEAD_INITIALIZER(dom_rtlist);
1381:
1.144 ozaki-r 1382: static void
1.105 dyoung 1383: rtcache_invalidate(struct dom_rtlist *rtlist)
1.83 joerg 1384: {
1.105 dyoung 1385: struct route *ro;
1.99 dyoung 1386:
1.105 dyoung 1387: while ((ro = LIST_FIRST(rtlist)) != NULL) {
1.114 dyoung 1388: rtcache_invariants(ro);
1.105 dyoung 1389: KASSERT(ro->_ro_rt != NULL);
1390: ro->ro_invalid = true;
1.99 dyoung 1391: LIST_REMOVE(ro, ro_rtcache_next);
1.105 dyoung 1392: LIST_INSERT_HEAD(&invalid_routes, ro, ro_rtcache_next);
1.114 dyoung 1393: rtcache_invariants(ro);
1.84 joerg 1394: }
1.105 dyoung 1395: }
1396:
1.144 ozaki-r 1397: static void
1.105 dyoung 1398: rtcache_clear(struct route *ro)
1399: {
1.114 dyoung 1400: rtcache_invariants(ro);
1.105 dyoung 1401: if (ro->_ro_rt == NULL)
1402: return;
1403:
1404: LIST_REMOVE(ro, ro_rtcache_next);
1405:
1.131 rmind 1406: rtfree(ro->_ro_rt);
1.105 dyoung 1407: ro->_ro_rt = NULL;
1.114 dyoung 1408: ro->ro_invalid = false;
1409: rtcache_invariants(ro);
1.83 joerg 1410: }
1411:
1.90 dyoung 1412: struct rtentry *
1.91 dyoung 1413: rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone,
1414: int *hitp)
1.90 dyoung 1415: {
1416: const struct sockaddr *odst;
1.104 dyoung 1417: struct rtentry *rt = NULL;
1.90 dyoung 1418:
1419: odst = rtcache_getdst(ro);
1.138 ozaki-r 1420: if (odst == NULL)
1421: goto miss;
1.90 dyoung 1422:
1.138 ozaki-r 1423: if (sockaddr_cmp(odst, dst) != 0) {
1.90 dyoung 1424: rtcache_free(ro);
1.138 ozaki-r 1425: goto miss;
1426: }
1427:
1428: rt = rtcache_validate(ro);
1429: if (rt == NULL) {
1.91 dyoung 1430: rtcache_clear(ro);
1.138 ozaki-r 1431: goto miss;
1432: }
1433:
1434: *hitp = 1;
1435: rtcache_invariants(ro);
1.90 dyoung 1436:
1.138 ozaki-r 1437: return rt;
1438: miss:
1439: *hitp = 0;
1440: if (rtcache_setdst(ro, dst) == 0)
1441: rt = _rtcache_init(ro, clone);
1.90 dyoung 1442:
1.114 dyoung 1443: rtcache_invariants(ro);
1444:
1.104 dyoung 1445: return rt;
1.90 dyoung 1446: }
1447:
1.83 joerg 1448: void
1.86 dyoung 1449: rtcache_free(struct route *ro)
1450: {
1451: rtcache_clear(ro);
1452: if (ro->ro_sa != NULL) {
1453: sockaddr_free(ro->ro_sa);
1454: ro->ro_sa = NULL;
1455: }
1.114 dyoung 1456: rtcache_invariants(ro);
1.86 dyoung 1457: }
1458:
1.90 dyoung 1459: int
1460: rtcache_setdst(struct route *ro, const struct sockaddr *sa)
1.83 joerg 1461: {
1.90 dyoung 1462: KASSERT(sa != NULL);
1463:
1.114 dyoung 1464: rtcache_invariants(ro);
1.142 ozaki-r 1465: if (ro->ro_sa != NULL) {
1466: if (ro->ro_sa->sa_family == sa->sa_family) {
1467: rtcache_clear(ro);
1468: sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa);
1.143 ozaki-r 1469: rtcache_invariants(ro);
1470: return 0;
1.114 dyoung 1471: }
1.143 ozaki-r 1472: /* free ro_sa, wrong family */
1473: rtcache_free(ro);
1.142 ozaki-r 1474: }
1.90 dyoung 1475:
1.107 dyoung 1476: KASSERT(ro->_ro_rt == NULL);
1477:
1.134 christos 1478: if ((ro->ro_sa = sockaddr_dup(sa, M_ZERO | M_NOWAIT)) == NULL) {
1.114 dyoung 1479: rtcache_invariants(ro);
1.90 dyoung 1480: return ENOMEM;
1.107 dyoung 1481: }
1.114 dyoung 1482: rtcache_invariants(ro);
1.90 dyoung 1483: return 0;
1.83 joerg 1484: }
1.92 dyoung 1485:
1.123 kefren 1486: const struct sockaddr *
1487: rt_settag(struct rtentry *rt, const struct sockaddr *tag)
1488: {
1489: if (rt->rt_tag != tag) {
1490: if (rt->rt_tag != NULL)
1491: sockaddr_free(rt->rt_tag);
1.134 christos 1492: rt->rt_tag = sockaddr_dup(tag, M_ZERO | M_NOWAIT);
1.123 kefren 1493: }
1494: return rt->rt_tag;
1495: }
1496:
1497: struct sockaddr *
1498: rt_gettag(struct rtentry *rt)
1499: {
1500: return rt->rt_tag;
1501: }
1.162 ! ozaki-r 1502:
! 1503: #ifdef DDB
! 1504:
! 1505: #include <machine/db_machdep.h>
! 1506: #include <ddb/db_interface.h>
! 1507: #include <ddb/db_output.h>
! 1508:
! 1509: #define rt_expire rt_rmx.rmx_expire
! 1510:
! 1511: static void
! 1512: db_print_sa(const struct sockaddr *sa)
! 1513: {
! 1514: int len;
! 1515: const u_char *p;
! 1516:
! 1517: if (sa == NULL) {
! 1518: db_printf("[NULL]");
! 1519: return;
! 1520: }
! 1521:
! 1522: p = (const u_char *)sa;
! 1523: len = sa->sa_len;
! 1524: db_printf("[");
! 1525: while (len > 0) {
! 1526: db_printf("%d", *p);
! 1527: p++; len--;
! 1528: if (len) db_printf(",");
! 1529: }
! 1530: db_printf("]\n");
! 1531: }
! 1532:
! 1533: static void
! 1534: db_print_ifa(struct ifaddr *ifa)
! 1535: {
! 1536: if (ifa == NULL)
! 1537: return;
! 1538: db_printf(" ifa_addr=");
! 1539: db_print_sa(ifa->ifa_addr);
! 1540: db_printf(" ifa_dsta=");
! 1541: db_print_sa(ifa->ifa_dstaddr);
! 1542: db_printf(" ifa_mask=");
! 1543: db_print_sa(ifa->ifa_netmask);
! 1544: db_printf(" flags=0x%x,refcnt=%d,metric=%d\n",
! 1545: ifa->ifa_flags,
! 1546: ifa->ifa_refcnt,
! 1547: ifa->ifa_metric);
! 1548: }
! 1549:
! 1550: /*
! 1551: * Function to pass to rt_walktree().
! 1552: * Return non-zero error to abort walk.
! 1553: */
! 1554: static int
! 1555: db_show_rtentry(struct rtentry *rt, void *w)
! 1556: {
! 1557: db_printf("rtentry=%p", rt);
! 1558:
! 1559: db_printf(" flags=0x%x refcnt=%d use=%"PRId64" expire=%"PRId64"\n",
! 1560: rt->rt_flags, rt->rt_refcnt,
! 1561: rt->rt_use, (uint64_t)rt->rt_expire);
! 1562:
! 1563: db_printf(" key="); db_print_sa(rt_getkey(rt));
! 1564: db_printf(" mask="); db_print_sa(rt_mask(rt));
! 1565: db_printf(" gw="); db_print_sa(rt->rt_gateway);
! 1566:
! 1567: db_printf(" ifp=%p ", rt->rt_ifp);
! 1568: if (rt->rt_ifp)
! 1569: db_printf("(%s)", rt->rt_ifp->if_xname);
! 1570: else
! 1571: db_printf("(NULL)");
! 1572:
! 1573: db_printf(" ifa=%p\n", rt->rt_ifa);
! 1574: db_print_ifa(rt->rt_ifa);
! 1575:
! 1576: db_printf(" gwroute=%p llinfo=%p\n",
! 1577: rt->rt_gwroute, rt->rt_llinfo);
! 1578:
! 1579: return 0;
! 1580: }
! 1581:
! 1582: /*
! 1583: * Function to print all the route trees.
! 1584: * Use this from ddb: "show routes"
! 1585: */
! 1586: void
! 1587: db_show_routes(db_expr_t addr, bool have_addr,
! 1588: db_expr_t count, const char *modif)
! 1589: {
! 1590: rt_walktree(AF_INET, db_show_rtentry, NULL);
! 1591: }
! 1592: #endif
CVSweb <webmaster@jp.NetBSD.org>