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 562c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 563c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) { 564c2c2a7c1SBjoern A. Zeeb error = EAFNOSUPPORT; 565c2c2a7c1SBjoern A. Zeeb goto out; 566c2c2a7c1SBjoern A. Zeeb } 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes /* verify the gateway is directly reachable */ 56985911824SLuigi Rizzo if ((ifa = ifa_ifwithnet(gateway)) == NULL) { 570df8bae1dSRodney W. Grimes error = ENETUNREACH; 571df8bae1dSRodney W. Grimes goto out; 572df8bae1dSRodney W. Grimes } 5738b07e49aSJulian Elischer rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ 574df8bae1dSRodney W. Grimes /* 575df8bae1dSRodney W. Grimes * If the redirect isn't from our current router for this dst, 576df8bae1dSRodney W. Grimes * it's either old or wrong. If it redirects us to ourselves, 577df8bae1dSRodney W. Grimes * we have a routing loop, perhaps as a result of an interface 578df8bae1dSRodney W. Grimes * going down recently. 579df8bae1dSRodney W. Grimes */ 580df8bae1dSRodney W. Grimes if (!(flags & RTF_DONE) && rt && 581956b0b65SJeffrey Hsu (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 582df8bae1dSRodney W. Grimes error = EINVAL; 5838896f83aSRobert Watson else if (ifa_ifwithaddr_check(gateway)) 584df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 585df8bae1dSRodney W. Grimes if (error) 586df8bae1dSRodney W. Grimes goto done; 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * Create a new entry if we just got back a wildcard entry 589df8bae1dSRodney W. Grimes * or the the lookup failed. This is necessary for hosts 590df8bae1dSRodney W. Grimes * which use routing redirects generated by smart gateways 591df8bae1dSRodney W. Grimes * to dynamically build the routing tables. 592df8bae1dSRodney W. Grimes */ 59385911824SLuigi Rizzo if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 594df8bae1dSRodney W. Grimes goto create; 595df8bae1dSRodney W. Grimes /* 596df8bae1dSRodney W. Grimes * Don't listen to the redirect if it's 597df8bae1dSRodney W. Grimes * for a route to an interface. 598df8bae1dSRodney W. Grimes */ 599df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) { 600df8bae1dSRodney W. Grimes if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 601df8bae1dSRodney W. Grimes /* 602df8bae1dSRodney W. Grimes * Changing from route to net => route to host. 603df8bae1dSRodney W. Grimes * Create new route, rather than smashing route to net. 604df8bae1dSRodney W. Grimes */ 605df8bae1dSRodney W. Grimes create: 6068e7e854cSKip Macy rt0 = rt; 6078e7e854cSKip Macy rt = NULL; 6088e7e854cSKip Macy 609df8bae1dSRodney W. Grimes flags |= RTF_GATEWAY | RTF_DYNAMIC; 6108071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 6118071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 6128071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 6138071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 6148071913dSRuslan Ermilov info.rti_ifa = ifa; 6158071913dSRuslan Ermilov info.rti_flags = flags; 6163120b9d4SKip Macy if (rt0 != NULL) 6173120b9d4SKip Macy RT_UNLOCK(rt0); /* drop lock to avoid LOR with RNH */ 6188b07e49aSJulian Elischer error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); 619d1dd20beSSam Leffler if (rt != NULL) { 6204de5d90cSSam Leffler RT_LOCK(rt); 6213120b9d4SKip Macy if (rt0 != NULL) 62229910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst); 6238071913dSRuslan Ermilov flags = rt->rt_flags; 624d1dd20beSSam Leffler } 6253120b9d4SKip Macy if (rt0 != NULL) 6263120b9d4SKip Macy RTFREE(rt0); 6278e7e854cSKip Macy 628603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_dynamic; 629df8bae1dSRodney W. Grimes } else { 6308e7e854cSKip Macy struct rtentry *gwrt; 6318e7e854cSKip Macy 632df8bae1dSRodney W. Grimes /* 633df8bae1dSRodney W. Grimes * Smash the current notion of the gateway to 634df8bae1dSRodney W. Grimes * this destination. Should check about netmask!!! 635df8bae1dSRodney W. Grimes */ 636df8bae1dSRodney W. Grimes rt->rt_flags |= RTF_MODIFIED; 637df8bae1dSRodney W. Grimes flags |= RTF_MODIFIED; 638603724d3SBjoern A. Zeeb stat = &V_rtstat.rts_newgateway; 639499676dfSJulian Elischer /* 640499676dfSJulian Elischer * add the key and gateway (in one malloc'd chunk). 641499676dfSJulian Elischer */ 6423120b9d4SKip Macy RT_UNLOCK(rt); 6433120b9d4SKip Macy RADIX_NODE_HEAD_LOCK(rnh); 6443120b9d4SKip Macy RT_LOCK(rt); 645df8bae1dSRodney W. Grimes rt_setgate(rt, rt_key(rt), gateway); 6463120b9d4SKip Macy gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED); 6473120b9d4SKip Macy RADIX_NODE_HEAD_UNLOCK(rnh); 64829910a5aSKip Macy EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst); 6498e7e854cSKip Macy RTFREE_LOCKED(gwrt); 650df8bae1dSRodney W. Grimes } 651df8bae1dSRodney W. Grimes } else 652df8bae1dSRodney W. Grimes error = EHOSTUNREACH; 653df8bae1dSRodney W. Grimes done: 654d1dd20beSSam Leffler if (rt) 6551951e633SJohn Baldwin RTFREE_LOCKED(rt); 656df8bae1dSRodney W. Grimes out: 657df8bae1dSRodney W. Grimes if (error) 658603724d3SBjoern A. Zeeb V_rtstat.rts_badredirect++; 659df8bae1dSRodney W. Grimes else if (stat != NULL) 660df8bae1dSRodney W. Grimes (*stat)++; 661df8bae1dSRodney W. Grimes bzero((caddr_t)&info, sizeof(info)); 662df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 663df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 664df8bae1dSRodney W. Grimes info.rti_info[RTAX_NETMASK] = netmask; 665df8bae1dSRodney W. Grimes info.rti_info[RTAX_AUTHOR] = src; 666df8bae1dSRodney W. Grimes rt_missmsg(RTM_REDIRECT, &info, flags, error); 667df8bae1dSRodney W. Grimes } 668df8bae1dSRodney W. Grimes 6698b07e49aSJulian Elischer int 6708b07e49aSJulian Elischer rtioctl(u_long req, caddr_t data) 6718b07e49aSJulian Elischer { 6728b07e49aSJulian Elischer return (rtioctl_fib(req, data, 0)); 6738b07e49aSJulian Elischer } 6748b07e49aSJulian Elischer 675df8bae1dSRodney W. Grimes /* 676df8bae1dSRodney W. Grimes * Routing table ioctl interface. 677df8bae1dSRodney W. Grimes */ 678df8bae1dSRodney W. Grimes int 6798b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 680df8bae1dSRodney W. Grimes { 6815090559bSChristian S.J. Peron 6825090559bSChristian S.J. Peron /* 6835090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 6845090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 6855090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 6865090559bSChristian S.J. Peron * in jails. 6875090559bSChristian S.J. Peron */ 688623ae52eSPoul-Henning Kamp #ifdef INET 689f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 6908b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 691623ae52eSPoul-Henning Kamp #else /* INET */ 692623ae52eSPoul-Henning Kamp return ENXIO; 693623ae52eSPoul-Henning Kamp #endif /* INET */ 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes 696df8bae1dSRodney W. Grimes struct ifaddr * 697d1dd20beSSam Leffler ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway) 698df8bae1dSRodney W. Grimes { 6998b07e49aSJulian Elischer return (ifa_ifwithroute_fib(flags, dst, gateway, 0)); 7008b07e49aSJulian Elischer } 7018b07e49aSJulian Elischer 7028b07e49aSJulian Elischer struct ifaddr * 7038b07e49aSJulian Elischer ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway, 7048b07e49aSJulian Elischer u_int fibnum) 7058b07e49aSJulian Elischer { 706df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 707e034e82cSQing Li int not_found = 0; 708d1dd20beSSam Leffler 709df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 710df8bae1dSRodney W. Grimes /* 711df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 712df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 713df8bae1dSRodney W. Grimes * we should search for the destination 714df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 715df8bae1dSRodney W. Grimes * we can use the local address. 716df8bae1dSRodney W. Grimes */ 71785911824SLuigi Rizzo ifa = NULL; 71885911824SLuigi Rizzo if (flags & RTF_HOST) 719df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(dst); 72085911824SLuigi Rizzo if (ifa == NULL) 721df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 722df8bae1dSRodney W. Grimes } else { 723df8bae1dSRodney W. Grimes /* 724df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 725df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 726df8bae1dSRodney W. Grimes * other end of a pt to pt link. 727df8bae1dSRodney W. Grimes */ 728df8bae1dSRodney W. Grimes ifa = ifa_ifwithdstaddr(gateway); 729df8bae1dSRodney W. Grimes } 73085911824SLuigi Rizzo if (ifa == NULL) 731df8bae1dSRodney W. Grimes ifa = ifa_ifwithnet(gateway); 73285911824SLuigi Rizzo if (ifa == NULL) { 7339b20205dSKip Macy struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum); 73485911824SLuigi Rizzo if (rt == NULL) 73585911824SLuigi Rizzo return (NULL); 736e034e82cSQing Li /* 737e034e82cSQing Li * dismiss a gateway that is reachable only 738e034e82cSQing Li * through the default router 739e034e82cSQing Li */ 740e034e82cSQing Li switch (gateway->sa_family) { 741e034e82cSQing Li case AF_INET: 742e034e82cSQing Li if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY) 743e034e82cSQing Li not_found = 1; 744e034e82cSQing Li break; 745e034e82cSQing Li case AF_INET6: 746e034e82cSQing Li if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr)) 747e034e82cSQing Li not_found = 1; 748e034e82cSQing Li break; 749e034e82cSQing Li default: 750e034e82cSQing Li break; 751e034e82cSQing Li } 7527138d65cSSam Leffler RT_REMREF(rt); 753d1dd20beSSam Leffler RT_UNLOCK(rt); 754e034e82cSQing Li if (not_found) 755e034e82cSQing Li return (NULL); 75685911824SLuigi Rizzo if ((ifa = rt->rt_ifa) == NULL) 75785911824SLuigi Rizzo return (NULL); 758df8bae1dSRodney W. Grimes } 759df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 760df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 761df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 76285911824SLuigi Rizzo if (ifa == NULL) 763df8bae1dSRodney W. Grimes ifa = oifa; 764df8bae1dSRodney W. Grimes } 765df8bae1dSRodney W. Grimes return (ifa); 766df8bae1dSRodney W. Grimes } 767df8bae1dSRodney W. Grimes 768b0a76b88SJulian Elischer /* 769b0a76b88SJulian Elischer * Do appropriate manipulations of a routing tree given 770b0a76b88SJulian Elischer * all the bits of info needed 771b0a76b88SJulian Elischer */ 772df8bae1dSRodney W. Grimes int 773d1dd20beSSam Leffler rtrequest(int req, 774d1dd20beSSam Leffler struct sockaddr *dst, 775d1dd20beSSam Leffler struct sockaddr *gateway, 776d1dd20beSSam Leffler struct sockaddr *netmask, 777d1dd20beSSam Leffler int flags, 778d1dd20beSSam Leffler struct rtentry **ret_nrt) 779df8bae1dSRodney W. Grimes { 7808b07e49aSJulian Elischer return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 0)); 7818b07e49aSJulian Elischer } 7828b07e49aSJulian Elischer 7838b07e49aSJulian Elischer int 7848b07e49aSJulian Elischer rtrequest_fib(int req, 7858b07e49aSJulian Elischer struct sockaddr *dst, 7868b07e49aSJulian Elischer struct sockaddr *gateway, 7878b07e49aSJulian Elischer struct sockaddr *netmask, 7888b07e49aSJulian Elischer int flags, 7898b07e49aSJulian Elischer struct rtentry **ret_nrt, 7908b07e49aSJulian Elischer u_int fibnum) 7918b07e49aSJulian Elischer { 7928071913dSRuslan Ermilov struct rt_addrinfo info; 7938071913dSRuslan Ermilov 794ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 795ac4a76ebSBjoern A. Zeeb return(EINVAL); 796ac4a76ebSBjoern A. Zeeb 7978071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 7988071913dSRuslan Ermilov info.rti_flags = flags; 7998071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 8008071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 8018071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 8028b07e49aSJulian Elischer return rtrequest1_fib(req, &info, ret_nrt, fibnum); 8038071913dSRuslan Ermilov } 8048071913dSRuslan Ermilov 8058071913dSRuslan Ermilov /* 8068071913dSRuslan Ermilov * These (questionable) definitions of apparent local variables apply 8078071913dSRuslan Ermilov * to the next two functions. XXXXXX!!! 8088071913dSRuslan Ermilov */ 8098071913dSRuslan Ermilov #define dst info->rti_info[RTAX_DST] 8108071913dSRuslan Ermilov #define gateway info->rti_info[RTAX_GATEWAY] 8118071913dSRuslan Ermilov #define netmask info->rti_info[RTAX_NETMASK] 8128071913dSRuslan Ermilov #define ifaaddr info->rti_info[RTAX_IFA] 8138071913dSRuslan Ermilov #define ifpaddr info->rti_info[RTAX_IFP] 8148071913dSRuslan Ermilov #define flags info->rti_flags 8158071913dSRuslan Ermilov 8168071913dSRuslan Ermilov int 817d1dd20beSSam Leffler rt_getifa(struct rt_addrinfo *info) 8188071913dSRuslan Ermilov { 8198b07e49aSJulian Elischer return (rt_getifa_fib(info, 0)); 8208b07e49aSJulian Elischer } 8218b07e49aSJulian Elischer 8228b07e49aSJulian Elischer int 8238b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 8248b07e49aSJulian Elischer { 8258071913dSRuslan Ermilov struct ifaddr *ifa; 8268071913dSRuslan Ermilov int error = 0; 8278071913dSRuslan Ermilov 8288071913dSRuslan Ermilov /* 8298071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 8308071913dSRuslan Ermilov * when protocol address is ambiguous. 8318071913dSRuslan Ermilov */ 8328071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 8338071913dSRuslan Ermilov ifpaddr->sa_family == AF_LINK && 8348071913dSRuslan Ermilov (ifa = ifa_ifwithnet(ifpaddr)) != NULL) 8358071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 8368071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 8378071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 8388071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 8398071913dSRuslan Ermilov struct sockaddr *sa; 8408071913dSRuslan Ermilov 8418071913dSRuslan Ermilov sa = ifaaddr != NULL ? ifaaddr : 8428071913dSRuslan Ermilov (gateway != NULL ? gateway : dst); 8438071913dSRuslan Ermilov if (sa != NULL && info->rti_ifp != NULL) 8448071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 8458071913dSRuslan Ermilov else if (dst != NULL && gateway != NULL) 8468b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, dst, gateway, 8478b07e49aSJulian Elischer fibnum); 8488071913dSRuslan Ermilov else if (sa != NULL) 8498b07e49aSJulian Elischer info->rti_ifa = ifa_ifwithroute_fib(flags, sa, sa, 8508b07e49aSJulian Elischer fibnum); 8518071913dSRuslan Ermilov } 8528071913dSRuslan Ermilov if ((ifa = info->rti_ifa) != NULL) { 8538071913dSRuslan Ermilov if (info->rti_ifp == NULL) 8548071913dSRuslan Ermilov info->rti_ifp = ifa->ifa_ifp; 8558071913dSRuslan Ermilov } else 8568071913dSRuslan Ermilov error = ENETUNREACH; 8578071913dSRuslan Ermilov return (error); 8588071913dSRuslan Ermilov } 8598071913dSRuslan Ermilov 8609c63e9dbSSam Leffler /* 8619c63e9dbSSam Leffler * Expunges references to a route that's about to be reclaimed. 8629c63e9dbSSam Leffler * The route must be locked. 8639c63e9dbSSam Leffler */ 8649c63e9dbSSam Leffler int 8659c63e9dbSSam Leffler rtexpunge(struct rtentry *rt) 8669c63e9dbSSam Leffler { 867b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 8689c63e9dbSSam Leffler struct radix_node *rn; 8699c63e9dbSSam Leffler struct radix_node_head *rnh; 8709c63e9dbSSam Leffler struct ifaddr *ifa; 8719c63e9dbSSam Leffler int error = 0; 8729c63e9dbSSam Leffler 8736e6b3f7cSQing Li /* 8746e6b3f7cSQing Li * Find the correct routing tree to use for this Address Family 8756e6b3f7cSQing Li */ 876c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 8779c63e9dbSSam Leffler RT_LOCK_ASSERT(rt); 8786e6b3f7cSQing Li if (rnh == NULL) 8796e6b3f7cSQing Li return (EAFNOSUPPORT); 8803120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 8819c63e9dbSSam Leffler #if 0 8829c63e9dbSSam Leffler /* 8839c63e9dbSSam Leffler * We cannot assume anything about the reference count 8849c63e9dbSSam Leffler * because protocols call us in many situations; often 8859c63e9dbSSam Leffler * before unwinding references to the table entry. 8869c63e9dbSSam Leffler */ 8879c63e9dbSSam Leffler KASSERT(rt->rt_refcnt <= 1, ("bogus refcnt %ld", rt->rt_refcnt)); 8889c63e9dbSSam Leffler #endif 8899c63e9dbSSam Leffler /* 8909c63e9dbSSam Leffler * Remove the item from the tree; it should be there, 8919c63e9dbSSam Leffler * but when callers invoke us blindly it may not (sigh). 8929c63e9dbSSam Leffler */ 8939c63e9dbSSam Leffler rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh); 89485911824SLuigi Rizzo if (rn == NULL) { 8959c63e9dbSSam Leffler error = ESRCH; 8969c63e9dbSSam Leffler goto bad; 8979c63e9dbSSam Leffler } 8989c63e9dbSSam Leffler KASSERT((rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) == 0, 8999c63e9dbSSam Leffler ("unexpected flags 0x%x", rn->rn_flags)); 900d6941ce9SLuigi Rizzo KASSERT(rt == RNTORT(rn), 9019c63e9dbSSam Leffler ("lookup mismatch, rt %p rn %p", rt, rn)); 9029c63e9dbSSam Leffler 9039c63e9dbSSam Leffler rt->rt_flags &= ~RTF_UP; 9049c63e9dbSSam Leffler 9059c63e9dbSSam Leffler /* 9069c63e9dbSSam Leffler * Give the protocol a chance to keep things in sync. 9079c63e9dbSSam Leffler */ 9089c63e9dbSSam Leffler if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) { 9099c63e9dbSSam Leffler struct rt_addrinfo info; 9109c63e9dbSSam Leffler 9119c63e9dbSSam Leffler bzero((caddr_t)&info, sizeof(info)); 9129c63e9dbSSam Leffler info.rti_flags = rt->rt_flags; 9139c63e9dbSSam Leffler info.rti_info[RTAX_DST] = rt_key(rt); 9149c63e9dbSSam Leffler info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 9159c63e9dbSSam Leffler info.rti_info[RTAX_NETMASK] = rt_mask(rt); 9169c63e9dbSSam Leffler ifa->ifa_rtrequest(RTM_DELETE, rt, &info); 9179c63e9dbSSam Leffler } 9189c63e9dbSSam Leffler 9199c63e9dbSSam Leffler /* 9209c63e9dbSSam Leffler * one more rtentry floating around that is not 9219c63e9dbSSam Leffler * linked to the routing table. 9229c63e9dbSSam Leffler */ 923603724d3SBjoern A. Zeeb V_rttrash++; 9249c63e9dbSSam Leffler bad: 9259c63e9dbSSam Leffler return (error); 9269c63e9dbSSam Leffler } 9279c63e9dbSSam Leffler 928427ac07fSKip Macy #ifdef RADIX_MPATH 929427ac07fSKip Macy static int 930427ac07fSKip Macy rn_mpath_update(int req, struct rt_addrinfo *info, 931427ac07fSKip Macy struct radix_node_head *rnh, struct rtentry **ret_nrt) 932427ac07fSKip Macy { 933427ac07fSKip Macy /* 934427ac07fSKip Macy * if we got multipath routes, we require users to specify 935427ac07fSKip Macy * a matching RTAX_GATEWAY. 936427ac07fSKip Macy */ 937427ac07fSKip Macy struct rtentry *rt, *rto = NULL; 938427ac07fSKip Macy register struct radix_node *rn; 939427ac07fSKip Macy int error = 0; 940427ac07fSKip Macy 941427ac07fSKip Macy rn = rnh->rnh_matchaddr(dst, rnh); 942427ac07fSKip Macy if (rn == NULL) 943427ac07fSKip Macy return (ESRCH); 944427ac07fSKip Macy rto = rt = RNTORT(rn); 945427ac07fSKip Macy rt = rt_mpath_matchgate(rt, gateway); 946427ac07fSKip Macy if (rt == NULL) 947427ac07fSKip Macy return (ESRCH); 948427ac07fSKip Macy /* 949427ac07fSKip Macy * this is the first entry in the chain 950427ac07fSKip Macy */ 951427ac07fSKip Macy if (rto == rt) { 952427ac07fSKip Macy rn = rn_mpath_next((struct radix_node *)rt); 953427ac07fSKip Macy /* 954427ac07fSKip Macy * there is another entry, now it's active 955427ac07fSKip Macy */ 956427ac07fSKip Macy if (rn) { 957427ac07fSKip Macy rto = RNTORT(rn); 958427ac07fSKip Macy RT_LOCK(rto); 959427ac07fSKip Macy rto->rt_flags |= RTF_UP; 960427ac07fSKip Macy RT_UNLOCK(rto); 961427ac07fSKip Macy } else if (rt->rt_flags & RTF_GATEWAY) { 962427ac07fSKip Macy /* 963427ac07fSKip Macy * For gateway routes, we need to 964427ac07fSKip Macy * make sure that we we are deleting 965427ac07fSKip Macy * the correct gateway. 966427ac07fSKip Macy * rt_mpath_matchgate() does not 967427ac07fSKip Macy * check the case when there is only 968427ac07fSKip Macy * one route in the chain. 969427ac07fSKip Macy */ 970427ac07fSKip Macy if (gateway && 971427ac07fSKip Macy (rt->rt_gateway->sa_len != gateway->sa_len || 972427ac07fSKip Macy memcmp(rt->rt_gateway, gateway, gateway->sa_len))) 973427ac07fSKip Macy error = ESRCH; 974427ac07fSKip Macy goto done; 975427ac07fSKip Macy } 976427ac07fSKip Macy /* 977427ac07fSKip Macy * use the normal delete code to remove 978427ac07fSKip Macy * the first entry 979427ac07fSKip Macy */ 980427ac07fSKip Macy if (req != RTM_DELETE) 981427ac07fSKip Macy goto nondelete; 982427ac07fSKip Macy 983427ac07fSKip Macy error = ENOENT; 984427ac07fSKip Macy goto done; 985427ac07fSKip Macy } 986427ac07fSKip Macy 987427ac07fSKip Macy /* 988427ac07fSKip Macy * if the entry is 2nd and on up 989427ac07fSKip Macy */ 990427ac07fSKip Macy if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt)) 991427ac07fSKip Macy panic ("rtrequest1: rt_mpath_deldup"); 992427ac07fSKip Macy RT_LOCK(rt); 993427ac07fSKip Macy RT_ADDREF(rt); 994427ac07fSKip Macy if (req == RTM_DELETE) { 995b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 996b58ea5f3SBjoern A. Zeeb 997427ac07fSKip Macy rt->rt_flags &= ~RTF_UP; 998427ac07fSKip Macy /* 999427ac07fSKip Macy * One more rtentry floating around that is not 1000427ac07fSKip Macy * linked to the routing table. rttrash will be decremented 1001427ac07fSKip Macy * when RTFREE(rt) is eventually called. 1002427ac07fSKip Macy */ 1003427ac07fSKip Macy V_rttrash++; 1004427ac07fSKip Macy 1005427ac07fSKip Macy } 1006427ac07fSKip Macy 1007427ac07fSKip Macy nondelete: 1008427ac07fSKip Macy if (req != RTM_DELETE) 1009427ac07fSKip Macy panic("unrecognized request %d", req); 1010427ac07fSKip Macy 1011427ac07fSKip Macy 1012427ac07fSKip Macy /* 1013427ac07fSKip Macy * If the caller wants it, then it can have it, 1014427ac07fSKip Macy * but it's up to it to free the rtentry as we won't be 1015427ac07fSKip Macy * doing it. 1016427ac07fSKip Macy */ 1017427ac07fSKip Macy if (ret_nrt) { 1018427ac07fSKip Macy *ret_nrt = rt; 1019427ac07fSKip Macy RT_UNLOCK(rt); 1020427ac07fSKip Macy } else 1021427ac07fSKip Macy RTFREE_LOCKED(rt); 1022427ac07fSKip Macy done: 1023427ac07fSKip Macy return (error); 1024427ac07fSKip Macy } 1025427ac07fSKip Macy #endif 1026427ac07fSKip Macy 10278071913dSRuslan Ermilov int 10288b07e49aSJulian Elischer rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, 10298b07e49aSJulian Elischer u_int fibnum) 10308b07e49aSJulian Elischer { 1031b58ea5f3SBjoern A. Zeeb INIT_VNET_RTABLE(curvnet); 10323120b9d4SKip Macy int error = 0, needlock = 0; 1033df8bae1dSRodney W. Grimes register struct rtentry *rt; 1034df8bae1dSRodney W. Grimes register struct radix_node *rn; 1035df8bae1dSRodney W. Grimes register struct radix_node_head *rnh; 1036df8bae1dSRodney W. Grimes struct ifaddr *ifa; 1037df8bae1dSRodney W. Grimes struct sockaddr *ndst; 1038df8bae1dSRodney W. Grimes #define senderr(x) { error = x ; goto bad; } 1039df8bae1dSRodney W. Grimes 10408b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); 10418b07e49aSJulian Elischer if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */ 10428b07e49aSJulian Elischer fibnum = 0; 1043b0a76b88SJulian Elischer /* 1044b0a76b88SJulian Elischer * Find the correct routing tree to use for this Address Family 1045b0a76b88SJulian Elischer */ 1046c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 104785911824SLuigi Rizzo if (rnh == NULL) 1048983985c1SJeffrey Hsu return (EAFNOSUPPORT); 10493120b9d4SKip Macy needlock = ((flags & RTF_RNH_LOCKED) == 0); 10503120b9d4SKip Macy flags &= ~RTF_RNH_LOCKED; 10513120b9d4SKip Macy if (needlock) 1052956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1053c96b8224SKip Macy else 1054c96b8224SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1055b0a76b88SJulian Elischer /* 1056b0a76b88SJulian Elischer * If we are adding a host route then we don't want to put 105766953138SRuslan Ermilov * a netmask in the tree, nor do we want to clone it. 1058b0a76b88SJulian Elischer */ 10596e6b3f7cSQing Li if (flags & RTF_HOST) 106085911824SLuigi Rizzo netmask = NULL; 10616e6b3f7cSQing Li 1062df8bae1dSRodney W. Grimes switch (req) { 1063df8bae1dSRodney W. Grimes case RTM_DELETE: 1064e440aed9SQing Li #ifdef RADIX_MPATH 1065e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1066427ac07fSKip Macy error = rn_mpath_update(req, info, rnh, ret_nrt); 1067e440aed9SQing Li /* 1068427ac07fSKip Macy * "bad" holds true for the success case 1069427ac07fSKip Macy * as well 1070e440aed9SQing Li */ 1071427ac07fSKip Macy if (error != ENOENT) 1072427ac07fSKip Macy goto bad; 1073e440aed9SQing Li } 1074ea9cd9f2SBjoern A. Zeeb #endif 1075b0a76b88SJulian Elischer /* 1076b0a76b88SJulian Elischer * Remove the item from the tree and return it. 1077b0a76b88SJulian Elischer * Complain if it is not there and do no more processing. 1078b0a76b88SJulian Elischer */ 1079d1dd20beSSam Leffler rn = rnh->rnh_deladdr(dst, netmask, rnh); 108085911824SLuigi Rizzo if (rn == NULL) 1081df8bae1dSRodney W. Grimes senderr(ESRCH); 1082df8bae1dSRodney W. Grimes if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 1083df8bae1dSRodney W. Grimes panic ("rtrequest delete"); 1084d6941ce9SLuigi Rizzo rt = RNTORT(rn); 1085d1dd20beSSam Leffler RT_LOCK(rt); 10867138d65cSSam Leffler RT_ADDREF(rt); 108771eba915SRuslan Ermilov rt->rt_flags &= ~RTF_UP; 1088c2bed6a3SGarrett Wollman 1089c2bed6a3SGarrett Wollman /* 1090499676dfSJulian Elischer * give the protocol a chance to keep things in sync. 1091b0a76b88SJulian Elischer */ 1092df8bae1dSRodney W. Grimes if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 10938071913dSRuslan Ermilov ifa->ifa_rtrequest(RTM_DELETE, rt, info); 1094499676dfSJulian Elischer 1095b0a76b88SJulian Elischer /* 1096d6941ce9SLuigi Rizzo * One more rtentry floating around that is not 1097d6941ce9SLuigi Rizzo * linked to the routing table. rttrash will be decremented 1098d6941ce9SLuigi Rizzo * when RTFREE(rt) is eventually called. 1099499676dfSJulian Elischer */ 1100603724d3SBjoern A. Zeeb V_rttrash++; 1101499676dfSJulian Elischer 1102499676dfSJulian Elischer /* 1103499676dfSJulian Elischer * If the caller wants it, then it can have it, 1104499676dfSJulian Elischer * but it's up to it to free the rtentry as we won't be 1105499676dfSJulian Elischer * doing it. 1106b0a76b88SJulian Elischer */ 1107d1dd20beSSam Leffler if (ret_nrt) { 1108df8bae1dSRodney W. Grimes *ret_nrt = rt; 1109d1dd20beSSam Leffler RT_UNLOCK(rt); 1110d1dd20beSSam Leffler } else 1111d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1112df8bae1dSRodney W. Grimes break; 1113df8bae1dSRodney W. Grimes case RTM_RESOLVE: 11146e6b3f7cSQing Li /* 11156e6b3f7cSQing Li * resolve was only used for route cloning 11166e6b3f7cSQing Li * here for compat 11176e6b3f7cSQing Li */ 11186e6b3f7cSQing Li break; 1119df8bae1dSRodney W. Grimes case RTM_ADD: 11205df72964SGarrett Wollman if ((flags & RTF_GATEWAY) && !gateway) 112116a2e0a6SQing Li senderr(EINVAL); 112216a2e0a6SQing Li if (dst && gateway && (dst->sa_family != gateway->sa_family) && 112316a2e0a6SQing Li (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) 112416a2e0a6SQing Li senderr(EINVAL); 11255df72964SGarrett Wollman 11268b07e49aSJulian Elischer if (info->rti_ifa == NULL && (error = rt_getifa_fib(info, fibnum))) 11278071913dSRuslan Ermilov senderr(error); 11288071913dSRuslan Ermilov ifa = info->rti_ifa; 11291ed81b73SMarko Zec rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO); 113085911824SLuigi Rizzo if (rt == NULL) 1131df8bae1dSRodney W. Grimes senderr(ENOBUFS); 1132d1dd20beSSam Leffler RT_LOCK_INIT(rt); 1133df8bae1dSRodney W. Grimes rt->rt_flags = RTF_UP | flags; 11348b07e49aSJulian Elischer rt->rt_fibnum = fibnum; 1135499676dfSJulian Elischer /* 1136499676dfSJulian Elischer * Add the gateway. Possibly re-malloc-ing the storage for it 11376e6b3f7cSQing Li * 1138499676dfSJulian Elischer */ 1139d1dd20beSSam Leffler RT_LOCK(rt); 1140831a80b0SMatthew Dillon if ((error = rt_setgate(rt, dst, gateway)) != 0) { 1141d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 11421ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1143704b0666SBill Fenner senderr(error); 1144df8bae1dSRodney W. Grimes } 1145499676dfSJulian Elischer 1146499676dfSJulian Elischer /* 1147499676dfSJulian Elischer * point to the (possibly newly malloc'd) dest address. 1148499676dfSJulian Elischer */ 1149d1dd20beSSam Leffler ndst = (struct sockaddr *)rt_key(rt); 1150499676dfSJulian Elischer 1151499676dfSJulian Elischer /* 1152499676dfSJulian Elischer * make sure it contains the value we want (masked if needed). 1153499676dfSJulian Elischer */ 1154df8bae1dSRodney W. Grimes if (netmask) { 1155df8bae1dSRodney W. Grimes rt_maskedcopy(dst, ndst, netmask); 1156df8bae1dSRodney W. Grimes } else 11571838a647SLuigi Rizzo bcopy(dst, ndst, dst->sa_len); 11588e718bb4SGarrett Wollman 11598e718bb4SGarrett Wollman /* 1160499676dfSJulian Elischer * Note that we now have a reference to the ifa. 11618e718bb4SGarrett Wollman * This moved from below so that rnh->rnh_addaddr() can 1162499676dfSJulian Elischer * examine the ifa and ifa->ifa_ifp if it so desires. 11638e718bb4SGarrett Wollman */ 11641099f828SRobert Watson ifa_ref(ifa); 11658e718bb4SGarrett Wollman rt->rt_ifa = ifa; 11668e718bb4SGarrett Wollman rt->rt_ifp = ifa->ifa_ifp; 1167427ac07fSKip Macy rt->rt_rmx.rmx_weight = 1; 11688e718bb4SGarrett Wollman 1169e440aed9SQing Li #ifdef RADIX_MPATH 1170e440aed9SQing Li /* do not permit exactly the same dst/mask/gw pair */ 1171e440aed9SQing Li if (rn_mpath_capable(rnh) && 1172e440aed9SQing Li rt_mpath_conflict(rnh, rt, netmask)) { 1173e440aed9SQing Li if (rt->rt_ifa) { 11741099f828SRobert Watson ifa_free(rt->rt_ifa); 1175e440aed9SQing Li } 1176e440aed9SQing Li Free(rt_key(rt)); 1177e440aed9SQing Li RT_LOCK_DESTROY(rt); 11781ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1179e440aed9SQing Li senderr(EEXIST); 1180e440aed9SQing Li } 1181e440aed9SQing Li #endif 1182e440aed9SQing Li 1183d1dd20beSSam Leffler /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ 1184d1dd20beSSam Leffler rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); 1185499676dfSJulian Elischer /* 1186499676dfSJulian Elischer * If it still failed to go into the tree, 1187499676dfSJulian Elischer * then un-make it (this should be a function) 1188499676dfSJulian Elischer */ 118985911824SLuigi Rizzo if (rn == NULL) { 1190d1dd20beSSam Leffler if (rt->rt_ifa) 11911099f828SRobert Watson ifa_free(rt->rt_ifa); 1192df8bae1dSRodney W. Grimes Free(rt_key(rt)); 1193d1dd20beSSam Leffler RT_LOCK_DESTROY(rt); 11941ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1195df8bae1dSRodney W. Grimes senderr(EEXIST); 1196df8bae1dSRodney W. Grimes } 1197499676dfSJulian Elischer 1198499676dfSJulian Elischer /* 1199a0c0e34bSGleb Smirnoff * If this protocol has something to add to this then 1200499676dfSJulian Elischer * allow it to do that as well. 1201499676dfSJulian Elischer */ 1202df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest) 12038071913dSRuslan Ermilov ifa->ifa_rtrequest(req, rt, info); 1204499676dfSJulian Elischer 1205cd02a0b7SGarrett Wollman /* 1206499676dfSJulian Elischer * actually return a resultant rtentry and 1207499676dfSJulian Elischer * give the caller a single reference. 1208499676dfSJulian Elischer */ 1209df8bae1dSRodney W. Grimes if (ret_nrt) { 1210df8bae1dSRodney W. Grimes *ret_nrt = rt; 12117138d65cSSam Leffler RT_ADDREF(rt); 1212df8bae1dSRodney W. Grimes } 1213d1dd20beSSam Leffler RT_UNLOCK(rt); 1214df8bae1dSRodney W. Grimes break; 12158071913dSRuslan Ermilov default: 12168071913dSRuslan Ermilov error = EOPNOTSUPP; 1217df8bae1dSRodney W. Grimes } 1218df8bae1dSRodney W. Grimes bad: 12193120b9d4SKip Macy if (needlock) 1220956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1221df8bae1dSRodney W. Grimes return (error); 1222d1dd20beSSam Leffler #undef senderr 1223d1dd20beSSam Leffler } 1224d1dd20beSSam Leffler 12258071913dSRuslan Ermilov #undef dst 12268071913dSRuslan Ermilov #undef gateway 12278071913dSRuslan Ermilov #undef netmask 12288071913dSRuslan Ermilov #undef ifaaddr 12298071913dSRuslan Ermilov #undef ifpaddr 12308071913dSRuslan Ermilov #undef flags 1231df8bae1dSRodney W. Grimes 1232df8bae1dSRodney W. Grimes int 1233d1dd20beSSam Leffler rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) 1234df8bae1dSRodney W. Grimes { 1235d1dd20beSSam Leffler /* XXX dst may be overwritten, can we move this to below */ 12366e6b3f7cSQing Li int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); 12376e6b3f7cSQing Li #ifdef INVARIANTS 1238c2c2a7c1SBjoern A. Zeeb struct radix_node_head *rnh; 1239c2c2a7c1SBjoern A. Zeeb 1240c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, dst->sa_family); 12416e6b3f7cSQing Li #endif 1242d1dd20beSSam Leffler 1243d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 12443120b9d4SKip Macy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1245df8bae1dSRodney W. Grimes 12461db1fffaSBill Fenner /* 124785911824SLuigi Rizzo * Prepare to store the gateway in rt->rt_gateway. 124885911824SLuigi Rizzo * Both dst and gateway are stored one after the other in the same 124985911824SLuigi Rizzo * malloc'd chunk. If we have room, we can reuse the old buffer, 125085911824SLuigi Rizzo * rt_gateway already points to the right place. 125185911824SLuigi Rizzo * Otherwise, malloc a new block and update the 'dst' address. 1252499676dfSJulian Elischer */ 125385911824SLuigi Rizzo if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) { 125485911824SLuigi Rizzo caddr_t new; 125585911824SLuigi Rizzo 1256df8bae1dSRodney W. Grimes R_Malloc(new, caddr_t, dlen + glen); 125785911824SLuigi Rizzo if (new == NULL) 12581db1fffaSBill Fenner return ENOBUFS; 1259499676dfSJulian Elischer /* 126085911824SLuigi Rizzo * XXX note, we copy from *dst and not *rt_key(rt) because 126185911824SLuigi Rizzo * rt_setgate() can be called to initialize a newly 126285911824SLuigi Rizzo * allocated route entry, in which case rt_key(rt) == NULL 126385911824SLuigi Rizzo * (and also rt->rt_gateway == NULL). 126485911824SLuigi Rizzo * Free()/free() handle a NULL argument just fine. 1265499676dfSJulian Elischer */ 12661838a647SLuigi Rizzo bcopy(dst, new, dlen); 126785911824SLuigi Rizzo Free(rt_key(rt)); /* free old block, if any */ 1268445e045bSAlexander Kabaev rt_key(rt) = (struct sockaddr *)new; 126985911824SLuigi Rizzo rt->rt_gateway = (struct sockaddr *)(new + dlen); 1270df8bae1dSRodney W. Grimes } 1271499676dfSJulian Elischer 1272499676dfSJulian Elischer /* 127385911824SLuigi Rizzo * Copy the new gateway value into the memory chunk. 127485911824SLuigi Rizzo */ 127585911824SLuigi Rizzo bcopy(gate, rt->rt_gateway, glen); 127685911824SLuigi Rizzo 12776e6b3f7cSQing Li return (0); 1278df8bae1dSRodney W. Grimes } 1279df8bae1dSRodney W. Grimes 1280f708ef1bSPoul-Henning Kamp static void 1281d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 1282df8bae1dSRodney W. Grimes { 1283df8bae1dSRodney W. Grimes register u_char *cp1 = (u_char *)src; 1284df8bae1dSRodney W. Grimes register u_char *cp2 = (u_char *)dst; 1285df8bae1dSRodney W. Grimes register u_char *cp3 = (u_char *)netmask; 1286df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 1287df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 1288df8bae1dSRodney W. Grimes 1289df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 1290df8bae1dSRodney W. Grimes cp3 += 2; 1291df8bae1dSRodney W. Grimes if (cplim > cplim2) 1292df8bae1dSRodney W. Grimes cplim = cplim2; 1293df8bae1dSRodney W. Grimes while (cp2 < cplim) 1294df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 1295df8bae1dSRodney W. Grimes if (cp2 < cplim2) 1296df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 1297df8bae1dSRodney W. Grimes } 1298df8bae1dSRodney W. Grimes 1299df8bae1dSRodney W. Grimes /* 1300df8bae1dSRodney W. Grimes * Set up a routing table entry, normally 1301df8bae1dSRodney W. Grimes * for an interface. 1302df8bae1dSRodney W. Grimes */ 13038b07e49aSJulian Elischer #define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 13048b07e49aSJulian Elischer static inline int 13058b07e49aSJulian Elischer rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 1306df8bae1dSRodney W. Grimes { 13075aca0b30SLuigi Rizzo struct sockaddr *dst; 13088071913dSRuslan Ermilov struct sockaddr *netmask; 130985911824SLuigi Rizzo struct rtentry *rt = NULL; 13108071913dSRuslan Ermilov struct rt_addrinfo info; 1311e440aed9SQing Li int error = 0; 13128b07e49aSJulian Elischer int startfib, endfib; 13138b07e49aSJulian Elischer char tempbuf[_SOCKADDR_TMPSIZE]; 13148b07e49aSJulian Elischer int didwork = 0; 13158b07e49aSJulian Elischer int a_failure = 0; 13166e6b3f7cSQing Li static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1317df8bae1dSRodney W. Grimes 13188071913dSRuslan Ermilov if (flags & RTF_HOST) { 13198071913dSRuslan Ermilov dst = ifa->ifa_dstaddr; 13208071913dSRuslan Ermilov netmask = NULL; 13218071913dSRuslan Ermilov } else { 13228071913dSRuslan Ermilov dst = ifa->ifa_addr; 13238071913dSRuslan Ermilov netmask = ifa->ifa_netmask; 13248071913dSRuslan Ermilov } 13258b07e49aSJulian Elischer if ( dst->sa_family != AF_INET) 13268b07e49aSJulian Elischer fibnum = 0; 13278b07e49aSJulian Elischer if (fibnum == -1) { 132866e8505fSJulian Elischer if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) { 132966e8505fSJulian Elischer startfib = endfib = curthread->td_proc->p_fibnum; 133066e8505fSJulian Elischer } else { 13318b07e49aSJulian Elischer startfib = 0; 13328b07e49aSJulian Elischer endfib = rt_numfibs - 1; 133366e8505fSJulian Elischer } 13348b07e49aSJulian Elischer } else { 13358b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 13368b07e49aSJulian Elischer startfib = fibnum; 13378b07e49aSJulian Elischer endfib = fibnum; 13388b07e49aSJulian Elischer } 1339ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 1340ac4a76ebSBjoern A. Zeeb return(EINVAL); 1341ac4a76ebSBjoern A. Zeeb 1342b0a76b88SJulian Elischer /* 13438b07e49aSJulian Elischer * If it's a delete, check that if it exists, 13448b07e49aSJulian Elischer * it's on the correct interface or we might scrub 13458b07e49aSJulian Elischer * a route to another ifa which would 1346b0a76b88SJulian Elischer * be confusing at best and possibly worse. 1347b0a76b88SJulian Elischer */ 1348df8bae1dSRodney W. Grimes if (cmd == RTM_DELETE) { 1349b0a76b88SJulian Elischer /* 1350b0a76b88SJulian Elischer * It's a delete, so it should already exist.. 1351b0a76b88SJulian Elischer * If it's a net, mask off the host bits 1352b0a76b88SJulian Elischer * (Assuming we have a mask) 13538b07e49aSJulian Elischer * XXX this is kinda inet specific.. 1354b0a76b88SJulian Elischer */ 13558071913dSRuslan Ermilov if (netmask != NULL) { 13568b07e49aSJulian Elischer rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 13578b07e49aSJulian Elischer dst = (struct sockaddr *)tempbuf; 1358df8bae1dSRodney W. Grimes } 13598b07e49aSJulian Elischer } 13608b07e49aSJulian Elischer /* 13618b07e49aSJulian Elischer * Now go through all the requested tables (fibs) and do the 13628b07e49aSJulian Elischer * requested action. Realistically, this will either be fib 0 13638b07e49aSJulian Elischer * for protocols that don't do multiple tables or all the 13648b07e49aSJulian Elischer * tables for those that do. XXX For this version only AF_INET. 13658b07e49aSJulian Elischer * When that changes code should be refactored to protocol 13668b07e49aSJulian Elischer * independent parts and protocol dependent parts. 13678b07e49aSJulian Elischer */ 13688b07e49aSJulian Elischer for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 13698b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 13708b07e49aSJulian Elischer struct radix_node_head *rnh; 13718b07e49aSJulian Elischer struct radix_node *rn; 1372b0a76b88SJulian Elischer /* 13738071913dSRuslan Ermilov * Look up an rtentry that is in the routing tree and 13748071913dSRuslan Ermilov * contains the correct info. 1375b0a76b88SJulian Elischer */ 1376c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1377c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 13788b07e49aSJulian Elischer /* this table doesn't exist but others might */ 13798b07e49aSJulian Elischer continue; 1380956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 1381e440aed9SQing Li #ifdef RADIX_MPATH 1382e440aed9SQing Li if (rn_mpath_capable(rnh)) { 1383e440aed9SQing Li 1384e440aed9SQing Li rn = rnh->rnh_matchaddr(dst, rnh); 1385e440aed9SQing Li if (rn == NULL) 1386e440aed9SQing Li error = ESRCH; 1387e440aed9SQing Li else { 1388e440aed9SQing Li rt = RNTORT(rn); 1389e440aed9SQing Li /* 13908b07e49aSJulian Elischer * for interface route the 13918b07e49aSJulian Elischer * rt->rt_gateway is sockaddr_intf 13928b07e49aSJulian Elischer * for cloning ARP entries, so 13938b07e49aSJulian Elischer * rt_mpath_matchgate must use the 13948b07e49aSJulian Elischer * interface address 1395e440aed9SQing Li */ 13968b07e49aSJulian Elischer rt = rt_mpath_matchgate(rt, 13978b07e49aSJulian Elischer ifa->ifa_addr); 1398e440aed9SQing Li if (!rt) 1399e440aed9SQing Li error = ESRCH; 1400e440aed9SQing Li } 1401e440aed9SQing Li } 1402e440aed9SQing Li else 1403e440aed9SQing Li #endif 14048b07e49aSJulian Elischer rn = rnh->rnh_lookup(dst, netmask, rnh); 14058b07e49aSJulian Elischer error = (rn == NULL || 14068071913dSRuslan Ermilov (rn->rn_flags & RNF_ROOT) || 1407d6941ce9SLuigi Rizzo RNTORT(rn)->rt_ifa != ifa || 140885911824SLuigi Rizzo !sa_equal((struct sockaddr *)rn->rn_key, dst)); 1409956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 1410956b0b65SJeffrey Hsu if (error) { 14118b07e49aSJulian Elischer /* this is only an error if bad on ALL tables */ 14128b07e49aSJulian Elischer continue; 1413df8bae1dSRodney W. Grimes } 1414b0a76b88SJulian Elischer } 1415b0a76b88SJulian Elischer /* 1416b0a76b88SJulian Elischer * Do the actual request 1417b0a76b88SJulian Elischer */ 14188071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 14198071913dSRuslan Ermilov info.rti_ifa = ifa; 14208071913dSRuslan Ermilov info.rti_flags = flags | ifa->ifa_flags; 14218071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 14226e6b3f7cSQing Li /* 14236e6b3f7cSQing Li * doing this for compatibility reasons 14246e6b3f7cSQing Li */ 14256e6b3f7cSQing Li if (cmd == RTM_ADD) 14266e6b3f7cSQing Li info.rti_info[RTAX_GATEWAY] = 14276e6b3f7cSQing Li (struct sockaddr *)&null_sdl; 14286e6b3f7cSQing Li else 14298071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 14308071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 14318b07e49aSJulian Elischer error = rtrequest1_fib(cmd, &info, &rt, fibnum); 14325aca0b30SLuigi Rizzo if (error == 0 && rt != NULL) { 14338071913dSRuslan Ermilov /* 14346f99b44cSBrian Somers * notify any listening routing agents of the change 14358071913dSRuslan Ermilov */ 1436d1dd20beSSam Leffler RT_LOCK(rt); 1437e440aed9SQing Li #ifdef RADIX_MPATH 1438e440aed9SQing Li /* 1439e440aed9SQing Li * in case address alias finds the first address 1440e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.246/24 1441e440aed9SQing Li * e.g. ifconfig bge0 192.103.54.247/24 1442e440aed9SQing Li * the address set in the route is 192.103.54.246 1443e440aed9SQing Li * so we need to replace it with 192.103.54.247 1444e440aed9SQing Li */ 14458b07e49aSJulian Elischer if (memcmp(rt->rt_ifa->ifa_addr, 14468b07e49aSJulian Elischer ifa->ifa_addr, ifa->ifa_addr->sa_len)) { 14471099f828SRobert Watson ifa_free(rt->rt_ifa); 14481099f828SRobert Watson ifa_ref(ifa); 1449e440aed9SQing Li rt->rt_ifp = ifa->ifa_ifp; 1450e440aed9SQing Li rt->rt_ifa = ifa; 1451e440aed9SQing Li } 1452e440aed9SQing Li #endif 14536e6b3f7cSQing Li /* 14546e6b3f7cSQing Li * doing this for compatibility reasons 14556e6b3f7cSQing Li */ 14566e6b3f7cSQing Li if (cmd == RTM_ADD) { 14576e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 14586e6b3f7cSQing Li rt->rt_ifp->if_type; 14596e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 14606e6b3f7cSQing Li rt->rt_ifp->if_index; 14616e6b3f7cSQing Li } 14628071913dSRuslan Ermilov rt_newaddrmsg(cmd, ifa, error, rt); 14638071913dSRuslan Ermilov if (cmd == RTM_DELETE) { 1464b0a76b88SJulian Elischer /* 14658b07e49aSJulian Elischer * If we are deleting, and we found an entry, 14668b07e49aSJulian Elischer * then it's been removed from the tree.. 14678b07e49aSJulian Elischer * now throw it away. 1468b0a76b88SJulian Elischer */ 1469d1dd20beSSam Leffler RTFREE_LOCKED(rt); 1470d1dd20beSSam Leffler } else { 1471d1dd20beSSam Leffler if (cmd == RTM_ADD) { 1472b0a76b88SJulian Elischer /* 14738b07e49aSJulian Elischer * We just wanted to add it.. 14748b07e49aSJulian Elischer * we don't actually need a reference. 1475b0a76b88SJulian Elischer */ 14767138d65cSSam Leffler RT_REMREF(rt); 1477df8bae1dSRodney W. Grimes } 1478d1dd20beSSam Leffler RT_UNLOCK(rt); 1479d1dd20beSSam Leffler } 14808b07e49aSJulian Elischer didwork = 1; 1481df8bae1dSRodney W. Grimes } 14828b07e49aSJulian Elischer if (error) 14838b07e49aSJulian Elischer a_failure = error; 14848b07e49aSJulian Elischer } 14858b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 14868b07e49aSJulian Elischer if (didwork) { 14878b07e49aSJulian Elischer error = 0; 14888b07e49aSJulian Elischer } else { 14898b07e49aSJulian Elischer /* we only give an error if it wasn't in any table */ 14908b07e49aSJulian Elischer error = ((flags & RTF_HOST) ? 14918b07e49aSJulian Elischer EHOSTUNREACH : ENETUNREACH); 14928b07e49aSJulian Elischer } 14938b07e49aSJulian Elischer } else { 14948b07e49aSJulian Elischer if (a_failure) { 14958b07e49aSJulian Elischer /* return an error if any of them failed */ 14968b07e49aSJulian Elischer error = a_failure; 14978b07e49aSJulian Elischer } 14988b07e49aSJulian Elischer } 14993ec66d6cSDavid Greenman return (error); 15003ec66d6cSDavid Greenman } 1501cb64988fSLuoqi Chen 15028b07e49aSJulian Elischer /* special one for inet internal use. may not use. */ 15038b07e49aSJulian Elischer int 15048b07e49aSJulian Elischer rtinit_fib(struct ifaddr *ifa, int cmd, int flags) 15058b07e49aSJulian Elischer { 15068b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, -1)); 15078b07e49aSJulian Elischer } 15088b07e49aSJulian Elischer 15098b07e49aSJulian Elischer /* 15108b07e49aSJulian Elischer * Set up a routing table entry, normally 15118b07e49aSJulian Elischer * for an interface. 15128b07e49aSJulian Elischer */ 15138b07e49aSJulian Elischer int 15148b07e49aSJulian Elischer rtinit(struct ifaddr *ifa, int cmd, int flags) 15158b07e49aSJulian Elischer { 15168b07e49aSJulian Elischer struct sockaddr *dst; 15178b07e49aSJulian Elischer int fib = 0; 15188b07e49aSJulian Elischer 15198b07e49aSJulian Elischer if (flags & RTF_HOST) { 15208b07e49aSJulian Elischer dst = ifa->ifa_dstaddr; 15218b07e49aSJulian Elischer } else { 15228b07e49aSJulian Elischer dst = ifa->ifa_addr; 15238b07e49aSJulian Elischer } 15248b07e49aSJulian Elischer 15258b07e49aSJulian Elischer if (dst->sa_family == AF_INET) 15268b07e49aSJulian Elischer fib = -1; 15278b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, fib)); 15288b07e49aSJulian Elischer } 15298b07e49aSJulian Elischer 15306a800098SYoshinobu Inoue /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */ 15316a800098SYoshinobu Inoue SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); 1532