LCOV - code coverage report
Current view: top level - net - route.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 814 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 50 0.0 %
Legend: Lines: hit not hit

          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 */

Generated by: LCOV version 1.13