Line data Source code
1 : /* $OpenBSD: route.c,v 1.377 2018/07/11 19:52:19 henning Exp $ */
2 : /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * Copyright (c) 1980, 1986, 1991, 1993
35 : * The Regents of the University of California. All rights reserved.
36 : *
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 University 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.
48 : *
49 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 : * @(#)route.c 8.2 (Berkeley) 11/15/93
62 : */
63 :
64 : /*
65 : * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
66 : *
67 : * NRL grants permission for redistribution and use in source and binary
68 : * forms, with or without modification, of the software and documentation
69 : * created at NRL provided that the following conditions are met:
70 : *
71 : * 1. Redistributions of source code must retain the above copyright
72 : * notice, this list of conditions and the following disclaimer.
73 : * 2. Redistributions in binary form must reproduce the above copyright
74 : * notice, this list of conditions and the following disclaimer in the
75 : * documentation and/or other materials provided with the distribution.
76 : * 3. All advertising materials mentioning features or use of this software
77 : * must display the following acknowledgements:
78 : * This product includes software developed by the University of
79 : * California, Berkeley and its contributors.
80 : * This product includes software developed at the Information
81 : * Technology Division, US Naval Research Laboratory.
82 : * 4. Neither the name of the NRL nor the names of its contributors
83 : * may be used to endorse or promote products derived from this software
84 : * without specific prior written permission.
85 : *
86 : * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
87 : * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
88 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
89 : * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
90 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
91 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
92 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
93 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
94 : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
95 : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
96 : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97 : *
98 : * The views and conclusions contained in the software and documentation
99 : * are those of the authors and should not be interpreted as representing
100 : * official policies, either expressed or implied, of the US Naval
101 : * Research Laboratory (NRL).
102 : */
103 :
104 : #include <sys/param.h>
105 : #include <sys/systm.h>
106 : #include <sys/mbuf.h>
107 : #include <sys/socket.h>
108 : #include <sys/socketvar.h>
109 : #include <sys/timeout.h>
110 : #include <sys/domain.h>
111 : #include <sys/protosw.h>
112 : #include <sys/ioctl.h>
113 : #include <sys/kernel.h>
114 : #include <sys/queue.h>
115 : #include <sys/pool.h>
116 : #include <sys/atomic.h>
117 :
118 : #include <net/if.h>
119 : #include <net/if_var.h>
120 : #include <net/if_dl.h>
121 : #include <net/route.h>
122 :
123 : #include <netinet/in.h>
124 : #include <netinet/ip_var.h>
125 : #include <netinet/in_var.h>
126 :
127 : #ifdef INET6
128 : #include <netinet/ip6.h>
129 : #include <netinet6/ip6_var.h>
130 : #include <netinet6/in6_var.h>
131 : #endif
132 :
133 : #ifdef MPLS
134 : #include <netmpls/mpls.h>
135 : #endif
136 :
137 : #ifdef BFD
138 : #include <net/bfd.h>
139 : #endif
140 :
141 : #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
142 :
143 : /* Give some jitter to hash, to avoid synchronization between routers. */
144 : static uint32_t rt_hashjitter;
145 :
146 : extern unsigned int rtmap_limit;
147 :
148 : struct cpumem * rtcounters;
149 : int rttrash; /* routes not in table but not freed */
150 : int ifatrash; /* ifas not in ifp list but not free */
151 :
152 : struct pool rtentry_pool; /* pool for rtentry structures */
153 : struct pool rttimer_pool; /* pool for rttimer structures */
154 :
155 : void rt_timer_init(void);
156 : int rt_setgwroute(struct rtentry *, u_int);
157 : void rt_putgwroute(struct rtentry *);
158 : int rtflushclone1(struct rtentry *, void *, u_int);
159 : void rtflushclone(unsigned int, struct rtentry *);
160 : int rt_ifa_purge_walker(struct rtentry *, void *, unsigned int);
161 : struct rtentry *rt_match(struct sockaddr *, uint32_t *, int, unsigned int);
162 : int rt_clone(struct rtentry **, struct sockaddr *, unsigned int);
163 : struct sockaddr *rt_plentosa(sa_family_t, int, struct sockaddr_in6 *);
164 :
165 : #ifdef DDB
166 : void db_print_sa(struct sockaddr *);
167 : void db_print_ifa(struct ifaddr *);
168 : int db_show_rtentry(struct rtentry *, void *, unsigned int);
169 : #endif
170 :
171 : #define LABELID_MAX 50000
172 :
173 : struct rt_label {
174 : TAILQ_ENTRY(rt_label) rtl_entry;
175 : char rtl_name[RTLABEL_LEN];
176 : u_int16_t rtl_id;
177 : int rtl_ref;
178 : };
179 :
180 : TAILQ_HEAD(rt_labels, rt_label) rt_labels = TAILQ_HEAD_INITIALIZER(rt_labels);
181 :
182 : void
183 0 : route_init(void)
184 : {
185 0 : rtcounters = counters_alloc(rts_ncounters);
186 :
187 0 : pool_init(&rtentry_pool, sizeof(struct rtentry), 0, IPL_SOFTNET, 0,
188 : "rtentry", NULL);
189 :
190 0 : while (rt_hashjitter == 0)
191 0 : rt_hashjitter = arc4random();
192 :
193 : #ifdef BFD
194 : bfdinit();
195 : #endif
196 0 : }
197 :
198 : /*
199 : * Returns 1 if the (cached) ``rt'' entry is still valid, 0 otherwise.
200 : */
201 : int
202 0 : rtisvalid(struct rtentry *rt)
203 : {
204 0 : if (rt == NULL)
205 0 : return (0);
206 :
207 0 : if (!ISSET(rt->rt_flags, RTF_UP))
208 0 : return (0);
209 :
210 0 : if (ISSET(rt->rt_flags, RTF_GATEWAY)) {
211 0 : KASSERT(rt->rt_gwroute != NULL);
212 0 : KASSERT(!ISSET(rt->rt_gwroute->rt_flags, RTF_GATEWAY));
213 0 : if (!ISSET(rt->rt_gwroute->rt_flags, RTF_UP))
214 0 : return (0);
215 : }
216 :
217 0 : return (1);
218 0 : }
219 :
220 : /*
221 : * Do the actual lookup for rtalloc(9), do not use directly!
222 : *
223 : * Return the best matching entry for the destination ``dst''.
224 : *
225 : * "RT_RESOLVE" means that a corresponding L2 entry should
226 : * be added to the routing table and resolved (via ARP or
227 : * NDP), if it does not exist.
228 : */
229 : struct rtentry *
230 0 : rt_match(struct sockaddr *dst, uint32_t *src, int flags, unsigned int tableid)
231 : {
232 0 : struct rtentry *rt = NULL;
233 :
234 0 : rt = rtable_match(tableid, dst, src);
235 0 : if (rt == NULL) {
236 0 : rtstat_inc(rts_unreach);
237 0 : return (NULL);
238 : }
239 :
240 0 : if (ISSET(rt->rt_flags, RTF_CLONING) && ISSET(flags, RT_RESOLVE))
241 0 : rt_clone(&rt, dst, tableid);
242 :
243 0 : rt->rt_use++;
244 0 : return (rt);
245 0 : }
246 :
247 : int
248 0 : rt_clone(struct rtentry **rtp, struct sockaddr *dst, unsigned int rtableid)
249 : {
250 0 : struct rt_addrinfo info;
251 0 : struct rtentry *rt = *rtp;
252 : int error = 0;
253 :
254 0 : memset(&info, 0, sizeof(info));
255 0 : info.rti_info[RTAX_DST] = dst;
256 :
257 : /*
258 : * The priority of cloned route should be different
259 : * to avoid conflict with /32 cloning routes.
260 : *
261 : * It should also be higher to let the ARP layer find
262 : * cloned routes instead of the cloning one.
263 : */
264 0 : KERNEL_LOCK();
265 0 : error = rtrequest(RTM_RESOLVE, &info, rt->rt_priority - 1, &rt,
266 : rtableid);
267 0 : KERNEL_UNLOCK();
268 0 : if (error) {
269 0 : rtm_miss(RTM_MISS, &info, 0, RTP_NONE, 0, error, rtableid);
270 0 : } else {
271 : /* Inform listeners of the new route */
272 0 : rtm_send(rt, RTM_ADD, 0, rtableid);
273 0 : rtfree(*rtp);
274 0 : *rtp = rt;
275 : }
276 0 : return (error);
277 0 : }
278 :
279 : /*
280 : * Originated from bridge_hash() in if_bridge.c
281 : */
282 : #define mix(a, b, c) do { \
283 : a -= b; a -= c; a ^= (c >> 13); \
284 : b -= c; b -= a; b ^= (a << 8); \
285 : c -= a; c -= b; c ^= (b >> 13); \
286 : a -= b; a -= c; a ^= (c >> 12); \
287 : b -= c; b -= a; b ^= (a << 16); \
288 : c -= a; c -= b; c ^= (b >> 5); \
289 : a -= b; a -= c; a ^= (c >> 3); \
290 : b -= c; b -= a; b ^= (a << 10); \
291 : c -= a; c -= b; c ^= (b >> 15); \
292 : } while (0)
293 :
294 : int
295 0 : rt_hash(struct rtentry *rt, struct sockaddr *dst, uint32_t *src)
296 : {
297 : uint32_t a, b, c;
298 :
299 0 : if (src == NULL || !rtisvalid(rt) || !ISSET(rt->rt_flags, RTF_MPATH))
300 0 : return (-1);
301 :
302 : a = b = 0x9e3779b9;
303 0 : c = rt_hashjitter;
304 :
305 0 : switch (dst->sa_family) {
306 : case AF_INET:
307 : {
308 : struct sockaddr_in *sin;
309 :
310 0 : if (!ipmultipath)
311 0 : return (-1);
312 :
313 0 : sin = satosin(dst);
314 0 : a += sin->sin_addr.s_addr;
315 0 : b += (src != NULL) ? src[0] : 0;
316 0 : mix(a, b, c);
317 0 : break;
318 : }
319 : #ifdef INET6
320 : case AF_INET6:
321 : {
322 : struct sockaddr_in6 *sin6;
323 :
324 0 : if (!ip6_multipath)
325 0 : return (-1);
326 :
327 0 : sin6 = satosin6(dst);
328 0 : a += sin6->sin6_addr.s6_addr32[0];
329 0 : b += sin6->sin6_addr.s6_addr32[2];
330 0 : c += (src != NULL) ? src[0] : 0;
331 0 : mix(a, b, c);
332 0 : a += sin6->sin6_addr.s6_addr32[1];
333 0 : b += sin6->sin6_addr.s6_addr32[3];
334 0 : c += (src != NULL) ? src[1] : 0;
335 0 : mix(a, b, c);
336 0 : a += sin6->sin6_addr.s6_addr32[2];
337 0 : b += sin6->sin6_addr.s6_addr32[1];
338 0 : c += (src != NULL) ? src[2] : 0;
339 0 : mix(a, b, c);
340 0 : a += sin6->sin6_addr.s6_addr32[3];
341 0 : b += sin6->sin6_addr.s6_addr32[0];
342 0 : c += (src != NULL) ? src[3] : 0;
343 0 : mix(a, b, c);
344 0 : break;
345 : }
346 : #endif /* INET6 */
347 : }
348 :
349 0 : return (c & 0xffff);
350 0 : }
351 :
352 : /*
353 : * Allocate a route, potentially using multipath to select the peer.
354 : */
355 : struct rtentry *
356 0 : rtalloc_mpath(struct sockaddr *dst, uint32_t *src, unsigned int rtableid)
357 : {
358 0 : return (rt_match(dst, src, RT_RESOLVE, rtableid));
359 : }
360 :
361 : /*
362 : * Look in the routing table for the best matching entry for
363 : * ``dst''.
364 : *
365 : * If a route with a gateway is found and its next hop is no
366 : * longer valid, try to cache it.
367 : */
368 : struct rtentry *
369 0 : rtalloc(struct sockaddr *dst, int flags, unsigned int rtableid)
370 : {
371 0 : return (rt_match(dst, NULL, flags, rtableid));
372 : }
373 :
374 : /*
375 : * Cache the route entry corresponding to a reachable next hop in
376 : * the gateway entry ``rt''.
377 : */
378 : int
379 0 : rt_setgwroute(struct rtentry *rt, u_int rtableid)
380 : {
381 0 : struct rtentry *prt, *nhrt;
382 0 : unsigned int rdomain = rtable_l2(rtableid);
383 : int error;
384 :
385 0 : NET_ASSERT_LOCKED();
386 :
387 0 : KASSERT(ISSET(rt->rt_flags, RTF_GATEWAY));
388 :
389 : /* If we cannot find a valid next hop bail. */
390 0 : nhrt = rt_match(rt->rt_gateway, NULL, RT_RESOLVE, rdomain);
391 0 : if (nhrt == NULL)
392 0 : return (ENOENT);
393 :
394 : /* Next hop entry must be on the same interface. */
395 0 : if (nhrt->rt_ifidx != rt->rt_ifidx) {
396 0 : struct sockaddr_in6 sa_mask;
397 :
398 : /*
399 : * If we found a non-L2 entry on a different interface
400 : * there's nothing we can do.
401 : */
402 0 : if (!ISSET(nhrt->rt_flags, RTF_LLINFO)) {
403 0 : rtfree(nhrt);
404 0 : return (EHOSTUNREACH);
405 : }
406 :
407 : /*
408 : * We found a L2 entry, so we might have multiple
409 : * RTF_CLONING routes for the same subnet. Query
410 : * the first route of the multipath chain and iterate
411 : * until we find the correct one.
412 : */
413 0 : prt = rtable_lookup(rdomain, rt_key(nhrt->rt_parent),
414 0 : rt_plen2mask(nhrt->rt_parent, &sa_mask), NULL, RTP_ANY);
415 0 : rtfree(nhrt);
416 :
417 0 : while (prt != NULL && prt->rt_ifidx != rt->rt_ifidx)
418 0 : prt = rtable_iterate(prt);
419 :
420 : /* We found nothing or a non-cloning MPATH route. */
421 0 : if (prt == NULL || !ISSET(prt->rt_flags, RTF_CLONING)) {
422 0 : rtfree(prt);
423 0 : return (EHOSTUNREACH);
424 : }
425 :
426 0 : error = rt_clone(&prt, rt->rt_gateway, rdomain);
427 0 : if (error) {
428 0 : rtfree(prt);
429 0 : return (error);
430 : }
431 : nhrt = prt;
432 0 : }
433 :
434 : /*
435 : * Next hop must be reachable, this also prevents rtentry
436 : * loops for example when rt->rt_gwroute points to rt.
437 : */
438 0 : if (ISSET(nhrt->rt_flags, RTF_CLONING|RTF_GATEWAY)) {
439 0 : rtfree(nhrt);
440 0 : return (ENETUNREACH);
441 : }
442 :
443 : /* Next hop is valid so remove possible old cache. */
444 0 : rt_putgwroute(rt);
445 0 : KASSERT(rt->rt_gwroute == NULL);
446 :
447 : /*
448 : * If the MTU of next hop is 0, this will reset the MTU of the
449 : * route to run PMTUD again from scratch.
450 : */
451 0 : if (!ISSET(rt->rt_locks, RTV_MTU) && (rt->rt_mtu > nhrt->rt_mtu))
452 0 : rt->rt_mtu = nhrt->rt_mtu;
453 :
454 : /*
455 : * To avoid reference counting problems when writting link-layer
456 : * addresses in an outgoing packet, we ensure that the lifetime
457 : * of a cached entry is greater that the bigger lifetime of the
458 : * gateway entries it is pointed by.
459 : */
460 0 : nhrt->rt_flags |= RTF_CACHED;
461 0 : nhrt->rt_cachecnt++;
462 :
463 0 : rt->rt_gwroute = nhrt;
464 :
465 0 : return (0);
466 0 : }
467 :
468 : /*
469 : * Invalidate the cached route entry of the gateway entry ``rt''.
470 : */
471 : void
472 0 : rt_putgwroute(struct rtentry *rt)
473 : {
474 0 : struct rtentry *nhrt = rt->rt_gwroute;
475 :
476 0 : NET_ASSERT_LOCKED();
477 :
478 0 : if (!ISSET(rt->rt_flags, RTF_GATEWAY) || nhrt == NULL)
479 0 : return;
480 :
481 0 : KASSERT(ISSET(nhrt->rt_flags, RTF_CACHED));
482 0 : KASSERT(nhrt->rt_cachecnt > 0);
483 :
484 0 : --nhrt->rt_cachecnt;
485 0 : if (nhrt->rt_cachecnt == 0)
486 0 : nhrt->rt_flags &= ~RTF_CACHED;
487 :
488 0 : rtfree(rt->rt_gwroute);
489 0 : rt->rt_gwroute = NULL;
490 0 : }
491 :
492 : void
493 0 : rtref(struct rtentry *rt)
494 : {
495 0 : atomic_inc_int(&rt->rt_refcnt);
496 0 : }
497 :
498 : void
499 0 : rtfree(struct rtentry *rt)
500 : {
501 : int refcnt;
502 :
503 0 : if (rt == NULL)
504 0 : return;
505 :
506 0 : refcnt = (int)atomic_dec_int_nv(&rt->rt_refcnt);
507 0 : if (refcnt <= 0) {
508 0 : KASSERT(!ISSET(rt->rt_flags, RTF_UP));
509 : KASSERT(!RT_ROOT(rt));
510 0 : atomic_dec_int(&rttrash);
511 0 : if (refcnt < 0) {
512 0 : printf("rtfree: %p not freed (neg refs)\n", rt);
513 0 : return;
514 : }
515 :
516 0 : KERNEL_LOCK();
517 0 : rt_timer_remove_all(rt);
518 0 : ifafree(rt->rt_ifa);
519 0 : rtlabel_unref(rt->rt_labelid);
520 : #ifdef MPLS
521 0 : rt_mpls_clear(rt);
522 : #endif
523 0 : free(rt->rt_gateway, M_RTABLE, ROUNDUP(rt->rt_gateway->sa_len));
524 0 : free(rt_key(rt), M_RTABLE, rt_key(rt)->sa_len);
525 0 : KERNEL_UNLOCK();
526 :
527 0 : pool_put(&rtentry_pool, rt);
528 0 : }
529 0 : }
530 :
531 : void
532 0 : ifafree(struct ifaddr *ifa)
533 : {
534 0 : if (ifa == NULL)
535 0 : panic("ifafree");
536 0 : if (ifa->ifa_refcnt == 0) {
537 0 : ifatrash--;
538 0 : free(ifa, M_IFADDR, 0);
539 0 : } else
540 0 : ifa->ifa_refcnt--;
541 0 : }
542 :
543 : /*
544 : * Force a routing table entry to the specified
545 : * destination to go through the given gateway.
546 : * Normally called as a result of a routing redirect
547 : * message from the network layer.
548 : */
549 : void
550 0 : rtredirect(struct sockaddr *dst, struct sockaddr *gateway,
551 : struct sockaddr *src, struct rtentry **rtp, unsigned int rdomain)
552 : {
553 0 : struct rtentry *rt;
554 : int error = 0;
555 : enum rtstat_counters stat = rts_ncounters;
556 0 : struct rt_addrinfo info;
557 : struct ifaddr *ifa;
558 : unsigned int ifidx = 0;
559 : int flags = RTF_GATEWAY|RTF_HOST;
560 : uint8_t prio = RTP_NONE;
561 :
562 0 : NET_ASSERT_LOCKED();
563 :
564 : /* verify the gateway is directly reachable */
565 0 : rt = rtalloc(gateway, 0, rdomain);
566 0 : if (!rtisvalid(rt) || ISSET(rt->rt_flags, RTF_GATEWAY)) {
567 0 : rtfree(rt);
568 : error = ENETUNREACH;
569 0 : goto out;
570 : }
571 0 : ifidx = rt->rt_ifidx;
572 0 : ifa = rt->rt_ifa;
573 0 : rtfree(rt);
574 0 : rt = NULL;
575 :
576 0 : rt = rtable_lookup(rdomain, dst, NULL, NULL, RTP_ANY);
577 : /*
578 : * If the redirect isn't from our current router for this dst,
579 : * it's either old or wrong. If it redirects us to ourselves,
580 : * we have a routing loop, perhaps as a result of an interface
581 : * going down recently.
582 : */
583 : #define equal(a1, a2) \
584 : ((a1)->sa_len == (a2)->sa_len && \
585 : bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
586 0 : if (rt != NULL && (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
587 0 : error = EINVAL;
588 0 : else if (ifa_ifwithaddr(gateway, rdomain) != NULL ||
589 0 : (gateway->sa_family = AF_INET &&
590 0 : in_broadcast(satosin(gateway)->sin_addr, rdomain)))
591 0 : error = EHOSTUNREACH;
592 0 : if (error)
593 : goto done;
594 : /*
595 : * Create a new entry if we just got back a wildcard entry
596 : * or the lookup failed. This is necessary for hosts
597 : * which use routing redirects generated by smart gateways
598 : * to dynamically build the routing tables.
599 : */
600 0 : if (rt == NULL)
601 : goto create;
602 : /*
603 : * Don't listen to the redirect if it's
604 : * for a route to an interface.
605 : */
606 0 : if (ISSET(rt->rt_flags, RTF_GATEWAY)) {
607 0 : if (!ISSET(rt->rt_flags, RTF_HOST)) {
608 : /*
609 : * Changing from route to net => route to host.
610 : * Create new route, rather than smashing route to net.
611 : */
612 : create:
613 0 : rtfree(rt);
614 : flags |= RTF_DYNAMIC;
615 0 : bzero(&info, sizeof(info));
616 0 : info.rti_info[RTAX_DST] = dst;
617 0 : info.rti_info[RTAX_GATEWAY] = gateway;
618 0 : info.rti_ifa = ifa;
619 0 : info.rti_flags = flags;
620 0 : rt = NULL;
621 0 : error = rtrequest(RTM_ADD, &info, RTP_DEFAULT, &rt,
622 : rdomain);
623 0 : if (error == 0) {
624 0 : flags = rt->rt_flags;
625 0 : prio = rt->rt_priority;
626 0 : }
627 : stat = rts_dynamic;
628 0 : } else {
629 : /*
630 : * Smash the current notion of the gateway to
631 : * this destination. Should check about netmask!!!
632 : */
633 0 : rt->rt_flags |= RTF_MODIFIED;
634 : flags |= RTF_MODIFIED;
635 0 : prio = rt->rt_priority;
636 : stat = rts_newgateway;
637 0 : rt_setgate(rt, gateway, rdomain);
638 : }
639 : } else
640 : error = EHOSTUNREACH;
641 : done:
642 0 : if (rt) {
643 0 : if (rtp && !error)
644 0 : *rtp = rt;
645 : else
646 0 : rtfree(rt);
647 : }
648 : out:
649 0 : if (error)
650 0 : rtstat_inc(rts_badredirect);
651 0 : else if (stat != rts_ncounters)
652 0 : rtstat_inc(stat);
653 0 : bzero((caddr_t)&info, sizeof(info));
654 0 : info.rti_info[RTAX_DST] = dst;
655 0 : info.rti_info[RTAX_GATEWAY] = gateway;
656 0 : info.rti_info[RTAX_AUTHOR] = src;
657 0 : rtm_miss(RTM_REDIRECT, &info, flags, prio, ifidx, error, rdomain);
658 0 : }
659 :
660 : /*
661 : * Delete a route and generate a message
662 : */
663 : int
664 0 : rtdeletemsg(struct rtentry *rt, struct ifnet *ifp, u_int tableid)
665 : {
666 : int error;
667 0 : struct rt_addrinfo info;
668 0 : struct sockaddr_in6 sa_mask;
669 :
670 0 : KASSERT(rt->rt_ifidx == ifp->if_index);
671 :
672 : /*
673 : * Request the new route so that the entry is not actually
674 : * deleted. That will allow the information being reported to
675 : * be accurate (and consistent with route_output()).
676 : */
677 0 : memset(&info, 0, sizeof(info));
678 0 : info.rti_info[RTAX_DST] = rt_key(rt);
679 0 : info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
680 0 : if (!ISSET(rt->rt_flags, RTF_HOST))
681 0 : info.rti_info[RTAX_NETMASK] = rt_plen2mask(rt, &sa_mask);
682 0 : error = rtrequest_delete(&info, rt->rt_priority, ifp, &rt, tableid);
683 0 : rtm_send(rt, RTM_DELETE, error, tableid);
684 0 : if (error == 0)
685 0 : rtfree(rt);
686 0 : return (error);
687 0 : }
688 :
689 : static inline int
690 0 : rtequal(struct rtentry *a, struct rtentry *b)
691 : {
692 0 : if (a == b)
693 0 : return 1;
694 :
695 0 : if (memcmp(rt_key(a), rt_key(b), rt_key(a)->sa_len) == 0 &&
696 0 : rt_plen(a) == rt_plen(b))
697 0 : return 1;
698 : else
699 0 : return 0;
700 0 : }
701 :
702 : int
703 0 : rtflushclone1(struct rtentry *rt, void *arg, u_int id)
704 : {
705 0 : struct rtentry *cloningrt = arg;
706 : struct ifnet *ifp;
707 : int error;
708 :
709 0 : if (!ISSET(rt->rt_flags, RTF_CLONED))
710 0 : return 0;
711 :
712 : /* Cached route must stay alive as long as their parent are alive. */
713 0 : if (ISSET(rt->rt_flags, RTF_CACHED) && (rt->rt_parent != cloningrt))
714 0 : return 0;
715 :
716 0 : if (!rtequal(rt->rt_parent, cloningrt))
717 0 : return 0;
718 : /*
719 : * This happens when an interface with a RTF_CLONING route is
720 : * being detached. In this case it's safe to bail because all
721 : * the routes are being purged by rt_ifa_purge().
722 : */
723 0 : ifp = if_get(rt->rt_ifidx);
724 0 : if (ifp == NULL)
725 0 : return 0;
726 :
727 0 : error = rtdeletemsg(rt, ifp, id);
728 0 : if (error == 0)
729 : error = EAGAIN;
730 :
731 0 : if_put(ifp);
732 0 : return error;
733 0 : }
734 :
735 : void
736 0 : rtflushclone(unsigned int rtableid, struct rtentry *parent)
737 : {
738 :
739 : #ifdef DIAGNOSTIC
740 0 : if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
741 0 : panic("rtflushclone: called with a non-cloning route");
742 : #endif
743 0 : rtable_walk(rtableid, rt_key(parent)->sa_family, rtflushclone1, parent);
744 0 : }
745 :
746 : int
747 0 : rtrequest_delete(struct rt_addrinfo *info, u_int8_t prio, struct ifnet *ifp,
748 : struct rtentry **ret_nrt, u_int tableid)
749 : {
750 : struct rtentry *rt;
751 : int error;
752 :
753 0 : NET_ASSERT_LOCKED();
754 :
755 0 : if (!rtable_exists(tableid))
756 0 : return (EAFNOSUPPORT);
757 0 : rt = rtable_lookup(tableid, info->rti_info[RTAX_DST],
758 0 : info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY], prio);
759 0 : if (rt == NULL)
760 0 : return (ESRCH);
761 :
762 : /* Make sure that's the route the caller want to delete. */
763 0 : if (ifp != NULL && ifp->if_index != rt->rt_ifidx) {
764 0 : rtfree(rt);
765 0 : return (ESRCH);
766 : }
767 :
768 : #ifdef BFD
769 : if (ISSET(rt->rt_flags, RTF_BFD))
770 : bfdclear(rt);
771 : #endif
772 :
773 0 : error = rtable_delete(tableid, info->rti_info[RTAX_DST],
774 0 : info->rti_info[RTAX_NETMASK], rt);
775 0 : if (error != 0) {
776 0 : rtfree(rt);
777 0 : return (ESRCH);
778 : }
779 :
780 : /* Release next hop cache before flushing cloned entries. */
781 0 : rt_putgwroute(rt);
782 :
783 : /* Clean up any cloned children. */
784 0 : if (ISSET(rt->rt_flags, RTF_CLONING))
785 0 : rtflushclone(tableid, rt);
786 :
787 0 : rtfree(rt->rt_parent);
788 0 : rt->rt_parent = NULL;
789 :
790 0 : rt->rt_flags &= ~RTF_UP;
791 :
792 0 : KASSERT(ifp->if_index == rt->rt_ifidx);
793 0 : ifp->if_rtrequest(ifp, RTM_DELETE, rt);
794 :
795 0 : atomic_inc_int(&rttrash);
796 :
797 0 : if (ret_nrt != NULL)
798 0 : *ret_nrt = rt;
799 : else
800 0 : rtfree(rt);
801 :
802 0 : return (0);
803 0 : }
804 :
805 : int
806 0 : rtrequest(int req, struct rt_addrinfo *info, u_int8_t prio,
807 : struct rtentry **ret_nrt, u_int tableid)
808 : {
809 : struct ifnet *ifp;
810 : struct rtentry *rt, *crt;
811 : struct ifaddr *ifa;
812 : struct sockaddr *ndst;
813 0 : struct sockaddr_rtlabel *sa_rl, sa_rl2;
814 0 : struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK };
815 : int dlen, error;
816 :
817 0 : NET_ASSERT_LOCKED();
818 :
819 0 : if (!rtable_exists(tableid))
820 0 : return (EAFNOSUPPORT);
821 0 : if (info->rti_flags & RTF_HOST)
822 0 : info->rti_info[RTAX_NETMASK] = NULL;
823 0 : switch (req) {
824 : case RTM_DELETE:
825 0 : return (EINVAL);
826 :
827 : case RTM_RESOLVE:
828 0 : if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
829 0 : return (EINVAL);
830 0 : if ((rt->rt_flags & RTF_CLONING) == 0)
831 0 : return (EINVAL);
832 0 : KASSERT(rt->rt_ifa->ifa_ifp != NULL);
833 0 : info->rti_ifa = rt->rt_ifa;
834 0 : info->rti_flags = rt->rt_flags | (RTF_CLONED|RTF_HOST);
835 0 : info->rti_flags &= ~(RTF_CLONING|RTF_CONNECTED|RTF_STATIC);
836 0 : info->rti_info[RTAX_GATEWAY] = sdltosa(&sa_dl);
837 0 : info->rti_info[RTAX_LABEL] =
838 0 : rtlabel_id2sa(rt->rt_labelid, &sa_rl2);
839 : /* FALLTHROUGH */
840 :
841 : case RTM_ADD:
842 0 : if (info->rti_ifa == NULL)
843 0 : return (EINVAL);
844 : ifa = info->rti_ifa;
845 0 : ifp = ifa->ifa_ifp;
846 0 : if (prio == 0)
847 0 : prio = ifp->if_priority + RTP_STATIC;
848 :
849 0 : dlen = info->rti_info[RTAX_DST]->sa_len;
850 0 : ndst = malloc(dlen, M_RTABLE, M_NOWAIT);
851 0 : if (ndst == NULL)
852 0 : return (ENOBUFS);
853 :
854 0 : if (info->rti_info[RTAX_NETMASK] != NULL)
855 0 : rt_maskedcopy(info->rti_info[RTAX_DST], ndst,
856 : info->rti_info[RTAX_NETMASK]);
857 : else
858 0 : memcpy(ndst, info->rti_info[RTAX_DST], dlen);
859 :
860 0 : rt = pool_get(&rtentry_pool, PR_NOWAIT | PR_ZERO);
861 0 : if (rt == NULL) {
862 0 : free(ndst, M_RTABLE, dlen);
863 0 : return (ENOBUFS);
864 : }
865 :
866 0 : rt->rt_refcnt = 1;
867 0 : rt->rt_flags = info->rti_flags | RTF_UP;
868 0 : rt->rt_priority = prio; /* init routing priority */
869 0 : LIST_INIT(&rt->rt_timer);
870 :
871 : /* Check the link state if the table supports it. */
872 0 : if (rtable_mpath_capable(tableid, ndst->sa_family) &&
873 0 : !ISSET(rt->rt_flags, RTF_LOCAL) &&
874 0 : (!LINK_STATE_IS_UP(ifp->if_link_state) ||
875 0 : !ISSET(ifp->if_flags, IFF_UP))) {
876 0 : rt->rt_flags &= ~RTF_UP;
877 0 : rt->rt_priority |= RTP_DOWN;
878 0 : }
879 :
880 0 : if (info->rti_info[RTAX_LABEL] != NULL) {
881 0 : sa_rl = (struct sockaddr_rtlabel *)
882 : info->rti_info[RTAX_LABEL];
883 0 : rt->rt_labelid = rtlabel_name2id(sa_rl->sr_label);
884 0 : }
885 :
886 : #ifdef MPLS
887 : /* We have to allocate additional space for MPLS infos */
888 0 : if (info->rti_flags & RTF_MPLS &&
889 0 : (info->rti_info[RTAX_SRC] != NULL ||
890 0 : info->rti_info[RTAX_DST]->sa_family == AF_MPLS)) {
891 0 : error = rt_mpls_set(rt, info->rti_info[RTAX_SRC],
892 0 : info->rti_mpls);
893 0 : if (error) {
894 0 : free(ndst, M_RTABLE, dlen);
895 0 : pool_put(&rtentry_pool, rt);
896 0 : return (error);
897 : }
898 : } else
899 0 : rt_mpls_clear(rt);
900 : #endif
901 :
902 0 : ifa->ifa_refcnt++;
903 0 : rt->rt_ifa = ifa;
904 0 : rt->rt_ifidx = ifp->if_index;
905 : /*
906 : * Copy metrics and a back pointer from the cloned
907 : * route's parent.
908 : */
909 0 : if (ISSET(rt->rt_flags, RTF_CLONED)) {
910 0 : rtref(*ret_nrt);
911 0 : rt->rt_parent = *ret_nrt;
912 0 : rt->rt_rmx = (*ret_nrt)->rt_rmx;
913 0 : }
914 :
915 : /*
916 : * We must set rt->rt_gateway before adding ``rt'' to
917 : * the routing table because the radix MPATH code use
918 : * it to (re)order routes.
919 : */
920 0 : if ((error = rt_setgate(rt, info->rti_info[RTAX_GATEWAY],
921 : tableid))) {
922 0 : ifafree(ifa);
923 0 : rtfree(rt->rt_parent);
924 0 : rt_putgwroute(rt);
925 0 : free(rt->rt_gateway, M_RTABLE, 0);
926 0 : free(ndst, M_RTABLE, dlen);
927 0 : pool_put(&rtentry_pool, rt);
928 0 : return (error);
929 : }
930 :
931 0 : error = rtable_insert(tableid, ndst,
932 0 : info->rti_info[RTAX_NETMASK], info->rti_info[RTAX_GATEWAY],
933 0 : rt->rt_priority, rt);
934 0 : if (error != 0 &&
935 0 : (crt = rtable_match(tableid, ndst, NULL)) != NULL) {
936 : /* overwrite cloned route */
937 0 : if (ISSET(crt->rt_flags, RTF_CLONED)) {
938 : struct ifnet *cifp;
939 :
940 0 : cifp = if_get(crt->rt_ifidx);
941 0 : KASSERT(cifp != NULL);
942 0 : rtdeletemsg(crt, cifp, tableid);
943 0 : if_put(cifp);
944 :
945 0 : error = rtable_insert(tableid, ndst,
946 0 : info->rti_info[RTAX_NETMASK],
947 0 : info->rti_info[RTAX_GATEWAY],
948 0 : rt->rt_priority, rt);
949 0 : }
950 0 : rtfree(crt);
951 0 : }
952 0 : if (error != 0) {
953 0 : ifafree(ifa);
954 0 : rtfree(rt->rt_parent);
955 0 : rt_putgwroute(rt);
956 0 : free(rt->rt_gateway, M_RTABLE, 0);
957 0 : free(ndst, M_RTABLE, dlen);
958 0 : pool_put(&rtentry_pool, rt);
959 0 : return (EEXIST);
960 : }
961 0 : ifp->if_rtrequest(ifp, req, rt);
962 :
963 0 : if_group_routechange(info->rti_info[RTAX_DST],
964 0 : info->rti_info[RTAX_NETMASK]);
965 :
966 0 : if (ret_nrt != NULL)
967 0 : *ret_nrt = rt;
968 : else
969 0 : rtfree(rt);
970 : break;
971 : }
972 :
973 0 : return (0);
974 0 : }
975 :
976 : int
977 0 : rt_setgate(struct rtentry *rt, struct sockaddr *gate, u_int rtableid)
978 : {
979 0 : int glen = ROUNDUP(gate->sa_len);
980 : struct sockaddr *sa;
981 :
982 0 : if (rt->rt_gateway == NULL || glen != ROUNDUP(rt->rt_gateway->sa_len)) {
983 0 : sa = malloc(glen, M_RTABLE, M_NOWAIT);
984 0 : if (sa == NULL)
985 0 : return (ENOBUFS);
986 0 : if (rt->rt_gateway != NULL) {
987 0 : free(rt->rt_gateway, M_RTABLE,
988 0 : ROUNDUP(rt->rt_gateway->sa_len));
989 0 : }
990 0 : rt->rt_gateway = sa;
991 0 : }
992 0 : memmove(rt->rt_gateway, gate, glen);
993 :
994 0 : if (ISSET(rt->rt_flags, RTF_GATEWAY))
995 0 : return (rt_setgwroute(rt, rtableid));
996 :
997 0 : return (0);
998 0 : }
999 :
1000 : /*
1001 : * Return the route entry containing the next hop link-layer
1002 : * address corresponding to ``rt''.
1003 : */
1004 : struct rtentry *
1005 0 : rt_getll(struct rtentry *rt)
1006 : {
1007 0 : if (ISSET(rt->rt_flags, RTF_GATEWAY)) {
1008 0 : KASSERT(rt->rt_gwroute != NULL);
1009 0 : return (rt->rt_gwroute);
1010 : }
1011 :
1012 0 : return (rt);
1013 0 : }
1014 :
1015 : void
1016 0 : rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
1017 : struct sockaddr *netmask)
1018 : {
1019 0 : u_char *cp1 = (u_char *)src;
1020 0 : u_char *cp2 = (u_char *)dst;
1021 0 : u_char *cp3 = (u_char *)netmask;
1022 0 : u_char *cplim = cp2 + *cp3;
1023 0 : u_char *cplim2 = cp2 + *cp1;
1024 :
1025 0 : *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
1026 0 : cp3 += 2;
1027 0 : if (cplim > cplim2)
1028 0 : cplim = cplim2;
1029 0 : while (cp2 < cplim)
1030 0 : *cp2++ = *cp1++ & *cp3++;
1031 0 : if (cp2 < cplim2)
1032 0 : bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
1033 0 : }
1034 :
1035 : int
1036 0 : rt_ifa_add(struct ifaddr *ifa, int flags, struct sockaddr *dst)
1037 : {
1038 0 : struct ifnet *ifp = ifa->ifa_ifp;
1039 0 : struct rtentry *rt;
1040 0 : struct sockaddr_rtlabel sa_rl;
1041 0 : struct rt_addrinfo info;
1042 0 : unsigned int rtableid = ifp->if_rdomain;
1043 0 : uint8_t prio = ifp->if_priority + RTP_STATIC;
1044 : int error;
1045 :
1046 0 : memset(&info, 0, sizeof(info));
1047 0 : info.rti_ifa = ifa;
1048 0 : info.rti_flags = flags | RTF_MPATH;
1049 0 : info.rti_info[RTAX_DST] = dst;
1050 0 : if (flags & RTF_LLINFO)
1051 0 : info.rti_info[RTAX_GATEWAY] = sdltosa(ifp->if_sadl);
1052 : else
1053 0 : info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
1054 0 : info.rti_info[RTAX_LABEL] = rtlabel_id2sa(ifp->if_rtlabelid, &sa_rl);
1055 :
1056 : #ifdef MPLS
1057 0 : if ((flags & RTF_MPLS) == RTF_MPLS) {
1058 0 : info.rti_mpls = MPLS_OP_POP;
1059 : /* MPLS routes only exist in rdomain 0 */
1060 : rtableid = 0;
1061 0 : }
1062 : #endif /* MPLS */
1063 :
1064 0 : if ((flags & RTF_HOST) == 0)
1065 0 : info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1066 :
1067 0 : if (flags & (RTF_LOCAL|RTF_BROADCAST))
1068 0 : prio = RTP_LOCAL;
1069 :
1070 0 : if (flags & RTF_CONNECTED)
1071 0 : prio = ifp->if_priority + RTP_CONNECTED;
1072 :
1073 0 : error = rtrequest(RTM_ADD, &info, prio, &rt, rtableid);
1074 0 : if (error == 0) {
1075 : /*
1076 : * A local route is created for every address configured
1077 : * on an interface, so use this information to notify
1078 : * userland that a new address has been added.
1079 : */
1080 0 : if (flags & RTF_LOCAL)
1081 0 : rtm_addr(RTM_NEWADDR, ifa);
1082 0 : rtm_send(rt, RTM_ADD, 0, rtableid);
1083 0 : rtfree(rt);
1084 0 : }
1085 0 : return (error);
1086 0 : }
1087 :
1088 : int
1089 0 : rt_ifa_del(struct ifaddr *ifa, int flags, struct sockaddr *dst)
1090 : {
1091 0 : struct ifnet *ifp = ifa->ifa_ifp;
1092 0 : struct rtentry *rt;
1093 : struct mbuf *m = NULL;
1094 : struct sockaddr *deldst;
1095 0 : struct rt_addrinfo info;
1096 0 : struct sockaddr_rtlabel sa_rl;
1097 0 : unsigned int rtableid = ifp->if_rdomain;
1098 0 : uint8_t prio = ifp->if_priority + RTP_STATIC;
1099 : int error;
1100 :
1101 : #ifdef MPLS
1102 0 : if ((flags & RTF_MPLS) == RTF_MPLS)
1103 : /* MPLS routes only exist in rdomain 0 */
1104 0 : rtableid = 0;
1105 : #endif /* MPLS */
1106 :
1107 0 : if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
1108 0 : m = m_get(M_DONTWAIT, MT_SONAME);
1109 0 : if (m == NULL)
1110 0 : return (ENOBUFS);
1111 0 : deldst = mtod(m, struct sockaddr *);
1112 0 : rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
1113 : dst = deldst;
1114 0 : }
1115 :
1116 0 : memset(&info, 0, sizeof(info));
1117 0 : info.rti_ifa = ifa;
1118 0 : info.rti_flags = flags;
1119 0 : info.rti_info[RTAX_DST] = dst;
1120 0 : if ((flags & RTF_LLINFO) == 0)
1121 0 : info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
1122 0 : info.rti_info[RTAX_LABEL] = rtlabel_id2sa(ifp->if_rtlabelid, &sa_rl);
1123 :
1124 0 : if ((flags & RTF_HOST) == 0)
1125 0 : info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
1126 :
1127 0 : if (flags & (RTF_LOCAL|RTF_BROADCAST))
1128 0 : prio = RTP_LOCAL;
1129 :
1130 0 : if (flags & RTF_CONNECTED)
1131 0 : prio = ifp->if_priority + RTP_CONNECTED;
1132 :
1133 0 : error = rtrequest_delete(&info, prio, ifp, &rt, rtableid);
1134 0 : if (error == 0) {
1135 0 : rtm_send(rt, RTM_DELETE, 0, rtableid);
1136 0 : if (flags & RTF_LOCAL)
1137 0 : rtm_addr(RTM_DELADDR, ifa);
1138 0 : rtfree(rt);
1139 0 : }
1140 0 : m_free(m);
1141 :
1142 0 : return (error);
1143 0 : }
1144 :
1145 : /*
1146 : * Add ifa's address as a local rtentry.
1147 : */
1148 : int
1149 0 : rt_ifa_addlocal(struct ifaddr *ifa)
1150 : {
1151 : struct rtentry *rt;
1152 : u_int flags = RTF_HOST|RTF_LOCAL;
1153 : int error = 0;
1154 :
1155 : /*
1156 : * If the configured address correspond to the magical "any"
1157 : * address do not add a local route entry because that might
1158 : * corrupt the routing tree which uses this value for the
1159 : * default routes.
1160 : */
1161 0 : switch (ifa->ifa_addr->sa_family) {
1162 : case AF_INET:
1163 0 : if (satosin(ifa->ifa_addr)->sin_addr.s_addr == INADDR_ANY)
1164 0 : return (0);
1165 : break;
1166 : #ifdef INET6
1167 : case AF_INET6:
1168 0 : if (IN6_ARE_ADDR_EQUAL(&satosin6(ifa->ifa_addr)->sin6_addr,
1169 : &in6addr_any))
1170 0 : return (0);
1171 : break;
1172 : #endif
1173 : default:
1174 : break;
1175 : }
1176 :
1177 0 : if (!ISSET(ifa->ifa_ifp->if_flags, (IFF_LOOPBACK|IFF_POINTOPOINT)))
1178 0 : flags |= RTF_LLINFO;
1179 :
1180 : /* If there is no local entry, allocate one. */
1181 0 : rt = rtalloc(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
1182 0 : if (rt == NULL || ISSET(rt->rt_flags, flags) != flags)
1183 0 : error = rt_ifa_add(ifa, flags, ifa->ifa_addr);
1184 0 : rtfree(rt);
1185 :
1186 0 : return (error);
1187 0 : }
1188 :
1189 : /*
1190 : * Remove local rtentry of ifa's addresss if it exists.
1191 : */
1192 : int
1193 0 : rt_ifa_dellocal(struct ifaddr *ifa)
1194 : {
1195 : struct rtentry *rt;
1196 : u_int flags = RTF_HOST|RTF_LOCAL;
1197 : int error = 0;
1198 :
1199 : /*
1200 : * We do not add local routes for such address, so do not bother
1201 : * removing them.
1202 : */
1203 0 : switch (ifa->ifa_addr->sa_family) {
1204 : case AF_INET:
1205 0 : if (satosin(ifa->ifa_addr)->sin_addr.s_addr == INADDR_ANY)
1206 0 : return (0);
1207 : break;
1208 : #ifdef INET6
1209 : case AF_INET6:
1210 0 : if (IN6_ARE_ADDR_EQUAL(&satosin6(ifa->ifa_addr)->sin6_addr,
1211 : &in6addr_any))
1212 0 : return (0);
1213 : break;
1214 : #endif
1215 : default:
1216 : break;
1217 : }
1218 :
1219 0 : if (!ISSET(ifa->ifa_ifp->if_flags, (IFF_LOOPBACK|IFF_POINTOPOINT)))
1220 0 : flags |= RTF_LLINFO;
1221 :
1222 : /*
1223 : * Before deleting, check if a corresponding local host
1224 : * route surely exists. With this check, we can avoid to
1225 : * delete an interface direct route whose destination is same
1226 : * as the address being removed. This can happen when removing
1227 : * a subnet-router anycast address on an interface attached
1228 : * to a shared medium.
1229 : */
1230 0 : rt = rtalloc(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
1231 0 : if (rt != NULL && ISSET(rt->rt_flags, flags) == flags)
1232 0 : error = rt_ifa_del(ifa, flags, ifa->ifa_addr);
1233 0 : rtfree(rt);
1234 :
1235 0 : return (error);
1236 0 : }
1237 :
1238 : /*
1239 : * Remove all addresses attached to ``ifa''.
1240 : */
1241 : void
1242 0 : rt_ifa_purge(struct ifaddr *ifa)
1243 : {
1244 0 : struct ifnet *ifp = ifa->ifa_ifp;
1245 : unsigned int rtableid;
1246 : int i;
1247 :
1248 0 : KASSERT(ifp != NULL);
1249 :
1250 0 : for (rtableid = 0; rtableid < rtmap_limit; rtableid++) {
1251 : /* skip rtables that are not in the rdomain of the ifp */
1252 0 : if (rtable_l2(rtableid) != ifp->if_rdomain)
1253 : continue;
1254 0 : for (i = 1; i <= AF_MAX; i++) {
1255 0 : rtable_walk(rtableid, i, rt_ifa_purge_walker, ifa);
1256 : }
1257 : }
1258 0 : }
1259 :
1260 : int
1261 0 : rt_ifa_purge_walker(struct rtentry *rt, void *vifa, unsigned int rtableid)
1262 : {
1263 0 : struct ifaddr *ifa = vifa;
1264 0 : struct ifnet *ifp = ifa->ifa_ifp;
1265 : int error;
1266 :
1267 0 : if (rt->rt_ifa != ifa)
1268 0 : return (0);
1269 :
1270 0 : if ((error = rtdeletemsg(rt, ifp, rtableid))) {
1271 0 : return (error);
1272 : }
1273 :
1274 0 : return (EAGAIN);
1275 0 : }
1276 :
1277 : /*
1278 : * Route timer routines. These routes allow functions to be called
1279 : * for various routes at any time. This is useful in supporting
1280 : * path MTU discovery and redirect route deletion.
1281 : *
1282 : * This is similar to some BSDI internal functions, but it provides
1283 : * for multiple queues for efficiency's sake...
1284 : */
1285 :
1286 : LIST_HEAD(, rttimer_queue) rttimer_queue_head;
1287 : static int rt_init_done = 0;
1288 :
1289 : #define RTTIMER_CALLOUT(r) { \
1290 : if (r->rtt_func != NULL) { \
1291 : (*r->rtt_func)(r->rtt_rt, r); \
1292 : } else { \
1293 : struct ifnet *ifp; \
1294 : \
1295 : ifp = if_get(r->rtt_rt->rt_ifidx); \
1296 : if (ifp != NULL) \
1297 : rtdeletemsg(r->rtt_rt, ifp, r->rtt_tableid); \
1298 : if_put(ifp); \
1299 : } \
1300 : }
1301 :
1302 : /*
1303 : * Some subtle order problems with domain initialization mean that
1304 : * we cannot count on this being run from rt_init before various
1305 : * protocol initializations are done. Therefore, we make sure
1306 : * that this is run when the first queue is added...
1307 : */
1308 :
1309 : void
1310 0 : rt_timer_init(void)
1311 : {
1312 : static struct timeout rt_timer_timeout;
1313 :
1314 0 : if (rt_init_done)
1315 0 : panic("rt_timer_init: already initialized");
1316 :
1317 0 : pool_init(&rttimer_pool, sizeof(struct rttimer), 0, IPL_SOFTNET, 0,
1318 : "rttmr", NULL);
1319 :
1320 0 : LIST_INIT(&rttimer_queue_head);
1321 0 : timeout_set_proc(&rt_timer_timeout, rt_timer_timer, &rt_timer_timeout);
1322 0 : timeout_add_sec(&rt_timer_timeout, 1);
1323 0 : rt_init_done = 1;
1324 0 : }
1325 :
1326 : struct rttimer_queue *
1327 0 : rt_timer_queue_create(u_int timeout)
1328 : {
1329 : struct rttimer_queue *rtq;
1330 :
1331 0 : if (rt_init_done == 0)
1332 0 : rt_timer_init();
1333 :
1334 0 : if ((rtq = malloc(sizeof(*rtq), M_RTABLE, M_NOWAIT|M_ZERO)) == NULL)
1335 0 : return (NULL);
1336 :
1337 0 : rtq->rtq_timeout = timeout;
1338 0 : rtq->rtq_count = 0;
1339 0 : TAILQ_INIT(&rtq->rtq_head);
1340 0 : LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
1341 :
1342 0 : return (rtq);
1343 0 : }
1344 :
1345 : void
1346 0 : rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
1347 : {
1348 0 : rtq->rtq_timeout = timeout;
1349 0 : }
1350 :
1351 : void
1352 0 : rt_timer_queue_destroy(struct rttimer_queue *rtq)
1353 : {
1354 : struct rttimer *r;
1355 :
1356 0 : NET_ASSERT_LOCKED();
1357 :
1358 0 : while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
1359 0 : LIST_REMOVE(r, rtt_link);
1360 0 : TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1361 0 : RTTIMER_CALLOUT(r);
1362 0 : pool_put(&rttimer_pool, r);
1363 0 : if (rtq->rtq_count > 0)
1364 0 : rtq->rtq_count--;
1365 : else
1366 0 : printf("rt_timer_queue_destroy: rtq_count reached 0\n");
1367 : }
1368 :
1369 0 : LIST_REMOVE(rtq, rtq_link);
1370 0 : free(rtq, M_RTABLE, sizeof(*rtq));
1371 0 : }
1372 :
1373 : unsigned long
1374 0 : rt_timer_queue_count(struct rttimer_queue *rtq)
1375 : {
1376 0 : return (rtq->rtq_count);
1377 : }
1378 :
1379 : void
1380 0 : rt_timer_remove_all(struct rtentry *rt)
1381 : {
1382 : struct rttimer *r;
1383 :
1384 0 : while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
1385 0 : LIST_REMOVE(r, rtt_link);
1386 0 : TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1387 0 : if (r->rtt_queue->rtq_count > 0)
1388 0 : r->rtt_queue->rtq_count--;
1389 : else
1390 0 : printf("rt_timer_remove_all: rtq_count reached 0\n");
1391 0 : pool_put(&rttimer_pool, r);
1392 : }
1393 0 : }
1394 :
1395 : int
1396 0 : rt_timer_add(struct rtentry *rt, void (*func)(struct rtentry *,
1397 : struct rttimer *), struct rttimer_queue *queue, u_int rtableid)
1398 : {
1399 : struct rttimer *r;
1400 : long current_time;
1401 :
1402 0 : current_time = time_uptime;
1403 0 : rt->rt_expire = time_uptime + queue->rtq_timeout;
1404 :
1405 : /*
1406 : * If there's already a timer with this action, destroy it before
1407 : * we add a new one.
1408 : */
1409 0 : LIST_FOREACH(r, &rt->rt_timer, rtt_link) {
1410 0 : if (r->rtt_func == func) {
1411 0 : LIST_REMOVE(r, rtt_link);
1412 0 : TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
1413 0 : if (r->rtt_queue->rtq_count > 0)
1414 0 : r->rtt_queue->rtq_count--;
1415 : else
1416 0 : printf("rt_timer_add: rtq_count reached 0\n");
1417 0 : pool_put(&rttimer_pool, r);
1418 0 : break; /* only one per list, so we can quit... */
1419 : }
1420 : }
1421 :
1422 0 : r = pool_get(&rttimer_pool, PR_NOWAIT | PR_ZERO);
1423 0 : if (r == NULL)
1424 0 : return (ENOBUFS);
1425 :
1426 0 : r->rtt_rt = rt;
1427 0 : r->rtt_time = current_time;
1428 0 : r->rtt_func = func;
1429 0 : r->rtt_queue = queue;
1430 0 : r->rtt_tableid = rtableid;
1431 0 : LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
1432 0 : TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1433 0 : r->rtt_queue->rtq_count++;
1434 :
1435 0 : return (0);
1436 0 : }
1437 :
1438 : void
1439 0 : rt_timer_timer(void *arg)
1440 : {
1441 0 : struct timeout *to = (struct timeout *)arg;
1442 : struct rttimer_queue *rtq;
1443 : struct rttimer *r;
1444 : long current_time;
1445 :
1446 0 : current_time = time_uptime;
1447 :
1448 0 : NET_LOCK();
1449 0 : LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) {
1450 0 : while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1451 0 : (r->rtt_time + rtq->rtq_timeout) < current_time) {
1452 0 : LIST_REMOVE(r, rtt_link);
1453 0 : TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1454 0 : RTTIMER_CALLOUT(r);
1455 0 : pool_put(&rttimer_pool, r);
1456 0 : if (rtq->rtq_count > 0)
1457 0 : rtq->rtq_count--;
1458 : else
1459 0 : printf("rt_timer_timer: rtq_count reached 0\n");
1460 : }
1461 : }
1462 0 : NET_UNLOCK();
1463 :
1464 0 : timeout_add_sec(to, 1);
1465 0 : }
1466 :
1467 : #ifdef MPLS
1468 : int
1469 0 : rt_mpls_set(struct rtentry *rt, struct sockaddr *src, uint8_t op)
1470 : {
1471 0 : struct sockaddr_mpls *psa_mpls = (struct sockaddr_mpls *)src;
1472 : struct rt_mpls *rt_mpls;
1473 :
1474 0 : rt->rt_llinfo = malloc(sizeof(struct rt_mpls), M_TEMP, M_NOWAIT|M_ZERO);
1475 0 : if (rt->rt_llinfo == NULL)
1476 0 : return (ENOMEM);
1477 :
1478 0 : rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
1479 0 : if (psa_mpls != NULL)
1480 0 : rt_mpls->mpls_label = psa_mpls->smpls_label;
1481 :
1482 0 : rt_mpls->mpls_operation = op;
1483 :
1484 : /* XXX: set experimental bits */
1485 0 : rt->rt_flags |= RTF_MPLS;
1486 :
1487 0 : return (0);
1488 0 : }
1489 :
1490 : void
1491 0 : rt_mpls_clear(struct rtentry *rt)
1492 : {
1493 0 : if (rt->rt_llinfo != NULL && rt->rt_flags & RTF_MPLS) {
1494 0 : free(rt->rt_llinfo, M_TEMP, sizeof(struct rt_mpls));
1495 0 : rt->rt_llinfo = NULL;
1496 0 : }
1497 0 : rt->rt_flags &= ~RTF_MPLS;
1498 0 : }
1499 : #endif
1500 :
1501 : u_int16_t
1502 0 : rtlabel_name2id(char *name)
1503 : {
1504 : struct rt_label *label, *p;
1505 : u_int16_t new_id = 1;
1506 :
1507 0 : if (!name[0])
1508 0 : return (0);
1509 :
1510 0 : TAILQ_FOREACH(label, &rt_labels, rtl_entry)
1511 0 : if (strcmp(name, label->rtl_name) == 0) {
1512 0 : label->rtl_ref++;
1513 0 : return (label->rtl_id);
1514 : }
1515 :
1516 : /*
1517 : * to avoid fragmentation, we do a linear search from the beginning
1518 : * and take the first free slot we find. if there is none or the list
1519 : * is empty, append a new entry at the end.
1520 : */
1521 0 : TAILQ_FOREACH(p, &rt_labels, rtl_entry) {
1522 0 : if (p->rtl_id != new_id)
1523 : break;
1524 0 : new_id = p->rtl_id + 1;
1525 : }
1526 0 : if (new_id > LABELID_MAX)
1527 0 : return (0);
1528 :
1529 0 : label = malloc(sizeof(*label), M_RTABLE, M_NOWAIT|M_ZERO);
1530 0 : if (label == NULL)
1531 0 : return (0);
1532 0 : strlcpy(label->rtl_name, name, sizeof(label->rtl_name));
1533 0 : label->rtl_id = new_id;
1534 0 : label->rtl_ref++;
1535 :
1536 0 : if (p != NULL) /* insert new entry before p */
1537 0 : TAILQ_INSERT_BEFORE(p, label, rtl_entry);
1538 : else /* either list empty or no free slot in between */
1539 0 : TAILQ_INSERT_TAIL(&rt_labels, label, rtl_entry);
1540 :
1541 0 : return (label->rtl_id);
1542 0 : }
1543 :
1544 : const char *
1545 0 : rtlabel_id2name(u_int16_t id)
1546 : {
1547 : struct rt_label *label;
1548 :
1549 0 : TAILQ_FOREACH(label, &rt_labels, rtl_entry)
1550 0 : if (label->rtl_id == id)
1551 0 : return (label->rtl_name);
1552 :
1553 0 : return (NULL);
1554 0 : }
1555 :
1556 : struct sockaddr *
1557 0 : rtlabel_id2sa(u_int16_t labelid, struct sockaddr_rtlabel *sa_rl)
1558 : {
1559 : const char *label;
1560 :
1561 0 : if (labelid == 0 || (label = rtlabel_id2name(labelid)) == NULL)
1562 0 : return (NULL);
1563 :
1564 0 : bzero(sa_rl, sizeof(*sa_rl));
1565 0 : sa_rl->sr_len = sizeof(*sa_rl);
1566 0 : sa_rl->sr_family = AF_UNSPEC;
1567 0 : strlcpy(sa_rl->sr_label, label, sizeof(sa_rl->sr_label));
1568 :
1569 0 : return ((struct sockaddr *)sa_rl);
1570 0 : }
1571 :
1572 : void
1573 0 : rtlabel_unref(u_int16_t id)
1574 : {
1575 : struct rt_label *p, *next;
1576 :
1577 0 : if (id == 0)
1578 0 : return;
1579 :
1580 0 : TAILQ_FOREACH_SAFE(p, &rt_labels, rtl_entry, next) {
1581 0 : if (id == p->rtl_id) {
1582 0 : if (--p->rtl_ref == 0) {
1583 0 : TAILQ_REMOVE(&rt_labels, p, rtl_entry);
1584 0 : free(p, M_RTABLE, sizeof(*p));
1585 0 : }
1586 : break;
1587 : }
1588 : }
1589 0 : }
1590 :
1591 : void
1592 0 : rt_if_track(struct ifnet *ifp)
1593 : {
1594 : int i;
1595 : u_int tid;
1596 :
1597 0 : for (tid = 0; tid < rtmap_limit; tid++) {
1598 : /* skip rtables that are not in the rdomain of the ifp */
1599 0 : if (rtable_l2(tid) != ifp->if_rdomain)
1600 : continue;
1601 0 : for (i = 1; i <= AF_MAX; i++) {
1602 0 : if (!rtable_mpath_capable(tid, i))
1603 : continue;
1604 :
1605 0 : rtable_walk(tid, i, rt_if_linkstate_change, ifp);
1606 0 : }
1607 : }
1608 0 : }
1609 :
1610 : int
1611 0 : rt_if_linkstate_change(struct rtentry *rt, void *arg, u_int id)
1612 : {
1613 0 : struct ifnet *ifp = arg;
1614 0 : struct sockaddr_in6 sa_mask;
1615 : int error;
1616 :
1617 0 : if (rt->rt_ifidx != ifp->if_index)
1618 0 : return (0);
1619 :
1620 : /* Local routes are always usable. */
1621 0 : if (rt->rt_flags & RTF_LOCAL) {
1622 0 : rt->rt_flags |= RTF_UP;
1623 0 : return (0);
1624 : }
1625 :
1626 0 : if (LINK_STATE_IS_UP(ifp->if_link_state) && ifp->if_flags & IFF_UP) {
1627 0 : if (ISSET(rt->rt_flags, RTF_UP))
1628 0 : return (0);
1629 :
1630 : /* bring route up */
1631 0 : rt->rt_flags |= RTF_UP;
1632 0 : error = rtable_mpath_reprio(id, rt_key(rt),
1633 0 : rt_plen2mask(rt, &sa_mask), rt->rt_priority & RTP_MASK, rt);
1634 0 : } else {
1635 : /*
1636 : * Remove redirected and cloned routes (mainly ARP)
1637 : * from down interfaces so we have a chance to get
1638 : * new routes from a better source.
1639 : */
1640 0 : if (ISSET(rt->rt_flags, RTF_CLONED|RTF_DYNAMIC) &&
1641 0 : !ISSET(rt->rt_flags, RTF_CACHED|RTF_BFD)) {
1642 0 : if ((error = rtdeletemsg(rt, ifp, id)))
1643 0 : return (error);
1644 0 : return (EAGAIN);
1645 : }
1646 :
1647 0 : if (!ISSET(rt->rt_flags, RTF_UP))
1648 0 : return (0);
1649 :
1650 : /* take route down */
1651 0 : rt->rt_flags &= ~RTF_UP;
1652 0 : error = rtable_mpath_reprio(id, rt_key(rt),
1653 0 : rt_plen2mask(rt, &sa_mask), rt->rt_priority | RTP_DOWN, rt);
1654 : }
1655 0 : if_group_routechange(rt_key(rt), rt_plen2mask(rt, &sa_mask));
1656 :
1657 0 : return (error);
1658 0 : }
1659 :
1660 : struct sockaddr *
1661 0 : rt_plentosa(sa_family_t af, int plen, struct sockaddr_in6 *sa_mask)
1662 : {
1663 0 : struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask;
1664 : #ifdef INET6
1665 : struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask;
1666 : #endif
1667 :
1668 0 : KASSERT(plen >= 0 || plen == -1);
1669 :
1670 0 : if (plen == -1)
1671 0 : return (NULL);
1672 :
1673 0 : memset(sa_mask, 0, sizeof(*sa_mask));
1674 :
1675 0 : switch (af) {
1676 : case AF_INET:
1677 0 : sin->sin_family = AF_INET;
1678 0 : sin->sin_len = sizeof(struct sockaddr_in);
1679 0 : in_prefixlen2mask(&sin->sin_addr, plen);
1680 0 : break;
1681 : #ifdef INET6
1682 : case AF_INET6:
1683 0 : sin6->sin6_family = AF_INET6;
1684 0 : sin6->sin6_len = sizeof(struct sockaddr_in6);
1685 0 : in6_prefixlen2mask(&sin6->sin6_addr, plen);
1686 0 : break;
1687 : #endif /* INET6 */
1688 : default:
1689 0 : return (NULL);
1690 : }
1691 :
1692 0 : return ((struct sockaddr *)sa_mask);
1693 0 : }
1694 :
1695 : struct sockaddr *
1696 0 : rt_plen2mask(struct rtentry *rt, struct sockaddr_in6 *sa_mask)
1697 : {
1698 0 : return (rt_plentosa(rt_key(rt)->sa_family, rt_plen(rt), sa_mask));
1699 : }
1700 :
1701 : #ifdef DDB
1702 : #include <machine/db_machdep.h>
1703 : #include <ddb/db_output.h>
1704 :
1705 : void
1706 0 : db_print_sa(struct sockaddr *sa)
1707 : {
1708 : int len;
1709 : u_char *p;
1710 :
1711 0 : if (sa == NULL) {
1712 0 : db_printf("[NULL]");
1713 0 : return;
1714 : }
1715 :
1716 0 : p = (u_char *)sa;
1717 0 : len = sa->sa_len;
1718 0 : db_printf("[");
1719 0 : while (len > 0) {
1720 0 : db_printf("%d", *p);
1721 0 : p++;
1722 0 : len--;
1723 0 : if (len)
1724 0 : db_printf(",");
1725 : }
1726 0 : db_printf("]\n");
1727 0 : }
1728 :
1729 : void
1730 0 : db_print_ifa(struct ifaddr *ifa)
1731 : {
1732 0 : if (ifa == NULL)
1733 : return;
1734 0 : db_printf(" ifa_addr=");
1735 0 : db_print_sa(ifa->ifa_addr);
1736 0 : db_printf(" ifa_dsta=");
1737 0 : db_print_sa(ifa->ifa_dstaddr);
1738 0 : db_printf(" ifa_mask=");
1739 0 : db_print_sa(ifa->ifa_netmask);
1740 0 : db_printf(" flags=0x%x, refcnt=%d, metric=%d\n",
1741 0 : ifa->ifa_flags, ifa->ifa_refcnt, ifa->ifa_metric);
1742 0 : }
1743 :
1744 : /*
1745 : * Function to pass to rtalble_walk().
1746 : * Return non-zero error to abort walk.
1747 : */
1748 : int
1749 0 : db_show_rtentry(struct rtentry *rt, void *w, unsigned int id)
1750 : {
1751 0 : db_printf("rtentry=%p", rt);
1752 :
1753 0 : db_printf(" flags=0x%x refcnt=%d use=%llu expire=%lld rtableid=%u\n",
1754 0 : rt->rt_flags, rt->rt_refcnt, rt->rt_use, rt->rt_expire, id);
1755 :
1756 0 : db_printf(" key="); db_print_sa(rt_key(rt));
1757 0 : db_printf(" plen=%d", rt_plen(rt));
1758 0 : db_printf(" gw="); db_print_sa(rt->rt_gateway);
1759 0 : db_printf(" ifidx=%u ", rt->rt_ifidx);
1760 0 : db_printf(" ifa=%p\n", rt->rt_ifa);
1761 0 : db_print_ifa(rt->rt_ifa);
1762 :
1763 0 : db_printf(" gwroute=%p llinfo=%p\n", rt->rt_gwroute, rt->rt_llinfo);
1764 0 : return (0);
1765 : }
1766 :
1767 : /*
1768 : * Function to print all the route trees.
1769 : * Use this from ddb: "call db_show_arptab"
1770 : */
1771 : int
1772 0 : db_show_arptab(void)
1773 : {
1774 0 : db_printf("Route tree for AF_INET\n");
1775 0 : rtable_walk(0, AF_INET, db_show_rtentry, NULL);
1776 0 : return (0);
1777 : }
1778 : #endif /* DDB */
|