1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1991, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 3142e9e16dSRuslan Ermilov * @(#)route.c 8.3.1.1 (Berkeley) 2/23/95 32c3aac50fSPeter Wemm * $FreeBSD$ 33df8bae1dSRodney W. Grimes */ 348b07e49aSJulian Elischer /************************************************************************ 358b07e49aSJulian Elischer * Note: In this file a 'fib' is a "forwarding information base" * 368b07e49aSJulian Elischer * Which is the new name for an in kernel routing (next hop) table. * 378b07e49aSJulian Elischer ***********************************************************************/ 38df8bae1dSRodney W. Grimes 391d5e9e22SEivind Eklund #include "opt_inet.h" 40096f2786SBjoern A. Zeeb #include "opt_inet6.h" 414bd49128SPeter Wemm #include "opt_mrouting.h" 42e440aed9SQing Li #include "opt_mpath.h" 43d6e23cf0SMichael Tuexen #include "opt_route.h" 444bd49128SPeter Wemm 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 474d1d4912SBruce Evans #include <sys/malloc.h> 48df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 508b07e49aSJulian Elischer #include <sys/sysctl.h> 513120b9d4SKip Macy #include <sys/syslog.h> 528b07e49aSJulian Elischer #include <sys/sysproto.h> 538b07e49aSJulian Elischer #include <sys/proc.h> 54df8bae1dSRodney W. Grimes #include <sys/domain.h> 5569104ebeSMichael Tuexen #include <sys/eventhandler.h> 56cb64988fSLuoqi Chen #include <sys/kernel.h> 5720efcfc6SAndrey V. Elsukov #include <sys/lock.h> 5820efcfc6SAndrey V. Elsukov #include <sys/rmlock.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <net/if.h> 6176039bc8SGleb Smirnoff #include <net/if_var.h> 626e6b3f7cSQing Li #include <net/if_dl.h> 63df8bae1dSRodney W. Grimes #include <net/route.h> 6461eee0e2SAlexander V. Chernikov #include <net/route_var.h> 65a6663252SAlexander V. Chernikov #include <net/route/nhop.h> 66a6663252SAlexander V. Chernikov #include <net/route/shared.h> 67530c0060SRobert Watson #include <net/vnet.h> 68df8bae1dSRodney W. Grimes 69e440aed9SQing Li #ifdef RADIX_MPATH 70e440aed9SQing Li #include <net/radix_mpath.h> 71e440aed9SQing Li #endif 72e440aed9SQing Li 73df8bae1dSRodney W. Grimes #include <netinet/in.h> 74b5e8ce9fSBruce Evans #include <netinet/ip_mroute.h> 75df8bae1dSRodney W. Grimes 762dc1d581SAndre Oppermann #include <vm/uma.h> 772dc1d581SAndre Oppermann 784871fc4aSJulian Elischer #define RT_MAXFIBS UINT16_MAX 79bfca216eSBjoern A. Zeeb 80bfca216eSBjoern A. Zeeb /* Kernel config default option. */ 81bfca216eSBjoern A. Zeeb #ifdef ROUTETABLES 82bfca216eSBjoern A. Zeeb #if ROUTETABLES <= 0 83bfca216eSBjoern A. Zeeb #error "ROUTETABLES defined too low" 84bfca216eSBjoern A. Zeeb #endif 85bfca216eSBjoern A. Zeeb #if ROUTETABLES > RT_MAXFIBS 86bfca216eSBjoern A. Zeeb #error "ROUTETABLES defined too big" 87bfca216eSBjoern A. Zeeb #endif 88bfca216eSBjoern A. Zeeb #define RT_NUMFIBS ROUTETABLES 89bfca216eSBjoern A. Zeeb #endif /* ROUTETABLES */ 90bfca216eSBjoern A. Zeeb /* Initialize to default if not otherwise set. */ 91bfca216eSBjoern A. Zeeb #ifndef RT_NUMFIBS 92bfca216eSBjoern A. Zeeb #define RT_NUMFIBS 1 93bfca216eSBjoern A. Zeeb #endif 94bfca216eSBjoern A. Zeeb 954871fc4aSJulian Elischer /* This is read-only.. */ 968b07e49aSJulian Elischer u_int rt_numfibs = RT_NUMFIBS; 97af3b2549SHans Petter Selasky SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RDTUN, &rt_numfibs, 0, ""); 988b07e49aSJulian Elischer 9966e8505fSJulian Elischer /* 10066e8505fSJulian Elischer * By default add routes to all fibs for new interfaces. 10166e8505fSJulian Elischer * Once this is set to 0 then only allocate routes on interface 10266e8505fSJulian Elischer * changes for the FIB of the caller when adding a new set of addresses 10366e8505fSJulian Elischer * to an interface. XXX this is a shotgun aproach to a problem that needs 10466e8505fSJulian Elischer * a more fine grained solution.. that will come. 105a8498625SBjoern A. Zeeb * XXX also has the problems getting the FIB from curthread which will not 106a8498625SBjoern A. Zeeb * always work given the fib can be overridden and prefixes can be added 107a8498625SBjoern A. Zeeb * from the network stack context. 10866e8505fSJulian Elischer */ 109ee0bd4b9SHiroki Sato VNET_DEFINE(u_int, rt_add_addr_allfibs) = 1; 110ee0bd4b9SHiroki Sato SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, 111ee0bd4b9SHiroki Sato &VNET_NAME(rt_add_addr_allfibs), 0, ""); 11266e8505fSJulian Elischer 113a6663252SAlexander V. Chernikov VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); 114185c3d2bSGleb Smirnoff 115185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSINIT(rtstat); 116185c3d2bSGleb Smirnoff #ifdef VIMAGE 117185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSUNINIT(rtstat); 118185c3d2bSGleb Smirnoff #endif 119b58ea5f3SBjoern A. Zeeb 12061eee0e2SAlexander V. Chernikov VNET_DEFINE(struct rib_head *, rt_tables); 12182cea7e6SBjoern A. Zeeb #define V_rt_tables VNET(rt_tables) 12282cea7e6SBjoern A. Zeeb 12382cea7e6SBjoern A. Zeeb VNET_DEFINE(int, rttrash); /* routes not in table but not freed */ 12482cea7e6SBjoern A. Zeeb #define V_rttrash VNET(rttrash) 12582cea7e6SBjoern A. Zeeb 126bfe1aba4SMarko Zec 127d6941ce9SLuigi Rizzo /* 128d6941ce9SLuigi Rizzo * Convert a 'struct radix_node *' to a 'struct rtentry *'. 129d6941ce9SLuigi Rizzo * The operation can be done safely (in this code) because a 130d6941ce9SLuigi Rizzo * 'struct rtentry' starts with two 'struct radix_node''s, the first 131d6941ce9SLuigi Rizzo * one representing leaf nodes in the routing tree, which is 132d6941ce9SLuigi Rizzo * what the code in radix.c passes us as a 'struct radix_node'. 133d6941ce9SLuigi Rizzo * 134d6941ce9SLuigi Rizzo * But because there are a lot of assumptions in this conversion, 135d6941ce9SLuigi Rizzo * do not cast explicitly, but always use the macro below. 136d6941ce9SLuigi Rizzo */ 137d6941ce9SLuigi Rizzo #define RNTORT(p) ((struct rtentry *)(p)) 138d6941ce9SLuigi Rizzo 1395f901c92SAndrew Turner VNET_DEFINE_STATIC(uma_zone_t, rtzone); /* Routing table UMA zone. */ 14082cea7e6SBjoern A. Zeeb #define V_rtzone VNET(rtzone) 14182cea7e6SBjoern A. Zeeb 142d6e23cf0SMichael Tuexen EVENTHANDLER_LIST_DEFINE(rt_addrmsg); 143d6e23cf0SMichael Tuexen 144fda45409SGleb Smirnoff static int rt_getifa_fib(struct rt_addrinfo *, u_int); 1450fb9298dSAlexander V. Chernikov static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); 146*539642a2SAlexander V. Chernikov static int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *, 147*539642a2SAlexander V. Chernikov void *arg); 14861eee0e2SAlexander V. Chernikov static struct rtentry *rt_unlinkrte(struct rib_head *rnh, 149e8b0643eSAlexander V. Chernikov struct rt_addrinfo *info, int *perror); 150e8b0643eSAlexander V. Chernikov static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info); 151e8b0643eSAlexander V. Chernikov #ifdef RADIX_MPATH 15261eee0e2SAlexander V. Chernikov static struct radix_node *rt_mpath_unlink(struct rib_head *rnh, 153e8b0643eSAlexander V. Chernikov struct rt_addrinfo *info, struct rtentry *rto, int *perror); 154e8b0643eSAlexander V. Chernikov #endif 1559a1b64d5SAlexander V. Chernikov static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, 1569a1b64d5SAlexander V. Chernikov int flags); 157c77462ddSAlexander V. Chernikov 158aef2d5fbSAlexander V. Chernikov static int add_route(struct rib_head *rnh, struct rt_addrinfo *info, 159aef2d5fbSAlexander V. Chernikov struct rtentry **ret_nrt); 160aef2d5fbSAlexander V. Chernikov static int del_route(struct rib_head *rnh, struct rt_addrinfo *info, 161aef2d5fbSAlexander V. Chernikov struct rtentry **ret_nrt); 162aef2d5fbSAlexander V. Chernikov static int change_route(struct rib_head *, struct rt_addrinfo *, 163aef2d5fbSAlexander V. Chernikov struct rtentry **); 164aef2d5fbSAlexander V. Chernikov 1657f948f12SAlexander V. Chernikov struct if_mtuinfo 1667f948f12SAlexander V. Chernikov { 1677f948f12SAlexander V. Chernikov struct ifnet *ifp; 1687f948f12SAlexander V. Chernikov int mtu; 1697f948f12SAlexander V. Chernikov }; 1707f948f12SAlexander V. Chernikov 1717f948f12SAlexander V. Chernikov static int if_updatemtu_cb(struct radix_node *, void *); 1727f948f12SAlexander V. Chernikov 1738b07e49aSJulian Elischer /* 1748b07e49aSJulian Elischer * handler for net.my_fibnum 1758b07e49aSJulian Elischer */ 1768b07e49aSJulian Elischer static int 1778b07e49aSJulian Elischer sysctl_my_fibnum(SYSCTL_HANDLER_ARGS) 178df8bae1dSRodney W. Grimes { 1798b07e49aSJulian Elischer int fibnum; 1808b07e49aSJulian Elischer int error; 1818b07e49aSJulian Elischer 1828b07e49aSJulian Elischer fibnum = curthread->td_proc->p_fibnum; 1838b07e49aSJulian Elischer error = sysctl_handle_int(oidp, &fibnum, 0, req); 1848b07e49aSJulian Elischer return (error); 185df8bae1dSRodney W. Grimes } 186df8bae1dSRodney W. Grimes 1877029da5cSPawel Biernacki SYSCTL_PROC(_net, OID_AUTO, my_fibnum, 1887029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1897029da5cSPawel Biernacki &sysctl_my_fibnum, "I", 1907029da5cSPawel Biernacki "default FIB of caller"); 1912dc1d581SAndre Oppermann 19261eee0e2SAlexander V. Chernikov static __inline struct rib_head ** 193c2c2a7c1SBjoern A. Zeeb rt_tables_get_rnh_ptr(int table, int fam) 194c2c2a7c1SBjoern A. Zeeb { 19561eee0e2SAlexander V. Chernikov struct rib_head **rnh; 196c2c2a7c1SBjoern A. Zeeb 19734a5582cSAlexander V. Chernikov KASSERT(table >= 0 && table < rt_numfibs, 19834a5582cSAlexander V. Chernikov ("%s: table out of bounds (0 <= %d < %d)", __func__, table, 19934a5582cSAlexander V. Chernikov rt_numfibs)); 20034a5582cSAlexander V. Chernikov KASSERT(fam >= 0 && fam < (AF_MAX + 1), 20134a5582cSAlexander V. Chernikov ("%s: fam out of bounds (0 <= %d < %d)", __func__, fam, AF_MAX+1)); 202c2c2a7c1SBjoern A. Zeeb 203c2c2a7c1SBjoern A. Zeeb /* rnh is [fib=0][af=0]. */ 20461eee0e2SAlexander V. Chernikov rnh = (struct rib_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 21161eee0e2SAlexander V. Chernikov struct rib_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 2184f321dbdSBjoern A. Zeeb u_int 21984cc0778SGeorge V. Neville-Neil rt_tables_get_gen(int table, int fam) 22084cc0778SGeorge V. Neville-Neil { 22184cc0778SGeorge V. Neville-Neil struct rib_head *rnh; 22284cc0778SGeorge V. Neville-Neil 22384cc0778SGeorge V. Neville-Neil rnh = *rt_tables_get_rnh_ptr(table, fam); 2246d768226SGeorge V. Neville-Neil KASSERT(rnh != NULL, ("%s: NULL rib_head pointer table %d fam %d", 2256d768226SGeorge V. Neville-Neil __func__, table, fam)); 22684cc0778SGeorge V. Neville-Neil return (rnh->rnh_gen); 22784cc0778SGeorge V. Neville-Neil } 22884cc0778SGeorge V. Neville-Neil 22984cc0778SGeorge V. Neville-Neil 230d0728d71SRobert Watson /* 231d0728d71SRobert Watson * route initialization must occur before ip6_init2(), which happenas at 232d0728d71SRobert Watson * SI_ORDER_MIDDLE. 233d0728d71SRobert Watson */ 2342eb5613fSLuigi Rizzo static void 2352eb5613fSLuigi Rizzo route_init(void) 236df8bae1dSRodney W. Grimes { 2378b07e49aSJulian Elischer 2386f95a5ebSJulian Elischer /* whack the tunable ints into line. */ 2398b07e49aSJulian Elischer if (rt_numfibs > RT_MAXFIBS) 2408b07e49aSJulian Elischer rt_numfibs = RT_MAXFIBS; 2418b07e49aSJulian Elischer if (rt_numfibs == 0) 2428b07e49aSJulian Elischer rt_numfibs = 1; 243a6663252SAlexander V. Chernikov nhops_init(); 2441ed81b73SMarko Zec } 245891cf3edSEd Maste SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); 2461ed81b73SMarko Zec 247e3a7aa6fSGleb Smirnoff static int 248e3a7aa6fSGleb Smirnoff rtentry_zinit(void *mem, int size, int how) 249e3a7aa6fSGleb Smirnoff { 250e3a7aa6fSGleb Smirnoff struct rtentry *rt = mem; 251e3a7aa6fSGleb Smirnoff 252b8af2820SMateusz Guzik rt->rt_pksent = counter_u64_alloc(how); 253e3a7aa6fSGleb Smirnoff if (rt->rt_pksent == NULL) 254e3a7aa6fSGleb Smirnoff return (ENOMEM); 255e3a7aa6fSGleb Smirnoff 256e3a7aa6fSGleb Smirnoff RT_LOCK_INIT(rt); 257e3a7aa6fSGleb Smirnoff 258e3a7aa6fSGleb Smirnoff return (0); 259e3a7aa6fSGleb Smirnoff } 260e3a7aa6fSGleb Smirnoff 261e3a7aa6fSGleb Smirnoff static void 262e3a7aa6fSGleb Smirnoff rtentry_zfini(void *mem, int size) 263e3a7aa6fSGleb Smirnoff { 264e3a7aa6fSGleb Smirnoff struct rtentry *rt = mem; 265e3a7aa6fSGleb Smirnoff 266e3a7aa6fSGleb Smirnoff RT_LOCK_DESTROY(rt); 267e3a7aa6fSGleb Smirnoff counter_u64_free(rt->rt_pksent); 268e3a7aa6fSGleb Smirnoff } 269e3a7aa6fSGleb Smirnoff 270e3a7aa6fSGleb Smirnoff static int 271e3a7aa6fSGleb Smirnoff rtentry_ctor(void *mem, int size, void *arg, int how) 272e3a7aa6fSGleb Smirnoff { 273e3a7aa6fSGleb Smirnoff struct rtentry *rt = mem; 274e3a7aa6fSGleb Smirnoff 275e3a7aa6fSGleb Smirnoff bzero(rt, offsetof(struct rtentry, rt_endzero)); 276e3a7aa6fSGleb Smirnoff counter_u64_zero(rt->rt_pksent); 277e8b0643eSAlexander V. Chernikov rt->rt_chain = NULL; 278e3a7aa6fSGleb Smirnoff 279e3a7aa6fSGleb Smirnoff return (0); 280e3a7aa6fSGleb Smirnoff } 281e3a7aa6fSGleb Smirnoff 282d0728d71SRobert Watson static void 283256ea2abSGleb Smirnoff rtentry_dtor(void *mem, int size, void *arg) 284256ea2abSGleb Smirnoff { 285256ea2abSGleb Smirnoff struct rtentry *rt = mem; 286256ea2abSGleb Smirnoff 287256ea2abSGleb Smirnoff RT_UNLOCK_COND(rt); 288256ea2abSGleb Smirnoff } 289256ea2abSGleb Smirnoff 290256ea2abSGleb Smirnoff static void 291d0728d71SRobert Watson vnet_route_init(const void *unused __unused) 2921ed81b73SMarko Zec { 2931ed81b73SMarko Zec struct domain *dom; 29461eee0e2SAlexander V. Chernikov struct rib_head **rnh; 295c2c2a7c1SBjoern A. Zeeb int table; 2961ed81b73SMarko Zec int fam; 2971ed81b73SMarko Zec 298c2c2a7c1SBjoern A. Zeeb V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) * 29961eee0e2SAlexander V. Chernikov sizeof(struct rib_head *), M_RTABLE, M_WAITOK|M_ZERO); 300c2c2a7c1SBjoern A. Zeeb 301e3a7aa6fSGleb Smirnoff V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), 302256ea2abSGleb Smirnoff rtentry_ctor, rtentry_dtor, 303e3a7aa6fSGleb Smirnoff rtentry_zinit, rtentry_zfini, UMA_ALIGN_PTR, 0); 3048b07e49aSJulian Elischer for (dom = domains; dom; dom = dom->dom_next) { 305b680a383SBjoern A. Zeeb if (dom->dom_rtattach == NULL) 306b680a383SBjoern A. Zeeb continue; 307b680a383SBjoern A. Zeeb 3088b07e49aSJulian Elischer for (table = 0; table < rt_numfibs; table++) { 309b680a383SBjoern A. Zeeb fam = dom->dom_family; 310b680a383SBjoern A. Zeeb if (table != 0 && fam != AF_INET6 && fam != AF_INET) 311b680a383SBjoern A. Zeeb break; 312b680a383SBjoern A. Zeeb 313c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh_ptr(table, fam); 314c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 315c2c2a7c1SBjoern A. Zeeb panic("%s: rnh NULL", __func__); 316ead85fe4SAlexander V. Chernikov dom->dom_rtattach((void **)rnh, 0, table); 3178b07e49aSJulian Elischer } 3188b07e49aSJulian Elischer } 3198b07e49aSJulian Elischer } 320d0728d71SRobert Watson VNET_SYSINIT(vnet_route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 321d0728d71SRobert Watson vnet_route_init, 0); 3228b07e49aSJulian Elischer 323bc29160dSMarko Zec #ifdef VIMAGE 324d0728d71SRobert Watson static void 325d0728d71SRobert Watson vnet_route_uninit(const void *unused __unused) 326bc29160dSMarko Zec { 327bc29160dSMarko Zec int table; 328bc29160dSMarko Zec int fam; 329bc29160dSMarko Zec struct domain *dom; 33061eee0e2SAlexander V. Chernikov struct rib_head **rnh; 331bc29160dSMarko Zec 332bc29160dSMarko Zec for (dom = domains; dom; dom = dom->dom_next) { 333b680a383SBjoern A. Zeeb if (dom->dom_rtdetach == NULL) 334b680a383SBjoern A. Zeeb continue; 335b680a383SBjoern A. Zeeb 336bc29160dSMarko Zec for (table = 0; table < rt_numfibs; table++) { 337b680a383SBjoern A. Zeeb fam = dom->dom_family; 338b680a383SBjoern A. Zeeb 339b680a383SBjoern A. Zeeb if (table != 0 && fam != AF_INET6 && fam != AF_INET) 340b680a383SBjoern A. Zeeb break; 341b680a383SBjoern A. Zeeb 342bc29160dSMarko Zec rnh = rt_tables_get_rnh_ptr(table, fam); 343bc29160dSMarko Zec if (rnh == NULL) 344bc29160dSMarko Zec panic("%s: rnh NULL", __func__); 34557c3556bSAlexander V. Chernikov dom->dom_rtdetach((void **)rnh, 0); 346bc29160dSMarko Zec } 347bc29160dSMarko Zec } 3486274ce3eSCraig Rodrigues 3496274ce3eSCraig Rodrigues free(V_rt_tables, M_RTABLE); 3506274ce3eSCraig Rodrigues uma_zdestroy(V_rtzone); 351bc29160dSMarko Zec } 35289856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, 353d0728d71SRobert Watson vnet_route_uninit, 0); 354bc29160dSMarko Zec #endif 355bc29160dSMarko Zec 35661eee0e2SAlexander V. Chernikov struct rib_head * 357ead85fe4SAlexander V. Chernikov rt_table_init(int offset, int family, u_int fibnum) 35861eee0e2SAlexander V. Chernikov { 35961eee0e2SAlexander V. Chernikov struct rib_head *rh; 36061eee0e2SAlexander V. Chernikov 36161eee0e2SAlexander V. Chernikov rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); 36261eee0e2SAlexander V. Chernikov 36361eee0e2SAlexander V. Chernikov /* TODO: These details should be hidded inside radix.c */ 36461eee0e2SAlexander V. Chernikov /* Init masks tree */ 36561eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); 36661eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); 36761eee0e2SAlexander V. Chernikov rh->head.rnh_masks = &rh->rmhead; 36861eee0e2SAlexander V. Chernikov 369ead85fe4SAlexander V. Chernikov /* Save metadata associated with this routing table. */ 370ead85fe4SAlexander V. Chernikov rh->rib_family = family; 371ead85fe4SAlexander V. Chernikov rh->rib_fibnum = fibnum; 372ead85fe4SAlexander V. Chernikov #ifdef VIMAGE 373ead85fe4SAlexander V. Chernikov rh->rib_vnet = curvnet; 374ead85fe4SAlexander V. Chernikov #endif 375ead85fe4SAlexander V. Chernikov 37634a5582cSAlexander V. Chernikov tmproutes_init(rh); 37734a5582cSAlexander V. Chernikov 37861eee0e2SAlexander V. Chernikov /* Init locks */ 379abe95d87SAndrey V. Elsukov RIB_LOCK_INIT(rh); 38061eee0e2SAlexander V. Chernikov 381a6663252SAlexander V. Chernikov nhops_init_rib(rh); 382a6663252SAlexander V. Chernikov 38361eee0e2SAlexander V. Chernikov /* Finally, set base callbacks */ 38461eee0e2SAlexander V. Chernikov rh->rnh_addaddr = rn_addroute; 38561eee0e2SAlexander V. Chernikov rh->rnh_deladdr = rn_delete; 38661eee0e2SAlexander V. Chernikov rh->rnh_matchaddr = rn_match; 38761eee0e2SAlexander V. Chernikov rh->rnh_lookup = rn_lookup; 38861eee0e2SAlexander V. Chernikov rh->rnh_walktree = rn_walktree; 38961eee0e2SAlexander V. Chernikov rh->rnh_walktree_from = rn_walktree_from; 39061eee0e2SAlexander V. Chernikov 39161eee0e2SAlexander V. Chernikov return (rh); 39261eee0e2SAlexander V. Chernikov } 39361eee0e2SAlexander V. Chernikov 394a5243af2SBjoern A. Zeeb static int 395a5243af2SBjoern A. Zeeb rt_freeentry(struct radix_node *rn, void *arg) 396a5243af2SBjoern A. Zeeb { 397a5243af2SBjoern A. Zeeb struct radix_head * const rnh = arg; 398a5243af2SBjoern A. Zeeb struct radix_node *x; 399a5243af2SBjoern A. Zeeb 400a5243af2SBjoern A. Zeeb x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); 401a5243af2SBjoern A. Zeeb if (x != NULL) 402a5243af2SBjoern A. Zeeb R_Free(x); 403a5243af2SBjoern A. Zeeb return (0); 404a5243af2SBjoern A. Zeeb } 405a5243af2SBjoern A. Zeeb 40661eee0e2SAlexander V. Chernikov void 40761eee0e2SAlexander V. Chernikov rt_table_destroy(struct rib_head *rh) 40861eee0e2SAlexander V. Chernikov { 40961eee0e2SAlexander V. Chernikov 41034a5582cSAlexander V. Chernikov tmproutes_destroy(rh); 41134a5582cSAlexander V. Chernikov 412a5243af2SBjoern A. Zeeb rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); 413a5243af2SBjoern A. Zeeb 414a6663252SAlexander V. Chernikov nhops_destroy_rib(rh); 415a6663252SAlexander V. Chernikov 41661eee0e2SAlexander V. Chernikov /* Assume table is already empty */ 417abe95d87SAndrey V. Elsukov RIB_LOCK_DESTROY(rh); 41861eee0e2SAlexander V. Chernikov free(rh, M_RTABLE); 41961eee0e2SAlexander V. Chernikov } 42061eee0e2SAlexander V. Chernikov 42161eee0e2SAlexander V. Chernikov 4228b07e49aSJulian Elischer #ifndef _SYS_SYSPROTO_H_ 4238b07e49aSJulian Elischer struct setfib_args { 4248b07e49aSJulian Elischer int fibnum; 4258b07e49aSJulian Elischer }; 4268b07e49aSJulian Elischer #endif 4278b07e49aSJulian Elischer int 4288451d0ddSKip Macy sys_setfib(struct thread *td, struct setfib_args *uap) 4298b07e49aSJulian Elischer { 4308b07e49aSJulian Elischer if (uap->fibnum < 0 || uap->fibnum >= rt_numfibs) 4318b07e49aSJulian Elischer return EINVAL; 4328b07e49aSJulian Elischer td->td_proc->p_fibnum = uap->fibnum; 4338b07e49aSJulian Elischer return (0); 434df8bae1dSRodney W. Grimes } 435df8bae1dSRodney W. Grimes 436df8bae1dSRodney W. Grimes /* 437df8bae1dSRodney W. Grimes * Packet routing routines. 438df8bae1dSRodney W. Grimes */ 439df8bae1dSRodney W. Grimes void 4408b07e49aSJulian Elischer rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum) 4418b07e49aSJulian Elischer { 4428b07e49aSJulian Elischer struct rtentry *rt; 4438b07e49aSJulian Elischer 4448b07e49aSJulian Elischer if ((rt = ro->ro_rt) != NULL) { 4458b07e49aSJulian Elischer if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 4468b07e49aSJulian Elischer return; 4478b07e49aSJulian Elischer RTFREE(rt); 4488b07e49aSJulian Elischer ro->ro_rt = NULL; 4498b07e49aSJulian Elischer } 4508b07e49aSJulian Elischer ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, fibnum); 451d1dd20beSSam Leffler if (ro->ro_rt) 452d1dd20beSSam Leffler RT_UNLOCK(ro->ro_rt); 453652082e6SGarrett Wollman } 454652082e6SGarrett Wollman 455b0a76b88SJulian Elischer /* 456b0a76b88SJulian Elischer * Look up the route that matches the address given 457b0a76b88SJulian Elischer * Or, at least try.. Create a cloned route if needed. 458d1dd20beSSam Leffler * 459d1dd20beSSam Leffler * The returned route, if any, is locked. 460b0a76b88SJulian Elischer */ 461df8bae1dSRodney W. Grimes struct rtentry * 462d1dd20beSSam Leffler rtalloc1(struct sockaddr *dst, int report, u_long ignflags) 463df8bae1dSRodney W. Grimes { 464a8498625SBjoern A. Zeeb 465a8498625SBjoern A. Zeeb return (rtalloc1_fib(dst, report, ignflags, RT_DEFAULT_FIB)); 4668b07e49aSJulian Elischer } 4678b07e49aSJulian Elischer 4688b07e49aSJulian Elischer struct rtentry * 4698b07e49aSJulian Elischer rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, 4708b07e49aSJulian Elischer u_int fibnum) 4718b07e49aSJulian Elischer { 47220efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 47361eee0e2SAlexander V. Chernikov struct rib_head *rh; 474d1dd20beSSam Leffler struct radix_node *rn; 475d1dd20beSSam Leffler struct rtentry *newrt; 476df8bae1dSRodney W. Grimes struct rt_addrinfo info; 4776e6b3f7cSQing Li int err = 0, msgtype = RTM_MISS; 478df8bae1dSRodney W. Grimes 4798b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); 48061eee0e2SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, dst->sa_family); 481e579f1c1SDmitry Chagin newrt = NULL; 48261eee0e2SAlexander V. Chernikov if (rh == NULL) 483523e6002SDmitry Chagin goto miss; 484523e6002SDmitry Chagin 485b0a76b88SJulian Elischer /* 486b0a76b88SJulian Elischer * Look up the address in the table for that Address Family 487b0a76b88SJulian Elischer */ 488b83aa367SAndrey V. Elsukov if ((ignflags & RTF_RNH_LOCKED) == 0) 48961eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 490b83aa367SAndrey V. Elsukov #ifdef INVARIANTS 491b83aa367SAndrey V. Elsukov else 492b83aa367SAndrey V. Elsukov RIB_LOCK_ASSERT(rh); 493b83aa367SAndrey V. Elsukov #endif 49461eee0e2SAlexander V. Chernikov rn = rh->rnh_matchaddr(dst, &rh->head); 4953120b9d4SKip Macy if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { 4966a873ef7SDmitry Chagin newrt = RNTORT(rn); 4973120b9d4SKip Macy RT_LOCK(newrt); 4983120b9d4SKip Macy RT_ADDREF(newrt); 499b83aa367SAndrey V. Elsukov if ((ignflags & RTF_RNH_LOCKED) == 0) 50061eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 5010eb64f4eSAlexander V. Chernikov return (newrt); 5026e6b3f7cSQing Li 503b83aa367SAndrey V. Elsukov } else if ((ignflags & RTF_RNH_LOCKED) == 0) 50461eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 505b0a76b88SJulian Elischer /* 5068f1c8adeSLuiz Otavio O Souza * Either we hit the root or could not find any match, 5078f1c8adeSLuiz Otavio O Souza * which basically means: "cannot get there from here". 508b0a76b88SJulian Elischer */ 509956b0b65SJeffrey Hsu miss: 510185c3d2bSGleb Smirnoff RTSTAT_INC(rts_unreach); 511523e6002SDmitry Chagin 5126e6b3f7cSQing Li if (report) { 513b0a76b88SJulian Elischer /* 514b0a76b88SJulian Elischer * If required, report the failure to the supervising 515b0a76b88SJulian Elischer * Authorities. 516b0a76b88SJulian Elischer * For a delete, this is not an error. (report == 0) 517b0a76b88SJulian Elischer */ 5186f5967c0SBruce Evans bzero(&info, sizeof(info)); 519df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 520528737fdSBjoern A. Zeeb rt_missmsg_fib(msgtype, &info, 0, err, fibnum); 521df8bae1dSRodney W. Grimes } 522df8bae1dSRodney W. Grimes return (newrt); 523df8bae1dSRodney W. Grimes } 524df8bae1dSRodney W. Grimes 525499676dfSJulian Elischer /* 526499676dfSJulian Elischer * Remove a reference count from an rtentry. 527499676dfSJulian Elischer * If the count gets low enough, take it out of the routing table 528499676dfSJulian Elischer */ 529df8bae1dSRodney W. Grimes void 530d1dd20beSSam Leffler rtfree(struct rtentry *rt) 531df8bae1dSRodney W. Grimes { 53261eee0e2SAlexander V. Chernikov struct rib_head *rnh; 533df8bae1dSRodney W. Grimes 534a0c0e34bSGleb Smirnoff KASSERT(rt != NULL,("%s: NULL rt", __func__)); 535c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 536a0c0e34bSGleb Smirnoff KASSERT(rnh != NULL,("%s: NULL rnh", __func__)); 537499676dfSJulian Elischer 538d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 539d1dd20beSSam Leffler 540499676dfSJulian Elischer /* 541a0c0e34bSGleb Smirnoff * The callers should use RTFREE_LOCKED() or RTFREE(), so 542a0c0e34bSGleb Smirnoff * we should come here exactly with the last reference. 543499676dfSJulian Elischer */ 5447138d65cSSam Leffler RT_REMREF(rt); 545a0c0e34bSGleb Smirnoff if (rt->rt_refcnt > 0) { 546a42ea597SQing Li log(LOG_DEBUG, "%s: %p has %d refs\n", __func__, rt, rt->rt_refcnt); 547d1dd20beSSam Leffler goto done; 548a0c0e34bSGleb Smirnoff } 5499c63e9dbSSam Leffler 5509c63e9dbSSam Leffler /* 5519c63e9dbSSam Leffler * On last reference give the "close method" a chance 5529c63e9dbSSam Leffler * to cleanup private state. This also permits (for 5539c63e9dbSSam Leffler * IPv4 and IPv6) a chance to decide if the routing table 5549c63e9dbSSam Leffler * entry should be purged immediately or at a later time. 5559c63e9dbSSam Leffler * When an immediate purge is to happen the close routine 5569c63e9dbSSam Leffler * typically calls rtexpunge which clears the RTF_UP flag 5579c63e9dbSSam Leffler * on the entry so that the code below reclaims the storage. 5589c63e9dbSSam Leffler */ 559d1dd20beSSam Leffler if (rt->rt_refcnt == 0 && rnh->rnh_close) 56061eee0e2SAlexander V. Chernikov rnh->rnh_close((struct radix_node *)rt, &rnh->head); 561499676dfSJulian Elischer 562499676dfSJulian Elischer /* 563499676dfSJulian Elischer * If we are no longer "up" (and ref == 0) 564499676dfSJulian Elischer * then we can free the resources associated 565499676dfSJulian Elischer * with the route. 566499676dfSJulian Elischer */ 567d1dd20beSSam Leffler if ((rt->rt_flags & RTF_UP) == 0) { 568df8bae1dSRodney W. Grimes if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 569df8bae1dSRodney W. Grimes panic("rtfree 2"); 570499676dfSJulian Elischer /* 571499676dfSJulian Elischer * the rtentry must have been removed from the routing table 572499676dfSJulian Elischer * so it is represented in rttrash.. remove that now. 573499676dfSJulian Elischer */ 574603724d3SBjoern A. Zeeb V_rttrash--; 575499676dfSJulian Elischer #ifdef DIAGNOSTIC 576df8bae1dSRodney W. Grimes if (rt->rt_refcnt < 0) { 577623ae52eSPoul-Henning Kamp printf("rtfree: %p not freed (neg refs)\n", rt); 578d1dd20beSSam Leffler goto done; 579df8bae1dSRodney W. Grimes } 580499676dfSJulian Elischer #endif 581499676dfSJulian Elischer /* 582499676dfSJulian Elischer * release references on items we hold them on.. 583499676dfSJulian Elischer * e.g other routes and ifaddrs. 584499676dfSJulian Elischer */ 58519fc74fbSJeffrey Hsu if (rt->rt_ifa) 5861099f828SRobert Watson ifa_free(rt->rt_ifa); 587499676dfSJulian Elischer /* 588499676dfSJulian Elischer * The key is separatly alloc'd so free it (see rt_setgate()). 589499676dfSJulian Elischer * This also frees the gateway, as they are always malloc'd 590499676dfSJulian Elischer * together. 591499676dfSJulian Elischer */ 5928b15f615SLuiz Otavio O Souza R_Free(rt_key(rt)); 593499676dfSJulian Elischer 594a6663252SAlexander V. Chernikov /* Unreference nexthop */ 595a6663252SAlexander V. Chernikov nhop_free(rt->rt_nhop); 596a6663252SAlexander V. Chernikov 597499676dfSJulian Elischer /* 598499676dfSJulian Elischer * and the rtentry itself of course 599499676dfSJulian Elischer */ 6001ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 601d1dd20beSSam Leffler return; 602df8bae1dSRodney W. Grimes } 603d1dd20beSSam Leffler done: 604d1dd20beSSam Leffler RT_UNLOCK(rt); 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes 607df8bae1dSRodney W. Grimes /* 608dd4776f0SAlexander V. Chernikov * Temporary RTFREE() function wrapper. 609dd4776f0SAlexander V. Chernikov * Intended to use in control plane code to 610dd4776f0SAlexander V. Chernikov * avoid exposing internal layout of 'struct rtentry'. 611dd4776f0SAlexander V. Chernikov */ 612dd4776f0SAlexander V. Chernikov void 613dd4776f0SAlexander V. Chernikov rtfree_func(struct rtentry *rt) 614dd4776f0SAlexander V. Chernikov { 615dd4776f0SAlexander V. Chernikov 616dd4776f0SAlexander V. Chernikov RTFREE(rt); 617dd4776f0SAlexander V. Chernikov } 618dd4776f0SAlexander V. Chernikov 619dd4776f0SAlexander V. Chernikov /* 62034a5582cSAlexander V. Chernikov * Adds a temporal redirect entry to the routing table. 62134a5582cSAlexander V. Chernikov * @fibnum: fib number 62234a5582cSAlexander V. Chernikov * @dst: destination to install redirect to 62334a5582cSAlexander V. Chernikov * @gateway: gateway to go via 62434a5582cSAlexander V. Chernikov * @author: sockaddr of originating router, can be NULL 62534a5582cSAlexander V. Chernikov * @ifp: interface to use for the redirected route 62634a5582cSAlexander V. Chernikov * @flags: set of flags to add. Allowed: RTF_GATEWAY 62734a5582cSAlexander V. Chernikov * @lifetime_sec: time in seconds to expire this redirect. 62834a5582cSAlexander V. Chernikov * 62934a5582cSAlexander V. Chernikov * Retuns 0 on success, errno otherwise. 630df8bae1dSRodney W. Grimes */ 63134a5582cSAlexander V. Chernikov int 63234a5582cSAlexander V. Chernikov rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, 63334a5582cSAlexander V. Chernikov struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) 6348b07e49aSJulian Elischer { 635f2b2e77aSAlexander V. Chernikov struct rtentry *rt; 63634a5582cSAlexander V. Chernikov int error; 637df8bae1dSRodney W. Grimes struct rt_addrinfo info; 63834a5582cSAlexander V. Chernikov struct rt_metrics rti_rmx; 639df8bae1dSRodney W. Grimes struct ifaddr *ifa; 640c2c2a7c1SBjoern A. Zeeb 641b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 642b8a6e03fSGleb Smirnoff 64334a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 64434a5582cSAlexander V. Chernikov return (EAFNOSUPPORT); 6458e7e854cSKip Macy 64634a5582cSAlexander V. Chernikov /* Verify the allowed flag mask. */ 64734a5582cSAlexander V. Chernikov KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 64834a5582cSAlexander V. Chernikov ("invalid redirect flags: %x", flags)); 64934a5582cSAlexander V. Chernikov 65034a5582cSAlexander V. Chernikov /* Get the best ifa for the given interface and gateway. */ 65134a5582cSAlexander V. Chernikov if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 65234a5582cSAlexander V. Chernikov return (ENETUNREACH); 65334a5582cSAlexander V. Chernikov ifa_ref(ifa); 65434a5582cSAlexander V. Chernikov 65534a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 6568071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 6578071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 6588071913dSRuslan Ermilov info.rti_ifa = ifa; 65934a5582cSAlexander V. Chernikov info.rti_ifp = ifp; 660ea277332SAlexander V. Chernikov info.rti_flags = flags | RTF_HOST | RTF_DYNAMIC; 66134a5582cSAlexander V. Chernikov 66234a5582cSAlexander V. Chernikov /* Setup route metrics to define expire time. */ 66334a5582cSAlexander V. Chernikov bzero(&rti_rmx, sizeof(rti_rmx)); 66434a5582cSAlexander V. Chernikov /* Set expire time as absolute. */ 66534a5582cSAlexander V. Chernikov rti_rmx.rmx_expire = lifetime_sec + time_second; 66634a5582cSAlexander V. Chernikov info.rti_mflags |= RTV_EXPIRE; 66734a5582cSAlexander V. Chernikov info.rti_rmx = &rti_rmx; 66834a5582cSAlexander V. Chernikov 6698b07e49aSJulian Elischer error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); 67034a5582cSAlexander V. Chernikov ifa_free(ifa); 67134a5582cSAlexander V. Chernikov 67234a5582cSAlexander V. Chernikov if (error != 0) { 67334a5582cSAlexander V. Chernikov /* TODO: add per-fib redirect stats. */ 67434a5582cSAlexander V. Chernikov return (error); 67534a5582cSAlexander V. Chernikov } 67634a5582cSAlexander V. Chernikov 6774de5d90cSSam Leffler RT_LOCK(rt); 6788071913dSRuslan Ermilov flags = rt->rt_flags; 6791951e633SJohn Baldwin RTFREE_LOCKED(rt); 68034a5582cSAlexander V. Chernikov 68134a5582cSAlexander V. Chernikov RTSTAT_INC(rts_dynamic); 68234a5582cSAlexander V. Chernikov 68334a5582cSAlexander V. Chernikov /* Send notification of a route addition to userland. */ 68434a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 685df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 686df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 68734a5582cSAlexander V. Chernikov info.rti_info[RTAX_AUTHOR] = author; 688528737fdSBjoern A. Zeeb rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); 68934a5582cSAlexander V. Chernikov 69034a5582cSAlexander V. Chernikov return (0); 691df8bae1dSRodney W. Grimes } 692df8bae1dSRodney W. Grimes 693df8bae1dSRodney W. Grimes /* 694df8bae1dSRodney W. Grimes * Routing table ioctl interface. 695df8bae1dSRodney W. Grimes */ 696df8bae1dSRodney W. Grimes int 6978b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 698df8bae1dSRodney W. Grimes { 6995090559bSChristian S.J. Peron 7005090559bSChristian S.J. Peron /* 7015090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 7025090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 7035090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 7045090559bSChristian S.J. Peron * in jails. 7055090559bSChristian S.J. Peron */ 706623ae52eSPoul-Henning Kamp #ifdef INET 707f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 7088b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 709623ae52eSPoul-Henning Kamp #else /* INET */ 710623ae52eSPoul-Henning Kamp return ENXIO; 711623ae52eSPoul-Henning Kamp #endif /* INET */ 712df8bae1dSRodney W. Grimes } 713df8bae1dSRodney W. Grimes 714df8bae1dSRodney W. Grimes struct ifaddr * 715441f9243SAlexander V. Chernikov ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, 7168b07e49aSJulian Elischer u_int fibnum) 7178b07e49aSJulian Elischer { 718f59c6cb0SAlexander V. Chernikov struct ifaddr *ifa; 719e034e82cSQing Li int not_found = 0; 720d1dd20beSSam Leffler 72197168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 722df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 723df8bae1dSRodney W. Grimes /* 724df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 725df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 726df8bae1dSRodney W. Grimes * we should search for the destination 727df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 728df8bae1dSRodney W. Grimes * we can use the local address. 729df8bae1dSRodney W. Grimes */ 73085911824SLuigi Rizzo ifa = NULL; 73185911824SLuigi Rizzo if (flags & RTF_HOST) 7324f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(dst, fibnum); 73385911824SLuigi Rizzo if (ifa == NULL) 734df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 735df8bae1dSRodney W. Grimes } else { 736df8bae1dSRodney W. Grimes /* 737df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 738df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 739df8bae1dSRodney W. Grimes * other end of a pt to pt link. 740df8bae1dSRodney W. Grimes */ 7414f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(gateway, fibnum); 742df8bae1dSRodney W. Grimes } 74385911824SLuigi Rizzo if (ifa == NULL) 7444f8585e0SAlan Somers ifa = ifa_ifwithnet(gateway, 0, fibnum); 74585911824SLuigi Rizzo if (ifa == NULL) { 746b83aa367SAndrey V. Elsukov struct rtentry *rt; 747b83aa367SAndrey V. Elsukov 748b83aa367SAndrey V. Elsukov rt = rtalloc1_fib(gateway, 0, flags, fibnum); 74985911824SLuigi Rizzo if (rt == NULL) 7504f6c66ccSMatt Macy goto out; 751e034e82cSQing Li /* 752e034e82cSQing Li * dismiss a gateway that is reachable only 753e034e82cSQing Li * through the default router 754e034e82cSQing Li */ 755e034e82cSQing Li switch (gateway->sa_family) { 756e034e82cSQing Li case AF_INET: 757e034e82cSQing Li if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY) 758e034e82cSQing Li not_found = 1; 759e034e82cSQing Li break; 760e034e82cSQing Li case AF_INET6: 761e034e82cSQing Li if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr)) 762e034e82cSQing Li not_found = 1; 763e034e82cSQing Li break; 764e034e82cSQing Li default: 765e034e82cSQing Li break; 766e034e82cSQing Li } 7678c0fec80SRobert Watson if (!not_found && rt->rt_ifa != NULL) { 7688c0fec80SRobert Watson ifa = rt->rt_ifa; 7698c0fec80SRobert Watson } 7707138d65cSSam Leffler RT_REMREF(rt); 771d1dd20beSSam Leffler RT_UNLOCK(rt); 7728c0fec80SRobert Watson if (not_found || ifa == NULL) 7734f6c66ccSMatt Macy goto out; 774df8bae1dSRodney W. Grimes } 775df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 776df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 777df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 77885911824SLuigi Rizzo if (ifa == NULL) 779df8bae1dSRodney W. Grimes ifa = oifa; 780df8bae1dSRodney W. Grimes } 7814f6c66ccSMatt Macy out: 782df8bae1dSRodney W. Grimes return (ifa); 783df8bae1dSRodney W. Grimes } 784df8bae1dSRodney W. Grimes 785b0a76b88SJulian Elischer /* 786b0a76b88SJulian Elischer * Do appropriate manipulations of a routing tree given 787b0a76b88SJulian Elischer * all the bits of info needed 788b0a76b88SJulian Elischer */ 789df8bae1dSRodney W. Grimes int 7908b07e49aSJulian Elischer rtrequest_fib(int req, 7918b07e49aSJulian Elischer struct sockaddr *dst, 7928b07e49aSJulian Elischer struct sockaddr *gateway, 7938b07e49aSJulian Elischer struct sockaddr *netmask, 7948b07e49aSJulian Elischer int flags, 7958b07e49aSJulian Elischer struct rtentry **ret_nrt, 7968b07e49aSJulian Elischer u_int fibnum) 7978b07e49aSJulian Elischer { 7988071913dSRuslan Ermilov struct rt_addrinfo info; 7998071913dSRuslan Ermilov 800ac4a76ebSBjoern A. Zeeb if (dst->sa_len == 0) 801ac4a76ebSBjoern A. Zeeb return(EINVAL); 802ac4a76ebSBjoern A. Zeeb 8038071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 8048071913dSRuslan Ermilov info.rti_flags = flags; 8058071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 8068071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 8078071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 8088b07e49aSJulian Elischer return rtrequest1_fib(req, &info, ret_nrt, fibnum); 8098071913dSRuslan Ermilov } 8108071913dSRuslan Ermilov 8114bdf0b6aSAlexander V. Chernikov 8122caee4beSAlexander V. Chernikov /* 8139a1b64d5SAlexander V. Chernikov * Copy most of @rt data into @info. 8149a1b64d5SAlexander V. Chernikov * 8159a1b64d5SAlexander V. Chernikov * If @flags contains NHR_COPY, copies dst,netmask and gw to the 8169a1b64d5SAlexander V. Chernikov * pointers specified by @info structure. Assume such pointers 8179a1b64d5SAlexander V. Chernikov * are zeroed sockaddr-like structures with sa_len field initialized 8189a1b64d5SAlexander V. Chernikov * to reflect size of the provided buffer. if no NHR_COPY is specified, 8199a1b64d5SAlexander V. Chernikov * point dst,netmask and gw @info fields to appropriate @rt values. 8209a1b64d5SAlexander V. Chernikov * 8216b5d8e30SMark Johnston * if @flags contains NHR_REF, do refcouting on rt_ifp and rt_ifa. 8229a1b64d5SAlexander V. Chernikov * 8239a1b64d5SAlexander V. Chernikov * Returns 0 on success. 8249a1b64d5SAlexander V. Chernikov */ 8259a1b64d5SAlexander V. Chernikov int 8269a1b64d5SAlexander V. Chernikov rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags) 8279a1b64d5SAlexander V. Chernikov { 8289a1b64d5SAlexander V. Chernikov struct rt_metrics *rmx; 8299a1b64d5SAlexander V. Chernikov struct sockaddr *src, *dst; 8309a1b64d5SAlexander V. Chernikov int sa_len; 8319a1b64d5SAlexander V. Chernikov 8329a1b64d5SAlexander V. Chernikov if (flags & NHR_COPY) { 8339a1b64d5SAlexander V. Chernikov /* Copy destination if dst is non-zero */ 8349a1b64d5SAlexander V. Chernikov src = rt_key(rt); 8359a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 8369a1b64d5SAlexander V. Chernikov sa_len = src->sa_len; 83716703ea8SAlexander V. Chernikov if (dst != NULL) { 8389a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 8399a1b64d5SAlexander V. Chernikov return (ENOMEM); 8409a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 8419a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 8429a1b64d5SAlexander V. Chernikov } 8439a1b64d5SAlexander V. Chernikov 8449a1b64d5SAlexander V. Chernikov /* Copy mask if set && dst is non-zero */ 8459a1b64d5SAlexander V. Chernikov src = rt_mask(rt); 8469a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_NETMASK]; 8479a1b64d5SAlexander V. Chernikov if (src != NULL && dst != NULL) { 8489a1b64d5SAlexander V. Chernikov 8499a1b64d5SAlexander V. Chernikov /* 8509a1b64d5SAlexander V. Chernikov * Radix stores different value in sa_len, 8519a1b64d5SAlexander V. Chernikov * assume rt_mask() to have the same length 8529a1b64d5SAlexander V. Chernikov * as rt_key() 8539a1b64d5SAlexander V. Chernikov */ 8549a1b64d5SAlexander V. Chernikov if (sa_len > dst->sa_len) 8559a1b64d5SAlexander V. Chernikov return (ENOMEM); 8569a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 8579a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 8589a1b64d5SAlexander V. Chernikov } 8599a1b64d5SAlexander V. Chernikov 8609a1b64d5SAlexander V. Chernikov /* Copy gateway is set && dst is non-zero */ 8619a1b64d5SAlexander V. Chernikov src = rt->rt_gateway; 8629a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_GATEWAY]; 8639a1b64d5SAlexander V. Chernikov if ((rt->rt_flags & RTF_GATEWAY) && src != NULL && dst != NULL){ 8649a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 8659a1b64d5SAlexander V. Chernikov return (ENOMEM); 8669a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 8679a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 8689a1b64d5SAlexander V. Chernikov } 8699a1b64d5SAlexander V. Chernikov } else { 8709a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 8719a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 8729a1b64d5SAlexander V. Chernikov if (rt_mask(rt) != NULL) { 8739a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 8749a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 8759a1b64d5SAlexander V. Chernikov } 8769a1b64d5SAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 8779a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = rt->rt_gateway; 8789a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 8799a1b64d5SAlexander V. Chernikov } 8809a1b64d5SAlexander V. Chernikov } 8819a1b64d5SAlexander V. Chernikov 8829a1b64d5SAlexander V. Chernikov rmx = info->rti_rmx; 8839a1b64d5SAlexander V. Chernikov if (rmx != NULL) { 8849a1b64d5SAlexander V. Chernikov info->rti_mflags |= RTV_MTU; 8859a1b64d5SAlexander V. Chernikov rmx->rmx_mtu = rt->rt_mtu; 8869a1b64d5SAlexander V. Chernikov } 8879a1b64d5SAlexander V. Chernikov 8889a1b64d5SAlexander V. Chernikov info->rti_flags = rt->rt_flags; 8899a1b64d5SAlexander V. Chernikov info->rti_ifp = rt->rt_ifp; 8909a1b64d5SAlexander V. Chernikov info->rti_ifa = rt->rt_ifa; 8919a1b64d5SAlexander V. Chernikov if (flags & NHR_REF) { 8929a1b64d5SAlexander V. Chernikov if_ref(info->rti_ifp); 8936b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 8949a1b64d5SAlexander V. Chernikov } 8959a1b64d5SAlexander V. Chernikov 8969a1b64d5SAlexander V. Chernikov return (0); 8979a1b64d5SAlexander V. Chernikov } 8989a1b64d5SAlexander V. Chernikov 8999a1b64d5SAlexander V. Chernikov /* 9009a1b64d5SAlexander V. Chernikov * Lookups up route entry for @dst in RIB database for fib @fibnum. 9019a1b64d5SAlexander V. Chernikov * Exports entry data to @info using rt_exportinfo(). 9029a1b64d5SAlexander V. Chernikov * 9036b5d8e30SMark Johnston * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa. 9046b5d8e30SMark Johnston * All references can be released later by calling rib_free_info(). 9059a1b64d5SAlexander V. Chernikov * 9069a1b64d5SAlexander V. Chernikov * Returns 0 on success. 9079a1b64d5SAlexander V. Chernikov * Returns ENOENT for lookup failure, ENOMEM for export failure. 9089a1b64d5SAlexander V. Chernikov */ 9099a1b64d5SAlexander V. Chernikov int 9109a1b64d5SAlexander V. Chernikov rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, 9119a1b64d5SAlexander V. Chernikov uint32_t flowid, struct rt_addrinfo *info) 9129a1b64d5SAlexander V. Chernikov { 91320efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 91461eee0e2SAlexander V. Chernikov struct rib_head *rh; 9159a1b64d5SAlexander V. Chernikov struct radix_node *rn; 9169a1b64d5SAlexander V. Chernikov struct rtentry *rt; 9179a1b64d5SAlexander V. Chernikov int error; 9189a1b64d5SAlexander V. Chernikov 9199a1b64d5SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum")); 9209a1b64d5SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, dst->sa_family); 9219a1b64d5SAlexander V. Chernikov if (rh == NULL) 9229a1b64d5SAlexander V. Chernikov return (ENOENT); 9239a1b64d5SAlexander V. Chernikov 92461eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 92561eee0e2SAlexander V. Chernikov rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head); 9269a1b64d5SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 9279a1b64d5SAlexander V. Chernikov rt = RNTORT(rn); 9289a1b64d5SAlexander V. Chernikov /* Ensure route & ifp is UP */ 9299a1b64d5SAlexander V. Chernikov if (RT_LINK_IS_UP(rt->rt_ifp)) { 9309a1b64d5SAlexander V. Chernikov flags = (flags & NHR_REF) | NHR_COPY; 9319a1b64d5SAlexander V. Chernikov error = rt_exportinfo(rt, info, flags); 93261eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 9339a1b64d5SAlexander V. Chernikov 9349a1b64d5SAlexander V. Chernikov return (error); 9359a1b64d5SAlexander V. Chernikov } 9369a1b64d5SAlexander V. Chernikov } 93761eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 9389a1b64d5SAlexander V. Chernikov 9399a1b64d5SAlexander V. Chernikov return (ENOENT); 9409a1b64d5SAlexander V. Chernikov } 9419a1b64d5SAlexander V. Chernikov 9429a1b64d5SAlexander V. Chernikov /* 9439a1b64d5SAlexander V. Chernikov * Releases all references acquired by rib_lookup_info() when 9449a1b64d5SAlexander V. Chernikov * called with NHR_REF flags. 9459a1b64d5SAlexander V. Chernikov */ 9469a1b64d5SAlexander V. Chernikov void 9479a1b64d5SAlexander V. Chernikov rib_free_info(struct rt_addrinfo *info) 9489a1b64d5SAlexander V. Chernikov { 9499a1b64d5SAlexander V. Chernikov 9506b5d8e30SMark Johnston ifa_free(info->rti_ifa); 9519a1b64d5SAlexander V. Chernikov if_rele(info->rti_ifp); 9529a1b64d5SAlexander V. Chernikov } 9539a1b64d5SAlexander V. Chernikov 9549a1b64d5SAlexander V. Chernikov /* 9552caee4beSAlexander V. Chernikov * Iterates over all existing fibs in system calling 9562caee4beSAlexander V. Chernikov * @setwa_f function prior to traversing each fib. 9572caee4beSAlexander V. Chernikov * Calls @wa_f function for each element in current fib. 9582caee4beSAlexander V. Chernikov * If af is not AF_UNSPEC, iterates over fibs in particular 9592caee4beSAlexander V. Chernikov * address family. 9602caee4beSAlexander V. Chernikov */ 9614bdf0b6aSAlexander V. Chernikov void 9622caee4beSAlexander V. Chernikov rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, 9632caee4beSAlexander V. Chernikov void *arg) 9644bdf0b6aSAlexander V. Chernikov { 96561eee0e2SAlexander V. Chernikov struct rib_head *rnh; 9664bdf0b6aSAlexander V. Chernikov uint32_t fibnum; 9674bdf0b6aSAlexander V. Chernikov int i; 9684bdf0b6aSAlexander V. Chernikov 9694bdf0b6aSAlexander V. Chernikov for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 9704bdf0b6aSAlexander V. Chernikov /* Do we want some specific family? */ 9714bdf0b6aSAlexander V. Chernikov if (af != AF_UNSPEC) { 9724bdf0b6aSAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, af); 9734bdf0b6aSAlexander V. Chernikov if (rnh == NULL) 9744bdf0b6aSAlexander V. Chernikov continue; 9754bdf0b6aSAlexander V. Chernikov if (setwa_f != NULL) 976e4790abfSAlexander V. Chernikov setwa_f(rnh, fibnum, af, arg); 9774bdf0b6aSAlexander V. Chernikov 97861eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 97961eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); 98061eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 9814bdf0b6aSAlexander V. Chernikov continue; 9824bdf0b6aSAlexander V. Chernikov } 9834bdf0b6aSAlexander V. Chernikov 9844bdf0b6aSAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 9854bdf0b6aSAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, i); 9864bdf0b6aSAlexander V. Chernikov if (rnh == NULL) 9874bdf0b6aSAlexander V. Chernikov continue; 9884bdf0b6aSAlexander V. Chernikov if (setwa_f != NULL) 9894bdf0b6aSAlexander V. Chernikov setwa_f(rnh, fibnum, i, arg); 9904bdf0b6aSAlexander V. Chernikov 99161eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 99261eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); 99361eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 9944bdf0b6aSAlexander V. Chernikov } 9954bdf0b6aSAlexander V. Chernikov } 9964bdf0b6aSAlexander V. Chernikov } 9974bdf0b6aSAlexander V. Chernikov 998e8b0643eSAlexander V. Chernikov struct rt_delinfo 999e8b0643eSAlexander V. Chernikov { 1000e8b0643eSAlexander V. Chernikov struct rt_addrinfo info; 100161eee0e2SAlexander V. Chernikov struct rib_head *rnh; 1002e8b0643eSAlexander V. Chernikov struct rtentry *head; 1003e8b0643eSAlexander V. Chernikov }; 1004e8b0643eSAlexander V. Chernikov 1005e8b0643eSAlexander V. Chernikov /* 1006e8b0643eSAlexander V. Chernikov * Conditionally unlinks @rn from radix tree based 1007e8b0643eSAlexander V. Chernikov * on info data passed in @arg. 1008e8b0643eSAlexander V. Chernikov */ 1009e8b0643eSAlexander V. Chernikov static int 1010e8b0643eSAlexander V. Chernikov rt_checkdelroute(struct radix_node *rn, void *arg) 1011e8b0643eSAlexander V. Chernikov { 1012e8b0643eSAlexander V. Chernikov struct rt_delinfo *di; 1013e8b0643eSAlexander V. Chernikov struct rt_addrinfo *info; 1014e8b0643eSAlexander V. Chernikov struct rtentry *rt; 1015e8b0643eSAlexander V. Chernikov int error; 1016e8b0643eSAlexander V. Chernikov 1017e8b0643eSAlexander V. Chernikov di = (struct rt_delinfo *)arg; 1018e8b0643eSAlexander V. Chernikov rt = (struct rtentry *)rn; 1019e8b0643eSAlexander V. Chernikov info = &di->info; 1020e8b0643eSAlexander V. Chernikov error = 0; 1021e8b0643eSAlexander V. Chernikov 1022e8b0643eSAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 1023e8b0643eSAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 1024e8b0643eSAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1025e8b0643eSAlexander V. Chernikov 1026e8b0643eSAlexander V. Chernikov rt = rt_unlinkrte(di->rnh, info, &error); 1027e8b0643eSAlexander V. Chernikov if (rt == NULL) { 1028e8b0643eSAlexander V. Chernikov /* Either not allowed or not matched. Skip entry */ 1029e8b0643eSAlexander V. Chernikov return (0); 1030e8b0643eSAlexander V. Chernikov } 1031e8b0643eSAlexander V. Chernikov 1032e8b0643eSAlexander V. Chernikov /* Entry was unlinked. Add to the list and return */ 1033e8b0643eSAlexander V. Chernikov rt->rt_chain = di->head; 1034e8b0643eSAlexander V. Chernikov di->head = rt; 1035e8b0643eSAlexander V. Chernikov 1036e8b0643eSAlexander V. Chernikov return (0); 1037e8b0643eSAlexander V. Chernikov } 1038e8b0643eSAlexander V. Chernikov 1039e8b0643eSAlexander V. Chernikov /* 104034a5582cSAlexander V. Chernikov * Iterates over a routing table specified by @fibnum and @family and 104134a5582cSAlexander V. Chernikov * deletes elements marked by @filter_f. 104234a5582cSAlexander V. Chernikov * @fibnum: rtable id 104334a5582cSAlexander V. Chernikov * @family: AF_ address family 104434a5582cSAlexander V. Chernikov * @filter_f: function returning non-zero value for items to delete 104534a5582cSAlexander V. Chernikov * @arg: data to pass to the @filter_f function 104634a5582cSAlexander V. Chernikov * @report: true if rtsock notification is needed. 1047e8b0643eSAlexander V. Chernikov */ 1048e8b0643eSAlexander V. Chernikov void 104934a5582cSAlexander V. Chernikov rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, void *arg, bool report) 1050e8b0643eSAlexander V. Chernikov { 105161eee0e2SAlexander V. Chernikov struct rib_head *rnh; 1052e8b0643eSAlexander V. Chernikov struct rt_delinfo di; 1053e8b0643eSAlexander V. Chernikov struct rtentry *rt; 105434a5582cSAlexander V. Chernikov 105534a5582cSAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, family); 105634a5582cSAlexander V. Chernikov if (rnh == NULL) 105734a5582cSAlexander V. Chernikov return; 1058e8b0643eSAlexander V. Chernikov 1059e8b0643eSAlexander V. Chernikov bzero(&di, sizeof(di)); 1060e8b0643eSAlexander V. Chernikov di.info.rti_filter = filter_f; 1061e8b0643eSAlexander V. Chernikov di.info.rti_filterdata = arg; 1062e8b0643eSAlexander V. Chernikov di.rnh = rnh; 1063e8b0643eSAlexander V. Chernikov 106461eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 106561eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); 106661eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 1067e8b0643eSAlexander V. Chernikov 1068e8b0643eSAlexander V. Chernikov if (di.head == NULL) 106934a5582cSAlexander V. Chernikov return; 1070e8b0643eSAlexander V. Chernikov 107134a5582cSAlexander V. Chernikov /* We might have something to reclaim. */ 1072e8b0643eSAlexander V. Chernikov while (di.head != NULL) { 1073e8b0643eSAlexander V. Chernikov rt = di.head; 1074e8b0643eSAlexander V. Chernikov di.head = rt->rt_chain; 1075e8b0643eSAlexander V. Chernikov rt->rt_chain = NULL; 1076e8b0643eSAlexander V. Chernikov 1077e8b0643eSAlexander V. Chernikov /* TODO std rt -> rt_addrinfo export */ 1078e8b0643eSAlexander V. Chernikov di.info.rti_info[RTAX_DST] = rt_key(rt); 1079e8b0643eSAlexander V. Chernikov di.info.rti_info[RTAX_NETMASK] = rt_mask(rt); 1080e8b0643eSAlexander V. Chernikov 1081e8b0643eSAlexander V. Chernikov rt_notifydelete(rt, &di.info); 108234a5582cSAlexander V. Chernikov 108334a5582cSAlexander V. Chernikov if (report) 108434a5582cSAlexander V. Chernikov rt_routemsg(RTM_DELETE, rt, rt->rt_ifp, 0, fibnum); 1085e8b0643eSAlexander V. Chernikov RTFREE_LOCKED(rt); 1086e8b0643eSAlexander V. Chernikov } 108734a5582cSAlexander V. Chernikov } 1088e8b0643eSAlexander V. Chernikov 108934a5582cSAlexander V. Chernikov /* 109034a5582cSAlexander V. Chernikov * Iterates over all existing fibs in system and deletes each element 109134a5582cSAlexander V. Chernikov * for which @filter_f function returns non-zero value. 109234a5582cSAlexander V. Chernikov * If @family is not AF_UNSPEC, iterates over fibs in particular 109334a5582cSAlexander V. Chernikov * address family. 109434a5582cSAlexander V. Chernikov */ 109534a5582cSAlexander V. Chernikov void 109634a5582cSAlexander V. Chernikov rt_foreach_fib_walk_del(int family, rt_filter_f_t *filter_f, void *arg) 109734a5582cSAlexander V. Chernikov { 109834a5582cSAlexander V. Chernikov u_int fibnum; 109934a5582cSAlexander V. Chernikov int i, start, end; 110034a5582cSAlexander V. Chernikov 110134a5582cSAlexander V. Chernikov for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 110234a5582cSAlexander V. Chernikov /* Do we want some specific family? */ 110334a5582cSAlexander V. Chernikov if (family != AF_UNSPEC) { 110434a5582cSAlexander V. Chernikov start = family; 110534a5582cSAlexander V. Chernikov end = family; 110634a5582cSAlexander V. Chernikov } else { 110734a5582cSAlexander V. Chernikov start = 1; 110834a5582cSAlexander V. Chernikov end = AF_MAX; 110934a5582cSAlexander V. Chernikov } 111034a5582cSAlexander V. Chernikov 111134a5582cSAlexander V. Chernikov for (i = start; i <= end; i++) { 111234a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, i) == NULL) 111334a5582cSAlexander V. Chernikov continue; 111434a5582cSAlexander V. Chernikov 111534a5582cSAlexander V. Chernikov rib_walk_del(fibnum, i, filter_f, arg, 0); 1116e8b0643eSAlexander V. Chernikov } 1117e8b0643eSAlexander V. Chernikov } 1118e8b0643eSAlexander V. Chernikov } 1119e8b0643eSAlexander V. Chernikov 11204bdf0b6aSAlexander V. Chernikov /* 11214bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 11224bdf0b6aSAlexander V. Chernikov * 11234bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 11244bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 11254bdf0b6aSAlexander V. Chernikov * 11264bdf0b6aSAlexander V. Chernikov * Arguments: 11274bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 1128*539642a2SAlexander V. Chernikov * nh pointer to nhop 11294bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 11304bdf0b6aSAlexander V. Chernikov * 11314bdf0b6aSAlexander V. Chernikov * Returns: 11324bdf0b6aSAlexander V. Chernikov * 0 successful 11334bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 11344bdf0b6aSAlexander V. Chernikov */ 11354bdf0b6aSAlexander V. Chernikov static int 1136*539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 11374bdf0b6aSAlexander V. Chernikov { 11384bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 11394bdf0b6aSAlexander V. Chernikov 1140*539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 11414bdf0b6aSAlexander V. Chernikov return (0); 11424bdf0b6aSAlexander V. Chernikov 11434bdf0b6aSAlexander V. Chernikov /* 11444bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 11454bdf0b6aSAlexander V. Chernikov * with cloned routes 11464bdf0b6aSAlexander V. Chernikov */ 11474bdf0b6aSAlexander V. Chernikov if ((rt->rt_flags & RTF_UP) == 0) 11484bdf0b6aSAlexander V. Chernikov return (0); 11494bdf0b6aSAlexander V. Chernikov 1150e8b0643eSAlexander V. Chernikov return (1); 11514bdf0b6aSAlexander V. Chernikov } 11524bdf0b6aSAlexander V. Chernikov 11534bdf0b6aSAlexander V. Chernikov /* 11544bdf0b6aSAlexander V. Chernikov * Delete all remaining routes using this interface 11554bdf0b6aSAlexander V. Chernikov * Unfortuneatly the only way to do this is to slog through 11564bdf0b6aSAlexander V. Chernikov * the entire routing table looking for routes which point 11574bdf0b6aSAlexander V. Chernikov * to this interface...oh well... 11584bdf0b6aSAlexander V. Chernikov */ 11594bdf0b6aSAlexander V. Chernikov void 116080ae8d60SBjoern A. Zeeb rt_flushifroutes_af(struct ifnet *ifp, int af) 116180ae8d60SBjoern A. Zeeb { 116280ae8d60SBjoern A. Zeeb KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d", 116380ae8d60SBjoern A. Zeeb __func__, af, AF_MAX)); 116480ae8d60SBjoern A. Zeeb 116580ae8d60SBjoern A. Zeeb rt_foreach_fib_walk_del(af, rt_ifdelroute, ifp); 116680ae8d60SBjoern A. Zeeb } 116780ae8d60SBjoern A. Zeeb 116880ae8d60SBjoern A. Zeeb void 11694bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 11704bdf0b6aSAlexander V. Chernikov { 11714bdf0b6aSAlexander V. Chernikov 1172e8b0643eSAlexander V. Chernikov rt_foreach_fib_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 11734bdf0b6aSAlexander V. Chernikov } 11744bdf0b6aSAlexander V. Chernikov 11758071913dSRuslan Ermilov /* 1176e8b0643eSAlexander V. Chernikov * Conditionally unlinks rtentry matching data inside @info from @rnh. 1177e8b0643eSAlexander V. Chernikov * Returns unlinked, locked and referenced @rtentry on success, 1178e8b0643eSAlexander V. Chernikov * Returns NULL and sets @perror to: 1179e8b0643eSAlexander V. Chernikov * ESRCH - if prefix was not found, 1180e8b0643eSAlexander V. Chernikov * EADDRINUSE - if trying to delete PINNED route without appropriate flag. 1181e8b0643eSAlexander V. Chernikov * ENOENT - if supplied filter function returned 0 (not matched). 1182e8b0643eSAlexander V. Chernikov */ 1183e8b0643eSAlexander V. Chernikov static struct rtentry * 118461eee0e2SAlexander V. Chernikov rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, int *perror) 1185e8b0643eSAlexander V. Chernikov { 1186e8b0643eSAlexander V. Chernikov struct sockaddr *dst, *netmask; 1187e8b0643eSAlexander V. Chernikov struct rtentry *rt; 1188e8b0643eSAlexander V. Chernikov struct radix_node *rn; 1189e8b0643eSAlexander V. Chernikov 1190e8b0643eSAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 1191e8b0643eSAlexander V. Chernikov netmask = info->rti_info[RTAX_NETMASK]; 1192e8b0643eSAlexander V. Chernikov 119361eee0e2SAlexander V. Chernikov rt = (struct rtentry *)rnh->rnh_lookup(dst, netmask, &rnh->head); 1194e8b0643eSAlexander V. Chernikov if (rt == NULL) { 1195e8b0643eSAlexander V. Chernikov *perror = ESRCH; 1196e8b0643eSAlexander V. Chernikov return (NULL); 1197e8b0643eSAlexander V. Chernikov } 1198e8b0643eSAlexander V. Chernikov 1199e8b0643eSAlexander V. Chernikov if ((info->rti_flags & RTF_PINNED) == 0) { 1200e8b0643eSAlexander V. Chernikov /* Check if target route can be deleted */ 1201e8b0643eSAlexander V. Chernikov if (rt->rt_flags & RTF_PINNED) { 1202e8b0643eSAlexander V. Chernikov *perror = EADDRINUSE; 1203e8b0643eSAlexander V. Chernikov return (NULL); 1204e8b0643eSAlexander V. Chernikov } 1205e8b0643eSAlexander V. Chernikov } 1206e8b0643eSAlexander V. Chernikov 1207e8b0643eSAlexander V. Chernikov if (info->rti_filter != NULL) { 1208*539642a2SAlexander V. Chernikov if (info->rti_filter(rt, rt->rt_nhop, info->rti_filterdata)==0){ 1209e8b0643eSAlexander V. Chernikov /* Not matched */ 1210e8b0643eSAlexander V. Chernikov *perror = ENOENT; 1211e8b0643eSAlexander V. Chernikov return (NULL); 1212e8b0643eSAlexander V. Chernikov } 1213e8b0643eSAlexander V. Chernikov 1214e8b0643eSAlexander V. Chernikov /* 1215e8b0643eSAlexander V. Chernikov * Filter function requested rte deletion. 1216e8b0643eSAlexander V. Chernikov * Ease the caller work by filling in remaining info 1217e8b0643eSAlexander V. Chernikov * from that particular entry. 1218e8b0643eSAlexander V. Chernikov */ 1219e8b0643eSAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = rt->rt_gateway; 1220e8b0643eSAlexander V. Chernikov } 1221e8b0643eSAlexander V. Chernikov 1222e8b0643eSAlexander V. Chernikov /* 1223e8b0643eSAlexander V. Chernikov * Remove the item from the tree and return it. 1224e8b0643eSAlexander V. Chernikov * Complain if it is not there and do no more processing. 1225e8b0643eSAlexander V. Chernikov */ 1226e8b0643eSAlexander V. Chernikov *perror = ESRCH; 1227e8b0643eSAlexander V. Chernikov #ifdef RADIX_MPATH 122861eee0e2SAlexander V. Chernikov if (rt_mpath_capable(rnh)) 1229e8b0643eSAlexander V. Chernikov rn = rt_mpath_unlink(rnh, info, rt, perror); 1230e8b0643eSAlexander V. Chernikov else 1231e8b0643eSAlexander V. Chernikov #endif 123261eee0e2SAlexander V. Chernikov rn = rnh->rnh_deladdr(dst, netmask, &rnh->head); 1233e8b0643eSAlexander V. Chernikov if (rn == NULL) 1234e8b0643eSAlexander V. Chernikov return (NULL); 1235e8b0643eSAlexander V. Chernikov 1236e8b0643eSAlexander V. Chernikov if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 1237e8b0643eSAlexander V. Chernikov panic ("rtrequest delete"); 1238e8b0643eSAlexander V. Chernikov 1239e8b0643eSAlexander V. Chernikov rt = RNTORT(rn); 1240e8b0643eSAlexander V. Chernikov RT_LOCK(rt); 1241e8b0643eSAlexander V. Chernikov RT_ADDREF(rt); 12424b3dc898SAlexander V. Chernikov rt->rt_flags &= ~RTF_UP; 1243e8b0643eSAlexander V. Chernikov 1244e8b0643eSAlexander V. Chernikov *perror = 0; 1245e8b0643eSAlexander V. Chernikov 1246e8b0643eSAlexander V. Chernikov return (rt); 1247e8b0643eSAlexander V. Chernikov } 1248e8b0643eSAlexander V. Chernikov 1249e8b0643eSAlexander V. Chernikov static void 1250e8b0643eSAlexander V. Chernikov rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info) 1251e8b0643eSAlexander V. Chernikov { 1252e8b0643eSAlexander V. Chernikov struct ifaddr *ifa; 1253e8b0643eSAlexander V. Chernikov 1254e8b0643eSAlexander V. Chernikov /* 1255e8b0643eSAlexander V. Chernikov * give the protocol a chance to keep things in sync. 1256e8b0643eSAlexander V. Chernikov */ 1257e8b0643eSAlexander V. Chernikov ifa = rt->rt_ifa; 1258e8b0643eSAlexander V. Chernikov if (ifa != NULL && ifa->ifa_rtrequest != NULL) 1259e8b0643eSAlexander V. Chernikov ifa->ifa_rtrequest(RTM_DELETE, rt, info); 1260e8b0643eSAlexander V. Chernikov 1261e8b0643eSAlexander V. Chernikov /* 1262e8b0643eSAlexander V. Chernikov * One more rtentry floating around that is not 1263e8b0643eSAlexander V. Chernikov * linked to the routing table. rttrash will be decremented 1264e8b0643eSAlexander V. Chernikov * when RTFREE(rt) is eventually called. 1265e8b0643eSAlexander V. Chernikov */ 1266e8b0643eSAlexander V. Chernikov V_rttrash++; 1267e8b0643eSAlexander V. Chernikov } 1268e8b0643eSAlexander V. Chernikov 1269e8b0643eSAlexander V. Chernikov 1270e8b0643eSAlexander V. Chernikov /* 12718071913dSRuslan Ermilov * These (questionable) definitions of apparent local variables apply 12728071913dSRuslan Ermilov * to the next two functions. XXXXXX!!! 12738071913dSRuslan Ermilov */ 12748071913dSRuslan Ermilov #define dst info->rti_info[RTAX_DST] 12758071913dSRuslan Ermilov #define gateway info->rti_info[RTAX_GATEWAY] 12768071913dSRuslan Ermilov #define netmask info->rti_info[RTAX_NETMASK] 12778071913dSRuslan Ermilov #define ifaaddr info->rti_info[RTAX_IFA] 12788071913dSRuslan Ermilov #define ifpaddr info->rti_info[RTAX_IFP] 12798071913dSRuslan Ermilov #define flags info->rti_flags 12808071913dSRuslan Ermilov 12818c0fec80SRobert Watson /* 12828c0fec80SRobert Watson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 12838c0fec80SRobert Watson * it will be referenced so the caller must free it. 12842ad7ed6eSAlexander V. Chernikov * 12852ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 12862ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 12878c0fec80SRobert Watson */ 12888b07e49aSJulian Elischer int 12898b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 12908b07e49aSJulian Elischer { 1291a68cc388SGleb Smirnoff struct epoch_tracker et; 12921ebec5faSMatt Macy int needref, error; 12938071913dSRuslan Ermilov 12948071913dSRuslan Ermilov /* 12958071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 12968071913dSRuslan Ermilov * when protocol address is ambiguous. 12978071913dSRuslan Ermilov */ 12981ebec5faSMatt Macy error = 0; 12991ebec5faSMatt Macy needref = (info->rti_ifa == NULL); 1300a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 13012ad7ed6eSAlexander V. Chernikov 13022ad7ed6eSAlexander V. Chernikov /* If we have interface specified by the ifindex in the address, use it */ 13038071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 13042ad7ed6eSAlexander V. Chernikov ifpaddr->sa_family == AF_LINK) { 13052ad7ed6eSAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; 13062ad7ed6eSAlexander V. Chernikov if (sdl->sdl_index != 0) 1307270b83b9SHans Petter Selasky info->rti_ifp = ifnet_byindex(sdl->sdl_index); 13088c0fec80SRobert Watson } 13092ad7ed6eSAlexander V. Chernikov /* 13102ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 13112ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 13122ad7ed6eSAlexander V. Chernikov */ 13138071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 13148071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 13158071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 13168071913dSRuslan Ermilov struct sockaddr *sa; 13178071913dSRuslan Ermilov 13182ad7ed6eSAlexander V. Chernikov /* 13192ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 13202ad7ed6eSAlexander V. Chernikov * 13212ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 13222ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 13232ad7ed6eSAlexander V. Chernikov * Order of preference: 13242ad7ed6eSAlexander V. Chernikov * 1) IFA address 13252ad7ed6eSAlexander V. Chernikov * 2) gateway address 13262ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 13272ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 13282ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 13292ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 13302ad7ed6eSAlexander V. Chernikov * ignore gateway 13312ad7ed6eSAlexander V. Chernikov * 3) final destination. 13322ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 13332ad7ed6eSAlexander V. Chernikov * -- else -- 13342ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 13352ad7ed6eSAlexander V. Chernikov */ 13362ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 13372ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 13382ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 13392ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 13402ad7ed6eSAlexander V. Chernikov sa = gateway; 13412ad7ed6eSAlexander V. Chernikov else 13422ad7ed6eSAlexander V. Chernikov sa = dst; 13432ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 13448071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 13452ad7ed6eSAlexander V. Chernikov /* Case 4 */ 13462ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 13472ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 13482ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 13494f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 13508b07e49aSJulian Elischer fibnum); 13518071913dSRuslan Ermilov else if (sa != NULL) 13524f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 13538b07e49aSJulian Elischer fibnum); 13548071913dSRuslan Ermilov } 13551ebec5faSMatt Macy if (needref && info->rti_ifa != NULL) { 13568071913dSRuslan Ermilov if (info->rti_ifp == NULL) 1357134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 13584f6c66ccSMatt Macy ifa_ref(info->rti_ifa); 13598071913dSRuslan Ermilov } else 13608071913dSRuslan Ermilov error = ENETUNREACH; 1361a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 13628071913dSRuslan Ermilov return (error); 13638071913dSRuslan Ermilov } 13648071913dSRuslan Ermilov 13657f948f12SAlexander V. Chernikov static int 13667f948f12SAlexander V. Chernikov if_updatemtu_cb(struct radix_node *rn, void *arg) 13677f948f12SAlexander V. Chernikov { 13687f948f12SAlexander V. Chernikov struct rtentry *rt; 13697f948f12SAlexander V. Chernikov struct if_mtuinfo *ifmtu; 13707f948f12SAlexander V. Chernikov 13717f948f12SAlexander V. Chernikov rt = (struct rtentry *)rn; 13727f948f12SAlexander V. Chernikov ifmtu = (struct if_mtuinfo *)arg; 13737f948f12SAlexander V. Chernikov 13747f948f12SAlexander V. Chernikov if (rt->rt_ifp != ifmtu->ifp) 13757f948f12SAlexander V. Chernikov return (0); 13767f948f12SAlexander V. Chernikov 13777f948f12SAlexander V. Chernikov if (rt->rt_mtu >= ifmtu->mtu) { 13787f948f12SAlexander V. Chernikov /* We have to decrease mtu regardless of flags */ 13797f948f12SAlexander V. Chernikov rt->rt_mtu = ifmtu->mtu; 13807f948f12SAlexander V. Chernikov return (0); 13817f948f12SAlexander V. Chernikov } 13827f948f12SAlexander V. Chernikov 13837f948f12SAlexander V. Chernikov /* 13847f948f12SAlexander V. Chernikov * New MTU is bigger. Check if are allowed to alter it 13857f948f12SAlexander V. Chernikov */ 13867f948f12SAlexander V. Chernikov if ((rt->rt_flags & (RTF_FIXEDMTU | RTF_GATEWAY | RTF_HOST)) != 0) { 13877f948f12SAlexander V. Chernikov 13887f948f12SAlexander V. Chernikov /* 13897f948f12SAlexander V. Chernikov * Skip routes with user-supplied MTU and 13907f948f12SAlexander V. Chernikov * non-interface routes 13917f948f12SAlexander V. Chernikov */ 13927f948f12SAlexander V. Chernikov return (0); 13937f948f12SAlexander V. Chernikov } 13947f948f12SAlexander V. Chernikov 13957f948f12SAlexander V. Chernikov /* We are safe to update route MTU */ 13967f948f12SAlexander V. Chernikov rt->rt_mtu = ifmtu->mtu; 13977f948f12SAlexander V. Chernikov 13987f948f12SAlexander V. Chernikov return (0); 13997f948f12SAlexander V. Chernikov } 14007f948f12SAlexander V. Chernikov 14017f948f12SAlexander V. Chernikov void 14027f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 14037f948f12SAlexander V. Chernikov { 14047f948f12SAlexander V. Chernikov struct if_mtuinfo ifmtu; 140561eee0e2SAlexander V. Chernikov struct rib_head *rnh; 14067f948f12SAlexander V. Chernikov int i, j; 14077f948f12SAlexander V. Chernikov 14087f948f12SAlexander V. Chernikov ifmtu.ifp = ifp; 14097f948f12SAlexander V. Chernikov 14107f948f12SAlexander V. Chernikov /* 14117f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 14127f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 14137f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 14147f948f12SAlexander V. Chernikov */ 14157f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 14167f948f12SAlexander V. Chernikov ifmtu.mtu = if_getmtu_family(ifp, i); 14177f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 14187f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 14197f948f12SAlexander V. Chernikov if (rnh == NULL) 14207f948f12SAlexander V. Chernikov continue; 142161eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 142261eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, if_updatemtu_cb, &ifmtu); 142361eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 1424a6663252SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, ifmtu.mtu); 14257f948f12SAlexander V. Chernikov } 14267f948f12SAlexander V. Chernikov } 14277f948f12SAlexander V. Chernikov } 14287f948f12SAlexander V. Chernikov 14297f948f12SAlexander V. Chernikov 14305a2f4cbdSAlexander V. Chernikov #if 0 14315a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 14325a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 14335a2f4cbdSAlexander V. Chernikov 14345a2f4cbdSAlexander V. Chernikov int 14355a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 14365a2f4cbdSAlexander V. Chernikov { 14375a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 14385a2f4cbdSAlexander V. Chernikov 14395a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 14405a2f4cbdSAlexander V. Chernikov case AF_INET: 14415a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 14425a2f4cbdSAlexander V. Chernikov break; 14435a2f4cbdSAlexander V. Chernikov case AF_INET6: 14445a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 14455a2f4cbdSAlexander V. Chernikov break; 14465a2f4cbdSAlexander V. Chernikov } 14475a2f4cbdSAlexander V. Chernikov 14485a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 14495a2f4cbdSAlexander V. Chernikov return (0); 14505a2f4cbdSAlexander V. Chernikov 14515a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 14525a2f4cbdSAlexander V. Chernikov return (0); 14535a2f4cbdSAlexander V. Chernikov 14545a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 14555a2f4cbdSAlexander V. Chernikov } 14565a2f4cbdSAlexander V. Chernikov 14575a2f4cbdSAlexander V. Chernikov int 14585a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 14595a2f4cbdSAlexander V. Chernikov { 14605a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 14615a2f4cbdSAlexander V. Chernikov int i = 0; 14625a2f4cbdSAlexander V. Chernikov 14635a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 14645a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 14655a2f4cbdSAlexander V. Chernikov 14665a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 14675a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 14685a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 14695a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 14705a2f4cbdSAlexander V. Chernikov } 14715a2f4cbdSAlexander V. Chernikov 14725a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 14735a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 14745a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, rt->rt_gateway); 14755a2f4cbdSAlexander V. Chernikov } 14765a2f4cbdSAlexander V. Chernikov 14775a2f4cbdSAlexander V. Chernikov return (i); 14785a2f4cbdSAlexander V. Chernikov } 14795a2f4cbdSAlexander V. Chernikov #endif 14805a2f4cbdSAlexander V. Chernikov 1481427ac07fSKip Macy #ifdef RADIX_MPATH 1482e8b0643eSAlexander V. Chernikov /* 1483e8b0643eSAlexander V. Chernikov * Deletes key for single-path routes, unlinks rtentry with 1484e8b0643eSAlexander V. Chernikov * gateway specified in @info from multi-path routes. 1485e8b0643eSAlexander V. Chernikov * 1486e8b0643eSAlexander V. Chernikov * Returnes unlinked entry. In case of failure, returns NULL 1487e8b0643eSAlexander V. Chernikov * and sets @perror to ESRCH. 1488e8b0643eSAlexander V. Chernikov */ 1489e8b0643eSAlexander V. Chernikov static struct radix_node * 149061eee0e2SAlexander V. Chernikov rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, 1491e8b0643eSAlexander V. Chernikov struct rtentry *rto, int *perror) 1492427ac07fSKip Macy { 1493427ac07fSKip Macy /* 1494427ac07fSKip Macy * if we got multipath routes, we require users to specify 1495427ac07fSKip Macy * a matching RTAX_GATEWAY. 1496427ac07fSKip Macy */ 1497e8b0643eSAlexander V. Chernikov struct rtentry *rt; // *rto = NULL; 1498f59c6cb0SAlexander V. Chernikov struct radix_node *rn; 1499e8b0643eSAlexander V. Chernikov struct sockaddr *gw; 1500427ac07fSKip Macy 1501e8b0643eSAlexander V. Chernikov gw = info->rti_info[RTAX_GATEWAY]; 1502e8b0643eSAlexander V. Chernikov rt = rt_mpath_matchgate(rto, gw); 1503e8b0643eSAlexander V. Chernikov if (rt == NULL) { 1504e8b0643eSAlexander V. Chernikov *perror = ESRCH; 1505e8b0643eSAlexander V. Chernikov return (NULL); 1506e8b0643eSAlexander V. Chernikov } 15075a2f4cbdSAlexander V. Chernikov 1508427ac07fSKip Macy /* 1509427ac07fSKip Macy * this is the first entry in the chain 1510427ac07fSKip Macy */ 1511427ac07fSKip Macy if (rto == rt) { 1512427ac07fSKip Macy rn = rn_mpath_next((struct radix_node *)rt); 1513427ac07fSKip Macy /* 1514427ac07fSKip Macy * there is another entry, now it's active 1515427ac07fSKip Macy */ 1516427ac07fSKip Macy if (rn) { 1517427ac07fSKip Macy rto = RNTORT(rn); 1518427ac07fSKip Macy RT_LOCK(rto); 1519427ac07fSKip Macy rto->rt_flags |= RTF_UP; 1520427ac07fSKip Macy RT_UNLOCK(rto); 1521427ac07fSKip Macy } else if (rt->rt_flags & RTF_GATEWAY) { 1522427ac07fSKip Macy /* 1523427ac07fSKip Macy * For gateway routes, we need to 1524427ac07fSKip Macy * make sure that we we are deleting 1525427ac07fSKip Macy * the correct gateway. 1526427ac07fSKip Macy * rt_mpath_matchgate() does not 1527427ac07fSKip Macy * check the case when there is only 1528427ac07fSKip Macy * one route in the chain. 1529427ac07fSKip Macy */ 1530e8b0643eSAlexander V. Chernikov if (gw && 1531e8b0643eSAlexander V. Chernikov (rt->rt_gateway->sa_len != gw->sa_len || 1532e8b0643eSAlexander V. Chernikov memcmp(rt->rt_gateway, gw, gw->sa_len))) { 1533e8b0643eSAlexander V. Chernikov *perror = ESRCH; 1534e8b0643eSAlexander V. Chernikov return (NULL); 1535e8b0643eSAlexander V. Chernikov } 15366a7bff2cSKip Macy } 15376a7bff2cSKip Macy 1538427ac07fSKip Macy /* 1539427ac07fSKip Macy * use the normal delete code to remove 1540427ac07fSKip Macy * the first entry 1541427ac07fSKip Macy */ 154261eee0e2SAlexander V. Chernikov rn = rnh->rnh_deladdr(dst, netmask, &rnh->head); 1543e8b0643eSAlexander V. Chernikov *perror = 0; 1544e8b0643eSAlexander V. Chernikov return (rn); 1545427ac07fSKip Macy } 1546427ac07fSKip Macy 1547427ac07fSKip Macy /* 1548427ac07fSKip Macy * if the entry is 2nd and on up 1549427ac07fSKip Macy */ 1550e8b0643eSAlexander V. Chernikov if (rt_mpath_deldup(rto, rt) == 0) 1551427ac07fSKip Macy panic ("rtrequest1: rt_mpath_deldup"); 1552e8b0643eSAlexander V. Chernikov *perror = 0; 1553e8b0643eSAlexander V. Chernikov rn = (struct radix_node *)rt; 1554e8b0643eSAlexander V. Chernikov return (rn); 1555427ac07fSKip Macy } 1556427ac07fSKip Macy #endif 1557427ac07fSKip Macy 1558aef2d5fbSAlexander V. Chernikov #undef dst 1559aef2d5fbSAlexander V. Chernikov #undef gateway 1560aef2d5fbSAlexander V. Chernikov #undef netmask 1561aef2d5fbSAlexander V. Chernikov #undef ifaaddr 1562aef2d5fbSAlexander V. Chernikov #undef ifpaddr 1563aef2d5fbSAlexander V. Chernikov #undef flags 1564aef2d5fbSAlexander V. Chernikov 15658071913dSRuslan Ermilov int 15668b07e49aSJulian Elischer rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, 15678b07e49aSJulian Elischer u_int fibnum) 15688b07e49aSJulian Elischer { 1569a6663252SAlexander V. Chernikov struct epoch_tracker et; 1570aef2d5fbSAlexander V. Chernikov const struct sockaddr *dst; 157161eee0e2SAlexander V. Chernikov struct rib_head *rnh; 1572aef2d5fbSAlexander V. Chernikov int error; 1573df8bae1dSRodney W. Grimes 15748b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); 1575aef2d5fbSAlexander V. Chernikov KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); 1576aef2d5fbSAlexander V. Chernikov 1577aef2d5fbSAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 1578aef2d5fbSAlexander V. Chernikov 1579b680a383SBjoern A. Zeeb switch (dst->sa_family) { 1580b680a383SBjoern A. Zeeb case AF_INET6: 1581b680a383SBjoern A. Zeeb case AF_INET: 1582b680a383SBjoern A. Zeeb /* We support multiple FIBs. */ 1583b680a383SBjoern A. Zeeb break; 1584b680a383SBjoern A. Zeeb default: 1585b680a383SBjoern A. Zeeb fibnum = RT_DEFAULT_FIB; 1586b680a383SBjoern A. Zeeb break; 1587b680a383SBjoern A. Zeeb } 1588b680a383SBjoern A. Zeeb 1589b0a76b88SJulian Elischer /* 1590b0a76b88SJulian Elischer * Find the correct routing tree to use for this Address Family 1591b0a76b88SJulian Elischer */ 1592c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 159385911824SLuigi Rizzo if (rnh == NULL) 1594983985c1SJeffrey Hsu return (EAFNOSUPPORT); 1595048738b5SAlexander V. Chernikov 1596b0a76b88SJulian Elischer /* 1597b0a76b88SJulian Elischer * If we are adding a host route then we don't want to put 159866953138SRuslan Ermilov * a netmask in the tree, nor do we want to clone it. 1599b0a76b88SJulian Elischer */ 1600aef2d5fbSAlexander V. Chernikov if (info->rti_flags & RTF_HOST) 1601aef2d5fbSAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = NULL; 16026e6b3f7cSQing Li 1603aef2d5fbSAlexander V. Chernikov error = 0; 1604df8bae1dSRodney W. Grimes switch (req) { 1605df8bae1dSRodney W. Grimes case RTM_DELETE: 1606aef2d5fbSAlexander V. Chernikov error = del_route(rnh, info, ret_nrt); 1607df8bae1dSRodney W. Grimes break; 1608df8bae1dSRodney W. Grimes case RTM_RESOLVE: 16096e6b3f7cSQing Li /* 16106e6b3f7cSQing Li * resolve was only used for route cloning 16116e6b3f7cSQing Li * here for compat 16126e6b3f7cSQing Li */ 16136e6b3f7cSQing Li break; 1614df8bae1dSRodney W. Grimes case RTM_ADD: 1615aef2d5fbSAlexander V. Chernikov error = add_route(rnh, info, ret_nrt); 1616aef2d5fbSAlexander V. Chernikov break; 1617aef2d5fbSAlexander V. Chernikov case RTM_CHANGE: 1618a6663252SAlexander V. Chernikov NET_EPOCH_ENTER(et); 1619aef2d5fbSAlexander V. Chernikov RIB_WLOCK(rnh); 1620aef2d5fbSAlexander V. Chernikov error = change_route(rnh, info, ret_nrt); 1621aef2d5fbSAlexander V. Chernikov RIB_WUNLOCK(rnh); 1622a6663252SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1623aef2d5fbSAlexander V. Chernikov break; 1624aef2d5fbSAlexander V. Chernikov default: 1625aef2d5fbSAlexander V. Chernikov error = EOPNOTSUPP; 1626aef2d5fbSAlexander V. Chernikov } 1627aef2d5fbSAlexander V. Chernikov 1628aef2d5fbSAlexander V. Chernikov return (error); 1629aef2d5fbSAlexander V. Chernikov } 1630aef2d5fbSAlexander V. Chernikov 1631aef2d5fbSAlexander V. Chernikov static int 1632aef2d5fbSAlexander V. Chernikov add_route(struct rib_head *rnh, struct rt_addrinfo *info, 1633aef2d5fbSAlexander V. Chernikov struct rtentry **ret_nrt) 1634aef2d5fbSAlexander V. Chernikov { 1635aef2d5fbSAlexander V. Chernikov struct sockaddr *dst, *ndst, *gateway, *netmask; 1636aef2d5fbSAlexander V. Chernikov struct rtentry *rt, *rt_old; 1637a6663252SAlexander V. Chernikov struct nhop_object *nh; 1638aef2d5fbSAlexander V. Chernikov struct radix_node *rn; 1639aef2d5fbSAlexander V. Chernikov struct ifaddr *ifa; 1640aef2d5fbSAlexander V. Chernikov int error, flags; 1641a6663252SAlexander V. Chernikov struct epoch_tracker et; 1642aef2d5fbSAlexander V. Chernikov 1643aef2d5fbSAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 1644aef2d5fbSAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 1645aef2d5fbSAlexander V. Chernikov netmask = info->rti_info[RTAX_NETMASK]; 1646aef2d5fbSAlexander V. Chernikov flags = info->rti_flags; 1647aef2d5fbSAlexander V. Chernikov 16485df72964SGarrett Wollman if ((flags & RTF_GATEWAY) && !gateway) 1649048738b5SAlexander V. Chernikov return (EINVAL); 165016a2e0a6SQing Li if (dst && gateway && (dst->sa_family != gateway->sa_family) && 165116a2e0a6SQing Li (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) 1652048738b5SAlexander V. Chernikov return (EINVAL); 16535df72964SGarrett Wollman 16548c0fec80SRobert Watson if (info->rti_ifa == NULL) { 1655aef2d5fbSAlexander V. Chernikov error = rt_getifa_fib(info, rnh->rib_fibnum); 16568c0fec80SRobert Watson if (error) 1657048738b5SAlexander V. Chernikov return (error); 16586b5d8e30SMark Johnston } else { 16596b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 16609379029aSMatt Macy } 1661a6663252SAlexander V. Chernikov 1662a6663252SAlexander V. Chernikov NET_EPOCH_ENTER(et); 1663a6663252SAlexander V. Chernikov error = nhop_create_from_info(rnh, info, &nh); 1664a6663252SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1665a6663252SAlexander V. Chernikov if (error != 0) { 1666a6663252SAlexander V. Chernikov ifa_free(info->rti_ifa); 1667a6663252SAlexander V. Chernikov return (error); 1668a6663252SAlexander V. Chernikov } 1669a6663252SAlexander V. Chernikov 1670e3a7aa6fSGleb Smirnoff rt = uma_zalloc(V_rtzone, M_NOWAIT); 16718c0fec80SRobert Watson if (rt == NULL) { 16726b5d8e30SMark Johnston ifa_free(info->rti_ifa); 1673a6663252SAlexander V. Chernikov nhop_free(nh); 1674048738b5SAlexander V. Chernikov return (ENOBUFS); 16758c0fec80SRobert Watson } 1676df8bae1dSRodney W. Grimes rt->rt_flags = RTF_UP | flags; 1677aef2d5fbSAlexander V. Chernikov rt->rt_fibnum = rnh->rib_fibnum; 1678a6663252SAlexander V. Chernikov rt->rt_nhop = nh; 1679499676dfSJulian Elischer /* 1680a8498625SBjoern A. Zeeb * Add the gateway. Possibly re-malloc-ing the storage for it. 1681499676dfSJulian Elischer */ 1682831a80b0SMatthew Dillon if ((error = rt_setgate(rt, dst, gateway)) != 0) { 16836b5d8e30SMark Johnston ifa_free(info->rti_ifa); 1684a6663252SAlexander V. Chernikov nhop_free(nh); 16851ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1686048738b5SAlexander V. Chernikov return (error); 1687df8bae1dSRodney W. Grimes } 1688499676dfSJulian Elischer 1689499676dfSJulian Elischer /* 1690499676dfSJulian Elischer * point to the (possibly newly malloc'd) dest address. 1691499676dfSJulian Elischer */ 1692d1dd20beSSam Leffler ndst = (struct sockaddr *)rt_key(rt); 1693499676dfSJulian Elischer 1694499676dfSJulian Elischer /* 1695499676dfSJulian Elischer * make sure it contains the value we want (masked if needed). 1696499676dfSJulian Elischer */ 1697df8bae1dSRodney W. Grimes if (netmask) { 1698df8bae1dSRodney W. Grimes rt_maskedcopy(dst, ndst, netmask); 1699df8bae1dSRodney W. Grimes } else 17001838a647SLuigi Rizzo bcopy(dst, ndst, dst->sa_len); 17018e718bb4SGarrett Wollman 17028e718bb4SGarrett Wollman /* 17038c0fec80SRobert Watson * We use the ifa reference returned by rt_getifa_fib(). 17048e718bb4SGarrett Wollman * This moved from below so that rnh->rnh_addaddr() can 1705499676dfSJulian Elischer * examine the ifa and ifa->ifa_ifp if it so desires. 17068e718bb4SGarrett Wollman */ 17079379029aSMatt Macy ifa = info->rti_ifa; 17088e718bb4SGarrett Wollman rt->rt_ifa = ifa; 17098e718bb4SGarrett Wollman rt->rt_ifp = ifa->ifa_ifp; 1710e3a7aa6fSGleb Smirnoff rt->rt_weight = 1; 17118e718bb4SGarrett Wollman 17121a75e3b2SAlexander V. Chernikov rt_setmetrics(info, rt); 17131a75e3b2SAlexander V. Chernikov 171461eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 1715048738b5SAlexander V. Chernikov RT_LOCK(rt); 1716e440aed9SQing Li #ifdef RADIX_MPATH 1717e440aed9SQing Li /* do not permit exactly the same dst/mask/gw pair */ 171861eee0e2SAlexander V. Chernikov if (rt_mpath_capable(rnh) && 1719e440aed9SQing Li rt_mpath_conflict(rnh, rt, netmask)) { 172061eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 1721048738b5SAlexander V. Chernikov 17221099f828SRobert Watson ifa_free(rt->rt_ifa); 17238b15f615SLuiz Otavio O Souza R_Free(rt_key(rt)); 1724a6663252SAlexander V. Chernikov nhop_free(nh); 17251ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1726048738b5SAlexander V. Chernikov return (EEXIST); 1727e440aed9SQing Li } 1728e440aed9SQing Li #endif 1729e440aed9SQing Li 1730d1dd20beSSam Leffler /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ 173161eee0e2SAlexander V. Chernikov rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); 17324b3dc898SAlexander V. Chernikov 173334a5582cSAlexander V. Chernikov if (rn != NULL && rt->rt_expire > 0) 173434a5582cSAlexander V. Chernikov tmproutes_update(rnh, rt); 173534a5582cSAlexander V. Chernikov 17364b3dc898SAlexander V. Chernikov rt_old = NULL; 17374b3dc898SAlexander V. Chernikov if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) { 17384b3dc898SAlexander V. Chernikov 17394b3dc898SAlexander V. Chernikov /* 17404b3dc898SAlexander V. Chernikov * Force removal and re-try addition 17414b3dc898SAlexander V. Chernikov * TODO: better multipath&pinned support 17424b3dc898SAlexander V. Chernikov */ 17434b3dc898SAlexander V. Chernikov struct sockaddr *info_dst = info->rti_info[RTAX_DST]; 17444b3dc898SAlexander V. Chernikov info->rti_info[RTAX_DST] = ndst; 17456af272d8SAlexander V. Chernikov /* Do not delete existing PINNED(interface) routes */ 17466af272d8SAlexander V. Chernikov info->rti_flags &= ~RTF_PINNED; 17474b3dc898SAlexander V. Chernikov rt_old = rt_unlinkrte(rnh, info, &error); 17486af272d8SAlexander V. Chernikov info->rti_flags |= RTF_PINNED; 17494b3dc898SAlexander V. Chernikov info->rti_info[RTAX_DST] = info_dst; 17504b3dc898SAlexander V. Chernikov if (rt_old != NULL) 175161eee0e2SAlexander V. Chernikov rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, 17524b3dc898SAlexander V. Chernikov rt->rt_nodes); 17534b3dc898SAlexander V. Chernikov } 175461eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 17554b3dc898SAlexander V. Chernikov 17564b3dc898SAlexander V. Chernikov if (rt_old != NULL) 17574b3dc898SAlexander V. Chernikov RT_UNLOCK(rt_old); 17584b3dc898SAlexander V. Chernikov 1759499676dfSJulian Elischer /* 1760499676dfSJulian Elischer * If it still failed to go into the tree, 1761499676dfSJulian Elischer * then un-make it (this should be a function) 1762499676dfSJulian Elischer */ 176385911824SLuigi Rizzo if (rn == NULL) { 17641099f828SRobert Watson ifa_free(rt->rt_ifa); 17658b15f615SLuiz Otavio O Souza R_Free(rt_key(rt)); 1766a6663252SAlexander V. Chernikov nhop_free(nh); 17671ed81b73SMarko Zec uma_zfree(V_rtzone, rt); 1768048738b5SAlexander V. Chernikov return (EEXIST); 1769df8bae1dSRodney W. Grimes } 1770499676dfSJulian Elischer 17714b3dc898SAlexander V. Chernikov if (rt_old != NULL) { 17724b3dc898SAlexander V. Chernikov rt_notifydelete(rt_old, info); 17734b3dc898SAlexander V. Chernikov RTFREE(rt_old); 17744b3dc898SAlexander V. Chernikov } 17754b3dc898SAlexander V. Chernikov 1776499676dfSJulian Elischer /* 1777a0c0e34bSGleb Smirnoff * If this protocol has something to add to this then 1778499676dfSJulian Elischer * allow it to do that as well. 1779499676dfSJulian Elischer */ 1780df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest) 1781aef2d5fbSAlexander V. Chernikov ifa->ifa_rtrequest(RTM_ADD, rt, info); 1782499676dfSJulian Elischer 1783cd02a0b7SGarrett Wollman /* 1784499676dfSJulian Elischer * actually return a resultant rtentry and 1785499676dfSJulian Elischer * give the caller a single reference. 1786499676dfSJulian Elischer */ 1787df8bae1dSRodney W. Grimes if (ret_nrt) { 1788df8bae1dSRodney W. Grimes *ret_nrt = rt; 17897138d65cSSam Leffler RT_ADDREF(rt); 1790df8bae1dSRodney W. Grimes } 179184cc0778SGeorge V. Neville-Neil rnh->rnh_gen++; /* Routing table updated */ 1792d1dd20beSSam Leffler RT_UNLOCK(rt); 1793048738b5SAlexander V. Chernikov 1794aef2d5fbSAlexander V. Chernikov return (0); 1795d1dd20beSSam Leffler } 1796d1dd20beSSam Leffler 1797c77462ddSAlexander V. Chernikov static int 1798aef2d5fbSAlexander V. Chernikov del_route(struct rib_head *rnh, struct rt_addrinfo *info, 1799aef2d5fbSAlexander V. Chernikov struct rtentry **ret_nrt) 1800aef2d5fbSAlexander V. Chernikov { 1801aef2d5fbSAlexander V. Chernikov struct sockaddr *dst, *netmask; 1802aef2d5fbSAlexander V. Chernikov struct sockaddr_storage mdst; 1803aef2d5fbSAlexander V. Chernikov struct rtentry *rt; 1804aef2d5fbSAlexander V. Chernikov int error; 1805aef2d5fbSAlexander V. Chernikov 1806aef2d5fbSAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 1807aef2d5fbSAlexander V. Chernikov netmask = info->rti_info[RTAX_NETMASK]; 1808aef2d5fbSAlexander V. Chernikov 1809aef2d5fbSAlexander V. Chernikov if (netmask) { 1810aef2d5fbSAlexander V. Chernikov if (dst->sa_len > sizeof(mdst)) 1811aef2d5fbSAlexander V. Chernikov return (EINVAL); 1812aef2d5fbSAlexander V. Chernikov rt_maskedcopy(dst, (struct sockaddr *)&mdst, netmask); 1813aef2d5fbSAlexander V. Chernikov dst = (struct sockaddr *)&mdst; 1814aef2d5fbSAlexander V. Chernikov } 1815aef2d5fbSAlexander V. Chernikov 1816aef2d5fbSAlexander V. Chernikov RIB_WLOCK(rnh); 1817aef2d5fbSAlexander V. Chernikov rt = rt_unlinkrte(rnh, info, &error); 1818aef2d5fbSAlexander V. Chernikov RIB_WUNLOCK(rnh); 1819aef2d5fbSAlexander V. Chernikov if (error != 0) 1820aef2d5fbSAlexander V. Chernikov return (error); 1821aef2d5fbSAlexander V. Chernikov 1822aef2d5fbSAlexander V. Chernikov rt_notifydelete(rt, info); 1823aef2d5fbSAlexander V. Chernikov 1824aef2d5fbSAlexander V. Chernikov /* 1825aef2d5fbSAlexander V. Chernikov * If the caller wants it, then it can have it, 1826aef2d5fbSAlexander V. Chernikov * but it's up to it to free the rtentry as we won't be 1827aef2d5fbSAlexander V. Chernikov * doing it. 1828aef2d5fbSAlexander V. Chernikov */ 1829aef2d5fbSAlexander V. Chernikov if (ret_nrt) { 1830aef2d5fbSAlexander V. Chernikov *ret_nrt = rt; 1831aef2d5fbSAlexander V. Chernikov RT_UNLOCK(rt); 1832aef2d5fbSAlexander V. Chernikov } else 1833aef2d5fbSAlexander V. Chernikov RTFREE_LOCKED(rt); 1834aef2d5fbSAlexander V. Chernikov 1835aef2d5fbSAlexander V. Chernikov return (0); 1836aef2d5fbSAlexander V. Chernikov } 1837aef2d5fbSAlexander V. Chernikov 1838aef2d5fbSAlexander V. Chernikov static int 1839aef2d5fbSAlexander V. Chernikov change_route(struct rib_head *rnh, struct rt_addrinfo *info, 1840aef2d5fbSAlexander V. Chernikov struct rtentry **ret_nrt) 1841c77462ddSAlexander V. Chernikov { 1842c77462ddSAlexander V. Chernikov struct rtentry *rt = NULL; 1843c77462ddSAlexander V. Chernikov int error = 0; 1844c77462ddSAlexander V. Chernikov int free_ifa = 0; 18451a75e3b2SAlexander V. Chernikov int family, mtu; 1846a6663252SAlexander V. Chernikov struct nhop_object *nh; 18477f948f12SAlexander V. Chernikov struct if_mtuinfo ifmtu; 1848c77462ddSAlexander V. Chernikov 1849bc3d87fdSRyan Stone RIB_WLOCK_ASSERT(rnh); 1850bc3d87fdSRyan Stone 1851c77462ddSAlexander V. Chernikov rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST], 185261eee0e2SAlexander V. Chernikov info->rti_info[RTAX_NETMASK], &rnh->head); 1853c77462ddSAlexander V. Chernikov 1854c77462ddSAlexander V. Chernikov if (rt == NULL) 1855c77462ddSAlexander V. Chernikov return (ESRCH); 1856c77462ddSAlexander V. Chernikov 1857c77462ddSAlexander V. Chernikov #ifdef RADIX_MPATH 1858c77462ddSAlexander V. Chernikov /* 1859c77462ddSAlexander V. Chernikov * If we got multipath routes, 1860c77462ddSAlexander V. Chernikov * we require users to specify a matching RTAX_GATEWAY. 1861c77462ddSAlexander V. Chernikov */ 186261eee0e2SAlexander V. Chernikov if (rt_mpath_capable(rnh)) { 1863c77462ddSAlexander V. Chernikov rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); 1864c77462ddSAlexander V. Chernikov if (rt == NULL) 1865c77462ddSAlexander V. Chernikov return (ESRCH); 1866c77462ddSAlexander V. Chernikov } 1867c77462ddSAlexander V. Chernikov #endif 1868c77462ddSAlexander V. Chernikov 1869a6663252SAlexander V. Chernikov nh = NULL; 1870c77462ddSAlexander V. Chernikov RT_LOCK(rt); 1871c77462ddSAlexander V. Chernikov 18721a75e3b2SAlexander V. Chernikov rt_setmetrics(info, rt); 18731a75e3b2SAlexander V. Chernikov 1874c77462ddSAlexander V. Chernikov /* 1875c77462ddSAlexander V. Chernikov * New gateway could require new ifaddr, ifp; 1876c77462ddSAlexander V. Chernikov * flags may also be different; ifp may be specified 1877c77462ddSAlexander V. Chernikov * by ll sockaddr when protocol address is ambiguous 1878c77462ddSAlexander V. Chernikov */ 1879c77462ddSAlexander V. Chernikov if (((rt->rt_flags & RTF_GATEWAY) && 1880c77462ddSAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] != NULL) || 1881c77462ddSAlexander V. Chernikov info->rti_info[RTAX_IFP] != NULL || 1882c77462ddSAlexander V. Chernikov (info->rti_info[RTAX_IFA] != NULL && 1883c77462ddSAlexander V. Chernikov !sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) { 1884b83aa367SAndrey V. Elsukov /* 1885b83aa367SAndrey V. Elsukov * XXX: Temporarily set RTF_RNH_LOCKED flag in the rti_flags 1886b83aa367SAndrey V. Elsukov * to avoid rlock in the ifa_ifwithroute(). 1887b83aa367SAndrey V. Elsukov */ 1888b83aa367SAndrey V. Elsukov info->rti_flags |= RTF_RNH_LOCKED; 1889aef2d5fbSAlexander V. Chernikov error = rt_getifa_fib(info, rnh->rib_fibnum); 1890b83aa367SAndrey V. Elsukov info->rti_flags &= ~RTF_RNH_LOCKED; 1891c77462ddSAlexander V. Chernikov if (info->rti_ifa != NULL) 1892c77462ddSAlexander V. Chernikov free_ifa = 1; 1893c77462ddSAlexander V. Chernikov 1894c77462ddSAlexander V. Chernikov if (error != 0) 1895a713ee5cSAlexander V. Chernikov goto bad; 1896c77462ddSAlexander V. Chernikov } 1897c77462ddSAlexander V. Chernikov 1898a6663252SAlexander V. Chernikov error = nhop_create_from_nhop(rnh, rt->rt_nhop, info, &nh); 1899a6663252SAlexander V. Chernikov if (error != 0) 1900a6663252SAlexander V. Chernikov goto bad; 1901a6663252SAlexander V. Chernikov 1902c77462ddSAlexander V. Chernikov /* Check if outgoing interface has changed */ 1903c77462ddSAlexander V. Chernikov if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa && 190419f41c2aSRyan Stone rt->rt_ifa != NULL) { 190519f41c2aSRyan Stone if (rt->rt_ifa->ifa_rtrequest != NULL) 1906c77462ddSAlexander V. Chernikov rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info); 1907c77462ddSAlexander V. Chernikov ifa_free(rt->rt_ifa); 19081ebec5faSMatt Macy rt->rt_ifa = NULL; 1909c77462ddSAlexander V. Chernikov } 1910c77462ddSAlexander V. Chernikov /* Update gateway address */ 1911c77462ddSAlexander V. Chernikov if (info->rti_info[RTAX_GATEWAY] != NULL) { 1912c77462ddSAlexander V. Chernikov error = rt_setgate(rt, rt_key(rt), info->rti_info[RTAX_GATEWAY]); 1913c77462ddSAlexander V. Chernikov if (error != 0) 1914a713ee5cSAlexander V. Chernikov goto bad; 1915c77462ddSAlexander V. Chernikov 1916c77462ddSAlexander V. Chernikov rt->rt_flags &= ~RTF_GATEWAY; 1917c77462ddSAlexander V. Chernikov rt->rt_flags |= (RTF_GATEWAY & info->rti_flags); 1918c77462ddSAlexander V. Chernikov } 1919c77462ddSAlexander V. Chernikov 1920c77462ddSAlexander V. Chernikov if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa) { 1921c77462ddSAlexander V. Chernikov ifa_ref(info->rti_ifa); 1922c77462ddSAlexander V. Chernikov rt->rt_ifa = info->rti_ifa; 1923c77462ddSAlexander V. Chernikov rt->rt_ifp = info->rti_ifp; 1924c77462ddSAlexander V. Chernikov } 1925c77462ddSAlexander V. Chernikov /* Allow some flags to be toggled on change. */ 1926c77462ddSAlexander V. Chernikov rt->rt_flags &= ~RTF_FMASK; 1927c77462ddSAlexander V. Chernikov rt->rt_flags |= info->rti_flags & RTF_FMASK; 1928c77462ddSAlexander V. Chernikov 1929c77462ddSAlexander V. Chernikov if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL) 1930c77462ddSAlexander V. Chernikov rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info); 1931c77462ddSAlexander V. Chernikov 19327f948f12SAlexander V. Chernikov /* Alter route MTU if necessary */ 19331a75e3b2SAlexander V. Chernikov if (rt->rt_ifp != NULL) { 19341a75e3b2SAlexander V. Chernikov family = info->rti_info[RTAX_DST]->sa_family; 19351a75e3b2SAlexander V. Chernikov mtu = if_getmtu_family(rt->rt_ifp, family); 19367f948f12SAlexander V. Chernikov /* Set default MTU */ 19377f948f12SAlexander V. Chernikov if (rt->rt_mtu == 0) 19381a75e3b2SAlexander V. Chernikov rt->rt_mtu = mtu; 19397f948f12SAlexander V. Chernikov if (rt->rt_mtu != mtu) { 19407f948f12SAlexander V. Chernikov /* Check if we really need to update */ 19417f948f12SAlexander V. Chernikov ifmtu.ifp = rt->rt_ifp; 19427f948f12SAlexander V. Chernikov ifmtu.mtu = mtu; 19437f948f12SAlexander V. Chernikov if_updatemtu_cb(rt->rt_nodes, &ifmtu); 19447f948f12SAlexander V. Chernikov } 19451a75e3b2SAlexander V. Chernikov } 19460fb9298dSAlexander V. Chernikov 1947a6663252SAlexander V. Chernikov /* Update nexthop */ 1948a6663252SAlexander V. Chernikov nhop_free(rt->rt_nhop); 1949a6663252SAlexander V. Chernikov rt->rt_nhop = nh; 1950a6663252SAlexander V. Chernikov nh = NULL; 1951a6663252SAlexander V. Chernikov 1952bc3d87fdSRyan Stone /* 1953bc3d87fdSRyan Stone * This route change may have modified the route's gateway. In that 1954bc3d87fdSRyan Stone * case, any inpcbs that have cached this route need to invalidate their 1955bc3d87fdSRyan Stone * llentry cache. 1956bc3d87fdSRyan Stone */ 1957bc3d87fdSRyan Stone rnh->rnh_gen++; 1958bc3d87fdSRyan Stone 1959c77462ddSAlexander V. Chernikov if (ret_nrt) { 1960c77462ddSAlexander V. Chernikov *ret_nrt = rt; 1961c77462ddSAlexander V. Chernikov RT_ADDREF(rt); 1962c77462ddSAlexander V. Chernikov } 1963c77462ddSAlexander V. Chernikov bad: 1964c77462ddSAlexander V. Chernikov RT_UNLOCK(rt); 1965a6663252SAlexander V. Chernikov if (nh != NULL) 1966a6663252SAlexander V. Chernikov nhop_free(nh); 19671ebec5faSMatt Macy if (free_ifa != 0) { 1968c77462ddSAlexander V. Chernikov ifa_free(info->rti_ifa); 19691ebec5faSMatt Macy info->rti_ifa = NULL; 19701ebec5faSMatt Macy } 1971c77462ddSAlexander V. Chernikov return (error); 1972c77462ddSAlexander V. Chernikov } 1973c77462ddSAlexander V. Chernikov 19740fb9298dSAlexander V. Chernikov static void 19750fb9298dSAlexander V. Chernikov rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) 19760fb9298dSAlexander V. Chernikov { 19770fb9298dSAlexander V. Chernikov 19787f948f12SAlexander V. Chernikov if (info->rti_mflags & RTV_MTU) { 19797f948f12SAlexander V. Chernikov if (info->rti_rmx->rmx_mtu != 0) { 19807f948f12SAlexander V. Chernikov 19817f948f12SAlexander V. Chernikov /* 19827f948f12SAlexander V. Chernikov * MTU was explicitly provided by user. 19837f948f12SAlexander V. Chernikov * Keep it. 19847f948f12SAlexander V. Chernikov */ 19857f948f12SAlexander V. Chernikov rt->rt_flags |= RTF_FIXEDMTU; 19867f948f12SAlexander V. Chernikov } else { 19877f948f12SAlexander V. Chernikov 19887f948f12SAlexander V. Chernikov /* 19897f948f12SAlexander V. Chernikov * User explicitly sets MTU to 0. 19907f948f12SAlexander V. Chernikov * Assume rollback to default. 19917f948f12SAlexander V. Chernikov */ 19927f948f12SAlexander V. Chernikov rt->rt_flags &= ~RTF_FIXEDMTU; 19937f948f12SAlexander V. Chernikov } 19940fb9298dSAlexander V. Chernikov rt->rt_mtu = info->rti_rmx->rmx_mtu; 19957f948f12SAlexander V. Chernikov } 19960fb9298dSAlexander V. Chernikov if (info->rti_mflags & RTV_WEIGHT) 19970fb9298dSAlexander V. Chernikov rt->rt_weight = info->rti_rmx->rmx_weight; 19980fb9298dSAlexander V. Chernikov /* Kernel -> userland timebase conversion. */ 19990fb9298dSAlexander V. Chernikov if (info->rti_mflags & RTV_EXPIRE) 20000fb9298dSAlexander V. Chernikov rt->rt_expire = info->rti_rmx->rmx_expire ? 20010fb9298dSAlexander V. Chernikov info->rti_rmx->rmx_expire - time_second + time_uptime : 0; 20020fb9298dSAlexander V. Chernikov } 20030fb9298dSAlexander V. Chernikov 2004df8bae1dSRodney W. Grimes int 2005d1dd20beSSam Leffler rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) 2006df8bae1dSRodney W. Grimes { 2007d1dd20beSSam Leffler /* XXX dst may be overwritten, can we move this to below */ 20086e6b3f7cSQing Li int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); 2009df8bae1dSRodney W. Grimes 20101db1fffaSBill Fenner /* 201185911824SLuigi Rizzo * Prepare to store the gateway in rt->rt_gateway. 201285911824SLuigi Rizzo * Both dst and gateway are stored one after the other in the same 201385911824SLuigi Rizzo * malloc'd chunk. If we have room, we can reuse the old buffer, 201485911824SLuigi Rizzo * rt_gateway already points to the right place. 201585911824SLuigi Rizzo * Otherwise, malloc a new block and update the 'dst' address. 2016499676dfSJulian Elischer */ 201785911824SLuigi Rizzo if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) { 201885911824SLuigi Rizzo caddr_t new; 201985911824SLuigi Rizzo 2020df8bae1dSRodney W. Grimes R_Malloc(new, caddr_t, dlen + glen); 202185911824SLuigi Rizzo if (new == NULL) 20221db1fffaSBill Fenner return ENOBUFS; 2023499676dfSJulian Elischer /* 202485911824SLuigi Rizzo * XXX note, we copy from *dst and not *rt_key(rt) because 202585911824SLuigi Rizzo * rt_setgate() can be called to initialize a newly 202685911824SLuigi Rizzo * allocated route entry, in which case rt_key(rt) == NULL 202785911824SLuigi Rizzo * (and also rt->rt_gateway == NULL). 202885911824SLuigi Rizzo * Free()/free() handle a NULL argument just fine. 2029499676dfSJulian Elischer */ 20301838a647SLuigi Rizzo bcopy(dst, new, dlen); 20318b15f615SLuiz Otavio O Souza R_Free(rt_key(rt)); /* free old block, if any */ 2032445e045bSAlexander Kabaev rt_key(rt) = (struct sockaddr *)new; 203385911824SLuigi Rizzo rt->rt_gateway = (struct sockaddr *)(new + dlen); 2034df8bae1dSRodney W. Grimes } 2035499676dfSJulian Elischer 2036499676dfSJulian Elischer /* 203785911824SLuigi Rizzo * Copy the new gateway value into the memory chunk. 203885911824SLuigi Rizzo */ 203985911824SLuigi Rizzo bcopy(gate, rt->rt_gateway, glen); 204085911824SLuigi Rizzo 20416e6b3f7cSQing Li return (0); 2042df8bae1dSRodney W. Grimes } 2043df8bae1dSRodney W. Grimes 2044c7ab6602SQing Li void 2045d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 2046df8bae1dSRodney W. Grimes { 2047f59c6cb0SAlexander V. Chernikov u_char *cp1 = (u_char *)src; 2048f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 2049f59c6cb0SAlexander V. Chernikov u_char *cp3 = (u_char *)netmask; 2050df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 2051df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 2052df8bae1dSRodney W. Grimes 2053df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 2054df8bae1dSRodney W. Grimes cp3 += 2; 2055df8bae1dSRodney W. Grimes if (cplim > cplim2) 2056df8bae1dSRodney W. Grimes cplim = cplim2; 2057df8bae1dSRodney W. Grimes while (cp2 < cplim) 2058df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 2059df8bae1dSRodney W. Grimes if (cp2 < cplim2) 2060df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 2061df8bae1dSRodney W. Grimes } 2062df8bae1dSRodney W. Grimes 2063df8bae1dSRodney W. Grimes /* 2064df8bae1dSRodney W. Grimes * Set up a routing table entry, normally 2065df8bae1dSRodney W. Grimes * for an interface. 2066df8bae1dSRodney W. Grimes */ 20678b07e49aSJulian Elischer #define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 20688b07e49aSJulian Elischer static inline int 20698b07e49aSJulian Elischer rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 2070df8bae1dSRodney W. Grimes { 207120efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 20725aca0b30SLuigi Rizzo struct sockaddr *dst; 20738071913dSRuslan Ermilov struct sockaddr *netmask; 207485911824SLuigi Rizzo struct rtentry *rt = NULL; 20758071913dSRuslan Ermilov struct rt_addrinfo info; 2076e440aed9SQing Li int error = 0; 20778b07e49aSJulian Elischer int startfib, endfib; 20788b07e49aSJulian Elischer char tempbuf[_SOCKADDR_TMPSIZE]; 20798b07e49aSJulian Elischer int didwork = 0; 20808b07e49aSJulian Elischer int a_failure = 0; 2081563ab4e4SAlexander V. Chernikov struct sockaddr_dl *sdl = NULL; 208261eee0e2SAlexander V. Chernikov struct rib_head *rnh; 2083df8bae1dSRodney W. Grimes 20848071913dSRuslan Ermilov if (flags & RTF_HOST) { 20858071913dSRuslan Ermilov dst = ifa->ifa_dstaddr; 20868071913dSRuslan Ermilov netmask = NULL; 20878071913dSRuslan Ermilov } else { 20888071913dSRuslan Ermilov dst = ifa->ifa_addr; 20898071913dSRuslan Ermilov netmask = ifa->ifa_netmask; 20908071913dSRuslan Ermilov } 2091b3dd0771SBjoern A. Zeeb if (dst->sa_len == 0) 2092b3dd0771SBjoern A. Zeeb return(EINVAL); 2093b680a383SBjoern A. Zeeb switch (dst->sa_family) { 2094b680a383SBjoern A. Zeeb case AF_INET6: 2095b680a383SBjoern A. Zeeb case AF_INET: 2096b680a383SBjoern A. Zeeb /* We support multiple FIBs. */ 2097b680a383SBjoern A. Zeeb break; 2098b680a383SBjoern A. Zeeb default: 2099b680a383SBjoern A. Zeeb fibnum = RT_DEFAULT_FIB; 2100b680a383SBjoern A. Zeeb break; 2101b680a383SBjoern A. Zeeb } 21027d9b6df1SAlexander V. Chernikov if (fibnum == RT_ALL_FIBS) { 2103ee0bd4b9SHiroki Sato if (V_rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) 21040489b891SAlan Somers startfib = endfib = ifa->ifa_ifp->if_fib; 2105ee0bd4b9SHiroki Sato else { 21068b07e49aSJulian Elischer startfib = 0; 21078b07e49aSJulian Elischer endfib = rt_numfibs - 1; 210866e8505fSJulian Elischer } 21098b07e49aSJulian Elischer } else { 21108b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 21118b07e49aSJulian Elischer startfib = fibnum; 21128b07e49aSJulian Elischer endfib = fibnum; 21138b07e49aSJulian Elischer } 2114ac4a76ebSBjoern A. Zeeb 2115b0a76b88SJulian Elischer /* 21168b07e49aSJulian Elischer * If it's a delete, check that if it exists, 21178b07e49aSJulian Elischer * it's on the correct interface or we might scrub 21188b07e49aSJulian Elischer * a route to another ifa which would 2119b0a76b88SJulian Elischer * be confusing at best and possibly worse. 2120b0a76b88SJulian Elischer */ 2121df8bae1dSRodney W. Grimes if (cmd == RTM_DELETE) { 2122b0a76b88SJulian Elischer /* 2123b0a76b88SJulian Elischer * It's a delete, so it should already exist.. 2124b0a76b88SJulian Elischer * If it's a net, mask off the host bits 2125b0a76b88SJulian Elischer * (Assuming we have a mask) 21268b07e49aSJulian Elischer * XXX this is kinda inet specific.. 2127b0a76b88SJulian Elischer */ 21288071913dSRuslan Ermilov if (netmask != NULL) { 21298b07e49aSJulian Elischer rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 21308b07e49aSJulian Elischer dst = (struct sockaddr *)tempbuf; 2131df8bae1dSRodney W. Grimes } 2132563ab4e4SAlexander V. Chernikov } else if (cmd == RTM_ADD) { 2133563ab4e4SAlexander V. Chernikov sdl = (struct sockaddr_dl *)tempbuf; 2134563ab4e4SAlexander V. Chernikov bzero(sdl, sizeof(struct sockaddr_dl)); 2135563ab4e4SAlexander V. Chernikov sdl->sdl_family = AF_LINK; 2136563ab4e4SAlexander V. Chernikov sdl->sdl_len = sizeof(struct sockaddr_dl); 2137563ab4e4SAlexander V. Chernikov sdl->sdl_type = ifa->ifa_ifp->if_type; 2138563ab4e4SAlexander V. Chernikov sdl->sdl_index = ifa->ifa_ifp->if_index; 21398b07e49aSJulian Elischer } 21408b07e49aSJulian Elischer /* 21418b07e49aSJulian Elischer * Now go through all the requested tables (fibs) and do the 21428b07e49aSJulian Elischer * requested action. Realistically, this will either be fib 0 21438b07e49aSJulian Elischer * for protocols that don't do multiple tables or all the 2144a8498625SBjoern A. Zeeb * tables for those that do. 21458b07e49aSJulian Elischer */ 21468b07e49aSJulian Elischer for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 21478b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 21488b07e49aSJulian Elischer struct radix_node *rn; 2149b0a76b88SJulian Elischer /* 21508071913dSRuslan Ermilov * Look up an rtentry that is in the routing tree and 21518071913dSRuslan Ermilov * contains the correct info. 2152b0a76b88SJulian Elischer */ 2153c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 2154c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 21558b07e49aSJulian Elischer /* this table doesn't exist but others might */ 21568b07e49aSJulian Elischer continue; 215761eee0e2SAlexander V. Chernikov RIB_RLOCK(rnh); 215861eee0e2SAlexander V. Chernikov rn = rnh->rnh_lookup(dst, netmask, &rnh->head); 2159e440aed9SQing Li #ifdef RADIX_MPATH 216061eee0e2SAlexander V. Chernikov if (rt_mpath_capable(rnh)) { 2161e440aed9SQing Li 2162e440aed9SQing Li if (rn == NULL) 2163e440aed9SQing Li error = ESRCH; 2164e440aed9SQing Li else { 2165e440aed9SQing Li rt = RNTORT(rn); 2166e440aed9SQing Li /* 21678b07e49aSJulian Elischer * for interface route the 21688b07e49aSJulian Elischer * rt->rt_gateway is sockaddr_intf 21698b07e49aSJulian Elischer * for cloning ARP entries, so 21708b07e49aSJulian Elischer * rt_mpath_matchgate must use the 21718b07e49aSJulian Elischer * interface address 2172e440aed9SQing Li */ 21738b07e49aSJulian Elischer rt = rt_mpath_matchgate(rt, 21748b07e49aSJulian Elischer ifa->ifa_addr); 2175034c09ffSAlexander V. Chernikov if (rt == NULL) 2176e440aed9SQing Li error = ESRCH; 2177e440aed9SQing Li } 2178e440aed9SQing Li } 2179e440aed9SQing Li #endif 21808b07e49aSJulian Elischer error = (rn == NULL || 21818071913dSRuslan Ermilov (rn->rn_flags & RNF_ROOT) || 21825a2f4cbdSAlexander V. Chernikov RNTORT(rn)->rt_ifa != ifa); 218361eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rnh); 2184956b0b65SJeffrey Hsu if (error) { 21858b07e49aSJulian Elischer /* this is only an error if bad on ALL tables */ 21868b07e49aSJulian Elischer continue; 2187df8bae1dSRodney W. Grimes } 2188b0a76b88SJulian Elischer } 2189b0a76b88SJulian Elischer /* 2190b0a76b88SJulian Elischer * Do the actual request 2191b0a76b88SJulian Elischer */ 21928071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 21938071913dSRuslan Ermilov info.rti_ifa = ifa; 21943034f43fSAlexander V. Chernikov info.rti_flags = flags | 21953034f43fSAlexander V. Chernikov (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; 21968071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 21976e6b3f7cSQing Li /* 21986e6b3f7cSQing Li * doing this for compatibility reasons 21996e6b3f7cSQing Li */ 22006e6b3f7cSQing Li if (cmd == RTM_ADD) 2201563ab4e4SAlexander V. Chernikov info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)sdl; 22026e6b3f7cSQing Li else 22038071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 22048071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 22058b07e49aSJulian Elischer error = rtrequest1_fib(cmd, &info, &rt, fibnum); 22065aca0b30SLuigi Rizzo if (error == 0 && rt != NULL) { 22078071913dSRuslan Ermilov /* 22086f99b44cSBrian Somers * notify any listening routing agents of the change 22098071913dSRuslan Ermilov */ 2210d1dd20beSSam Leffler RT_LOCK(rt); 2211e440aed9SQing Li #ifdef RADIX_MPATH 2212e440aed9SQing Li /* 2213e440aed9SQing Li * in case address alias finds the first address 22148d74af36SBjoern A. Zeeb * e.g. ifconfig bge0 192.0.2.246/24 22158d74af36SBjoern A. Zeeb * e.g. ifconfig bge0 192.0.2.247/24 22168d74af36SBjoern A. Zeeb * the address set in the route is 192.0.2.246 22178d74af36SBjoern A. Zeeb * so we need to replace it with 192.0.2.247 2218e440aed9SQing Li */ 22198b07e49aSJulian Elischer if (memcmp(rt->rt_ifa->ifa_addr, 22208b07e49aSJulian Elischer ifa->ifa_addr, ifa->ifa_addr->sa_len)) { 22211099f828SRobert Watson ifa_free(rt->rt_ifa); 22221099f828SRobert Watson ifa_ref(ifa); 2223e440aed9SQing Li rt->rt_ifp = ifa->ifa_ifp; 2224e440aed9SQing Li rt->rt_ifa = ifa; 2225e440aed9SQing Li } 2226e440aed9SQing Li #endif 22277f279720SMichael Tuexen RT_ADDREF(rt); 22287f279720SMichael Tuexen RT_UNLOCK(rt); 2229e02d3fe7SAlexander V. Chernikov rt_newaddrmsg_fib(cmd, ifa, rt, fibnum); 22307f279720SMichael Tuexen RT_LOCK(rt); 22317f279720SMichael Tuexen RT_REMREF(rt); 22328071913dSRuslan Ermilov if (cmd == RTM_DELETE) { 2233b0a76b88SJulian Elischer /* 22348b07e49aSJulian Elischer * If we are deleting, and we found an entry, 22358b07e49aSJulian Elischer * then it's been removed from the tree.. 22368b07e49aSJulian Elischer * now throw it away. 2237b0a76b88SJulian Elischer */ 2238d1dd20beSSam Leffler RTFREE_LOCKED(rt); 2239d1dd20beSSam Leffler } else { 2240d1dd20beSSam Leffler if (cmd == RTM_ADD) { 2241b0a76b88SJulian Elischer /* 22428b07e49aSJulian Elischer * We just wanted to add it.. 22438b07e49aSJulian Elischer * we don't actually need a reference. 2244b0a76b88SJulian Elischer */ 22457138d65cSSam Leffler RT_REMREF(rt); 2246df8bae1dSRodney W. Grimes } 2247d1dd20beSSam Leffler RT_UNLOCK(rt); 2248d1dd20beSSam Leffler } 22498b07e49aSJulian Elischer didwork = 1; 2250df8bae1dSRodney W. Grimes } 22518b07e49aSJulian Elischer if (error) 22528b07e49aSJulian Elischer a_failure = error; 22538b07e49aSJulian Elischer } 22548b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 22558b07e49aSJulian Elischer if (didwork) { 22568b07e49aSJulian Elischer error = 0; 22578b07e49aSJulian Elischer } else { 22588b07e49aSJulian Elischer /* we only give an error if it wasn't in any table */ 22598b07e49aSJulian Elischer error = ((flags & RTF_HOST) ? 22608b07e49aSJulian Elischer EHOSTUNREACH : ENETUNREACH); 22618b07e49aSJulian Elischer } 22628b07e49aSJulian Elischer } else { 22638b07e49aSJulian Elischer if (a_failure) { 22648b07e49aSJulian Elischer /* return an error if any of them failed */ 22658b07e49aSJulian Elischer error = a_failure; 22668b07e49aSJulian Elischer } 22678b07e49aSJulian Elischer } 22683ec66d6cSDavid Greenman return (error); 22693ec66d6cSDavid Greenman } 2270cb64988fSLuoqi Chen 22718b07e49aSJulian Elischer /* 22728b07e49aSJulian Elischer * Set up a routing table entry, normally 22738b07e49aSJulian Elischer * for an interface. 22748b07e49aSJulian Elischer */ 22758b07e49aSJulian Elischer int 22768b07e49aSJulian Elischer rtinit(struct ifaddr *ifa, int cmd, int flags) 22778b07e49aSJulian Elischer { 22788b07e49aSJulian Elischer struct sockaddr *dst; 2279a8498625SBjoern A. Zeeb int fib = RT_DEFAULT_FIB; 22808b07e49aSJulian Elischer 22818b07e49aSJulian Elischer if (flags & RTF_HOST) { 22828b07e49aSJulian Elischer dst = ifa->ifa_dstaddr; 22838b07e49aSJulian Elischer } else { 22848b07e49aSJulian Elischer dst = ifa->ifa_addr; 22858b07e49aSJulian Elischer } 22868b07e49aSJulian Elischer 2287b680a383SBjoern A. Zeeb switch (dst->sa_family) { 2288b680a383SBjoern A. Zeeb case AF_INET6: 2289b680a383SBjoern A. Zeeb case AF_INET: 2290b680a383SBjoern A. Zeeb /* We do support multiple FIBs. */ 22917d9b6df1SAlexander V. Chernikov fib = RT_ALL_FIBS; 2292b680a383SBjoern A. Zeeb break; 2293b680a383SBjoern A. Zeeb } 22948b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, fib)); 22958b07e49aSJulian Elischer } 22964cbac30bSAlexander V. Chernikov 22974cbac30bSAlexander V. Chernikov /* 22984cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 22994cbac30bSAlexander V. Chernikov * Returns 0 on success. 23004cbac30bSAlexander V. Chernikov */ 23014cbac30bSAlexander V. Chernikov int 23024cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 23034cbac30bSAlexander V. Chernikov { 23044cbac30bSAlexander V. Chernikov 23054cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 2306d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 2307d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 2308d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 23094cbac30bSAlexander V. Chernikov 2310d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 23114cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 23124cbac30bSAlexander V. Chernikov } 23134cbac30bSAlexander V. Chernikov 23144cbac30bSAlexander V. Chernikov /* 2315e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 2316e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 2317e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 2318e02d3fe7SAlexander V. Chernikov * @ifp: target route interface 2319e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 2320e02d3fe7SAlexander V. Chernikov * 23214cbac30bSAlexander V. Chernikov * Returns 0 on success. 23224cbac30bSAlexander V. Chernikov */ 23234cbac30bSAlexander V. Chernikov int 2324e02d3fe7SAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int rti_addrs, 23254cbac30bSAlexander V. Chernikov int fibnum) 23264cbac30bSAlexander V. Chernikov { 23274cbac30bSAlexander V. Chernikov 23284cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 2329d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 23304cbac30bSAlexander V. Chernikov 2331d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 2332d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 23334cbac30bSAlexander V. Chernikov 23344cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 23354cbac30bSAlexander V. Chernikov 2336e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, ifp, 0, fibnum)); 23374cbac30bSAlexander V. Chernikov } 23384cbac30bSAlexander V. Chernikov 2339e02d3fe7SAlexander V. Chernikov /* 2340e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 2341e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 2342e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 2343e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 2344e02d3fe7SAlexander V. Chernikov * 2345e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 2346e02d3fe7SAlexander V. Chernikov */ 2347e02d3fe7SAlexander V. Chernikov int 2348e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 23494cbac30bSAlexander V. Chernikov { 23504cbac30bSAlexander V. Chernikov 2351e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 2352e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 2353e02d3fe7SAlexander V. Chernikov 2354e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 2355e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 2356e02d3fe7SAlexander V. Chernikov 2357e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 2358e02d3fe7SAlexander V. Chernikov 2359e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 23604cbac30bSAlexander V. Chernikov } 23614cbac30bSAlexander V. Chernikov 2362e02d3fe7SAlexander V. Chernikov 23634cbac30bSAlexander V. Chernikov /* 23644cbac30bSAlexander V. Chernikov * This is called to generate messages from the routing socket 23654cbac30bSAlexander V. Chernikov * indicating a network interface has had addresses associated with it. 23664cbac30bSAlexander V. Chernikov */ 23674cbac30bSAlexander V. Chernikov void 2368e02d3fe7SAlexander V. Chernikov rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum) 23694cbac30bSAlexander V. Chernikov { 23704cbac30bSAlexander V. Chernikov 23714cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 23724cbac30bSAlexander V. Chernikov ("unexpected cmd %u", cmd)); 2373d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 2374d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 23754cbac30bSAlexander V. Chernikov 23764cbac30bSAlexander V. Chernikov if (cmd == RTM_ADD) { 23774cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 23784cbac30bSAlexander V. Chernikov if (rt != NULL) 2379e02d3fe7SAlexander V. Chernikov rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum); 23804cbac30bSAlexander V. Chernikov } else { 23814cbac30bSAlexander V. Chernikov if (rt != NULL) 2382e02d3fe7SAlexander V. Chernikov rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum); 23834cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 23844cbac30bSAlexander V. Chernikov } 23854cbac30bSAlexander V. Chernikov } 23864cbac30bSAlexander V. Chernikov 2387