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> 54603724d3SBjoern A. Zeeb #include <sys/vimage.h> 55df8bae1dSRodney W. Grimes 56df8bae1dSRodney W. Grimes #include <net/if.h> 576e6b3f7cSQing Li #include <net/if_dl.h> 58df8bae1dSRodney W. Grimes #include <net/route.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> 664b79449eSBjoern A. Zeeb #include <netinet/vinet.h> 67df8bae1dSRodney W. Grimes 682dc1d581SAndre Oppermann #include <vm/uma.h> 692dc1d581SAndre Oppermann 708b07e49aSJulian Elischer u_int rt_numfibs = RT_NUMFIBS; 718b07e49aSJulian Elischer SYSCTL_INT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, ""); 7266e8505fSJulian Elischer /* 7366e8505fSJulian Elischer * Allow the boot code to allow LESS than RT_MAXFIBS to be used. 7466e8505fSJulian Elischer * We can't do more because storage is statically allocated for now. 7566e8505fSJulian Elischer * (for compatibility reasons.. this will change). 7666e8505fSJulian Elischer */ 778b07e49aSJulian Elischer TUNABLE_INT("net.fibs", &rt_numfibs); 788b07e49aSJulian Elischer 7966e8505fSJulian Elischer /* 8066e8505fSJulian Elischer * By default add routes to all fibs for new interfaces. 8166e8505fSJulian Elischer * Once this is set to 0 then only allocate routes on interface 8266e8505fSJulian Elischer * changes for the FIB of the caller when adding a new set of addresses 8366e8505fSJulian Elischer * to an interface. XXX this is a shotgun aproach to a problem that needs 8466e8505fSJulian Elischer * a more fine grained solution.. that will come. 8566e8505fSJulian Elischer */ 8666e8505fSJulian Elischer u_int rt_add_addr_allfibs = 1; 8766e8505fSJulian Elischer SYSCTL_INT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW, 8866e8505fSJulian Elischer &rt_add_addr_allfibs, 0, ""); 8966e8505fSJulian Elischer TUNABLE_INT("net.add_addr_allfibs", &rt_add_addr_allfibs); 9066e8505fSJulian Elischer 9144e33a07SMarko Zec #ifdef VIMAGE_GLOBALS 92c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rt_tables; 93f987f193SBjoern A. Zeeb static uma_zone_t rtzone; /* Routing table UMA zone. */ 94f987f193SBjoern A. Zeeb int rttrash; /* routes not in table but not freed */ 95f987f193SBjoern A. Zeeb struct rtstat rtstat; 9644e33a07SMarko Zec #endif 97df8bae1dSRodney W. Grimes 98b58ea5f3SBjoern A. Zeeb #ifndef VIMAGE_GLOBALS 99b58ea5f3SBjoern A. Zeeb struct vnet_rtable { 100b58ea5f3SBjoern A. Zeeb struct radix_node_head *_rt_tables; 101b58ea5f3SBjoern A. Zeeb uma_zone_t _rtzone; 102b58ea5f3SBjoern A. Zeeb int _rttrash; 103b58ea5f3SBjoern A. Zeeb struct rtstat _rtstat; 104b58ea5f3SBjoern A. Zeeb }; 105b58ea5f3SBjoern A. Zeeb 106b58ea5f3SBjoern A. Zeeb /* Size guard. See sys/vimage.h. */ 107b58ea5f3SBjoern A. Zeeb VIMAGE_CTASSERT(SIZEOF_vnet_rtable, sizeof(struct vnet_rtable)); 108b58ea5f3SBjoern A. Zeeb 109b58ea5f3SBjoern A. Zeeb #ifndef VIMAGE 110b58ea5f3SBjoern A. Zeeb static struct vnet_rtable vnet_rtable_0; 111b58ea5f3SBjoern A. Zeeb #endif 112b58ea5f3SBjoern A. Zeeb #endif 113b58ea5f3SBjoern A. Zeeb 114b58ea5f3SBjoern A. Zeeb /* 115b58ea5f3SBjoern A. Zeeb * Symbol translation macros 116b58ea5f3SBjoern A. Zeeb */ 117b58ea5f3SBjoern A. Zeeb #define INIT_VNET_RTABLE(vnet) \ 118b58ea5f3SBjoern A. Zeeb INIT_FROM_VNET(vnet, VNET_MOD_RTABLE, struct vnet_rtable, vnet_rtable) 119b58ea5f3SBjoern A. Zeeb 120b58ea5f3SBjoern A. Zeeb #define VNET_RTABLE(sym) VSYM(vnet_rtable, sym) 121b58ea5f3SBjoern A. Zeeb 122b58ea5f3SBjoern A. Zeeb #define V_rt_tables VNET_RTABLE(rt_tables) 123b58ea5f3SBjoern A. Zeeb #define V_rtstat VNET_RTABLE(rtstat) 124b58ea5f3SBjoern A. Zeeb #define V_rttrash VNET_RTABLE(rttrash) 125b58ea5f3SBjoern A. Zeeb #define V_rtzone VNET_RTABLE(rtzone) 126b58ea5f3SBjoern A. Zeeb 127929ddbbbSAlfred Perlstein static void rt_maskedcopy(struct sockaddr *, 128929ddbbbSAlfred Perlstein struct sockaddr *, struct sockaddr *); 1291ed81b73SMarko Zec static int vnet_route_iattach(const void *); 130bc29160dSMarko Zec #ifdef VIMAGE 131bc29160dSMarko Zec static int vnet_route_idetach(const void *); 132bc29160dSMarko Zec #endif 133f708ef1bSPoul-Henning Kamp 134bfe1aba4SMarko Zec #ifndef VIMAGE_GLOBALS 135b58ea5f3SBjoern A. Zeeb static struct vnet_symmap vnet_rtable_symmap[] = { 136b58ea5f3SBjoern A. Zeeb VNET_SYMMAP(rtable, rt_tables), 137b58ea5f3SBjoern A. Zeeb VNET_SYMMAP(rtable, rtstat), 138b58ea5f3SBjoern A. Zeeb VNET_SYMMAP(rtable, rttrash), 139b58ea5f3SBjoern A. Zeeb VNET_SYMMAP_END 140b58ea5f3SBjoern A. Zeeb }; 141b58ea5f3SBjoern A. Zeeb 142bfe1aba4SMarko Zec static const vnet_modinfo_t vnet_rtable_modinfo = { 143bfe1aba4SMarko Zec .vmi_id = VNET_MOD_RTABLE, 144bfe1aba4SMarko Zec .vmi_name = "rtable", 145b58ea5f3SBjoern A. Zeeb .vmi_size = sizeof(struct vnet_rtable), 146b58ea5f3SBjoern A. Zeeb .vmi_symmap = vnet_rtable_symmap, 147bc29160dSMarko Zec .vmi_iattach = vnet_route_iattach, 148bc29160dSMarko Zec #ifdef VIMAGE 149bc29160dSMarko Zec .vmi_idetach = vnet_route_idetach 150bc29160dSMarko Zec #endif 151bfe1aba4SMarko Zec }; 152bfe1aba4SMarko Zec #endif /* !VIMAGE_GLOBALS */ 153bfe1aba4SMarko Zec 154d6941ce9SLuigi Rizzo /* compare two sockaddr structures */ 155d6941ce9SLuigi Rizzo #define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) 156d6941ce9SLuigi Rizzo 157d6941ce9SLuigi Rizzo /* 158d6941ce9SLuigi Rizzo * Convert a 'struct radix_node *' to a 'struct rtentry *'. 159d6941ce9SLuigi Rizzo * The operation can be done safely (in this code) because a 160d6941ce9SLuigi Rizzo * 'struct rtentry' starts with two 'struct radix_node''s, the first 161d6941ce9SLuigi Rizzo * one representing leaf nodes in the routing tree, which is 162d6941ce9SLuigi Rizzo * what the code in radix.c passes us as a 'struct radix_node'. 163d6941ce9SLuigi Rizzo * 164d6941ce9SLuigi Rizzo * But because there are a lot of assumptions in this conversion, 165d6941ce9SLuigi Rizzo * do not cast explicitly, but always use the macro below. 166d6941ce9SLuigi Rizzo */ 167d6941ce9SLuigi Rizzo #define RNTORT(p) ((struct rtentry *)(p)) 168d6941ce9SLuigi Rizzo 1698b07e49aSJulian Elischer #if 0 1708b07e49aSJulian Elischer /* default fib for tunnels to use */ 1718b07e49aSJulian Elischer u_int tunnel_fib = 0; 1728b07e49aSJulian Elischer SYSCTL_INT(_net, OID_AUTO, tunnelfib, CTLFLAG_RD, &tunnel_fib, 0, ""); 1738b07e49aSJulian Elischer #endif 1748b07e49aSJulian Elischer 1758b07e49aSJulian Elischer /* 1768b07e49aSJulian Elischer * handler for net.my_fibnum 1778b07e49aSJulian Elischer */ 1788b07e49aSJulian Elischer static int 1798b07e49aSJulian Elischer sysctl_my_fibnum(SYSCTL_HANDLER_ARGS) 180df8bae1dSRodney W. Grimes { 1818b07e49aSJulian Elischer int fibnum; 1828b07e49aSJulian Elischer int error; 1838b07e49aSJulian Elischer 1848b07e49aSJulian Elischer fibnum = curthread->td_proc->p_fibnum; 1858b07e49aSJulian Elischer error = sysctl_handle_int(oidp, &fibnum, 0, req); 1868b07e49aSJulian Elischer return (error); 187df8bae1dSRodney W. Grimes } 188df8bae1dSRodney W. Grimes 1898b07e49aSJulian Elischer SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, 1908b07e49aSJulian Elischer NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); 1912dc1d581SAndre Oppermann 192c2c2a7c1SBjoern A. Zeeb static __inline struct radix_node_head ** 193c2c2a7c1SBjoern A. Zeeb rt_tables_get_rnh_ptr(int table, int fam) 194c2c2a7c1SBjoern A. Zeeb { 195b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 196c2c2a7c1SBjoern A. Zeeb struct radix_node_head **rnh; 197c2c2a7c1SBjoern A. Zeeb 198c2c2a7c1SBjoern A. Zeeb KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", 199c2c2a7c1SBjoern A. Zeeb __func__)); 200c2c2a7c1SBjoern A. Zeeb KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.", 201c2c2a7c1SBjoern A. Zeeb __func__)); 202c2c2a7c1SBjoern A. Zeeb 203c2c2a7c1SBjoern A. Zeeb /* rnh is [fib=0][af=0]. */ 204c2c2a7c1SBjoern A. Zeeb rnh = (struct radix_node_head **)V_rt_tables; 205c2c2a7c1SBjoern A. Zeeb /* Get the offset to the requested table and fam. */ 206c2c2a7c1SBjoern A. Zeeb rnh += table * (AF_MAX+1) + fam; 207c2c2a7c1SBjoern A. Zeeb 208c2c2a7c1SBjoern A. Zeeb return (rnh); 209c2c2a7c1SBjoern A. Zeeb } 210c2c2a7c1SBjoern A. Zeeb 211c2c2a7c1SBjoern A. Zeeb struct radix_node_head * 212c2c2a7c1SBjoern A. Zeeb rt_tables_get_rnh(int table, int fam) 213c2c2a7c1SBjoern A. Zeeb { 214c2c2a7c1SBjoern A. Zeeb 215c2c2a7c1SBjoern A. Zeeb return (*rt_tables_get_rnh_ptr(table, fam)); 216c2c2a7c1SBjoern A. Zeeb } 217c2c2a7c1SBjoern A. Zeeb 2182eb5613fSLuigi Rizzo static void 2192eb5613fSLuigi Rizzo route_init(void) 220df8bae1dSRodney W. Grimes { 2218b07e49aSJulian Elischer 2226f95a5ebSJulian Elischer /* whack the tunable ints into line. */ 2238b07e49aSJulian Elischer if (rt_numfibs > RT_MAXFIBS) 2248b07e49aSJulian Elischer rt_numfibs = RT_MAXFIBS; 2258b07e49aSJulian Elischer if (rt_numfibs == 0) 2268b07e49aSJulian Elischer rt_numfibs = 1; 227df8bae1dSRodney W. Grimes rn_init(); /* initialize all zeroes, all ones, mask table */ 2288b07e49aSJulian Elischer 229bfe1aba4SMarko Zec #ifndef VIMAGE_GLOBALS 230bfe1aba4SMarko Zec vnet_mod_register(&vnet_rtable_modinfo); 231bfe1aba4SMarko Zec #else 2321ed81b73SMarko Zec vnet_route_iattach(NULL); 233bfe1aba4SMarko Zec #endif 2341ed81b73SMarko Zec } 2351ed81b73SMarko Zec 236bc29160dSMarko Zec static int 237bc29160dSMarko Zec vnet_route_iattach(const void *unused __unused) 2381ed81b73SMarko Zec { 239b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 2401ed81b73SMarko Zec struct domain *dom; 241c2c2a7c1SBjoern A. Zeeb struct radix_node_head **rnh; 242c2c2a7c1SBjoern A. Zeeb int table; 2431ed81b73SMarko Zec int fam; 2441ed81b73SMarko Zec 245c2c2a7c1SBjoern A. Zeeb V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) * 246c2c2a7c1SBjoern A. Zeeb sizeof(struct radix_node_head *), M_RTABLE, M_WAITOK|M_ZERO); 247c2c2a7c1SBjoern A. Zeeb 2481ed81b73SMarko Zec V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), NULL, NULL, 2491ed81b73SMarko Zec NULL, NULL, UMA_ALIGN_PTR, 0); 2508b07e49aSJulian Elischer for (dom = domains; dom; dom = dom->dom_next) { 2518b07e49aSJulian Elischer if (dom->dom_rtattach) { 2528b07e49aSJulian Elischer for (table = 0; table < rt_numfibs; table++) { 2538b07e49aSJulian Elischer if ( (fam = dom->dom_family) == AF_INET || 2548b07e49aSJulian Elischer table == 0) { 2558b07e49aSJulian Elischer /* for now only AF_INET has > 1 table */ 2568b07e49aSJulian Elischer /* XXX MRT 2578b07e49aSJulian Elischer * rtattach will be also called 2588b07e49aSJulian Elischer * from vfs_export.c but the 2598b07e49aSJulian Elischer * offset will be 0 2608b07e49aSJulian Elischer * (only for AF_INET and AF_INET6 2618b07e49aSJulian Elischer * which don't need it anyhow) 2628b07e49aSJulian Elischer */ 263c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh_ptr(table, fam); 264c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 265c2c2a7c1SBjoern A. Zeeb panic("%s: rnh NULL", __func__); 266c2c2a7c1SBjoern A. Zeeb dom->dom_rtattach((void **)rnh, 2678b07e49aSJulian Elischer dom->dom_rtoffset); 2688b07e49aSJulian Elischer } else { 2698b07e49aSJulian Elischer break; 2708b07e49aSJulian Elischer } 2718b07e49aSJulian Elischer } 2728b07e49aSJulian Elischer } 2738b07e49aSJulian Elischer } 2741ed81b73SMarko Zec 2751ed81b73SMarko Zec return (0); 2768b07e49aSJulian Elischer } 2778b07e49aSJulian Elischer 278bc29160dSMarko Zec #ifdef VIMAGE 279bc29160dSMarko Zec static int 280bc29160dSMarko Zec vnet_route_idetach(const void *unused __unused) 281bc29160dSMarko Zec { 282bc29160dSMarko Zec int table; 283bc29160dSMarko Zec int fam; 284bc29160dSMarko Zec struct domain *dom; 285bc29160dSMarko Zec struct radix_node_head **rnh; 286bc29160dSMarko Zec 287bc29160dSMarko Zec for (dom = domains; dom; dom = dom->dom_next) { 288bc29160dSMarko Zec if (dom->dom_rtdetach) { 289bc29160dSMarko Zec for (table = 0; table < rt_numfibs; table++) { 290bc29160dSMarko Zec if ( (fam = dom->dom_family) == AF_INET || 291bc29160dSMarko Zec table == 0) { 292bc29160dSMarko Zec /* For now only AF_INET has > 1 tbl. */ 293bc29160dSMarko Zec rnh = rt_tables_get_rnh_ptr(table, fam); 294bc29160dSMarko Zec if (rnh == NULL) 295bc29160dSMarko Zec panic("%s: rnh NULL", __func__); 296bc29160dSMarko Zec dom->dom_rtdetach((void **)rnh, 297bc29160dSMarko Zec dom->dom_rtoffset); 298bc29160dSMarko Zec } else { 299bc29160dSMarko Zec break; 300bc29160dSMarko Zec } 301bc29160dSMarko Zec } 302bc29160dSMarko Zec } 303bc29160dSMarko Zec } 304bc29160dSMarko Zec return (0); 305bc29160dSMarko Zec } 306bc29160dSMarko Zec #endif 307bc29160dSMarko Zec 3088b07e49aSJulian Elischer #ifndef _SYS_SYSPROTO_H_ 3098b07e49aSJulian Elischer struct setfib_args { 3108b07e49aSJulian Elischer int fibnum; 3118b07e49aSJulian Elischer }; 3128b07e49aSJulian Elischer #endif 3138b07e49aSJulian Elischer int 3148b07e49aSJulian Elischer setfib(struct thread *td, struct setfib_args *uap) 3158b07e49aSJulian Elischer { 3168b07e49aSJulian Elischer if (uap->fibnum < 0 || uap->fibnum >= rt_numfibs) 3178b07e49aSJulian Elischer return EINVAL; 3188b07e49aSJulian Elischer td->td_proc->p_fibnum = uap->fibnum; 3198b07e49aSJulian Elischer return (0); 320df8bae1dSRodney W. Grimes } 321df8bae1dSRodney W. Grimes 322df8bae1dSRodney W. Grimes /* 323df8bae1dSRodney W. Grimes * Packet routing routines. 324df8bae1dSRodney W. Grimes */ 325df8bae1dSRodney W. Grimes void 326d1dd20beSSam Leffler rtalloc(struct route *ro) 327df8bae1dSRodney W. Grimes { 3288b07e49aSJulian Elischer rtalloc_ign_fib(ro, 0UL, 0); 3298b07e49aSJulian Elischer } 3308b07e49aSJulian Elischer 3318b07e49aSJulian Elischer void 3328b07e49aSJulian Elischer rtalloc_fib(struct route *ro, u_int fibnum) 3338b07e49aSJulian Elischer { 3348b07e49aSJulian Elischer rtalloc_ign_fib(ro, 0UL, fibnum); 335df8bae1dSRodney W. Grimes } 336df8bae1dSRodney W. Grimes 337652082e6SGarrett Wollman void 338d1dd20beSSam Leffler rtalloc_ign(struct route *ro, u_long ignore) 339652082e6SGarrett Wollman { 34068f956b8SJohn Polstra struct rtentry *rt; 34168f956b8SJohn Polstra 34268f956b8SJohn Polstra if ((rt = ro->ro_rt) != NULL) { 34368f956b8SJohn Polstra if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 34468f956b8SJohn Polstra return; 34568f956b8SJohn Polstra RTFREE(rt); 34666810dd0SYoshinobu Inoue ro->ro_rt = NULL; 34768f956b8SJohn Polstra } 3488b07e49aSJulian Elischer ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, 0); 3498b07e49aSJulian Elischer if (ro->ro_rt) 3508b07e49aSJulian Elischer RT_UNLOCK(ro->ro_rt); 3518b07e49aSJulian Elischer } 3528b07e49aSJulian Elischer 3538b07e49aSJulian Elischer void 3548b07e49aSJulian Elischer rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum) 3558b07e49aSJulian Elischer { 3568b07e49aSJulian Elischer struct rtentry *rt; 3578b07e49aSJulian Elischer 3588b07e49aSJulian Elischer if ((rt = ro->ro_rt) != NULL) { 3598b07e49aSJulian Elischer if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 3608b07e49aSJulian Elischer return; 3618b07e49aSJulian Elischer RTFREE(rt); 3628b07e49aSJulian Elischer ro->ro_rt = NULL; 3638b07e49aSJulian Elischer } 3648b07e49aSJulian Elischer ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, fibnum); 365d1dd20beSSam Leffler if (ro->ro_rt) 366d1dd20beSSam Leffler RT_UNLOCK(ro->ro_rt); 367652082e6SGarrett Wollman } 368652082e6SGarrett Wollman 369b0a76b88SJulian Elischer /* 370b0a76b88SJulian Elischer * Look up the route that matches the address given 371b0a76b88SJulian Elischer * Or, at least try.. Create a cloned route if needed. 372d1dd20beSSam Leffler * 373d1dd20beSSam Leffler * The returned route, if any, is locked. 374b0a76b88SJulian Elischer */ 375df8bae1dSRodney W. Grimes struct rtentry * 376d1dd20beSSam Leffler rtalloc1(struct sockaddr *dst, int report, u_long ignflags) 377df8bae1dSRodney W. Grimes { 3788b07e49aSJulian Elischer return (rtalloc1_fib(dst, report, ignflags, 0)); 3798b07e49aSJulian Elischer } 3808b07e49aSJulian Elischer 3818b07e49aSJulian Elischer struct rtentry * 3828b07e49aSJulian Elischer rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, 3838b07e49aSJulian Elischer u_int fibnum) 3848b07e49aSJulian Elischer { 385b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 3868b07e49aSJulian Elischer struct radix_node_head *rnh; 387d1dd20beSSam Leffler struct rtentry *rt; 388d1dd20beSSam Leffler struct radix_node *rn; 389d1dd20beSSam Leffler struct rtentry *newrt; 390df8bae1dSRodney W. Grimes struct rt_addrinfo info; 3916e6b3f7cSQing Li int err = 0, msgtype = RTM_MISS; 3923120b9d4SKip Macy int needlock; 393df8bae1dSRodney W. Grimes 3948b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); 3958b07e49aSJulian Elischer if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */ 3968b07e49aSJulian Elischer fibnum = 0; 397c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 39885911824SLuigi Rizzo newrt = NULL; 399b0a76b88SJulian Elischer /* 400b0a76b88SJulian Elischer * Look up the address in the table for that Address Family 401b0a76b88SJulian Elischer */ 402956b0b65SJeffrey Hsu if (rnh == NULL) { 403603724d3SBjoern A. Zeeb V_rtstat.rts_unreach++; 4046e6b3f7cSQing Li goto miss; 405956b0b65SJeffrey Hsu } 4063120b9d4SKip Macy needlock = !(ignflags & RTF_RNH_LOCKED); 4073120b9d4SKip Macy if (needlock) 4083120b9d4SKip Macy RADIX_NODE_HEAD_RLOCK(rnh); 4093120b9d4SKip Macy #ifdef INVARIANTS 4103120b9d4SKip Macy else 4113120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 4123120b9d4SKip Macy #endif 4133120b9d4SKip Macy rn = rnh->rnh_matchaddr(dst, rnh); 4143120b9d4SKip Macy if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { 415d6941ce9SLuigi Rizzo newrt = rt = RNTORT(rn); 4163120b9d4SKip Macy RT_LOCK(newrt); 4173120b9d4SKip Macy RT_ADDREF(newrt); 4183120b9d4SKip Macy if (needlock) 4193120b9d4SKip Macy RADIX_NODE_HEAD_RUNLOCK(rnh); 4203120b9d4SKip Macy goto done; 4216e6b3f7cSQing Li 4226e6b3f7cSQing Li } else if (needlock) 4233120b9d4SKip Macy RADIX_NODE_HEAD_RUNLOCK(rnh); 4243120b9d4SKip Macy 425b0a76b88SJulian Elischer /* 426b0a76b88SJulian Elischer * Either we hit the root or couldn't find any match, 427b0a76b88SJulian Elischer * Which basically means 428b0a76b88SJulian Elischer * "caint get there frm here" 429b0a76b88SJulian Elischer */ 430603724d3SBjoern A. Zeeb V_rtstat.rts_unreach++; 431956b0b65SJeffrey Hsu miss: 4326e6b3f7cSQing Li if (report) { 433b0a76b88SJulian Elischer /* 434b0a76b88SJulian Elischer * If required, report the failure to the supervising 435b0a76b88SJulian Elischer * Authorities. 436b0a76b88SJulian Elischer * For a delete, this is not an error. (report == 0) 437b0a76b88SJulian Elischer */ 4386f5967c0SBruce Evans bzero(&info, sizeof(info)); 439df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 440df8bae1dSRodney W. Grimes rt_missmsg(msgtype, &info, 0, err); 441df8bae1dSRodney W. Grimes } 4423120b9d4SKip Macy done: 443d1dd20beSSam Leffler if (newrt) 444d1dd20beSSam Leffler RT_LOCK_ASSERT(newrt); 445df8bae1dSRodney W. Grimes return (newrt); 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes 448499676dfSJulian Elischer /* 449499676dfSJulian Elischer * Remove a reference count from an rtentry. 450499676dfSJulian Elischer * If the count gets low enough, take it out of the routing table 451499676dfSJulian Elischer */ 452df8bae1dSRodney W. Grimes void 453d1dd20beSSam Leffler rtfree(struct rtentry *rt) 454df8bae1dSRodney W. Grimes { 455b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 45685911824SLuigi Rizzo struct radix_node_head *rnh; 457df8bae1dSRodney W. Grimes 458a0c0e34bSGleb Smirnoff KASSERT(rt != NULL,("%s: NULL rt", __func__)); 459c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 460a0c0e34bSGleb Smirnoff KASSERT(rnh != NULL,("%s: NULL rnh", __func__)); 461499676dfSJulian Elischer 462d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 463d1dd20beSSam Leffler 464499676dfSJulian Elischer /* 465a0c0e34bSGleb Smirnoff * The callers should use RTFREE_LOCKED() or RTFREE(), so 466a0c0e34bSGleb Smirnoff * we should come here exactly with the last reference. 467499676dfSJulian Elischer */ 4687138d65cSSam Leffler RT_REMREF(rt); 469a0c0e34bSGleb Smirnoff if (rt->rt_refcnt > 0) { 470a42ea597SQing Li log(LOG_DEBUG, "%s: %p has %d refs\n", __func__, rt, rt->rt_refcnt); 471d1dd20beSSam Leffler goto done; 472a0c0e34bSGleb Smirnoff } 4739c63e9dbSSam Leffler 4749c63e9dbSSam Leffler /* 4759c63e9dbSSam Leffler * On last reference give the "close method" a chance 4769c63e9dbSSam Leffler * to cleanup private state. This also permits (for 4779c63e9dbSSam Leffler * IPv4 and IPv6) a chance to decide if the routing table 4789c63e9dbSSam Leffler * entry should be purged immediately or at a later time. 4799c63e9dbSSam Leffler * When an immediate purge is to happen the close routine 4809c63e9dbSSam Leffler * typically calls rtexpunge which clears the RTF_UP flag 4819c63e9dbSSam Leffler * on the entry so that the code below reclaims the storage. 4829c63e9dbSSam Leffler */ 483d1dd20beSSam Leffler if (rt->rt_refcnt == 0 && rnh->rnh_close) 4845c2dae8eSGarrett Wollman rnh->rnh_close((struct radix_node *)rt, rnh); 485499676dfSJulian Elischer 486499676dfSJulian Elischer /* 487499676dfSJulian Elischer * If we are no longer "up" (and ref == 0) 488499676dfSJulian Elischer * then we can free the resources associated 489499676dfSJulian Elischer * with the route. 490499676dfSJulian Elischer */ 491d1dd20beSSam Leffler if ((rt->rt_flags & RTF_UP) == 0) { 492df8bae1dSRodney W. Grimes if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 493df8bae1dSRodney W. Grimes panic("rtfree 2"); 494499676dfSJulian Elischer /* 495499676dfSJulian Elischer * the rtentry must have been removed from the routing table 496499676dfSJulian Elischer * so it is represented in rttrash.. remove that now. 497499676dfSJulian Elischer */ 498603724d3SBjoern A. Zeeb V_rttrash--; 499499676dfSJulian Elischer #ifdef DIAGNOSTIC 500df8bae1dSRodney W. Grimes if (rt->rt_refcnt < 0) { 501623ae52eSPoul-Henning Kamp printf("rtfree: %p not freed (neg refs)\n", rt); 502d1dd20beSSam Leffler goto done; 503df8bae1dSRodney W. Grimes } 504499676dfSJulian Elischer #endif 505499676dfSJulian Elischer /* 506499676dfSJulian Elischer * release references on items we hold them on.. 507499676dfSJulian Elischer * e.g other routes and ifaddrs. 508499676dfSJulian Elischer */ 50919fc74fbSJeffrey Hsu if (rt->rt_ifa) 5101099f828SRobert Watson ifa_free(rt->rt_ifa); 511499676dfSJulian Elischer /* 512499676dfSJulian Elischer * The key is separatly alloc'd so free it (see rt_setgate()). 513499676dfSJulian Elischer * This also frees the gateway, as they are always malloc'd 514499676dfSJulian Elischer * together. 515499676dfSJulian Elischer */ 516df8bae1dSRodney W. Grimes Free(rt_key(rt)); 517499676dfSJulian Elischer 518499676dfSJulian Elischer /* 519499676dfSJulian Elischer * and the rtentry itself of course 520499676dfSJulian Elischer */ 521d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 5221ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 523d1dd20beSSam Leffler return; 524df8bae1dSRodney W. Grimes } 525d1dd20beSSam Leffler done: 526d1dd20beSSam Leffler RT_UNLOCK(rt); 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes 529df8bae1dSRodney W. Grimes 530df8bae1dSRodney W. Grimes /* 531df8bae1dSRodney W. Grimes * Force a routing table entry to the specified 532df8bae1dSRodney W. Grimes * destination to go through the given gateway. 533df8bae1dSRodney W. Grimes * Normally called as a result of a routing redirect 534df8bae1dSRodney W. Grimes * message from the network layer. 535df8bae1dSRodney W. Grimes */ 53626f9a767SRodney W. Grimes void 537d1dd20beSSam Leffler rtredirect(struct sockaddr *dst, 538d1dd20beSSam Leffler struct sockaddr *gateway, 539d1dd20beSSam Leffler struct sockaddr *netmask, 540d1dd20beSSam Leffler int flags, 541d1dd20beSSam Leffler struct sockaddr *src) 542df8bae1dSRodney W. Grimes { 5438b07e49aSJulian Elischer rtredirect_fib(dst, gateway, netmask, flags, src, 0); 5448b07e49aSJulian Elischer } 5458b07e49aSJulian Elischer 5468b07e49aSJulian Elischer void 5478b07e49aSJulian Elischer rtredirect_fib(struct sockaddr *dst, 5488b07e49aSJulian Elischer struct sockaddr *gateway, 5498b07e49aSJulian Elischer struct sockaddr *netmask, 5508b07e49aSJulian Elischer int flags, 5518b07e49aSJulian Elischer struct sockaddr *src, 5528b07e49aSJulian Elischer u_int fibnum) 5538b07e49aSJulian Elischer { 554b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 5558e7e854cSKip Macy struct rtentry *rt, *rt0 = NULL; 556df8bae1dSRodney W. Grimes int error = 0; 55785911824SLuigi Rizzo short *stat = NULL; 558df8bae1dSRodney W. Grimes struct rt_addrinfo info; 559df8bae1dSRodney W. Grimes struct ifaddr *ifa; 560c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rnh; 561c2c2a7c1SBjoern A. Zeeb 5628c0fec80SRobert Watson ifa = NULL; 563c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 564c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) { 565c2c2a7c1SBjoern A. Zeeb error = EAFNOSUPPORT; 566c2c2a7c1SBjoern A. Zeeb goto out; 567c2c2a7c1SBjoern A. Zeeb } 568df8bae1dSRodney W. Grimes 569df8bae1dSRodney W. Grimes /* verify the gateway is directly reachable */ 57085911824SLuigi Rizzo if ((ifa = ifa_ifwithnet(gateway)) == NULL) { 571df8bae1dSRodney W. Grimes error = ENETUNREACH; 572df8bae1dSRodney W. Grimes goto out; 573df8bae1dSRodney W. Grimes } 5748b07e49aSJulian Elischer rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ 575df8bae1dSRodney W. Grimes /* 576df8bae1dSRodney W. Grimes * If the redirect isn't from our current router for this dst, 577df8bae1dSRodney W. Grimes * it's either old or wrong. If it redirects us to ourselves, 578df8bae1dSRodney W. Grimes * we have a routing loop, perhaps as a result of an interface 579df8bae1dSRodney W. Grimes * going down recently. 580df8bae1dSRodney W. Grimes */ 581df8bae1dSRodney W. Grimes if (!(flags & RTF_DONE) && rt && 582956b0b65SJeffrey Hsu (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 583df8bae1dSRodney W. Grimes error = EINVAL; 5848896f83aSRobert Watson else if (ifa_ifwithaddr_check(gateway)) 585df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 586df8bae1dSRodney W. Grimes if (error) 587df8bae1dSRodney W. Grimes goto done; 588df8bae1dSRodney W. Grimes /* 589df8bae1dSRodney W. Grimes * Create a new entry if we just got back a wildcard entry 590df8bae1dSRodney W. Grimes * or the the lookup failed. This is necessary for hosts 591df8bae1dSRodney W. Grimes * which use routing redirects generated by smart gateways 592df8bae1dSRodney W. Grimes * to dynamically build the routing tables. 593df8bae1dSRodney W. Grimes */ 59485911824SLuigi Rizzo if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 595df8bae1dSRodney W. Grimes goto create; 596df8bae1dSRodney W. Grimes /* 597df8bae1dSRodney W. Grimes * Don't listen to the redirect if it's 598df8bae1dSRodney W. Grimes * for a route to an interface. 599df8bae1dSRodney W. Grimes */ 600df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 601df8bae1dSRodney W. Grimes if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 602df8bae1dSRodney W. Grimes /* 603df8bae1dSRodney W. Grimes * Changing from route to net => route to host. 604df8bae1dSRodney W. Grimes * Create new route, rather than smashing route to net. 605df8bae1dSRodney W. Grimes */ 606df8bae1dSRodney W. Grimes create: 6078e7e854cSKip Macy rt0 = rt; 6088e7e854cSKip Macy rt = NULL; 6098e7e854cSKip Macy 610df8bae1dSRodney W. Grimes flags |= RTF_GATEWAY | RTF_DYNAMIC; 6118071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 6128071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 6138071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 6148071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 6158071913dSRuslan Ermilov info.rti_ifa = ifa; 6168071913dSRuslan Ermilov info.rti_flags = flags; 6173120b9d4SKip Macy if (rt0 != NULL) 6183120b9d4SKip Macy RT_UNLOCK(rt0); /* drop lock to avoid LOR with RNH */ 6198b07e49aSJulian Elischer error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); 620d1dd20beSSam Leffler if (rt != NULL) { 6214de5d90cSSam Leffler RT_LOCK(rt); 6223120b9d4SKip Macy if (rt0 != NULL) 62329910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst); 6248071913dSRuslan Ermilov flags = rt->rt_flags; 625d1dd20beSSam Leffler } 6263120b9d4SKip Macy if (rt0 != NULL) 6273120b9d4SKip Macy RTFREE(rt0); 6288e7e854cSKip Macy 629603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_dynamic; 630df8bae1dSRodney W. Grimes } else { 6318e7e854cSKip Macy struct rtentry *gwrt; 6328e7e854cSKip Macy 633df8bae1dSRodney W. Grimes /* 634df8bae1dSRodney W. Grimes * Smash the current notion of the gateway to 635df8bae1dSRodney W. Grimes * this destination. Should check about netmask!!! 636df8bae1dSRodney W. Grimes */ 637df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_MODIFIED; 638df8bae1dSRodney W. Grimes flags |= RTF_MODIFIED; 639603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_newgateway; 640499676dfSJulian Elischer /* 641499676dfSJulian Elischer * add the key and gateway (in one malloc'd chunk). 642499676dfSJulian Elischer */ 6433120b9d4SKip Macy RT_UNLOCK(rt); 6443120b9d4SKip Macy RADIX_NODE_HEAD_LOCK(rnh); 6453120b9d4SKip Macy RT_LOCK(rt); 646df8bae1dSRodney W. Grimes rt_setgate(rt, rt_key(rt), gateway); 6473120b9d4SKip Macy gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED); 6483120b9d4SKip Macy RADIX_NODE_HEAD_UNLOCK(rnh); 64929910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst); 6508e7e854cSKip Macy RTFREE_LOCKED(gwrt); 651df8bae1dSRodney W. Grimes } 652df8bae1dSRodney W. Grimes } else 653df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 654df8bae1dSRodney W. Grimes done: 655d1dd20beSSam Leffler if (rt) 6561951e633SJohn Baldwin RTFREE_LOCKED(rt); 657df8bae1dSRodney W. Grimes out: 658df8bae1dSRodney W. Grimes if (error) 659603724d3SBjoern A. Zeeb V_rtstat.rts_badredirect++; 660df8bae1dSRodney W. Grimes else if (stat != NULL) 661df8bae1dSRodney W. Grimes (*stat)++; 662df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 663df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 664df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 665df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = netmask; 666df8bae1dSRodney W. Grimes info.rti_info[RTAX_AUTHOR] = src; 667df8bae1dSRodney W. Grimes rt_missmsg(RTM_REDIRECT, &info, flags, error); 6688c0fec80SRobert Watson if (ifa != NULL) 6698c0fec80SRobert Watson ifa_free(ifa); 670df8bae1dSRodney W. Grimes } 671df8bae1dSRodney W. Grimes 6728b07e49aSJulian Elischer int 6738b07e49aSJulian Elischer rtioctl(u_long req, caddr_t data) 6748b07e49aSJulian Elischer { 6758b07e49aSJulian Elischer return (rtioctl_fib(req, data, 0)); 6768b07e49aSJulian Elischer } 6778b07e49aSJulian Elischer 678df8bae1dSRodney W. Grimes /* 679df8bae1dSRodney W. Grimes * Routing table ioctl interface. 680df8bae1dSRodney W. Grimes */ 681df8bae1dSRodney W. Grimes int 6828b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 683df8bae1dSRodney W. Grimes { 6845090559bSChristian S.J. Peron 6855090559bSChristian S.J. Peron /* 6865090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 6875090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 6885090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 6895090559bSChristian S.J. Peron * in jails. 6905090559bSChristian S.J. Peron */ 691623ae52eSPoul-Henning Kamp #ifdef INET 692f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 6938b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 694623ae52eSPoul-Henning Kamp #else /* INET */ 695623ae52eSPoul-Henning Kamp return ENXIO; 696623ae52eSPoul-Henning Kamp #endif /* INET */ 697df8bae1dSRodney W. Grimes } 698df8bae1dSRodney W. Grimes 6998c0fec80SRobert Watson /* 7008c0fec80SRobert Watson * For both ifa_ifwithroute() routines, 'ifa' is returned referenced. 7018c0fec80SRobert Watson */ 702df8bae1dSRodney W. Grimes struct ifaddr * 703d1dd20beSSam Leffler ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway) 704df8bae1dSRodney W. Grimes { 7058b07e49aSJulian Elischer return (ifa_ifwithroute_fib(flags, dst, gateway, 0)); 7068b07e49aSJulian Elischer } 7078b07e49aSJulian Elischer 7088b07e49aSJulian Elischer struct ifaddr * 7098b07e49aSJulian Elischer ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway, 7108b07e49aSJulian Elischer u_int fibnum) 7118b07e49aSJulian Elischer { 712df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 713e034e82cSQing Li int not_found = 0; 714d1dd20beSSam Leffler 715df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 716df8bae1dSRodney W. Grimes /* 717df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 718df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 719df8bae1dSRodney W. Grimes * we should search for the destination 720df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 721df8bae1dSRodney W. Grimes * we can use the local address. 722df8bae1dSRodney W. Grimes */ 72385911824SLuigi Rizzo ifa = NULL; 72485911824SLuigi Rizzo if (flags & RTF_HOST) 725df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(dst); 72685911824SLuigi Rizzo if (ifa == NULL) 727df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 728df8bae1dSRodney W. Grimes } else { 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 731df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 732df8bae1dSRodney W. Grimes * other end of a pt to pt link. 733df8bae1dSRodney W. Grimes */ 734df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(gateway); 735df8bae1dSRodney W. Grimes } 73685911824SLuigi Rizzo if (ifa == NULL) 737df8bae1dSRodney W. Grimes ifa = ifa_ifwithnet(gateway); 73885911824SLuigi Rizzo if (ifa == NULL) { 7399b20205dSKip Macy struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum); 74085911824SLuigi Rizzo if (rt == NULL) 74185911824SLuigi Rizzo return (NULL); 742e034e82cSQing Li /* 743e034e82cSQing Li * dismiss a gateway that is reachable only 744e034e82cSQing Li * through the default router 745e034e82cSQing Li */ 746e034e82cSQing Li switch (gateway->sa_family) { 747e034e82cSQing Li case AF_INET: 748e034e82cSQing Li if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY) 749e034e82cSQing Li not_found = 1; 750e034e82cSQing Li break; 751e034e82cSQing Li case AF_INET6: 752e034e82cSQing Li if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr)) 753e034e82cSQing Li not_found = 1; 754e034e82cSQing Li break; 755e034e82cSQing Li default: 756e034e82cSQing Li break; 757e034e82cSQing Li } 7588c0fec80SRobert Watson if (!not_found && rt->rt_ifa != NULL) { 7598c0fec80SRobert Watson ifa = rt->rt_ifa; 7608c0fec80SRobert Watson ifa_ref(ifa); 7618c0fec80SRobert Watson } 7627138d65cSSam Leffler RT_REMREF(rt); 763d1dd20beSSam Leffler RT_UNLOCK(rt); 7648c0fec80SRobert Watson if (not_found || ifa == NULL) 76585911824SLuigi Rizzo return (NULL); 766df8bae1dSRodney W. Grimes } 767df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 768df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 769df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 77085911824SLuigi Rizzo if (ifa == NULL) 771df8bae1dSRodney W. Grimes ifa = oifa; 7728c0fec80SRobert Watson else 7738c0fec80SRobert Watson ifa_free(oifa); 774df8bae1dSRodney W. Grimes } 775df8bae1dSRodney W. Grimes return (ifa); 776df8bae1dSRodney W. Grimes } 777df8bae1dSRodney W. Grimes 778b0a76b88SJulian Elischer /* 779b0a76b88SJulian Elischer * Do appropriate manipulations of a routing tree given 780b0a76b88SJulian Elischer * all the bits of info needed 781b0a76b88SJulian Elischer */ 782df8bae1dSRodney W. Grimes int 783d1dd20beSSam Leffler rtrequest(int req, 784d1dd20beSSam Leffler struct sockaddr *dst, 785d1dd20beSSam Leffler struct sockaddr *gateway, 786d1dd20beSSam Leffler struct sockaddr *netmask, 787d1dd20beSSam Leffler int flags, 788d1dd20beSSam Leffler struct rtentry **ret_nrt) 789df8bae1dSRodney W. Grimes { 7908b07e49aSJulian Elischer return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 0)); 7918b07e49aSJulian Elischer } 7928b07e49aSJulian Elischer 7938b07e49aSJulian Elischer int 7948b07e49aSJulian Elischer rtrequest_fib(int req, 7958b07e49aSJulian Elischer struct sockaddr *dst, 7968b07e49aSJulian Elischer struct sockaddr *gateway, 7978b07e49aSJulian Elischer struct sockaddr *netmask, 7988b07e49aSJulian Elischer int flags, 7998b07e49aSJulian Elischer struct rtentry **ret_nrt, 8008b07e49aSJulian Elischer u_int fibnum) 8018b07e49aSJulian Elischer { 8028071913dSRuslan Ermilov struct rt_addrinfo info; 8038071913dSRuslan Ermilov 804ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 805ac4a76ebSBjoern A. Zeeb return(EINVAL); 806ac4a76ebSBjoern A. Zeeb 8078071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 8088071913dSRuslan Ermilov info.rti_flags = flags; 8098071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 8108071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 8118071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 8128b07e49aSJulian Elischer return rtrequest1_fib(req, &info, ret_nrt, fibnum); 8138071913dSRuslan Ermilov } 8148071913dSRuslan Ermilov 8158071913dSRuslan Ermilov /* 8168071913dSRuslan Ermilov * These (questionable) definitions of apparent local variables apply 8178071913dSRuslan Ermilov * to the next two functions. XXXXXX!!! 8188071913dSRuslan Ermilov */ 8198071913dSRuslan Ermilov #define dst info->rti_info[RTAX_DST] 8208071913dSRuslan Ermilov #define gateway info->rti_info[RTAX_GATEWAY] 8218071913dSRuslan Ermilov #define netmask info->rti_info[RTAX_NETMASK] 8228071913dSRuslan Ermilov #define ifaaddr info->rti_info[RTAX_IFA] 8238071913dSRuslan Ermilov #define ifpaddr info->rti_info[RTAX_IFP] 8248071913dSRuslan Ermilov #define flags info->rti_flags 8258071913dSRuslan Ermilov 8268071913dSRuslan Ermilov int 827d1dd20beSSam Leffler rt_getifa(struct rt_addrinfo *info) 8288071913dSRuslan Ermilov { 8298b07e49aSJulian Elischer return (rt_getifa_fib(info, 0)); 8308b07e49aSJulian Elischer } 8318b07e49aSJulian Elischer 8328c0fec80SRobert Watson /* 8338c0fec80SRobert Watson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 8348c0fec80SRobert Watson * it will be referenced so the caller must free it. 8358c0fec80SRobert Watson */ 8368b07e49aSJulian Elischer int 8378b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 8388b07e49aSJulian Elischer { 8398071913dSRuslan Ermilov struct ifaddr *ifa; 8408071913dSRuslan Ermilov int error = 0; 8418071913dSRuslan Ermilov 8428071913dSRuslan Ermilov /* 8438071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 8448071913dSRuslan Ermilov * when protocol address is ambiguous. 8458071913dSRuslan Ermilov */ 8468071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 8478071913dSRuslan Ermilov ifpaddr->sa_family == AF_LINK && 8488c0fec80SRobert Watson (ifa = ifa_ifwithnet(ifpaddr)) != NULL) { 8498071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 8508c0fec80SRobert Watson ifa_free(ifa); 8518c0fec80SRobert Watson } 8528071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 8538071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 8548071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 8558071913dSRuslan Ermilov struct sockaddr *sa; 8568071913dSRuslan Ermilov 8578071913dSRuslan Ermilov sa = ifaaddr != NULL ? ifaaddr : 8588071913dSRuslan Ermilov (gateway != NULL ? gateway : dst); 8598071913dSRuslan Ermilov if (sa != NULL && info->rti_ifp != NULL) 8608071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 8618071913dSRuslan Ermilov else if (dst != NULL && gateway != NULL) 8628b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, dst, gateway, 8638b07e49aSJulian Elischer fibnum); 8648071913dSRuslan Ermilov else if (sa != NULL) 8658b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, sa, sa, 8668b07e49aSJulian Elischer fibnum); 8678071913dSRuslan Ermilov } 8688071913dSRuslan Ermilov if ((ifa = info->rti_ifa) != NULL) { 8698071913dSRuslan Ermilov if (info->rti_ifp == NULL) 8708071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 8718071913dSRuslan Ermilov } else 8728071913dSRuslan Ermilov error = ENETUNREACH; 8738071913dSRuslan Ermilov return (error); 8748071913dSRuslan Ermilov } 8758071913dSRuslan Ermilov 8769c63e9dbSSam Leffler /* 8779c63e9dbSSam Leffler * Expunges references to a route that's about to be reclaimed. 8789c63e9dbSSam Leffler * The route must be locked. 8799c63e9dbSSam Leffler */ 8809c63e9dbSSam Leffler int 8819c63e9dbSSam Leffler rtexpunge(struct rtentry *rt) 8829c63e9dbSSam Leffler { 883b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 8849c63e9dbSSam Leffler struct radix_node *rn; 8859c63e9dbSSam Leffler struct radix_node_head *rnh; 8869c63e9dbSSam Leffler struct ifaddr *ifa; 8879c63e9dbSSam Leffler int error = 0; 8889c63e9dbSSam Leffler 8896e6b3f7cSQing Li /* 8906e6b3f7cSQing Li * Find the correct routing tree to use for this Address Family 8916e6b3f7cSQing Li */ 892c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 8939c63e9dbSSam Leffler RT_LOCK_ASSERT(rt); 8946e6b3f7cSQing Li if (rnh == NULL) 8956e6b3f7cSQing Li return (EAFNOSUPPORT); 8963120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 8979c63e9dbSSam Leffler #if 0 8989c63e9dbSSam Leffler /* 8999c63e9dbSSam Leffler * We cannot assume anything about the reference count 9009c63e9dbSSam Leffler * because protocols call us in many situations; often 9019c63e9dbSSam Leffler * before unwinding references to the table entry. 9029c63e9dbSSam Leffler */ 9039c63e9dbSSam Leffler KASSERT(rt->rt_refcnt <= 1, ("bogus refcnt %ld", rt->rt_refcnt)); 9049c63e9dbSSam Leffler #endif 9059c63e9dbSSam Leffler /* 9069c63e9dbSSam Leffler * Remove the item from the tree; it should be there, 9079c63e9dbSSam Leffler * but when callers invoke us blindly it may not (sigh). 9089c63e9dbSSam Leffler */ 9099c63e9dbSSam Leffler rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh); 91085911824SLuigi Rizzo if (rn == NULL) { 9119c63e9dbSSam Leffler error = ESRCH; 9129c63e9dbSSam Leffler goto bad; 9139c63e9dbSSam Leffler } 9149c63e9dbSSam Leffler KASSERT((rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) == 0, 9159c63e9dbSSam Leffler ("unexpected flags 0x%x", rn->rn_flags)); 916d6941ce9SLuigi Rizzo KASSERT(rt == RNTORT(rn), 9179c63e9dbSSam Leffler ("lookup mismatch, rt %p rn %p", rt, rn)); 9189c63e9dbSSam Leffler 9199c63e9dbSSam Leffler rt->rt_flags &= ~RTF_UP; 9209c63e9dbSSam Leffler 9219c63e9dbSSam Leffler /* 9229c63e9dbSSam Leffler * Give the protocol a chance to keep things in sync. 9239c63e9dbSSam Leffler */ 9249c63e9dbSSam Leffler if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) { 9259c63e9dbSSam Leffler struct rt_addrinfo info; 9269c63e9dbSSam Leffler 9279c63e9dbSSam Leffler bzero((caddr_t)&info, sizeof(info)); 9289c63e9dbSSam Leffler info.rti_flags = rt->rt_flags; 9299c63e9dbSSam Leffler info.rti_info[RTAX_DST] = rt_key(rt); 9309c63e9dbSSam Leffler info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 9319c63e9dbSSam Leffler info.rti_info[RTAX_NETMASK] = rt_mask(rt); 9329c63e9dbSSam Leffler ifa->ifa_rtrequest(RTM_DELETE, rt, &info); 9339c63e9dbSSam Leffler } 9349c63e9dbSSam Leffler 9359c63e9dbSSam Leffler /* 9369c63e9dbSSam Leffler * one more rtentry floating around that is not 9379c63e9dbSSam Leffler * linked to the routing table. 9389c63e9dbSSam Leffler */ 939603724d3SBjoern A. Zeeb V_rttrash++; 9409c63e9dbSSam Leffler bad: 9419c63e9dbSSam Leffler return (error); 9429c63e9dbSSam Leffler } 9439c63e9dbSSam Leffler 944427ac07fSKip Macy #ifdef RADIX_MPATH 945427ac07fSKip Macy static int 946427ac07fSKip Macy rn_mpath_update(int req, struct rt_addrinfo *info, 947427ac07fSKip Macy struct radix_node_head *rnh, struct rtentry **ret_nrt) 948427ac07fSKip Macy { 949427ac07fSKip Macy /* 950427ac07fSKip Macy * if we got multipath routes, we require users to specify 951427ac07fSKip Macy * a matching RTAX_GATEWAY. 952427ac07fSKip Macy */ 953427ac07fSKip Macy struct rtentry *rt, *rto = NULL; 954427ac07fSKip Macy register struct radix_node *rn; 955427ac07fSKip Macy int error = 0; 956427ac07fSKip Macy 957427ac07fSKip Macy rn = rnh->rnh_matchaddr(dst, rnh); 958427ac07fSKip Macy if (rn == NULL) 959427ac07fSKip Macy return (ESRCH); 960427ac07fSKip Macy rto = rt = RNTORT(rn); 961427ac07fSKip Macy rt = rt_mpath_matchgate(rt, gateway); 962427ac07fSKip Macy if (rt == NULL) 963427ac07fSKip Macy return (ESRCH); 964427ac07fSKip Macy /* 965427ac07fSKip Macy * this is the first entry in the chain 966427ac07fSKip Macy */ 967427ac07fSKip Macy if (rto == rt) { 968427ac07fSKip Macy rn = rn_mpath_next((struct radix_node *)rt); 969427ac07fSKip Macy /* 970427ac07fSKip Macy * there is another entry, now it's active 971427ac07fSKip Macy */ 972427ac07fSKip Macy if (rn) { 973427ac07fSKip Macy rto = RNTORT(rn); 974427ac07fSKip Macy RT_LOCK(rto); 975427ac07fSKip Macy rto->rt_flags |= RTF_UP; 976427ac07fSKip Macy RT_UNLOCK(rto); 977427ac07fSKip Macy } else if (rt->rt_flags & RTF_GATEWAY) { 978427ac07fSKip Macy /* 979427ac07fSKip Macy * For gateway routes, we need to 980427ac07fSKip Macy * make sure that we we are deleting 981427ac07fSKip Macy * the correct gateway. 982427ac07fSKip Macy * rt_mpath_matchgate() does not 983427ac07fSKip Macy * check the case when there is only 984427ac07fSKip Macy * one route in the chain. 985427ac07fSKip Macy */ 986427ac07fSKip Macy if (gateway && 987427ac07fSKip Macy (rt->rt_gateway->sa_len != gateway->sa_len || 988427ac07fSKip Macy memcmp(rt->rt_gateway, gateway, gateway->sa_len))) 989427ac07fSKip Macy error = ESRCH; 990427ac07fSKip Macy goto done; 991427ac07fSKip Macy } 992427ac07fSKip Macy /* 993427ac07fSKip Macy * use the normal delete code to remove 994427ac07fSKip Macy * the first entry 995427ac07fSKip Macy */ 996427ac07fSKip Macy if (req != RTM_DELETE) 997427ac07fSKip Macy goto nondelete; 998427ac07fSKip Macy 999427ac07fSKip Macy error = ENOENT; 1000427ac07fSKip Macy goto done; 1001427ac07fSKip Macy } 1002427ac07fSKip Macy 1003427ac07fSKip Macy /* 1004427ac07fSKip Macy * if the entry is 2nd and on up 1005427ac07fSKip Macy */ 1006427ac07fSKip Macy if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt)) 1007427ac07fSKip Macy panic ("rtrequest1: rt_mpath_deldup"); 1008427ac07fSKip Macy RT_LOCK(rt); 1009427ac07fSKip Macy RT_ADDREF(rt); 1010427ac07fSKip Macy if (req == RTM_DELETE) { 1011b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 1012b58ea5f3SBjoern A. Zeeb 1013427ac07fSKip Macy rt->rt_flags &= ~RTF_UP; 1014427ac07fSKip Macy /* 1015427ac07fSKip Macy * One more rtentry floating around that is not 1016427ac07fSKip Macy * linked to the routing table. rttrash will be decremented 1017427ac07fSKip Macy * when RTFREE(rt) is eventually called. 1018427ac07fSKip Macy */ 1019427ac07fSKip Macy V_rttrash++; 1020427ac07fSKip Macy 1021427ac07fSKip Macy } 1022427ac07fSKip Macy 1023427ac07fSKip Macy nondelete: 1024427ac07fSKip Macy if (req != RTM_DELETE) 1025427ac07fSKip Macy panic("unrecognized request %d", req); 1026427ac07fSKip Macy 1027427ac07fSKip Macy 1028427ac07fSKip Macy /* 1029427ac07fSKip Macy * If the caller wants it, then it can have it, 1030427ac07fSKip Macy * but it's up to it to free the rtentry as we won't be 1031427ac07fSKip Macy * doing it. 1032427ac07fSKip Macy */ 1033427ac07fSKip Macy if (ret_nrt) { 1034427ac07fSKip Macy *ret_nrt = rt; 1035427ac07fSKip Macy RT_UNLOCK(rt); 1036427ac07fSKip Macy } else 1037427ac07fSKip Macy RTFREE_LOCKED(rt); 1038427ac07fSKip Macy done: 1039427ac07fSKip Macy return (error); 1040427ac07fSKip Macy } 1041427ac07fSKip Macy #endif 1042427ac07fSKip Macy 10438071913dSRuslan Ermilov int 10448b07e49aSJulian Elischer rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, 10458b07e49aSJulian Elischer u_int fibnum) 10468b07e49aSJulian Elischer { 1047b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 10483120b9d4SKip Macy int error = 0, needlock = 0; 1049df8bae1dSRodney W. Grimes register struct rtentry *rt; 1050df8bae1dSRodney W. Grimes register struct radix_node *rn; 1051df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1052df8bae1dSRodney W. Grimes struct ifaddr *ifa; 1053df8bae1dSRodney W. Grimes struct sockaddr *ndst; 1054df8bae1dSRodney W. Grimes #define senderr(x) { error = x ; goto bad; } 1055df8bae1dSRodney W. Grimes 10568b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); 10578b07e49aSJulian Elischer if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */ 10588b07e49aSJulian Elischer fibnum = 0; 1059b0a76b88SJulian Elischer /* 1060b0a76b88SJulian Elischer * Find the correct routing tree to use for this Address Family 1061b0a76b88SJulian Elischer */ 1062c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 106385911824SLuigi Rizzo if (rnh == NULL) 1064983985c1SJeffrey Hsu return (EAFNOSUPPORT); 10653120b9d4SKip Macy needlock = ((flags & RTF_RNH_LOCKED) == 0); 10663120b9d4SKip Macy flags &= ~RTF_RNH_LOCKED; 10673120b9d4SKip Macy if (needlock) 1068956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1069c96b8224SKip Macy else 1070c96b8224SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1071b0a76b88SJulian Elischer /* 1072b0a76b88SJulian Elischer * If we are adding a host route then we don't want to put 107366953138SRuslan Ermilov * a netmask in the tree, nor do we want to clone it. 1074b0a76b88SJulian Elischer */ 10756e6b3f7cSQing Li if (flags & RTF_HOST) 107685911824SLuigi Rizzo netmask = NULL; 10776e6b3f7cSQing Li 1078df8bae1dSRodney W. Grimes switch (req) { 1079df8bae1dSRodney W. Grimes case RTM_DELETE: 1080e440aed9SQing Li #ifdef RADIX_MPATH 1081e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1082427ac07fSKip Macy error = rn_mpath_update(req, info, rnh, ret_nrt); 1083e440aed9SQing Li /* 1084427ac07fSKip Macy * "bad" holds true for the success case 1085427ac07fSKip Macy * as well 1086e440aed9SQing Li */ 1087427ac07fSKip Macy if (error != ENOENT) 1088427ac07fSKip Macy goto bad; 1089e440aed9SQing Li } 1090ea9cd9f2SBjoern A. Zeeb #endif 1091b0a76b88SJulian Elischer /* 1092b0a76b88SJulian Elischer * Remove the item from the tree and return it. 1093b0a76b88SJulian Elischer * Complain if it is not there and do no more processing. 1094b0a76b88SJulian Elischer */ 1095d1dd20beSSam Leffler rn = rnh->rnh_deladdr(dst, netmask, rnh); 109685911824SLuigi Rizzo if (rn == NULL) 1097df8bae1dSRodney W. Grimes senderr(ESRCH); 1098df8bae1dSRodney W. Grimes if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 1099df8bae1dSRodney W. Grimes panic ("rtrequest delete"); 1100d6941ce9SLuigi Rizzo rt = RNTORT(rn); 1101d1dd20beSSam Leffler RT_LOCK(rt); 11027138d65cSSam Leffler RT_ADDREF(rt); 110371eba915SRuslan Ermilov rt->rt_flags &= ~RTF_UP; 1104c2bed6a3SGarrett Wollman 1105c2bed6a3SGarrett Wollman /* 1106499676dfSJulian Elischer * give the protocol a chance to keep things in sync. 1107b0a76b88SJulian Elischer */ 1108df8bae1dSRodney W. Grimes if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 11098071913dSRuslan Ermilov ifa->ifa_rtrequest(RTM_DELETE, rt, info); 1110499676dfSJulian Elischer 1111b0a76b88SJulian Elischer /* 1112d6941ce9SLuigi Rizzo * One more rtentry floating around that is not 1113d6941ce9SLuigi Rizzo * linked to the routing table. rttrash will be decremented 1114d6941ce9SLuigi Rizzo * when RTFREE(rt) is eventually called. 1115499676dfSJulian Elischer */ 1116603724d3SBjoern A. Zeeb V_rttrash++; 1117499676dfSJulian Elischer 1118499676dfSJulian Elischer /* 1119499676dfSJulian Elischer * If the caller wants it, then it can have it, 1120499676dfSJulian Elischer * but it's up to it to free the rtentry as we won't be 1121499676dfSJulian Elischer * doing it. 1122b0a76b88SJulian Elischer */ 1123d1dd20beSSam Leffler if (ret_nrt) { 1124df8bae1dSRodney W. Grimes *ret_nrt = rt; 1125d1dd20beSSam Leffler RT_UNLOCK(rt); 1126d1dd20beSSam Leffler } else 1127d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1128df8bae1dSRodney W. Grimes break; 1129df8bae1dSRodney W. Grimes case RTM_RESOLVE: 11306e6b3f7cSQing Li /* 11316e6b3f7cSQing Li * resolve was only used for route cloning 11326e6b3f7cSQing Li * here for compat 11336e6b3f7cSQing Li */ 11346e6b3f7cSQing Li break; 1135df8bae1dSRodney W. Grimes case RTM_ADD: 11365df72964SGarrett Wollman if ((flags & RTF_GATEWAY) && !gateway) 113716a2e0a6SQing Li senderr(EINVAL); 113816a2e0a6SQing Li if (dst && gateway && (dst->sa_family != gateway->sa_family) && 113916a2e0a6SQing Li (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) 114016a2e0a6SQing Li senderr(EINVAL); 11415df72964SGarrett Wollman 11428c0fec80SRobert Watson if (info->rti_ifa == NULL) { 11438c0fec80SRobert Watson error = rt_getifa_fib(info, fibnum); 11448c0fec80SRobert Watson if (error) 11458071913dSRuslan Ermilov senderr(error); 11468c0fec80SRobert Watson } else 11478c0fec80SRobert Watson ifa_ref(info->rti_ifa); 11488071913dSRuslan Ermilov ifa = info->rti_ifa; 11491ed81b73SMarko Zec rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO); 11508c0fec80SRobert Watson if (rt == NULL) { 11518c0fec80SRobert Watson if (ifa != NULL) 11528c0fec80SRobert Watson ifa_free(ifa); 1153df8bae1dSRodney W. Grimes senderr(ENOBUFS); 11548c0fec80SRobert Watson } 1155d1dd20beSSam Leffler RT_LOCK_INIT(rt); 1156df8bae1dSRodney W. Grimes rt->rt_flags = RTF_UP | flags; 11578b07e49aSJulian Elischer rt->rt_fibnum = fibnum; 1158499676dfSJulian Elischer /* 1159499676dfSJulian Elischer * Add the gateway. Possibly re-malloc-ing the storage for it 11606e6b3f7cSQing Li * 1161499676dfSJulian Elischer */ 1162d1dd20beSSam Leffler RT_LOCK(rt); 1163831a80b0SMatthew Dillon if ((error = rt_setgate(rt, dst, gateway)) != 0) { 1164d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 11658c0fec80SRobert Watson if (ifa != NULL) 11668c0fec80SRobert Watson ifa_free(ifa); 11671ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1168704b0666SBill Fenner senderr(error); 1169df8bae1dSRodney W. Grimes } 1170499676dfSJulian Elischer 1171499676dfSJulian Elischer /* 1172499676dfSJulian Elischer * point to the (possibly newly malloc'd) dest address. 1173499676dfSJulian Elischer */ 1174d1dd20beSSam Leffler ndst = (struct sockaddr *)rt_key(rt); 1175499676dfSJulian Elischer 1176499676dfSJulian Elischer /* 1177499676dfSJulian Elischer * make sure it contains the value we want (masked if needed). 1178499676dfSJulian Elischer */ 1179df8bae1dSRodney W. Grimes if (netmask) { 1180df8bae1dSRodney W. Grimes rt_maskedcopy(dst, ndst, netmask); 1181df8bae1dSRodney W. Grimes } else 11821838a647SLuigi Rizzo bcopy(dst, ndst, dst->sa_len); 11838e718bb4SGarrett Wollman 11848e718bb4SGarrett Wollman /* 11858c0fec80SRobert Watson * We use the ifa reference returned by rt_getifa_fib(). 11868e718bb4SGarrett Wollman * This moved from below so that rnh->rnh_addaddr() can 1187499676dfSJulian Elischer * examine the ifa and ifa->ifa_ifp if it so desires. 11888e718bb4SGarrett Wollman */ 11898e718bb4SGarrett Wollman rt->rt_ifa = ifa; 11908e718bb4SGarrett Wollman rt->rt_ifp = ifa->ifa_ifp; 1191427ac07fSKip Macy rt->rt_rmx.rmx_weight = 1; 11928e718bb4SGarrett Wollman 1193e440aed9SQing Li #ifdef RADIX_MPATH 1194e440aed9SQing Li /* do not permit exactly the same dst/mask/gw pair */ 1195e440aed9SQing Li if (rn_mpath_capable(rnh) && 1196e440aed9SQing Li rt_mpath_conflict(rnh, rt, netmask)) { 1197e440aed9SQing Li if (rt->rt_ifa) { 11981099f828SRobert Watson ifa_free(rt->rt_ifa); 1199e440aed9SQing Li } 1200e440aed9SQing Li Free(rt_key(rt)); 1201e440aed9SQing Li RT_LOCK_DESTROY(rt); 12021ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1203e440aed9SQing Li senderr(EEXIST); 1204e440aed9SQing Li } 1205e440aed9SQing Li #endif 1206e440aed9SQing Li 1207d1dd20beSSam Leffler /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ 1208d1dd20beSSam Leffler rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); 1209499676dfSJulian Elischer /* 1210499676dfSJulian Elischer * If it still failed to go into the tree, 1211499676dfSJulian Elischer * then un-make it (this should be a function) 1212499676dfSJulian Elischer */ 121385911824SLuigi Rizzo if (rn == NULL) { 1214d1dd20beSSam Leffler if (rt->rt_ifa) 12151099f828SRobert Watson ifa_free(rt->rt_ifa); 1216df8bae1dSRodney W. Grimes Free(rt_key(rt)); 1217d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 12181ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1219df8bae1dSRodney W. Grimes senderr(EEXIST); 1220df8bae1dSRodney W. Grimes } 1221499676dfSJulian Elischer 1222499676dfSJulian Elischer /* 1223a0c0e34bSGleb Smirnoff * If this protocol has something to add to this then 1224499676dfSJulian Elischer * allow it to do that as well. 1225499676dfSJulian Elischer */ 1226df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest) 12278071913dSRuslan Ermilov ifa->ifa_rtrequest(req, rt, info); 1228499676dfSJulian Elischer 1229cd02a0b7SGarrett Wollman /* 1230499676dfSJulian Elischer * actually return a resultant rtentry and 1231499676dfSJulian Elischer * give the caller a single reference. 1232499676dfSJulian Elischer */ 1233df8bae1dSRodney W. Grimes if (ret_nrt) { 1234df8bae1dSRodney W. Grimes *ret_nrt = rt; 12357138d65cSSam Leffler RT_ADDREF(rt); 1236df8bae1dSRodney W. Grimes } 1237d1dd20beSSam Leffler RT_UNLOCK(rt); 1238df8bae1dSRodney W. Grimes break; 12398071913dSRuslan Ermilov default: 12408071913dSRuslan Ermilov error = EOPNOTSUPP; 1241df8bae1dSRodney W. Grimes } 1242df8bae1dSRodney W. Grimes bad: 12433120b9d4SKip Macy if (needlock) 1244956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1245df8bae1dSRodney W. Grimes return (error); 1246d1dd20beSSam Leffler #undef senderr 1247d1dd20beSSam Leffler } 1248d1dd20beSSam Leffler 12498071913dSRuslan Ermilov #undef dst 12508071913dSRuslan Ermilov #undef gateway 12518071913dSRuslan Ermilov #undef netmask 12528071913dSRuslan Ermilov #undef ifaaddr 12538071913dSRuslan Ermilov #undef ifpaddr 12548071913dSRuslan Ermilov #undef flags 1255df8bae1dSRodney W. Grimes 1256df8bae1dSRodney W. Grimes int 1257d1dd20beSSam Leffler rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) 1258df8bae1dSRodney W. Grimes { 1259d1dd20beSSam Leffler /* XXX dst may be overwritten, can we move this to below */ 12606e6b3f7cSQing Li int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); 12616e6b3f7cSQing Li #ifdef INVARIANTS 1262c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rnh; 1263c2c2a7c1SBjoern A. Zeeb 1264c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, dst->sa_family); 12656e6b3f7cSQing Li #endif 1266d1dd20beSSam Leffler 1267d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 12683120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1269df8bae1dSRodney W. Grimes 12701db1fffaSBill Fenner /* 127185911824SLuigi Rizzo * Prepare to store the gateway in rt->rt_gateway. 127285911824SLuigi Rizzo * Both dst and gateway are stored one after the other in the same 127385911824SLuigi Rizzo * malloc'd chunk. If we have room, we can reuse the old buffer, 127485911824SLuigi Rizzo * rt_gateway already points to the right place. 127585911824SLuigi Rizzo * Otherwise, malloc a new block and update the 'dst' address. 1276499676dfSJulian Elischer */ 127785911824SLuigi Rizzo if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) { 127885911824SLuigi Rizzo caddr_t new; 127985911824SLuigi Rizzo 1280df8bae1dSRodney W. Grimes R_Malloc(new, caddr_t, dlen + glen); 128185911824SLuigi Rizzo if (new == NULL) 12821db1fffaSBill Fenner return ENOBUFS; 1283499676dfSJulian Elischer /* 128485911824SLuigi Rizzo * XXX note, we copy from *dst and not *rt_key(rt) because 128585911824SLuigi Rizzo * rt_setgate() can be called to initialize a newly 128685911824SLuigi Rizzo * allocated route entry, in which case rt_key(rt) == NULL 128785911824SLuigi Rizzo * (and also rt->rt_gateway == NULL). 128885911824SLuigi Rizzo * Free()/free() handle a NULL argument just fine. 1289499676dfSJulian Elischer */ 12901838a647SLuigi Rizzo bcopy(dst, new, dlen); 129185911824SLuigi Rizzo Free(rt_key(rt)); /* free old block, if any */ 1292445e045bSAlexander Kabaev rt_key(rt) = (struct sockaddr *)new; 129385911824SLuigi Rizzo rt->rt_gateway = (struct sockaddr *)(new + dlen); 1294df8bae1dSRodney W. Grimes } 1295499676dfSJulian Elischer 1296499676dfSJulian Elischer /* 129785911824SLuigi Rizzo * Copy the new gateway value into the memory chunk. 129885911824SLuigi Rizzo */ 129985911824SLuigi Rizzo bcopy(gate, rt->rt_gateway, glen); 130085911824SLuigi Rizzo 13016e6b3f7cSQing Li return (0); 1302df8bae1dSRodney W. Grimes } 1303df8bae1dSRodney W. Grimes 1304f708ef1bSPoul-Henning Kamp static void 1305d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 1306df8bae1dSRodney W. Grimes { 1307df8bae1dSRodney W. Grimes register u_char *cp1 = (u_char *)src; 1308df8bae1dSRodney W. Grimes register u_char *cp2 = (u_char *)dst; 1309df8bae1dSRodney W. Grimes register u_char *cp3 = (u_char *)netmask; 1310df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 1311df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 1312df8bae1dSRodney W. Grimes 1313df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 1314df8bae1dSRodney W. Grimes cp3 += 2; 1315df8bae1dSRodney W. Grimes if (cplim > cplim2) 1316df8bae1dSRodney W. Grimes cplim = cplim2; 1317df8bae1dSRodney W. Grimes while (cp2 < cplim) 1318df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 1319df8bae1dSRodney W. Grimes if (cp2 < cplim2) 1320df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 1321df8bae1dSRodney W. Grimes } 1322df8bae1dSRodney W. Grimes 1323df8bae1dSRodney W. Grimes /* 1324df8bae1dSRodney W. Grimes * Set up a routing table entry, normally 1325df8bae1dSRodney W. Grimes * for an interface. 1326df8bae1dSRodney W. Grimes */ 13278b07e49aSJulian Elischer #define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 13288b07e49aSJulian Elischer static inline int 13298b07e49aSJulian Elischer rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 1330df8bae1dSRodney W. Grimes { 13315aca0b30SLuigi Rizzo struct sockaddr *dst; 13328071913dSRuslan Ermilov struct sockaddr *netmask; 133385911824SLuigi Rizzo struct rtentry *rt = NULL; 13348071913dSRuslan Ermilov struct rt_addrinfo info; 1335e440aed9SQing Li int error = 0; 13368b07e49aSJulian Elischer int startfib, endfib; 13378b07e49aSJulian Elischer char tempbuf[_SOCKADDR_TMPSIZE]; 13388b07e49aSJulian Elischer int didwork = 0; 13398b07e49aSJulian Elischer int a_failure = 0; 13406e6b3f7cSQing Li static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1341df8bae1dSRodney W. Grimes 13428071913dSRuslan Ermilov if (flags & RTF_HOST) { 13438071913dSRuslan Ermilov dst = ifa->ifa_dstaddr; 13448071913dSRuslan Ermilov netmask = NULL; 13458071913dSRuslan Ermilov } else { 13468071913dSRuslan Ermilov dst = ifa->ifa_addr; 13478071913dSRuslan Ermilov netmask = ifa->ifa_netmask; 13488071913dSRuslan Ermilov } 13498b07e49aSJulian Elischer if ( dst->sa_family != AF_INET) 13508b07e49aSJulian Elischer fibnum = 0; 13518b07e49aSJulian Elischer if (fibnum == -1) { 135266e8505fSJulian Elischer if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) { 135366e8505fSJulian Elischer startfib = endfib = curthread->td_proc->p_fibnum; 135466e8505fSJulian Elischer } else { 13558b07e49aSJulian Elischer startfib = 0; 13568b07e49aSJulian Elischer endfib = rt_numfibs - 1; 135766e8505fSJulian Elischer } 13588b07e49aSJulian Elischer } else { 13598b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 13608b07e49aSJulian Elischer startfib = fibnum; 13618b07e49aSJulian Elischer endfib = fibnum; 13628b07e49aSJulian Elischer } 1363ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 1364ac4a76ebSBjoern A. Zeeb return(EINVAL); 1365ac4a76ebSBjoern A. Zeeb 1366b0a76b88SJulian Elischer /* 13678b07e49aSJulian Elischer * If it's a delete, check that if it exists, 13688b07e49aSJulian Elischer * it's on the correct interface or we might scrub 13698b07e49aSJulian Elischer * a route to another ifa which would 1370b0a76b88SJulian Elischer * be confusing at best and possibly worse. 1371b0a76b88SJulian Elischer */ 1372df8bae1dSRodney W. Grimes if (cmd == RTM_DELETE) { 1373b0a76b88SJulian Elischer /* 1374b0a76b88SJulian Elischer * It's a delete, so it should already exist.. 1375b0a76b88SJulian Elischer * If it's a net, mask off the host bits 1376b0a76b88SJulian Elischer * (Assuming we have a mask) 13778b07e49aSJulian Elischer * XXX this is kinda inet specific.. 1378b0a76b88SJulian Elischer */ 13798071913dSRuslan Ermilov if (netmask != NULL) { 13808b07e49aSJulian Elischer rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 13818b07e49aSJulian Elischer dst = (struct sockaddr *)tempbuf; 1382df8bae1dSRodney W. Grimes } 13838b07e49aSJulian Elischer } 13848b07e49aSJulian Elischer /* 13858b07e49aSJulian Elischer * Now go through all the requested tables (fibs) and do the 13868b07e49aSJulian Elischer * requested action. Realistically, this will either be fib 0 13878b07e49aSJulian Elischer * for protocols that don't do multiple tables or all the 13888b07e49aSJulian Elischer * tables for those that do. XXX For this version only AF_INET. 13898b07e49aSJulian Elischer * When that changes code should be refactored to protocol 13908b07e49aSJulian Elischer * independent parts and protocol dependent parts. 13918b07e49aSJulian Elischer */ 13928b07e49aSJulian Elischer for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 13938b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 13948b07e49aSJulian Elischer struct radix_node_head *rnh; 13958b07e49aSJulian Elischer struct radix_node *rn; 1396b0a76b88SJulian Elischer /* 13978071913dSRuslan Ermilov * Look up an rtentry that is in the routing tree and 13988071913dSRuslan Ermilov * contains the correct info. 1399b0a76b88SJulian Elischer */ 1400c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1401c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 14028b07e49aSJulian Elischer /* this table doesn't exist but others might */ 14038b07e49aSJulian Elischer continue; 1404956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1405e440aed9SQing Li #ifdef RADIX_MPATH 1406e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1407e440aed9SQing Li 1408e440aed9SQing Li rn = rnh->rnh_matchaddr(dst, rnh); 1409e440aed9SQing Li if (rn == NULL) 1410e440aed9SQing Li error = ESRCH; 1411e440aed9SQing Li else { 1412e440aed9SQing Li rt = RNTORT(rn); 1413e440aed9SQing Li /* 14148b07e49aSJulian Elischer * for interface route the 14158b07e49aSJulian Elischer * rt->rt_gateway is sockaddr_intf 14168b07e49aSJulian Elischer * for cloning ARP entries, so 14178b07e49aSJulian Elischer * rt_mpath_matchgate must use the 14188b07e49aSJulian Elischer * interface address 1419e440aed9SQing Li */ 14208b07e49aSJulian Elischer rt = rt_mpath_matchgate(rt, 14218b07e49aSJulian Elischer ifa->ifa_addr); 1422e440aed9SQing Li if (!rt) 1423e440aed9SQing Li error = ESRCH; 1424e440aed9SQing Li } 1425e440aed9SQing Li } 1426e440aed9SQing Li else 1427e440aed9SQing Li #endif 14288b07e49aSJulian Elischer rn = rnh->rnh_lookup(dst, netmask, rnh); 14298b07e49aSJulian Elischer error = (rn == NULL || 14308071913dSRuslan Ermilov (rn->rn_flags & RNF_ROOT) || 1431d6941ce9SLuigi Rizzo RNTORT(rn)->rt_ifa != ifa || 143285911824SLuigi Rizzo !sa_equal((struct sockaddr *)rn->rn_key, dst)); 1433956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1434956b0b65SJeffrey Hsu if (error) { 14358b07e49aSJulian Elischer /* this is only an error if bad on ALL tables */ 14368b07e49aSJulian Elischer continue; 1437df8bae1dSRodney W. Grimes } 1438b0a76b88SJulian Elischer } 1439b0a76b88SJulian Elischer /* 1440b0a76b88SJulian Elischer * Do the actual request 1441b0a76b88SJulian Elischer */ 14428071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 14438071913dSRuslan Ermilov info.rti_ifa = ifa; 14448071913dSRuslan Ermilov info.rti_flags = flags | ifa->ifa_flags; 14458071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 14466e6b3f7cSQing Li /* 14476e6b3f7cSQing Li * doing this for compatibility reasons 14486e6b3f7cSQing Li */ 14496e6b3f7cSQing Li if (cmd == RTM_ADD) 14506e6b3f7cSQing Li info.rti_info[RTAX_GATEWAY] = 14516e6b3f7cSQing Li (struct sockaddr *)&null_sdl; 14526e6b3f7cSQing Li else 14538071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 14548071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 14558b07e49aSJulian Elischer error = rtrequest1_fib(cmd, &info, &rt, fibnum); 14565aca0b30SLuigi Rizzo if (error == 0 && rt != NULL) { 14578071913dSRuslan Ermilov /* 14586f99b44cSBrian Somers * notify any listening routing agents of the change 14598071913dSRuslan Ermilov */ 1460d1dd20beSSam Leffler RT_LOCK(rt); 1461e440aed9SQing Li #ifdef RADIX_MPATH 1462e440aed9SQing Li /* 1463e440aed9SQing Li * in case address alias finds the first address 1464e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.246/24 1465e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.247/24 1466e440aed9SQing Li * the address set in the route is 192.103.54.246 1467e440aed9SQing Li * so we need to replace it with 192.103.54.247 1468e440aed9SQing Li */ 14698b07e49aSJulian Elischer if (memcmp(rt->rt_ifa->ifa_addr, 14708b07e49aSJulian Elischer ifa->ifa_addr, ifa->ifa_addr->sa_len)) { 14711099f828SRobert Watson ifa_free(rt->rt_ifa); 14721099f828SRobert Watson ifa_ref(ifa); 1473e440aed9SQing Li rt->rt_ifp = ifa->ifa_ifp; 1474e440aed9SQing Li rt->rt_ifa = ifa; 1475e440aed9SQing Li } 1476e440aed9SQing Li #endif 14776e6b3f7cSQing Li /* 14786e6b3f7cSQing Li * doing this for compatibility reasons 14796e6b3f7cSQing Li */ 14806e6b3f7cSQing Li if (cmd == RTM_ADD) { 14816e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 14826e6b3f7cSQing Li rt->rt_ifp->if_type; 14836e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 14846e6b3f7cSQing Li rt->rt_ifp->if_index; 14856e6b3f7cSQing Li } 14868071913dSRuslan Ermilov rt_newaddrmsg(cmd, ifa, error, rt); 14878071913dSRuslan Ermilov if (cmd == RTM_DELETE) { 1488b0a76b88SJulian Elischer /* 14898b07e49aSJulian Elischer * If we are deleting, and we found an entry, 14908b07e49aSJulian Elischer * then it's been removed from the tree.. 14918b07e49aSJulian Elischer * now throw it away. 1492b0a76b88SJulian Elischer */ 1493d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1494d1dd20beSSam Leffler } else { 1495d1dd20beSSam Leffler if (cmd == RTM_ADD) { 1496b0a76b88SJulian Elischer /* 14978b07e49aSJulian Elischer * We just wanted to add it.. 14988b07e49aSJulian Elischer * we don't actually need a reference. 1499b0a76b88SJulian Elischer */ 15007138d65cSSam Leffler RT_REMREF(rt); 1501df8bae1dSRodney W. Grimes } 1502d1dd20beSSam Leffler RT_UNLOCK(rt); 1503d1dd20beSSam Leffler } 15048b07e49aSJulian Elischer didwork = 1; 1505df8bae1dSRodney W. Grimes } 15068b07e49aSJulian Elischer if (error) 15078b07e49aSJulian Elischer a_failure = error; 15088b07e49aSJulian Elischer } 15098b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 15108b07e49aSJulian Elischer if (didwork) { 15118b07e49aSJulian Elischer error = 0; 15128b07e49aSJulian Elischer } else { 15138b07e49aSJulian Elischer /* we only give an error if it wasn't in any table */ 15148b07e49aSJulian Elischer error = ((flags & RTF_HOST) ? 15158b07e49aSJulian Elischer EHOSTUNREACH : ENETUNREACH); 15168b07e49aSJulian Elischer } 15178b07e49aSJulian Elischer } else { 15188b07e49aSJulian Elischer if (a_failure) { 15198b07e49aSJulian Elischer /* return an error if any of them failed */ 15208b07e49aSJulian Elischer error = a_failure; 15218b07e49aSJulian Elischer } 15228b07e49aSJulian Elischer } 15233ec66d6cSDavid Greenman return (error); 15243ec66d6cSDavid Greenman } 1525cb64988fSLuoqi Chen 15268b07e49aSJulian Elischer /* special one for inet internal use. may not use. */ 15278b07e49aSJulian Elischer int 15288b07e49aSJulian Elischer rtinit_fib(struct ifaddr *ifa, int cmd, int flags) 15298b07e49aSJulian Elischer { 15308b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, -1)); 15318b07e49aSJulian Elischer } 15328b07e49aSJulian Elischer 15338b07e49aSJulian Elischer /* 15348b07e49aSJulian Elischer * Set up a routing table entry, normally 15358b07e49aSJulian Elischer * for an interface. 15368b07e49aSJulian Elischer */ 15378b07e49aSJulian Elischer int 15388b07e49aSJulian Elischer rtinit(struct ifaddr *ifa, int cmd, int flags) 15398b07e49aSJulian Elischer { 15408b07e49aSJulian Elischer struct sockaddr *dst; 15418b07e49aSJulian Elischer int fib = 0; 15428b07e49aSJulian Elischer 15438b07e49aSJulian Elischer if (flags & RTF_HOST) { 15448b07e49aSJulian Elischer dst = ifa->ifa_dstaddr; 15458b07e49aSJulian Elischer } else { 15468b07e49aSJulian Elischer dst = ifa->ifa_addr; 15478b07e49aSJulian Elischer } 15488b07e49aSJulian Elischer 15498b07e49aSJulian Elischer if (dst->sa_family == AF_INET) 15508b07e49aSJulian Elischer fib = -1; 15518b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, fib)); 15528b07e49aSJulian Elischer } 15538b07e49aSJulian Elischer 15546a800098SYoshinobu Inoue /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */ 15556a800098SYoshinobu Inoue SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); 1556