1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 2942e9e16dSRuslan Ermilov * @(#)route.c 8.3.1.1 (Berkeley) 2/23/95 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 328b07e49aSJulian Elischer /************************************************************************ 338b07e49aSJulian Elischer * Note: In this file a 'fib' is a "forwarding information base" * 348b07e49aSJulian Elischer * Which is the new name for an in kernel routing (next hop) table. * 358b07e49aSJulian Elischer ***********************************************************************/ 36df8bae1dSRodney W. Grimes 371d5e9e22SEivind Eklund #include "opt_inet.h" 388b07e49aSJulian Elischer #include "opt_route.h" 394bd49128SPeter Wemm #include "opt_mrouting.h" 40e440aed9SQing Li #include "opt_mpath.h" 414bd49128SPeter Wemm 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 446e6b3f7cSQing Li #include <sys/syslog.h> 454d1d4912SBruce Evans #include <sys/malloc.h> 46df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 488b07e49aSJulian Elischer #include <sys/sysctl.h> 493120b9d4SKip Macy #include <sys/syslog.h> 508b07e49aSJulian Elischer #include <sys/sysproto.h> 518b07e49aSJulian Elischer #include <sys/proc.h> 52df8bae1dSRodney W. Grimes #include <sys/domain.h> 53cb64988fSLuoqi Chen #include <sys/kernel.h> 54df8bae1dSRodney W. Grimes 55df8bae1dSRodney W. Grimes #include <net/if.h> 566e6b3f7cSQing Li #include <net/if_dl.h> 57df8bae1dSRodney W. Grimes #include <net/route.h> 58530c0060SRobert Watson #include <net/vnet.h> 59df8bae1dSRodney W. Grimes 60e440aed9SQing Li #ifdef RADIX_MPATH 61e440aed9SQing Li #include <net/radix_mpath.h> 62e440aed9SQing Li #endif 63e440aed9SQing Li 64df8bae1dSRodney W. Grimes #include <netinet/in.h> 65b5e8ce9fSBruce Evans #include <netinet/ip_mroute.h> 66df8bae1dSRodney W. Grimes 672dc1d581SAndre Oppermann #include <vm/uma.h> 682dc1d581SAndre Oppermann 698b07e49aSJulian Elischer u_int rt_numfibs = RT_NUMFIBS; 708b07e49aSJulian Elischer SYSCTL_INT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, ""); 7166e8505fSJulian Elischer /* 7266e8505fSJulian Elischer * Allow the boot code to allow LESS than RT_MAXFIBS to be used. 7366e8505fSJulian Elischer * We can't do more because storage is statically allocated for now. 7466e8505fSJulian Elischer * (for compatibility reasons.. this will change). 7566e8505fSJulian Elischer */ 768b07e49aSJulian Elischer TUNABLE_INT("net.fibs", &rt_numfibs); 778b07e49aSJulian Elischer 7866e8505fSJulian Elischer /* 7966e8505fSJulian Elischer * By default add routes to all fibs for new interfaces. 8066e8505fSJulian Elischer * Once this is set to 0 then only allocate routes on interface 8166e8505fSJulian Elischer * changes for the FIB of the caller when adding a new set of addresses 8266e8505fSJulian Elischer * to an interface. XXX this is a shotgun aproach to a problem that needs 8366e8505fSJulian Elischer * a more fine grained solution.. that will come. 8466e8505fSJulian Elischer */ 8566e8505fSJulian Elischer u_int rt_add_addr_allfibs = 1; 8666e8505fSJulian Elischer SYSCTL_INT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW, 8766e8505fSJulian Elischer &rt_add_addr_allfibs, 0, ""); 8866e8505fSJulian Elischer TUNABLE_INT("net.add_addr_allfibs", &rt_add_addr_allfibs); 8966e8505fSJulian Elischer 90eddfbb76SRobert Watson VNET_DEFINE(struct radix_node_head *, rt_tables); 91eddfbb76SRobert Watson static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ 92eddfbb76SRobert Watson VNET_DEFINE(int, rttrash); /* routes not in table but not freed */ 93eddfbb76SRobert Watson VNET_DEFINE(struct rtstat, rtstat); 94df8bae1dSRodney W. Grimes 951e77c105SRobert Watson #define V_rt_tables VNET(rt_tables) 961e77c105SRobert Watson #define V_rtzone VNET(rtzone) 971e77c105SRobert Watson #define V_rttrash VNET(rttrash) 981e77c105SRobert Watson #define V_rtstat VNET(rtstat) 99b58ea5f3SBjoern A. Zeeb 100929ddbbbSAlfred Perlstein static void rt_maskedcopy(struct sockaddr *, 101929ddbbbSAlfred Perlstein struct sockaddr *, struct sockaddr *); 102bfe1aba4SMarko Zec 103d6941ce9SLuigi Rizzo /* compare two sockaddr structures */ 104d6941ce9SLuigi Rizzo #define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) 105d6941ce9SLuigi Rizzo 106d6941ce9SLuigi Rizzo /* 107d6941ce9SLuigi Rizzo * Convert a 'struct radix_node *' to a 'struct rtentry *'. 108d6941ce9SLuigi Rizzo * The operation can be done safely (in this code) because a 109d6941ce9SLuigi Rizzo * 'struct rtentry' starts with two 'struct radix_node''s, the first 110d6941ce9SLuigi Rizzo * one representing leaf nodes in the routing tree, which is 111d6941ce9SLuigi Rizzo * what the code in radix.c passes us as a 'struct radix_node'. 112d6941ce9SLuigi Rizzo * 113d6941ce9SLuigi Rizzo * But because there are a lot of assumptions in this conversion, 114d6941ce9SLuigi Rizzo * do not cast explicitly, but always use the macro below. 115d6941ce9SLuigi Rizzo */ 116d6941ce9SLuigi Rizzo #define RNTORT(p) ((struct rtentry *)(p)) 117d6941ce9SLuigi Rizzo 1188b07e49aSJulian Elischer #if 0 1198b07e49aSJulian Elischer /* default fib for tunnels to use */ 1208b07e49aSJulian Elischer u_int tunnel_fib = 0; 1218b07e49aSJulian Elischer SYSCTL_INT(_net, OID_AUTO, tunnelfib, CTLFLAG_RD, &tunnel_fib, 0, ""); 1228b07e49aSJulian Elischer #endif 1238b07e49aSJulian Elischer 1248b07e49aSJulian Elischer /* 1258b07e49aSJulian Elischer * handler for net.my_fibnum 1268b07e49aSJulian Elischer */ 1278b07e49aSJulian Elischer static int 1288b07e49aSJulian Elischer sysctl_my_fibnum(SYSCTL_HANDLER_ARGS) 129df8bae1dSRodney W. Grimes { 1308b07e49aSJulian Elischer int fibnum; 1318b07e49aSJulian Elischer int error; 1328b07e49aSJulian Elischer 1338b07e49aSJulian Elischer fibnum = curthread->td_proc->p_fibnum; 1348b07e49aSJulian Elischer error = sysctl_handle_int(oidp, &fibnum, 0, req); 1358b07e49aSJulian Elischer return (error); 136df8bae1dSRodney W. Grimes } 137df8bae1dSRodney W. Grimes 1388b07e49aSJulian Elischer SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, 1398b07e49aSJulian Elischer NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); 1402dc1d581SAndre Oppermann 141c2c2a7c1SBjoern A. Zeeb static __inline struct radix_node_head ** 142c2c2a7c1SBjoern A. Zeeb rt_tables_get_rnh_ptr(int table, int fam) 143c2c2a7c1SBjoern A. Zeeb { 144c2c2a7c1SBjoern A. Zeeb struct radix_node_head **rnh; 145c2c2a7c1SBjoern A. Zeeb 146c2c2a7c1SBjoern A. Zeeb KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", 147c2c2a7c1SBjoern A. Zeeb __func__)); 148c2c2a7c1SBjoern A. Zeeb KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.", 149c2c2a7c1SBjoern A. Zeeb __func__)); 150c2c2a7c1SBjoern A. Zeeb 151c2c2a7c1SBjoern A. Zeeb /* rnh is [fib=0][af=0]. */ 152c2c2a7c1SBjoern A. Zeeb rnh = (struct radix_node_head **)V_rt_tables; 153c2c2a7c1SBjoern A. Zeeb /* Get the offset to the requested table and fam. */ 154c2c2a7c1SBjoern A. Zeeb rnh += table * (AF_MAX+1) + fam; 155c2c2a7c1SBjoern A. Zeeb 156c2c2a7c1SBjoern A. Zeeb return (rnh); 157c2c2a7c1SBjoern A. Zeeb } 158c2c2a7c1SBjoern A. Zeeb 159c2c2a7c1SBjoern A. Zeeb struct radix_node_head * 160c2c2a7c1SBjoern A. Zeeb rt_tables_get_rnh(int table, int fam) 161c2c2a7c1SBjoern A. Zeeb { 162c2c2a7c1SBjoern A. Zeeb 163c2c2a7c1SBjoern A. Zeeb return (*rt_tables_get_rnh_ptr(table, fam)); 164c2c2a7c1SBjoern A. Zeeb } 165c2c2a7c1SBjoern A. Zeeb 166d0728d71SRobert Watson /* 167d0728d71SRobert Watson * route initialization must occur before ip6_init2(), which happenas at 168d0728d71SRobert Watson * SI_ORDER_MIDDLE. 169d0728d71SRobert Watson */ 1702eb5613fSLuigi Rizzo static void 1712eb5613fSLuigi Rizzo route_init(void) 172df8bae1dSRodney W. Grimes { 1738b07e49aSJulian Elischer 1746f95a5ebSJulian Elischer /* whack the tunable ints into line. */ 1758b07e49aSJulian Elischer if (rt_numfibs > RT_MAXFIBS) 1768b07e49aSJulian Elischer rt_numfibs = RT_MAXFIBS; 1778b07e49aSJulian Elischer if (rt_numfibs == 0) 1788b07e49aSJulian Elischer rt_numfibs = 1; 179df8bae1dSRodney W. Grimes rn_init(); /* initialize all zeroes, all ones, mask table */ 1801ed81b73SMarko Zec } 181d0728d71SRobert Watson SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); 1821ed81b73SMarko Zec 183d0728d71SRobert Watson static void 184d0728d71SRobert Watson vnet_route_init(const void *unused __unused) 1851ed81b73SMarko Zec { 1861ed81b73SMarko Zec struct domain *dom; 187c2c2a7c1SBjoern A. Zeeb struct radix_node_head **rnh; 188c2c2a7c1SBjoern A. Zeeb int table; 1891ed81b73SMarko Zec int fam; 1901ed81b73SMarko Zec 191c2c2a7c1SBjoern A. Zeeb V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) * 192c2c2a7c1SBjoern A. Zeeb sizeof(struct radix_node_head *), M_RTABLE, M_WAITOK|M_ZERO); 193c2c2a7c1SBjoern A. Zeeb 1941ed81b73SMarko Zec V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), NULL, NULL, 1951ed81b73SMarko Zec NULL, NULL, UMA_ALIGN_PTR, 0); 1968b07e49aSJulian Elischer for (dom = domains; dom; dom = dom->dom_next) { 1978b07e49aSJulian Elischer if (dom->dom_rtattach) { 1988b07e49aSJulian Elischer for (table = 0; table < rt_numfibs; table++) { 1998b07e49aSJulian Elischer if ( (fam = dom->dom_family) == AF_INET || 2008b07e49aSJulian Elischer table == 0) { 2018b07e49aSJulian Elischer /* for now only AF_INET has > 1 table */ 2028b07e49aSJulian Elischer /* XXX MRT 2038b07e49aSJulian Elischer * rtattach will be also called 2048b07e49aSJulian Elischer * from vfs_export.c but the 2058b07e49aSJulian Elischer * offset will be 0 2068b07e49aSJulian Elischer * (only for AF_INET and AF_INET6 2078b07e49aSJulian Elischer * which don't need it anyhow) 2088b07e49aSJulian Elischer */ 209c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh_ptr(table, fam); 210c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 211c2c2a7c1SBjoern A. Zeeb panic("%s: rnh NULL", __func__); 212c2c2a7c1SBjoern A. Zeeb dom->dom_rtattach((void **)rnh, 2138b07e49aSJulian Elischer dom->dom_rtoffset); 2148b07e49aSJulian Elischer } else { 2158b07e49aSJulian Elischer break; 2168b07e49aSJulian Elischer } 2178b07e49aSJulian Elischer } 2188b07e49aSJulian Elischer } 2198b07e49aSJulian Elischer } 2208b07e49aSJulian Elischer } 221d0728d71SRobert Watson VNET_SYSINIT(vnet_route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 222d0728d71SRobert Watson vnet_route_init, 0); 2238b07e49aSJulian Elischer 224bc29160dSMarko Zec #ifdef VIMAGE 225d0728d71SRobert Watson static void 226d0728d71SRobert Watson vnet_route_uninit(const void *unused __unused) 227bc29160dSMarko Zec { 228bc29160dSMarko Zec int table; 229bc29160dSMarko Zec int fam; 230bc29160dSMarko Zec struct domain *dom; 231bc29160dSMarko Zec struct radix_node_head **rnh; 232bc29160dSMarko Zec 233bc29160dSMarko Zec for (dom = domains; dom; dom = dom->dom_next) { 234bc29160dSMarko Zec if (dom->dom_rtdetach) { 235bc29160dSMarko Zec for (table = 0; table < rt_numfibs; table++) { 236bc29160dSMarko Zec if ( (fam = dom->dom_family) == AF_INET || 237bc29160dSMarko Zec table == 0) { 238bc29160dSMarko Zec /* For now only AF_INET has > 1 tbl. */ 239bc29160dSMarko Zec rnh = rt_tables_get_rnh_ptr(table, fam); 240bc29160dSMarko Zec if (rnh == NULL) 241bc29160dSMarko Zec panic("%s: rnh NULL", __func__); 242bc29160dSMarko Zec dom->dom_rtdetach((void **)rnh, 243bc29160dSMarko Zec dom->dom_rtoffset); 244bc29160dSMarko Zec } else { 245bc29160dSMarko Zec break; 246bc29160dSMarko Zec } 247bc29160dSMarko Zec } 248bc29160dSMarko Zec } 249bc29160dSMarko Zec } 250bc29160dSMarko Zec } 251d0728d71SRobert Watson VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, 252d0728d71SRobert Watson vnet_route_uninit, 0); 253bc29160dSMarko Zec #endif 254bc29160dSMarko Zec 2558b07e49aSJulian Elischer #ifndef _SYS_SYSPROTO_H_ 2568b07e49aSJulian Elischer struct setfib_args { 2578b07e49aSJulian Elischer int fibnum; 2588b07e49aSJulian Elischer }; 2598b07e49aSJulian Elischer #endif 2608b07e49aSJulian Elischer int 2618b07e49aSJulian Elischer setfib(struct thread *td, struct setfib_args *uap) 2628b07e49aSJulian Elischer { 2638b07e49aSJulian Elischer if (uap->fibnum < 0 || uap->fibnum >= rt_numfibs) 2648b07e49aSJulian Elischer return EINVAL; 2658b07e49aSJulian Elischer td->td_proc->p_fibnum = uap->fibnum; 2668b07e49aSJulian Elischer return (0); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 269df8bae1dSRodney W. Grimes /* 270df8bae1dSRodney W. Grimes * Packet routing routines. 271df8bae1dSRodney W. Grimes */ 272df8bae1dSRodney W. Grimes void 273d1dd20beSSam Leffler rtalloc(struct route *ro) 274df8bae1dSRodney W. Grimes { 2758b07e49aSJulian Elischer rtalloc_ign_fib(ro, 0UL, 0); 2768b07e49aSJulian Elischer } 2778b07e49aSJulian Elischer 2788b07e49aSJulian Elischer void 2798b07e49aSJulian Elischer rtalloc_fib(struct route *ro, u_int fibnum) 2808b07e49aSJulian Elischer { 2818b07e49aSJulian Elischer rtalloc_ign_fib(ro, 0UL, fibnum); 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes 284652082e6SGarrett Wollman void 285d1dd20beSSam Leffler rtalloc_ign(struct route *ro, u_long ignore) 286652082e6SGarrett Wollman { 28768f956b8SJohn Polstra struct rtentry *rt; 28868f956b8SJohn Polstra 28968f956b8SJohn Polstra if ((rt = ro->ro_rt) != NULL) { 29068f956b8SJohn Polstra if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 29168f956b8SJohn Polstra return; 29268f956b8SJohn Polstra RTFREE(rt); 29366810dd0SYoshinobu Inoue ro->ro_rt = NULL; 29468f956b8SJohn Polstra } 2958b07e49aSJulian Elischer ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, 0); 2968b07e49aSJulian Elischer if (ro->ro_rt) 2978b07e49aSJulian Elischer RT_UNLOCK(ro->ro_rt); 2988b07e49aSJulian Elischer } 2998b07e49aSJulian Elischer 3008b07e49aSJulian Elischer void 3018b07e49aSJulian Elischer rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum) 3028b07e49aSJulian Elischer { 3038b07e49aSJulian Elischer struct rtentry *rt; 3048b07e49aSJulian Elischer 3058b07e49aSJulian Elischer if ((rt = ro->ro_rt) != NULL) { 3068b07e49aSJulian Elischer if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 3078b07e49aSJulian Elischer return; 3088b07e49aSJulian Elischer RTFREE(rt); 3098b07e49aSJulian Elischer ro->ro_rt = NULL; 3108b07e49aSJulian Elischer } 3118b07e49aSJulian Elischer ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, fibnum); 312d1dd20beSSam Leffler if (ro->ro_rt) 313d1dd20beSSam Leffler RT_UNLOCK(ro->ro_rt); 314652082e6SGarrett Wollman } 315652082e6SGarrett Wollman 316b0a76b88SJulian Elischer /* 317b0a76b88SJulian Elischer * Look up the route that matches the address given 318b0a76b88SJulian Elischer * Or, at least try.. Create a cloned route if needed. 319d1dd20beSSam Leffler * 320d1dd20beSSam Leffler * The returned route, if any, is locked. 321b0a76b88SJulian Elischer */ 322df8bae1dSRodney W. Grimes struct rtentry * 323d1dd20beSSam Leffler rtalloc1(struct sockaddr *dst, int report, u_long ignflags) 324df8bae1dSRodney W. Grimes { 3258b07e49aSJulian Elischer return (rtalloc1_fib(dst, report, ignflags, 0)); 3268b07e49aSJulian Elischer } 3278b07e49aSJulian Elischer 3288b07e49aSJulian Elischer struct rtentry * 3298b07e49aSJulian Elischer rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, 3308b07e49aSJulian Elischer u_int fibnum) 3318b07e49aSJulian Elischer { 3328b07e49aSJulian Elischer struct radix_node_head *rnh; 333d1dd20beSSam Leffler struct rtentry *rt; 334d1dd20beSSam Leffler struct radix_node *rn; 335d1dd20beSSam Leffler struct rtentry *newrt; 336df8bae1dSRodney W. Grimes struct rt_addrinfo info; 3376e6b3f7cSQing Li int err = 0, msgtype = RTM_MISS; 3383120b9d4SKip Macy int needlock; 339df8bae1dSRodney W. Grimes 3408b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); 3418b07e49aSJulian Elischer if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */ 3428b07e49aSJulian Elischer fibnum = 0; 343c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 34485911824SLuigi Rizzo newrt = NULL; 345b0a76b88SJulian Elischer /* 346b0a76b88SJulian Elischer * Look up the address in the table for that Address Family 347b0a76b88SJulian Elischer */ 348956b0b65SJeffrey Hsu if (rnh == NULL) { 349603724d3SBjoern A. Zeeb V_rtstat.rts_unreach++; 3506e6b3f7cSQing Li goto miss; 351956b0b65SJeffrey Hsu } 3523120b9d4SKip Macy needlock = !(ignflags & RTF_RNH_LOCKED); 3533120b9d4SKip Macy if (needlock) 3543120b9d4SKip Macy RADIX_NODE_HEAD_RLOCK(rnh); 3553120b9d4SKip Macy #ifdef INVARIANTS 3563120b9d4SKip Macy else 3573120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 3583120b9d4SKip Macy #endif 3593120b9d4SKip Macy rn = rnh->rnh_matchaddr(dst, rnh); 3603120b9d4SKip Macy if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { 361d6941ce9SLuigi Rizzo newrt = rt = RNTORT(rn); 3623120b9d4SKip Macy RT_LOCK(newrt); 3633120b9d4SKip Macy RT_ADDREF(newrt); 3643120b9d4SKip Macy if (needlock) 3653120b9d4SKip Macy RADIX_NODE_HEAD_RUNLOCK(rnh); 3663120b9d4SKip Macy goto done; 3676e6b3f7cSQing Li 3686e6b3f7cSQing Li } else if (needlock) 3693120b9d4SKip Macy RADIX_NODE_HEAD_RUNLOCK(rnh); 3703120b9d4SKip Macy 371b0a76b88SJulian Elischer /* 372b0a76b88SJulian Elischer * Either we hit the root or couldn't find any match, 373b0a76b88SJulian Elischer * Which basically means 374b0a76b88SJulian Elischer * "caint get there frm here" 375b0a76b88SJulian Elischer */ 376603724d3SBjoern A. Zeeb V_rtstat.rts_unreach++; 377956b0b65SJeffrey Hsu miss: 3786e6b3f7cSQing Li if (report) { 379b0a76b88SJulian Elischer /* 380b0a76b88SJulian Elischer * If required, report the failure to the supervising 381b0a76b88SJulian Elischer * Authorities. 382b0a76b88SJulian Elischer * For a delete, this is not an error. (report == 0) 383b0a76b88SJulian Elischer */ 3846f5967c0SBruce Evans bzero(&info, sizeof(info)); 385df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 386df8bae1dSRodney W. Grimes rt_missmsg(msgtype, &info, 0, err); 387df8bae1dSRodney W. Grimes } 3883120b9d4SKip Macy done: 389d1dd20beSSam Leffler if (newrt) 390d1dd20beSSam Leffler RT_LOCK_ASSERT(newrt); 391df8bae1dSRodney W. Grimes return (newrt); 392df8bae1dSRodney W. Grimes } 393df8bae1dSRodney W. Grimes 394499676dfSJulian Elischer /* 395499676dfSJulian Elischer * Remove a reference count from an rtentry. 396499676dfSJulian Elischer * If the count gets low enough, take it out of the routing table 397499676dfSJulian Elischer */ 398df8bae1dSRodney W. Grimes void 399d1dd20beSSam Leffler rtfree(struct rtentry *rt) 400df8bae1dSRodney W. Grimes { 40185911824SLuigi Rizzo struct radix_node_head *rnh; 402df8bae1dSRodney W. Grimes 403a0c0e34bSGleb Smirnoff KASSERT(rt != NULL,("%s: NULL rt", __func__)); 404c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 405a0c0e34bSGleb Smirnoff KASSERT(rnh != NULL,("%s: NULL rnh", __func__)); 406499676dfSJulian Elischer 407d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 408d1dd20beSSam Leffler 409499676dfSJulian Elischer /* 410a0c0e34bSGleb Smirnoff * The callers should use RTFREE_LOCKED() or RTFREE(), so 411a0c0e34bSGleb Smirnoff * we should come here exactly with the last reference. 412499676dfSJulian Elischer */ 4137138d65cSSam Leffler RT_REMREF(rt); 414a0c0e34bSGleb Smirnoff if (rt->rt_refcnt > 0) { 415a42ea597SQing Li log(LOG_DEBUG, "%s: %p has %d refs\n", __func__, rt, rt->rt_refcnt); 416d1dd20beSSam Leffler goto done; 417a0c0e34bSGleb Smirnoff } 4189c63e9dbSSam Leffler 4199c63e9dbSSam Leffler /* 4209c63e9dbSSam Leffler * On last reference give the "close method" a chance 4219c63e9dbSSam Leffler * to cleanup private state. This also permits (for 4229c63e9dbSSam Leffler * IPv4 and IPv6) a chance to decide if the routing table 4239c63e9dbSSam Leffler * entry should be purged immediately or at a later time. 4249c63e9dbSSam Leffler * When an immediate purge is to happen the close routine 4259c63e9dbSSam Leffler * typically calls rtexpunge which clears the RTF_UP flag 4269c63e9dbSSam Leffler * on the entry so that the code below reclaims the storage. 4279c63e9dbSSam Leffler */ 428d1dd20beSSam Leffler if (rt->rt_refcnt == 0 && rnh->rnh_close) 4295c2dae8eSGarrett Wollman rnh->rnh_close((struct radix_node *)rt, rnh); 430499676dfSJulian Elischer 431499676dfSJulian Elischer /* 432499676dfSJulian Elischer * If we are no longer "up" (and ref == 0) 433499676dfSJulian Elischer * then we can free the resources associated 434499676dfSJulian Elischer * with the route. 435499676dfSJulian Elischer */ 436d1dd20beSSam Leffler if ((rt->rt_flags & RTF_UP) == 0) { 437df8bae1dSRodney W. Grimes if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 438df8bae1dSRodney W. Grimes panic("rtfree 2"); 439499676dfSJulian Elischer /* 440499676dfSJulian Elischer * the rtentry must have been removed from the routing table 441499676dfSJulian Elischer * so it is represented in rttrash.. remove that now. 442499676dfSJulian Elischer */ 443603724d3SBjoern A. Zeeb V_rttrash--; 444499676dfSJulian Elischer #ifdef DIAGNOSTIC 445df8bae1dSRodney W. Grimes if (rt->rt_refcnt < 0) { 446623ae52eSPoul-Henning Kamp printf("rtfree: %p not freed (neg refs)\n", rt); 447d1dd20beSSam Leffler goto done; 448df8bae1dSRodney W. Grimes } 449499676dfSJulian Elischer #endif 450499676dfSJulian Elischer /* 451499676dfSJulian Elischer * release references on items we hold them on.. 452499676dfSJulian Elischer * e.g other routes and ifaddrs. 453499676dfSJulian Elischer */ 45419fc74fbSJeffrey Hsu if (rt->rt_ifa) 4551099f828SRobert Watson ifa_free(rt->rt_ifa); 456499676dfSJulian Elischer /* 457499676dfSJulian Elischer * The key is separatly alloc'd so free it (see rt_setgate()). 458499676dfSJulian Elischer * This also frees the gateway, as they are always malloc'd 459499676dfSJulian Elischer * together. 460499676dfSJulian Elischer */ 461df8bae1dSRodney W. Grimes Free(rt_key(rt)); 462499676dfSJulian Elischer 463499676dfSJulian Elischer /* 464499676dfSJulian Elischer * and the rtentry itself of course 465499676dfSJulian Elischer */ 466d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 4671ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 468d1dd20beSSam Leffler return; 469df8bae1dSRodney W. Grimes } 470d1dd20beSSam Leffler done: 471d1dd20beSSam Leffler RT_UNLOCK(rt); 472df8bae1dSRodney W. Grimes } 473df8bae1dSRodney W. Grimes 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * Force a routing table entry to the specified 477df8bae1dSRodney W. Grimes * destination to go through the given gateway. 478df8bae1dSRodney W. Grimes * Normally called as a result of a routing redirect 479df8bae1dSRodney W. Grimes * message from the network layer. 480df8bae1dSRodney W. Grimes */ 48126f9a767SRodney W. Grimes void 482d1dd20beSSam Leffler rtredirect(struct sockaddr *dst, 483d1dd20beSSam Leffler struct sockaddr *gateway, 484d1dd20beSSam Leffler struct sockaddr *netmask, 485d1dd20beSSam Leffler int flags, 486d1dd20beSSam Leffler struct sockaddr *src) 487df8bae1dSRodney W. Grimes { 4888b07e49aSJulian Elischer rtredirect_fib(dst, gateway, netmask, flags, src, 0); 4898b07e49aSJulian Elischer } 4908b07e49aSJulian Elischer 4918b07e49aSJulian Elischer void 4928b07e49aSJulian Elischer rtredirect_fib(struct sockaddr *dst, 4938b07e49aSJulian Elischer struct sockaddr *gateway, 4948b07e49aSJulian Elischer struct sockaddr *netmask, 4958b07e49aSJulian Elischer int flags, 4968b07e49aSJulian Elischer struct sockaddr *src, 4978b07e49aSJulian Elischer u_int fibnum) 4988b07e49aSJulian Elischer { 4998e7e854cSKip Macy struct rtentry *rt, *rt0 = NULL; 500df8bae1dSRodney W. Grimes int error = 0; 50185911824SLuigi Rizzo short *stat = NULL; 502df8bae1dSRodney W. Grimes struct rt_addrinfo info; 503df8bae1dSRodney W. Grimes struct ifaddr *ifa; 504c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rnh; 505c2c2a7c1SBjoern A. Zeeb 5068c0fec80SRobert Watson ifa = NULL; 507c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 508c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) { 509c2c2a7c1SBjoern A. Zeeb error = EAFNOSUPPORT; 510c2c2a7c1SBjoern A. Zeeb goto out; 511c2c2a7c1SBjoern A. Zeeb } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes /* verify the gateway is directly reachable */ 51485911824SLuigi Rizzo if ((ifa = ifa_ifwithnet(gateway)) == NULL) { 515df8bae1dSRodney W. Grimes error = ENETUNREACH; 516df8bae1dSRodney W. Grimes goto out; 517df8bae1dSRodney W. Grimes } 5188b07e49aSJulian Elischer rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ 519df8bae1dSRodney W. Grimes /* 520df8bae1dSRodney W. Grimes * If the redirect isn't from our current router for this dst, 521df8bae1dSRodney W. Grimes * it's either old or wrong. If it redirects us to ourselves, 522df8bae1dSRodney W. Grimes * we have a routing loop, perhaps as a result of an interface 523df8bae1dSRodney W. Grimes * going down recently. 524df8bae1dSRodney W. Grimes */ 525df8bae1dSRodney W. Grimes if (!(flags & RTF_DONE) && rt && 526956b0b65SJeffrey Hsu (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 527df8bae1dSRodney W. Grimes error = EINVAL; 5288896f83aSRobert Watson else if (ifa_ifwithaddr_check(gateway)) 529df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 530df8bae1dSRodney W. Grimes if (error) 531df8bae1dSRodney W. Grimes goto done; 532df8bae1dSRodney W. Grimes /* 533df8bae1dSRodney W. Grimes * Create a new entry if we just got back a wildcard entry 534df8bae1dSRodney W. Grimes * or the the lookup failed. This is necessary for hosts 535df8bae1dSRodney W. Grimes * which use routing redirects generated by smart gateways 536df8bae1dSRodney W. Grimes * to dynamically build the routing tables. 537df8bae1dSRodney W. Grimes */ 53885911824SLuigi Rizzo if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 539df8bae1dSRodney W. Grimes goto create; 540df8bae1dSRodney W. Grimes /* 541df8bae1dSRodney W. Grimes * Don't listen to the redirect if it's 542df8bae1dSRodney W. Grimes * for a route to an interface. 543df8bae1dSRodney W. Grimes */ 544df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 545df8bae1dSRodney W. Grimes if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 546df8bae1dSRodney W. Grimes /* 547df8bae1dSRodney W. Grimes * Changing from route to net => route to host. 548df8bae1dSRodney W. Grimes * Create new route, rather than smashing route to net. 549df8bae1dSRodney W. Grimes */ 550df8bae1dSRodney W. Grimes create: 5518e7e854cSKip Macy rt0 = rt; 5528e7e854cSKip Macy rt = NULL; 5538e7e854cSKip Macy 554df8bae1dSRodney W. Grimes flags |= RTF_GATEWAY | RTF_DYNAMIC; 5558071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 5568071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 5578071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 5588071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 5598071913dSRuslan Ermilov info.rti_ifa = ifa; 5608071913dSRuslan Ermilov info.rti_flags = flags; 5613120b9d4SKip Macy if (rt0 != NULL) 5623120b9d4SKip Macy RT_UNLOCK(rt0); /* drop lock to avoid LOR with RNH */ 5638b07e49aSJulian Elischer error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); 564d1dd20beSSam Leffler if (rt != NULL) { 5654de5d90cSSam Leffler RT_LOCK(rt); 5663120b9d4SKip Macy if (rt0 != NULL) 56729910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst); 5688071913dSRuslan Ermilov flags = rt->rt_flags; 569d1dd20beSSam Leffler } 5703120b9d4SKip Macy if (rt0 != NULL) 5713120b9d4SKip Macy RTFREE(rt0); 5728e7e854cSKip Macy 573603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_dynamic; 574df8bae1dSRodney W. Grimes } else { 5758e7e854cSKip Macy struct rtentry *gwrt; 5768e7e854cSKip Macy 577df8bae1dSRodney W. Grimes /* 578df8bae1dSRodney W. Grimes * Smash the current notion of the gateway to 579df8bae1dSRodney W. Grimes * this destination. Should check about netmask!!! 580df8bae1dSRodney W. Grimes */ 581df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_MODIFIED; 582df8bae1dSRodney W. Grimes flags |= RTF_MODIFIED; 583603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_newgateway; 584499676dfSJulian Elischer /* 585499676dfSJulian Elischer * add the key and gateway (in one malloc'd chunk). 586499676dfSJulian Elischer */ 5873120b9d4SKip Macy RT_UNLOCK(rt); 5883120b9d4SKip Macy RADIX_NODE_HEAD_LOCK(rnh); 5893120b9d4SKip Macy RT_LOCK(rt); 590df8bae1dSRodney W. Grimes rt_setgate(rt, rt_key(rt), gateway); 5913120b9d4SKip Macy gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED); 5923120b9d4SKip Macy RADIX_NODE_HEAD_UNLOCK(rnh); 59329910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst); 5948e7e854cSKip Macy RTFREE_LOCKED(gwrt); 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes } else 597df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 598df8bae1dSRodney W. Grimes done: 599d1dd20beSSam Leffler if (rt) 6001951e633SJohn Baldwin RTFREE_LOCKED(rt); 601df8bae1dSRodney W. Grimes out: 602df8bae1dSRodney W. Grimes if (error) 603603724d3SBjoern A. Zeeb V_rtstat.rts_badredirect++; 604df8bae1dSRodney W. Grimes else if (stat != NULL) 605df8bae1dSRodney W. Grimes (*stat)++; 606df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 607df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 608df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 609df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = netmask; 610df8bae1dSRodney W. Grimes info.rti_info[RTAX_AUTHOR] = src; 611df8bae1dSRodney W. Grimes rt_missmsg(RTM_REDIRECT, &info, flags, error); 6128c0fec80SRobert Watson if (ifa != NULL) 6138c0fec80SRobert Watson ifa_free(ifa); 614df8bae1dSRodney W. Grimes } 615df8bae1dSRodney W. Grimes 6168b07e49aSJulian Elischer int 6178b07e49aSJulian Elischer rtioctl(u_long req, caddr_t data) 6188b07e49aSJulian Elischer { 6198b07e49aSJulian Elischer return (rtioctl_fib(req, data, 0)); 6208b07e49aSJulian Elischer } 6218b07e49aSJulian Elischer 622df8bae1dSRodney W. Grimes /* 623df8bae1dSRodney W. Grimes * Routing table ioctl interface. 624df8bae1dSRodney W. Grimes */ 625df8bae1dSRodney W. Grimes int 6268b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 627df8bae1dSRodney W. Grimes { 6285090559bSChristian S.J. Peron 6295090559bSChristian S.J. Peron /* 6305090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 6315090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 6325090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 6335090559bSChristian S.J. Peron * in jails. 6345090559bSChristian S.J. Peron */ 635623ae52eSPoul-Henning Kamp #ifdef INET 636f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 6378b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 638623ae52eSPoul-Henning Kamp #else /* INET */ 639623ae52eSPoul-Henning Kamp return ENXIO; 640623ae52eSPoul-Henning Kamp #endif /* INET */ 641df8bae1dSRodney W. Grimes } 642df8bae1dSRodney W. Grimes 6438c0fec80SRobert Watson /* 6448c0fec80SRobert Watson * For both ifa_ifwithroute() routines, 'ifa' is returned referenced. 6458c0fec80SRobert Watson */ 646df8bae1dSRodney W. Grimes struct ifaddr * 647d1dd20beSSam Leffler ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway) 648df8bae1dSRodney W. Grimes { 6498b07e49aSJulian Elischer return (ifa_ifwithroute_fib(flags, dst, gateway, 0)); 6508b07e49aSJulian Elischer } 6518b07e49aSJulian Elischer 6528b07e49aSJulian Elischer struct ifaddr * 6538b07e49aSJulian Elischer ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway, 6548b07e49aSJulian Elischer u_int fibnum) 6558b07e49aSJulian Elischer { 656df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 657e034e82cSQing Li int not_found = 0; 658d1dd20beSSam Leffler 659df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 660df8bae1dSRodney W. Grimes /* 661df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 662df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 663df8bae1dSRodney W. Grimes * we should search for the destination 664df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 665df8bae1dSRodney W. Grimes * we can use the local address. 666df8bae1dSRodney W. Grimes */ 66785911824SLuigi Rizzo ifa = NULL; 66885911824SLuigi Rizzo if (flags & RTF_HOST) 669df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(dst); 67085911824SLuigi Rizzo if (ifa == NULL) 671df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 672df8bae1dSRodney W. Grimes } else { 673df8bae1dSRodney W. Grimes /* 674df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 675df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 676df8bae1dSRodney W. Grimes * other end of a pt to pt link. 677df8bae1dSRodney W. Grimes */ 678df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(gateway); 679df8bae1dSRodney W. Grimes } 68085911824SLuigi Rizzo if (ifa == NULL) 681df8bae1dSRodney W. Grimes ifa = ifa_ifwithnet(gateway); 68285911824SLuigi Rizzo if (ifa == NULL) { 6839b20205dSKip Macy struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum); 68485911824SLuigi Rizzo if (rt == NULL) 68585911824SLuigi Rizzo return (NULL); 686e034e82cSQing Li /* 687e034e82cSQing Li * dismiss a gateway that is reachable only 688e034e82cSQing Li * through the default router 689e034e82cSQing Li */ 690e034e82cSQing Li switch (gateway->sa_family) { 691e034e82cSQing Li case AF_INET: 692e034e82cSQing Li if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY) 693e034e82cSQing Li not_found = 1; 694e034e82cSQing Li break; 695e034e82cSQing Li case AF_INET6: 696e034e82cSQing Li if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr)) 697e034e82cSQing Li not_found = 1; 698e034e82cSQing Li break; 699e034e82cSQing Li default: 700e034e82cSQing Li break; 701e034e82cSQing Li } 7028c0fec80SRobert Watson if (!not_found && rt->rt_ifa != NULL) { 7038c0fec80SRobert Watson ifa = rt->rt_ifa; 7048c0fec80SRobert Watson ifa_ref(ifa); 7058c0fec80SRobert Watson } 7067138d65cSSam Leffler RT_REMREF(rt); 707d1dd20beSSam Leffler RT_UNLOCK(rt); 7088c0fec80SRobert Watson if (not_found || ifa == NULL) 70985911824SLuigi Rizzo return (NULL); 710df8bae1dSRodney W. Grimes } 711df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 712df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 713df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 71485911824SLuigi Rizzo if (ifa == NULL) 715df8bae1dSRodney W. Grimes ifa = oifa; 7168c0fec80SRobert Watson else 7178c0fec80SRobert Watson ifa_free(oifa); 718df8bae1dSRodney W. Grimes } 719df8bae1dSRodney W. Grimes return (ifa); 720df8bae1dSRodney W. Grimes } 721df8bae1dSRodney W. Grimes 722b0a76b88SJulian Elischer /* 723b0a76b88SJulian Elischer * Do appropriate manipulations of a routing tree given 724b0a76b88SJulian Elischer * all the bits of info needed 725b0a76b88SJulian Elischer */ 726df8bae1dSRodney W. Grimes int 727d1dd20beSSam Leffler rtrequest(int req, 728d1dd20beSSam Leffler struct sockaddr *dst, 729d1dd20beSSam Leffler struct sockaddr *gateway, 730d1dd20beSSam Leffler struct sockaddr *netmask, 731d1dd20beSSam Leffler int flags, 732d1dd20beSSam Leffler struct rtentry **ret_nrt) 733df8bae1dSRodney W. Grimes { 7348b07e49aSJulian Elischer return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 0)); 7358b07e49aSJulian Elischer } 7368b07e49aSJulian Elischer 7378b07e49aSJulian Elischer int 7388b07e49aSJulian Elischer rtrequest_fib(int req, 7398b07e49aSJulian Elischer struct sockaddr *dst, 7408b07e49aSJulian Elischer struct sockaddr *gateway, 7418b07e49aSJulian Elischer struct sockaddr *netmask, 7428b07e49aSJulian Elischer int flags, 7438b07e49aSJulian Elischer struct rtentry **ret_nrt, 7448b07e49aSJulian Elischer u_int fibnum) 7458b07e49aSJulian Elischer { 7468071913dSRuslan Ermilov struct rt_addrinfo info; 7478071913dSRuslan Ermilov 748ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 749ac4a76ebSBjoern A. Zeeb return(EINVAL); 750ac4a76ebSBjoern A. Zeeb 7518071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 7528071913dSRuslan Ermilov info.rti_flags = flags; 7538071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 7548071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 7558071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 7568b07e49aSJulian Elischer return rtrequest1_fib(req, &info, ret_nrt, fibnum); 7578071913dSRuslan Ermilov } 7588071913dSRuslan Ermilov 7598071913dSRuslan Ermilov /* 7608071913dSRuslan Ermilov * These (questionable) definitions of apparent local variables apply 7618071913dSRuslan Ermilov * to the next two functions. XXXXXX!!! 7628071913dSRuslan Ermilov */ 7638071913dSRuslan Ermilov #define dst info->rti_info[RTAX_DST] 7648071913dSRuslan Ermilov #define gateway info->rti_info[RTAX_GATEWAY] 7658071913dSRuslan Ermilov #define netmask info->rti_info[RTAX_NETMASK] 7668071913dSRuslan Ermilov #define ifaaddr info->rti_info[RTAX_IFA] 7678071913dSRuslan Ermilov #define ifpaddr info->rti_info[RTAX_IFP] 7688071913dSRuslan Ermilov #define flags info->rti_flags 7698071913dSRuslan Ermilov 7708071913dSRuslan Ermilov int 771d1dd20beSSam Leffler rt_getifa(struct rt_addrinfo *info) 7728071913dSRuslan Ermilov { 7738b07e49aSJulian Elischer return (rt_getifa_fib(info, 0)); 7748b07e49aSJulian Elischer } 7758b07e49aSJulian Elischer 7768c0fec80SRobert Watson /* 7778c0fec80SRobert Watson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 7788c0fec80SRobert Watson * it will be referenced so the caller must free it. 7798c0fec80SRobert Watson */ 7808b07e49aSJulian Elischer int 7818b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 7828b07e49aSJulian Elischer { 7838071913dSRuslan Ermilov struct ifaddr *ifa; 7848071913dSRuslan Ermilov int error = 0; 7858071913dSRuslan Ermilov 7868071913dSRuslan Ermilov /* 7878071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 7888071913dSRuslan Ermilov * when protocol address is ambiguous. 7898071913dSRuslan Ermilov */ 7908071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 7918071913dSRuslan Ermilov ifpaddr->sa_family == AF_LINK && 7928c0fec80SRobert Watson (ifa = ifa_ifwithnet(ifpaddr)) != NULL) { 7938071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 7948c0fec80SRobert Watson ifa_free(ifa); 7958c0fec80SRobert Watson } 7968071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 7978071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 7988071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 7998071913dSRuslan Ermilov struct sockaddr *sa; 8008071913dSRuslan Ermilov 8018071913dSRuslan Ermilov sa = ifaaddr != NULL ? ifaaddr : 8028071913dSRuslan Ermilov (gateway != NULL ? gateway : dst); 8038071913dSRuslan Ermilov if (sa != NULL && info->rti_ifp != NULL) 8048071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 8058071913dSRuslan Ermilov else if (dst != NULL && gateway != NULL) 8068b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, dst, gateway, 8078b07e49aSJulian Elischer fibnum); 8088071913dSRuslan Ermilov else if (sa != NULL) 8098b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, sa, sa, 8108b07e49aSJulian Elischer fibnum); 8118071913dSRuslan Ermilov } 8128071913dSRuslan Ermilov if ((ifa = info->rti_ifa) != NULL) { 8138071913dSRuslan Ermilov if (info->rti_ifp == NULL) 8148071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 8158071913dSRuslan Ermilov } else 8168071913dSRuslan Ermilov error = ENETUNREACH; 8178071913dSRuslan Ermilov return (error); 8188071913dSRuslan Ermilov } 8198071913dSRuslan Ermilov 8209c63e9dbSSam Leffler /* 8219c63e9dbSSam Leffler * Expunges references to a route that's about to be reclaimed. 8229c63e9dbSSam Leffler * The route must be locked. 8239c63e9dbSSam Leffler */ 8249c63e9dbSSam Leffler int 8259c63e9dbSSam Leffler rtexpunge(struct rtentry *rt) 8269c63e9dbSSam Leffler { 8279c63e9dbSSam Leffler struct radix_node *rn; 8289c63e9dbSSam Leffler struct radix_node_head *rnh; 8299c63e9dbSSam Leffler struct ifaddr *ifa; 8309c63e9dbSSam Leffler int error = 0; 8319c63e9dbSSam Leffler 8326e6b3f7cSQing Li /* 8336e6b3f7cSQing Li * Find the correct routing tree to use for this Address Family 8346e6b3f7cSQing Li */ 835c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 8369c63e9dbSSam Leffler RT_LOCK_ASSERT(rt); 8376e6b3f7cSQing Li if (rnh == NULL) 8386e6b3f7cSQing Li return (EAFNOSUPPORT); 8393120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 8409c63e9dbSSam Leffler #if 0 8419c63e9dbSSam Leffler /* 8429c63e9dbSSam Leffler * We cannot assume anything about the reference count 8439c63e9dbSSam Leffler * because protocols call us in many situations; often 8449c63e9dbSSam Leffler * before unwinding references to the table entry. 8459c63e9dbSSam Leffler */ 8469c63e9dbSSam Leffler KASSERT(rt->rt_refcnt <= 1, ("bogus refcnt %ld", rt->rt_refcnt)); 8479c63e9dbSSam Leffler #endif 8489c63e9dbSSam Leffler /* 8499c63e9dbSSam Leffler * Remove the item from the tree; it should be there, 8509c63e9dbSSam Leffler * but when callers invoke us blindly it may not (sigh). 8519c63e9dbSSam Leffler */ 8529c63e9dbSSam Leffler rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh); 85385911824SLuigi Rizzo if (rn == NULL) { 8549c63e9dbSSam Leffler error = ESRCH; 8559c63e9dbSSam Leffler goto bad; 8569c63e9dbSSam Leffler } 8579c63e9dbSSam Leffler KASSERT((rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) == 0, 8589c63e9dbSSam Leffler ("unexpected flags 0x%x", rn->rn_flags)); 859d6941ce9SLuigi Rizzo KASSERT(rt == RNTORT(rn), 8609c63e9dbSSam Leffler ("lookup mismatch, rt %p rn %p", rt, rn)); 8619c63e9dbSSam Leffler 8629c63e9dbSSam Leffler rt->rt_flags &= ~RTF_UP; 8639c63e9dbSSam Leffler 8649c63e9dbSSam Leffler /* 8659c63e9dbSSam Leffler * Give the protocol a chance to keep things in sync. 8669c63e9dbSSam Leffler */ 8679c63e9dbSSam Leffler if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) { 8689c63e9dbSSam Leffler struct rt_addrinfo info; 8699c63e9dbSSam Leffler 8709c63e9dbSSam Leffler bzero((caddr_t)&info, sizeof(info)); 8719c63e9dbSSam Leffler info.rti_flags = rt->rt_flags; 8729c63e9dbSSam Leffler info.rti_info[RTAX_DST] = rt_key(rt); 8739c63e9dbSSam Leffler info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 8749c63e9dbSSam Leffler info.rti_info[RTAX_NETMASK] = rt_mask(rt); 8759c63e9dbSSam Leffler ifa->ifa_rtrequest(RTM_DELETE, rt, &info); 8769c63e9dbSSam Leffler } 8779c63e9dbSSam Leffler 8789c63e9dbSSam Leffler /* 8799c63e9dbSSam Leffler * one more rtentry floating around that is not 8809c63e9dbSSam Leffler * linked to the routing table. 8819c63e9dbSSam Leffler */ 882603724d3SBjoern A. Zeeb V_rttrash++; 8839c63e9dbSSam Leffler bad: 8849c63e9dbSSam Leffler return (error); 8859c63e9dbSSam Leffler } 8869c63e9dbSSam Leffler 887427ac07fSKip Macy #ifdef RADIX_MPATH 888427ac07fSKip Macy static int 889427ac07fSKip Macy rn_mpath_update(int req, struct rt_addrinfo *info, 890427ac07fSKip Macy struct radix_node_head *rnh, struct rtentry **ret_nrt) 891427ac07fSKip Macy { 892427ac07fSKip Macy /* 893427ac07fSKip Macy * if we got multipath routes, we require users to specify 894427ac07fSKip Macy * a matching RTAX_GATEWAY. 895427ac07fSKip Macy */ 896427ac07fSKip Macy struct rtentry *rt, *rto = NULL; 897427ac07fSKip Macy register struct radix_node *rn; 898427ac07fSKip Macy int error = 0; 899427ac07fSKip Macy 900427ac07fSKip Macy rn = rnh->rnh_matchaddr(dst, rnh); 901427ac07fSKip Macy if (rn == NULL) 902427ac07fSKip Macy return (ESRCH); 903427ac07fSKip Macy rto = rt = RNTORT(rn); 904427ac07fSKip Macy rt = rt_mpath_matchgate(rt, gateway); 905427ac07fSKip Macy if (rt == NULL) 906427ac07fSKip Macy return (ESRCH); 907427ac07fSKip Macy /* 908427ac07fSKip Macy * this is the first entry in the chain 909427ac07fSKip Macy */ 910427ac07fSKip Macy if (rto == rt) { 911427ac07fSKip Macy rn = rn_mpath_next((struct radix_node *)rt); 912427ac07fSKip Macy /* 913427ac07fSKip Macy * there is another entry, now it's active 914427ac07fSKip Macy */ 915427ac07fSKip Macy if (rn) { 916427ac07fSKip Macy rto = RNTORT(rn); 917427ac07fSKip Macy RT_LOCK(rto); 918427ac07fSKip Macy rto->rt_flags |= RTF_UP; 919427ac07fSKip Macy RT_UNLOCK(rto); 920427ac07fSKip Macy } else if (rt->rt_flags & RTF_GATEWAY) { 921427ac07fSKip Macy /* 922427ac07fSKip Macy * For gateway routes, we need to 923427ac07fSKip Macy * make sure that we we are deleting 924427ac07fSKip Macy * the correct gateway. 925427ac07fSKip Macy * rt_mpath_matchgate() does not 926427ac07fSKip Macy * check the case when there is only 927427ac07fSKip Macy * one route in the chain. 928427ac07fSKip Macy */ 929427ac07fSKip Macy if (gateway && 930427ac07fSKip Macy (rt->rt_gateway->sa_len != gateway->sa_len || 931427ac07fSKip Macy memcmp(rt->rt_gateway, gateway, gateway->sa_len))) 932427ac07fSKip Macy error = ESRCH; 9336a7bff2cSKip Macy else { 9346a7bff2cSKip Macy /* 9356a7bff2cSKip Macy * remove from tree before returning it 9366a7bff2cSKip Macy * to the caller 9376a7bff2cSKip Macy */ 9386a7bff2cSKip Macy rn = rnh->rnh_deladdr(dst, netmask, rnh); 9396a7bff2cSKip Macy KASSERT(rt == RNTORT(rn), ("radix node disappeared")); 9406a7bff2cSKip Macy goto gwdelete; 9416a7bff2cSKip Macy } 9426a7bff2cSKip Macy 943427ac07fSKip Macy } 944427ac07fSKip Macy /* 945427ac07fSKip Macy * use the normal delete code to remove 946427ac07fSKip Macy * the first entry 947427ac07fSKip Macy */ 948427ac07fSKip Macy if (req != RTM_DELETE) 949427ac07fSKip Macy goto nondelete; 950427ac07fSKip Macy 951427ac07fSKip Macy error = ENOENT; 952427ac07fSKip Macy goto done; 953427ac07fSKip Macy } 954427ac07fSKip Macy 955427ac07fSKip Macy /* 956427ac07fSKip Macy * if the entry is 2nd and on up 957427ac07fSKip Macy */ 958427ac07fSKip Macy if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt)) 959427ac07fSKip Macy panic ("rtrequest1: rt_mpath_deldup"); 9606a7bff2cSKip Macy gwdelete: 961427ac07fSKip Macy RT_LOCK(rt); 962427ac07fSKip Macy RT_ADDREF(rt); 963427ac07fSKip Macy if (req == RTM_DELETE) { 964427ac07fSKip Macy rt->rt_flags &= ~RTF_UP; 965427ac07fSKip Macy /* 966427ac07fSKip Macy * One more rtentry floating around that is not 967427ac07fSKip Macy * linked to the routing table. rttrash will be decremented 968427ac07fSKip Macy * when RTFREE(rt) is eventually called. 969427ac07fSKip Macy */ 970427ac07fSKip Macy V_rttrash++; 971427ac07fSKip Macy } 972427ac07fSKip Macy 973427ac07fSKip Macy nondelete: 974427ac07fSKip Macy if (req != RTM_DELETE) 975427ac07fSKip Macy panic("unrecognized request %d", req); 976427ac07fSKip Macy 977427ac07fSKip Macy 978427ac07fSKip Macy /* 979427ac07fSKip Macy * If the caller wants it, then it can have it, 980427ac07fSKip Macy * but it's up to it to free the rtentry as we won't be 981427ac07fSKip Macy * doing it. 982427ac07fSKip Macy */ 983427ac07fSKip Macy if (ret_nrt) { 984427ac07fSKip Macy *ret_nrt = rt; 985427ac07fSKip Macy RT_UNLOCK(rt); 986427ac07fSKip Macy } else 987427ac07fSKip Macy RTFREE_LOCKED(rt); 988427ac07fSKip Macy done: 989427ac07fSKip Macy return (error); 990427ac07fSKip Macy } 991427ac07fSKip Macy #endif 992427ac07fSKip Macy 9938071913dSRuslan Ermilov int 9948b07e49aSJulian Elischer rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, 9958b07e49aSJulian Elischer u_int fibnum) 9968b07e49aSJulian Elischer { 9973120b9d4SKip Macy int error = 0, needlock = 0; 998df8bae1dSRodney W. Grimes register struct rtentry *rt; 999df8bae1dSRodney W. Grimes register struct radix_node *rn; 1000df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1001df8bae1dSRodney W. Grimes struct ifaddr *ifa; 1002df8bae1dSRodney W. Grimes struct sockaddr *ndst; 1003df8bae1dSRodney W. Grimes #define senderr(x) { error = x ; goto bad; } 1004df8bae1dSRodney W. Grimes 10058b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); 10068b07e49aSJulian Elischer if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */ 10078b07e49aSJulian Elischer fibnum = 0; 1008b0a76b88SJulian Elischer /* 1009b0a76b88SJulian Elischer * Find the correct routing tree to use for this Address Family 1010b0a76b88SJulian Elischer */ 1011c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 101285911824SLuigi Rizzo if (rnh == NULL) 1013983985c1SJeffrey Hsu return (EAFNOSUPPORT); 10143120b9d4SKip Macy needlock = ((flags & RTF_RNH_LOCKED) == 0); 10153120b9d4SKip Macy flags &= ~RTF_RNH_LOCKED; 10163120b9d4SKip Macy if (needlock) 1017956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1018c96b8224SKip Macy else 1019c96b8224SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1020b0a76b88SJulian Elischer /* 1021b0a76b88SJulian Elischer * If we are adding a host route then we don't want to put 102266953138SRuslan Ermilov * a netmask in the tree, nor do we want to clone it. 1023b0a76b88SJulian Elischer */ 10246e6b3f7cSQing Li if (flags & RTF_HOST) 102585911824SLuigi Rizzo netmask = NULL; 10266e6b3f7cSQing Li 1027df8bae1dSRodney W. Grimes switch (req) { 1028df8bae1dSRodney W. Grimes case RTM_DELETE: 1029e440aed9SQing Li #ifdef RADIX_MPATH 1030e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1031427ac07fSKip Macy error = rn_mpath_update(req, info, rnh, ret_nrt); 1032e440aed9SQing Li /* 1033427ac07fSKip Macy * "bad" holds true for the success case 1034427ac07fSKip Macy * as well 1035e440aed9SQing Li */ 1036427ac07fSKip Macy if (error != ENOENT) 1037427ac07fSKip Macy goto bad; 1038e440aed9SQing Li } 1039ea9cd9f2SBjoern A. Zeeb #endif 1040b0a76b88SJulian Elischer /* 1041b0a76b88SJulian Elischer * Remove the item from the tree and return it. 1042b0a76b88SJulian Elischer * Complain if it is not there and do no more processing. 1043b0a76b88SJulian Elischer */ 1044d1dd20beSSam Leffler rn = rnh->rnh_deladdr(dst, netmask, rnh); 104585911824SLuigi Rizzo if (rn == NULL) 1046df8bae1dSRodney W. Grimes senderr(ESRCH); 1047df8bae1dSRodney W. Grimes if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 1048df8bae1dSRodney W. Grimes panic ("rtrequest delete"); 1049d6941ce9SLuigi Rizzo rt = RNTORT(rn); 1050d1dd20beSSam Leffler RT_LOCK(rt); 10517138d65cSSam Leffler RT_ADDREF(rt); 105271eba915SRuslan Ermilov rt->rt_flags &= ~RTF_UP; 1053c2bed6a3SGarrett Wollman 1054c2bed6a3SGarrett Wollman /* 1055499676dfSJulian Elischer * give the protocol a chance to keep things in sync. 1056b0a76b88SJulian Elischer */ 1057df8bae1dSRodney W. Grimes if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 10588071913dSRuslan Ermilov ifa->ifa_rtrequest(RTM_DELETE, rt, info); 1059499676dfSJulian Elischer 1060b0a76b88SJulian Elischer /* 1061d6941ce9SLuigi Rizzo * One more rtentry floating around that is not 1062d6941ce9SLuigi Rizzo * linked to the routing table. rttrash will be decremented 1063d6941ce9SLuigi Rizzo * when RTFREE(rt) is eventually called. 1064499676dfSJulian Elischer */ 1065603724d3SBjoern A. Zeeb V_rttrash++; 1066499676dfSJulian Elischer 1067499676dfSJulian Elischer /* 1068499676dfSJulian Elischer * If the caller wants it, then it can have it, 1069499676dfSJulian Elischer * but it's up to it to free the rtentry as we won't be 1070499676dfSJulian Elischer * doing it. 1071b0a76b88SJulian Elischer */ 1072d1dd20beSSam Leffler if (ret_nrt) { 1073df8bae1dSRodney W. Grimes *ret_nrt = rt; 1074d1dd20beSSam Leffler RT_UNLOCK(rt); 1075d1dd20beSSam Leffler } else 1076d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1077df8bae1dSRodney W. Grimes break; 1078df8bae1dSRodney W. Grimes case RTM_RESOLVE: 10796e6b3f7cSQing Li /* 10806e6b3f7cSQing Li * resolve was only used for route cloning 10816e6b3f7cSQing Li * here for compat 10826e6b3f7cSQing Li */ 10836e6b3f7cSQing Li break; 1084df8bae1dSRodney W. Grimes case RTM_ADD: 10855df72964SGarrett Wollman if ((flags & RTF_GATEWAY) && !gateway) 108616a2e0a6SQing Li senderr(EINVAL); 108716a2e0a6SQing Li if (dst && gateway && (dst->sa_family != gateway->sa_family) && 108816a2e0a6SQing Li (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) 108916a2e0a6SQing Li senderr(EINVAL); 10905df72964SGarrett Wollman 10918c0fec80SRobert Watson if (info->rti_ifa == NULL) { 10928c0fec80SRobert Watson error = rt_getifa_fib(info, fibnum); 10938c0fec80SRobert Watson if (error) 10948071913dSRuslan Ermilov senderr(error); 10958c0fec80SRobert Watson } else 10968c0fec80SRobert Watson ifa_ref(info->rti_ifa); 10978071913dSRuslan Ermilov ifa = info->rti_ifa; 10981ed81b73SMarko Zec rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO); 10998c0fec80SRobert Watson if (rt == NULL) { 11008c0fec80SRobert Watson if (ifa != NULL) 11018c0fec80SRobert Watson ifa_free(ifa); 1102df8bae1dSRodney W. Grimes senderr(ENOBUFS); 11038c0fec80SRobert Watson } 1104d1dd20beSSam Leffler RT_LOCK_INIT(rt); 1105df8bae1dSRodney W. Grimes rt->rt_flags = RTF_UP | flags; 11068b07e49aSJulian Elischer rt->rt_fibnum = fibnum; 1107499676dfSJulian Elischer /* 1108499676dfSJulian Elischer * Add the gateway. Possibly re-malloc-ing the storage for it 11096e6b3f7cSQing Li * 1110499676dfSJulian Elischer */ 1111d1dd20beSSam Leffler RT_LOCK(rt); 1112831a80b0SMatthew Dillon if ((error = rt_setgate(rt, dst, gateway)) != 0) { 1113d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 11148c0fec80SRobert Watson if (ifa != NULL) 11158c0fec80SRobert Watson ifa_free(ifa); 11161ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1117704b0666SBill Fenner senderr(error); 1118df8bae1dSRodney W. Grimes } 1119499676dfSJulian Elischer 1120499676dfSJulian Elischer /* 1121499676dfSJulian Elischer * point to the (possibly newly malloc'd) dest address. 1122499676dfSJulian Elischer */ 1123d1dd20beSSam Leffler ndst = (struct sockaddr *)rt_key(rt); 1124499676dfSJulian Elischer 1125499676dfSJulian Elischer /* 1126499676dfSJulian Elischer * make sure it contains the value we want (masked if needed). 1127499676dfSJulian Elischer */ 1128df8bae1dSRodney W. Grimes if (netmask) { 1129df8bae1dSRodney W. Grimes rt_maskedcopy(dst, ndst, netmask); 1130df8bae1dSRodney W. Grimes } else 11311838a647SLuigi Rizzo bcopy(dst, ndst, dst->sa_len); 11328e718bb4SGarrett Wollman 11338e718bb4SGarrett Wollman /* 11348c0fec80SRobert Watson * We use the ifa reference returned by rt_getifa_fib(). 11358e718bb4SGarrett Wollman * This moved from below so that rnh->rnh_addaddr() can 1136499676dfSJulian Elischer * examine the ifa and ifa->ifa_ifp if it so desires. 11378e718bb4SGarrett Wollman */ 11388e718bb4SGarrett Wollman rt->rt_ifa = ifa; 11398e718bb4SGarrett Wollman rt->rt_ifp = ifa->ifa_ifp; 1140427ac07fSKip Macy rt->rt_rmx.rmx_weight = 1; 11418e718bb4SGarrett Wollman 1142e440aed9SQing Li #ifdef RADIX_MPATH 1143e440aed9SQing Li /* do not permit exactly the same dst/mask/gw pair */ 1144e440aed9SQing Li if (rn_mpath_capable(rnh) && 1145e440aed9SQing Li rt_mpath_conflict(rnh, rt, netmask)) { 1146e440aed9SQing Li if (rt->rt_ifa) { 11471099f828SRobert Watson ifa_free(rt->rt_ifa); 1148e440aed9SQing Li } 1149e440aed9SQing Li Free(rt_key(rt)); 1150e440aed9SQing Li RT_LOCK_DESTROY(rt); 11511ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1152e440aed9SQing Li senderr(EEXIST); 1153e440aed9SQing Li } 1154e440aed9SQing Li #endif 1155e440aed9SQing Li 1156d1dd20beSSam Leffler /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ 1157d1dd20beSSam Leffler rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); 1158499676dfSJulian Elischer /* 1159499676dfSJulian Elischer * If it still failed to go into the tree, 1160499676dfSJulian Elischer * then un-make it (this should be a function) 1161499676dfSJulian Elischer */ 116285911824SLuigi Rizzo if (rn == NULL) { 1163d1dd20beSSam Leffler if (rt->rt_ifa) 11641099f828SRobert Watson ifa_free(rt->rt_ifa); 1165df8bae1dSRodney W. Grimes Free(rt_key(rt)); 1166d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 11671ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1168df8bae1dSRodney W. Grimes senderr(EEXIST); 1169df8bae1dSRodney W. Grimes } 1170499676dfSJulian Elischer 1171499676dfSJulian Elischer /* 1172a0c0e34bSGleb Smirnoff * If this protocol has something to add to this then 1173499676dfSJulian Elischer * allow it to do that as well. 1174499676dfSJulian Elischer */ 1175df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest) 11768071913dSRuslan Ermilov ifa->ifa_rtrequest(req, rt, info); 1177499676dfSJulian Elischer 1178cd02a0b7SGarrett Wollman /* 1179499676dfSJulian Elischer * actually return a resultant rtentry and 1180499676dfSJulian Elischer * give the caller a single reference. 1181499676dfSJulian Elischer */ 1182df8bae1dSRodney W. Grimes if (ret_nrt) { 1183df8bae1dSRodney W. Grimes *ret_nrt = rt; 11847138d65cSSam Leffler RT_ADDREF(rt); 1185df8bae1dSRodney W. Grimes } 1186d1dd20beSSam Leffler RT_UNLOCK(rt); 1187df8bae1dSRodney W. Grimes break; 11888071913dSRuslan Ermilov default: 11898071913dSRuslan Ermilov error = EOPNOTSUPP; 1190df8bae1dSRodney W. Grimes } 1191df8bae1dSRodney W. Grimes bad: 11923120b9d4SKip Macy if (needlock) 1193956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1194df8bae1dSRodney W. Grimes return (error); 1195d1dd20beSSam Leffler #undef senderr 1196d1dd20beSSam Leffler } 1197d1dd20beSSam Leffler 11988071913dSRuslan Ermilov #undef dst 11998071913dSRuslan Ermilov #undef gateway 12008071913dSRuslan Ermilov #undef netmask 12018071913dSRuslan Ermilov #undef ifaaddr 12028071913dSRuslan Ermilov #undef ifpaddr 12038071913dSRuslan Ermilov #undef flags 1204df8bae1dSRodney W. Grimes 1205df8bae1dSRodney W. Grimes int 1206d1dd20beSSam Leffler rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) 1207df8bae1dSRodney W. Grimes { 1208d1dd20beSSam Leffler /* XXX dst may be overwritten, can we move this to below */ 12096e6b3f7cSQing Li int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); 12106e6b3f7cSQing Li #ifdef INVARIANTS 1211c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rnh; 1212c2c2a7c1SBjoern A. Zeeb 1213c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, dst->sa_family); 12146e6b3f7cSQing Li #endif 1215d1dd20beSSam Leffler 1216d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 12173120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1218df8bae1dSRodney W. Grimes 12191db1fffaSBill Fenner /* 122085911824SLuigi Rizzo * Prepare to store the gateway in rt->rt_gateway. 122185911824SLuigi Rizzo * Both dst and gateway are stored one after the other in the same 122285911824SLuigi Rizzo * malloc'd chunk. If we have room, we can reuse the old buffer, 122385911824SLuigi Rizzo * rt_gateway already points to the right place. 122485911824SLuigi Rizzo * Otherwise, malloc a new block and update the 'dst' address. 1225499676dfSJulian Elischer */ 122685911824SLuigi Rizzo if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) { 122785911824SLuigi Rizzo caddr_t new; 122885911824SLuigi Rizzo 1229df8bae1dSRodney W. Grimes R_Malloc(new, caddr_t, dlen + glen); 123085911824SLuigi Rizzo if (new == NULL) 12311db1fffaSBill Fenner return ENOBUFS; 1232499676dfSJulian Elischer /* 123385911824SLuigi Rizzo * XXX note, we copy from *dst and not *rt_key(rt) because 123485911824SLuigi Rizzo * rt_setgate() can be called to initialize a newly 123585911824SLuigi Rizzo * allocated route entry, in which case rt_key(rt) == NULL 123685911824SLuigi Rizzo * (and also rt->rt_gateway == NULL). 123785911824SLuigi Rizzo * Free()/free() handle a NULL argument just fine. 1238499676dfSJulian Elischer */ 12391838a647SLuigi Rizzo bcopy(dst, new, dlen); 124085911824SLuigi Rizzo Free(rt_key(rt)); /* free old block, if any */ 1241445e045bSAlexander Kabaev rt_key(rt) = (struct sockaddr *)new; 124285911824SLuigi Rizzo rt->rt_gateway = (struct sockaddr *)(new + dlen); 1243df8bae1dSRodney W. Grimes } 1244499676dfSJulian Elischer 1245499676dfSJulian Elischer /* 124685911824SLuigi Rizzo * Copy the new gateway value into the memory chunk. 124785911824SLuigi Rizzo */ 124885911824SLuigi Rizzo bcopy(gate, rt->rt_gateway, glen); 124985911824SLuigi Rizzo 12506e6b3f7cSQing Li return (0); 1251df8bae1dSRodney W. Grimes } 1252df8bae1dSRodney W. Grimes 1253f708ef1bSPoul-Henning Kamp static void 1254d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 1255df8bae1dSRodney W. Grimes { 1256df8bae1dSRodney W. Grimes register u_char *cp1 = (u_char *)src; 1257df8bae1dSRodney W. Grimes register u_char *cp2 = (u_char *)dst; 1258df8bae1dSRodney W. Grimes register u_char *cp3 = (u_char *)netmask; 1259df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 1260df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 1261df8bae1dSRodney W. Grimes 1262df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 1263df8bae1dSRodney W. Grimes cp3 += 2; 1264df8bae1dSRodney W. Grimes if (cplim > cplim2) 1265df8bae1dSRodney W. Grimes cplim = cplim2; 1266df8bae1dSRodney W. Grimes while (cp2 < cplim) 1267df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 1268df8bae1dSRodney W. Grimes if (cp2 < cplim2) 1269df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 1270df8bae1dSRodney W. Grimes } 1271df8bae1dSRodney W. Grimes 1272df8bae1dSRodney W. Grimes /* 1273df8bae1dSRodney W. Grimes * Set up a routing table entry, normally 1274df8bae1dSRodney W. Grimes * for an interface. 1275df8bae1dSRodney W. Grimes */ 12768b07e49aSJulian Elischer #define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 12778b07e49aSJulian Elischer static inline int 12788b07e49aSJulian Elischer rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 1279df8bae1dSRodney W. Grimes { 12805aca0b30SLuigi Rizzo struct sockaddr *dst; 12818071913dSRuslan Ermilov struct sockaddr *netmask; 128285911824SLuigi Rizzo struct rtentry *rt = NULL; 12838071913dSRuslan Ermilov struct rt_addrinfo info; 1284e440aed9SQing Li int error = 0; 12858b07e49aSJulian Elischer int startfib, endfib; 12868b07e49aSJulian Elischer char tempbuf[_SOCKADDR_TMPSIZE]; 12878b07e49aSJulian Elischer int didwork = 0; 12888b07e49aSJulian Elischer int a_failure = 0; 12896e6b3f7cSQing Li static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1290df8bae1dSRodney W. Grimes 12918071913dSRuslan Ermilov if (flags & RTF_HOST) { 12928071913dSRuslan Ermilov dst = ifa->ifa_dstaddr; 12938071913dSRuslan Ermilov netmask = NULL; 12948071913dSRuslan Ermilov } else { 12958071913dSRuslan Ermilov dst = ifa->ifa_addr; 12968071913dSRuslan Ermilov netmask = ifa->ifa_netmask; 12978071913dSRuslan Ermilov } 12988b07e49aSJulian Elischer if ( dst->sa_family != AF_INET) 12998b07e49aSJulian Elischer fibnum = 0; 13008b07e49aSJulian Elischer if (fibnum == -1) { 130166e8505fSJulian Elischer if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) { 130266e8505fSJulian Elischer startfib = endfib = curthread->td_proc->p_fibnum; 130366e8505fSJulian Elischer } else { 13048b07e49aSJulian Elischer startfib = 0; 13058b07e49aSJulian Elischer endfib = rt_numfibs - 1; 130666e8505fSJulian Elischer } 13078b07e49aSJulian Elischer } else { 13088b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 13098b07e49aSJulian Elischer startfib = fibnum; 13108b07e49aSJulian Elischer endfib = fibnum; 13118b07e49aSJulian Elischer } 1312ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 1313ac4a76ebSBjoern A. Zeeb return(EINVAL); 1314ac4a76ebSBjoern A. Zeeb 1315b0a76b88SJulian Elischer /* 13168b07e49aSJulian Elischer * If it's a delete, check that if it exists, 13178b07e49aSJulian Elischer * it's on the correct interface or we might scrub 13188b07e49aSJulian Elischer * a route to another ifa which would 1319b0a76b88SJulian Elischer * be confusing at best and possibly worse. 1320b0a76b88SJulian Elischer */ 1321df8bae1dSRodney W. Grimes if (cmd == RTM_DELETE) { 1322b0a76b88SJulian Elischer /* 1323b0a76b88SJulian Elischer * It's a delete, so it should already exist.. 1324b0a76b88SJulian Elischer * If it's a net, mask off the host bits 1325b0a76b88SJulian Elischer * (Assuming we have a mask) 13268b07e49aSJulian Elischer * XXX this is kinda inet specific.. 1327b0a76b88SJulian Elischer */ 13288071913dSRuslan Ermilov if (netmask != NULL) { 13298b07e49aSJulian Elischer rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 13308b07e49aSJulian Elischer dst = (struct sockaddr *)tempbuf; 1331df8bae1dSRodney W. Grimes } 13328b07e49aSJulian Elischer } 13338b07e49aSJulian Elischer /* 13348b07e49aSJulian Elischer * Now go through all the requested tables (fibs) and do the 13358b07e49aSJulian Elischer * requested action. Realistically, this will either be fib 0 13368b07e49aSJulian Elischer * for protocols that don't do multiple tables or all the 13378b07e49aSJulian Elischer * tables for those that do. XXX For this version only AF_INET. 13388b07e49aSJulian Elischer * When that changes code should be refactored to protocol 13398b07e49aSJulian Elischer * independent parts and protocol dependent parts. 13408b07e49aSJulian Elischer */ 13418b07e49aSJulian Elischer for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 13428b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 13438b07e49aSJulian Elischer struct radix_node_head *rnh; 13448b07e49aSJulian Elischer struct radix_node *rn; 1345b0a76b88SJulian Elischer /* 13468071913dSRuslan Ermilov * Look up an rtentry that is in the routing tree and 13478071913dSRuslan Ermilov * contains the correct info. 1348b0a76b88SJulian Elischer */ 1349c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1350c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 13518b07e49aSJulian Elischer /* this table doesn't exist but others might */ 13528b07e49aSJulian Elischer continue; 1353956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1354e440aed9SQing Li #ifdef RADIX_MPATH 1355e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1356e440aed9SQing Li 1357e440aed9SQing Li rn = rnh->rnh_matchaddr(dst, rnh); 1358e440aed9SQing Li if (rn == NULL) 1359e440aed9SQing Li error = ESRCH; 1360e440aed9SQing Li else { 1361e440aed9SQing Li rt = RNTORT(rn); 1362e440aed9SQing Li /* 13638b07e49aSJulian Elischer * for interface route the 13648b07e49aSJulian Elischer * rt->rt_gateway is sockaddr_intf 13658b07e49aSJulian Elischer * for cloning ARP entries, so 13668b07e49aSJulian Elischer * rt_mpath_matchgate must use the 13678b07e49aSJulian Elischer * interface address 1368e440aed9SQing Li */ 13698b07e49aSJulian Elischer rt = rt_mpath_matchgate(rt, 13708b07e49aSJulian Elischer ifa->ifa_addr); 1371e440aed9SQing Li if (!rt) 1372e440aed9SQing Li error = ESRCH; 1373e440aed9SQing Li } 1374e440aed9SQing Li } 1375e440aed9SQing Li else 1376e440aed9SQing Li #endif 13778b07e49aSJulian Elischer rn = rnh->rnh_lookup(dst, netmask, rnh); 13788b07e49aSJulian Elischer error = (rn == NULL || 13798071913dSRuslan Ermilov (rn->rn_flags & RNF_ROOT) || 1380d6941ce9SLuigi Rizzo RNTORT(rn)->rt_ifa != ifa || 138185911824SLuigi Rizzo !sa_equal((struct sockaddr *)rn->rn_key, dst)); 1382956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1383956b0b65SJeffrey Hsu if (error) { 13848b07e49aSJulian Elischer /* this is only an error if bad on ALL tables */ 13858b07e49aSJulian Elischer continue; 1386df8bae1dSRodney W. Grimes } 1387b0a76b88SJulian Elischer } 1388b0a76b88SJulian Elischer /* 1389b0a76b88SJulian Elischer * Do the actual request 1390b0a76b88SJulian Elischer */ 13918071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 13928071913dSRuslan Ermilov info.rti_ifa = ifa; 13938071913dSRuslan Ermilov info.rti_flags = flags | ifa->ifa_flags; 13948071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 13956e6b3f7cSQing Li /* 13966e6b3f7cSQing Li * doing this for compatibility reasons 13976e6b3f7cSQing Li */ 13986e6b3f7cSQing Li if (cmd == RTM_ADD) 13996e6b3f7cSQing Li info.rti_info[RTAX_GATEWAY] = 14006e6b3f7cSQing Li (struct sockaddr *)&null_sdl; 14016e6b3f7cSQing Li else 14028071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 14038071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 14048b07e49aSJulian Elischer error = rtrequest1_fib(cmd, &info, &rt, fibnum); 14055aca0b30SLuigi Rizzo if (error == 0 && rt != NULL) { 14068071913dSRuslan Ermilov /* 14076f99b44cSBrian Somers * notify any listening routing agents of the change 14088071913dSRuslan Ermilov */ 1409d1dd20beSSam Leffler RT_LOCK(rt); 1410e440aed9SQing Li #ifdef RADIX_MPATH 1411e440aed9SQing Li /* 1412e440aed9SQing Li * in case address alias finds the first address 1413e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.246/24 1414e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.247/24 1415e440aed9SQing Li * the address set in the route is 192.103.54.246 1416e440aed9SQing Li * so we need to replace it with 192.103.54.247 1417e440aed9SQing Li */ 14188b07e49aSJulian Elischer if (memcmp(rt->rt_ifa->ifa_addr, 14198b07e49aSJulian Elischer ifa->ifa_addr, ifa->ifa_addr->sa_len)) { 14201099f828SRobert Watson ifa_free(rt->rt_ifa); 14211099f828SRobert Watson ifa_ref(ifa); 1422e440aed9SQing Li rt->rt_ifp = ifa->ifa_ifp; 1423e440aed9SQing Li rt->rt_ifa = ifa; 1424e440aed9SQing Li } 1425e440aed9SQing Li #endif 14266e6b3f7cSQing Li /* 14276e6b3f7cSQing Li * doing this for compatibility reasons 14286e6b3f7cSQing Li */ 14296e6b3f7cSQing Li if (cmd == RTM_ADD) { 14306e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 14316e6b3f7cSQing Li rt->rt_ifp->if_type; 14326e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 14336e6b3f7cSQing Li rt->rt_ifp->if_index; 14346e6b3f7cSQing Li } 14358071913dSRuslan Ermilov rt_newaddrmsg(cmd, ifa, error, rt); 14368071913dSRuslan Ermilov if (cmd == RTM_DELETE) { 1437b0a76b88SJulian Elischer /* 14388b07e49aSJulian Elischer * If we are deleting, and we found an entry, 14398b07e49aSJulian Elischer * then it's been removed from the tree.. 14408b07e49aSJulian Elischer * now throw it away. 1441b0a76b88SJulian Elischer */ 1442d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1443d1dd20beSSam Leffler } else { 1444d1dd20beSSam Leffler if (cmd == RTM_ADD) { 1445b0a76b88SJulian Elischer /* 14468b07e49aSJulian Elischer * We just wanted to add it.. 14478b07e49aSJulian Elischer * we don't actually need a reference. 1448b0a76b88SJulian Elischer */ 14497138d65cSSam Leffler RT_REMREF(rt); 1450df8bae1dSRodney W. Grimes } 1451d1dd20beSSam Leffler RT_UNLOCK(rt); 1452d1dd20beSSam Leffler } 14538b07e49aSJulian Elischer didwork = 1; 1454df8bae1dSRodney W. Grimes } 14558b07e49aSJulian Elischer if (error) 14568b07e49aSJulian Elischer a_failure = error; 14578b07e49aSJulian Elischer } 14588b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 14598b07e49aSJulian Elischer if (didwork) { 14608b07e49aSJulian Elischer error = 0; 14618b07e49aSJulian Elischer } else { 14628b07e49aSJulian Elischer /* we only give an error if it wasn't in any table */ 14638b07e49aSJulian Elischer error = ((flags & RTF_HOST) ? 14648b07e49aSJulian Elischer EHOSTUNREACH : ENETUNREACH); 14658b07e49aSJulian Elischer } 14668b07e49aSJulian Elischer } else { 14678b07e49aSJulian Elischer if (a_failure) { 14688b07e49aSJulian Elischer /* return an error if any of them failed */ 14698b07e49aSJulian Elischer error = a_failure; 14708b07e49aSJulian Elischer } 14718b07e49aSJulian Elischer } 14723ec66d6cSDavid Greenman return (error); 14733ec66d6cSDavid Greenman } 1474cb64988fSLuoqi Chen 14758b07e49aSJulian Elischer /* special one for inet internal use. may not use. */ 14768b07e49aSJulian Elischer int 14778b07e49aSJulian Elischer rtinit_fib(struct ifaddr *ifa, int cmd, int flags) 14788b07e49aSJulian Elischer { 14798b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, -1)); 14808b07e49aSJulian Elischer } 14818b07e49aSJulian Elischer 14828b07e49aSJulian Elischer /* 14838b07e49aSJulian Elischer * Set up a routing table entry, normally 14848b07e49aSJulian Elischer * for an interface. 14858b07e49aSJulian Elischer */ 14868b07e49aSJulian Elischer int 14878b07e49aSJulian Elischer rtinit(struct ifaddr *ifa, int cmd, int flags) 14888b07e49aSJulian Elischer { 14898b07e49aSJulian Elischer struct sockaddr *dst; 14908b07e49aSJulian Elischer int fib = 0; 14918b07e49aSJulian Elischer 14928b07e49aSJulian Elischer if (flags & RTF_HOST) { 14938b07e49aSJulian Elischer dst = ifa->ifa_dstaddr; 14948b07e49aSJulian Elischer } else { 14958b07e49aSJulian Elischer dst = ifa->ifa_addr; 14968b07e49aSJulian Elischer } 14978b07e49aSJulian Elischer 14988b07e49aSJulian Elischer if (dst->sa_family == AF_INET) 14998b07e49aSJulian Elischer fib = -1; 15008b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, fib)); 15018b07e49aSJulian Elischer } 1502