1139823Simp/*- 21541Srgrimes * Copyright (c) 1980, 1986, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 29108270Sru * @(#)route.c 8.3.1.1 (Berkeley) 2/23/95 3050477Speter * $FreeBSD$ 311541Srgrimes */ 32178888Sjulian/************************************************************************ 33178888Sjulian * Note: In this file a 'fib' is a "forwarding information base" * 34178888Sjulian * Which is the new name for an in kernel routing (next hop) table. * 35178888Sjulian ***********************************************************************/ 361541Srgrimes 3732350Seivind#include "opt_inet.h" 38231852Sbz#include "opt_inet6.h" 39178888Sjulian#include "opt_route.h" 40265717Smelifaro#include "opt_sctp.h" 4114328Speter#include "opt_mrouting.h" 42178167Sqingli#include "opt_mpath.h" 4314328Speter 441541Srgrimes#include <sys/param.h> 451541Srgrimes#include <sys/systm.h> 46186119Sqingli#include <sys/syslog.h> 4729024Sbde#include <sys/malloc.h> 481541Srgrimes#include <sys/mbuf.h> 491541Srgrimes#include <sys/socket.h> 50178888Sjulian#include <sys/sysctl.h> 51185747Skmacy#include <sys/syslog.h> 52178888Sjulian#include <sys/sysproto.h> 53178888Sjulian#include <sys/proc.h> 541541Srgrimes#include <sys/domain.h> 5546161Sluoqi#include <sys/kernel.h> 561541Srgrimes 571541Srgrimes#include <net/if.h> 58186119Sqingli#include <net/if_dl.h> 591541Srgrimes#include <net/route.h> 60196019Srwatson#include <net/vnet.h> 61197687Sqingli#include <net/flowtable.h> 621541Srgrimes 63178167Sqingli#ifdef RADIX_MPATH 64178167Sqingli#include <net/radix_mpath.h> 65178167Sqingli#endif 66178167Sqingli 671541Srgrimes#include <netinet/in.h> 687090Sbde#include <netinet/ip_mroute.h> 691541Srgrimes 70133513Sandre#include <vm/uma.h> 71133513Sandre 72250700Sjulian#define RT_MAXFIBS UINT16_MAX 73233113Sbz 74233113Sbz/* Kernel config default option. */ 75233113Sbz#ifdef ROUTETABLES 76233113Sbz#if ROUTETABLES <= 0 77233113Sbz#error "ROUTETABLES defined too low" 78233113Sbz#endif 79233113Sbz#if ROUTETABLES > RT_MAXFIBS 80233113Sbz#error "ROUTETABLES defined too big" 81233113Sbz#endif 82233113Sbz#define RT_NUMFIBS ROUTETABLES 83233113Sbz#endif /* ROUTETABLES */ 84233113Sbz/* Initialize to default if not otherwise set. */ 85233113Sbz#ifndef RT_NUMFIBS 86233113Sbz#define RT_NUMFIBS 1 87233113Sbz#endif 88233113Sbz 89265717Smelifaro#if defined(INET) || defined(INET6) 90265717Smelifaro#ifdef SCTP 91265717Smelifaroextern void sctp_addr_change(struct ifaddr *ifa, int cmd); 92265717Smelifaro#endif /* SCTP */ 93265717Smelifaro#endif 94265717Smelifaro 95265717Smelifaro 96250700Sjulian/* This is read-only.. */ 97178888Sjulianu_int rt_numfibs = RT_NUMFIBS; 98217322SmdfSYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, ""); 99250700Sjulian/* and this can be set too big but will be fixed before it is used */ 100178888SjulianTUNABLE_INT("net.fibs", &rt_numfibs); 101178888Sjulian 102180840Sjulian/* 103180840Sjulian * By default add routes to all fibs for new interfaces. 104180840Sjulian * Once this is set to 0 then only allocate routes on interface 105180840Sjulian * changes for the FIB of the caller when adding a new set of addresses 106180840Sjulian * to an interface. XXX this is a shotgun aproach to a problem that needs 107180840Sjulian * a more fine grained solution.. that will come. 108231852Sbz * XXX also has the problems getting the FIB from curthread which will not 109231852Sbz * always work given the fib can be overridden and prefixes can be added 110231852Sbz * from the network stack context. 111180840Sjulian */ 112180840Sjulianu_int rt_add_addr_allfibs = 1; 113217322SmdfSYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW, 114180840Sjulian &rt_add_addr_allfibs, 0, ""); 115180840SjulianTUNABLE_INT("net.add_addr_allfibs", &rt_add_addr_allfibs); 116180840Sjulian 117195699SrwatsonVNET_DEFINE(struct rtstat, rtstat); 118207369Sbz#define V_rtstat VNET(rtstat) 1191541Srgrimes 120207369SbzVNET_DEFINE(struct radix_node_head *, rt_tables); 121195727Srwatson#define V_rt_tables VNET(rt_tables) 122207369Sbz 123207369SbzVNET_DEFINE(int, rttrash); /* routes not in table but not freed */ 124195727Srwatson#define V_rttrash VNET(rttrash) 125194640Sbz 12612820Sphk 127128524Sluigi/* compare two sockaddr structures */ 128265717Smelifaro#define sa_equal(a1, a2) (((a1)->sa_len == (a2)->sa_len) && \ 129265717Smelifaro (bcmp((a1), (a2), (a1)->sa_len) == 0)) 130128524Sluigi 131128524Sluigi/* 132128524Sluigi * Convert a 'struct radix_node *' to a 'struct rtentry *'. 133128524Sluigi * The operation can be done safely (in this code) because a 134128524Sluigi * 'struct rtentry' starts with two 'struct radix_node''s, the first 135128524Sluigi * one representing leaf nodes in the routing tree, which is 136128524Sluigi * what the code in radix.c passes us as a 'struct radix_node'. 137128524Sluigi * 138128524Sluigi * But because there are a lot of assumptions in this conversion, 139128524Sluigi * do not cast explicitly, but always use the macro below. 140128524Sluigi */ 141128524Sluigi#define RNTORT(p) ((struct rtentry *)(p)) 142128524Sluigi 143215701Sdimstatic VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ 144207369Sbz#define V_rtzone VNET(rtzone) 145207369Sbz 146178888Sjulian/* 147178888Sjulian * handler for net.my_fibnum 148178888Sjulian */ 149178888Sjulianstatic int 150178888Sjuliansysctl_my_fibnum(SYSCTL_HANDLER_ARGS) 1511541Srgrimes{ 152178888Sjulian int fibnum; 153178888Sjulian int error; 154178888Sjulian 155178888Sjulian fibnum = curthread->td_proc->p_fibnum; 156178888Sjulian error = sysctl_handle_int(oidp, &fibnum, 0, req); 157178888Sjulian return (error); 1581541Srgrimes} 1591541Srgrimes 160178888SjulianSYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, 161178888Sjulian NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); 162133513Sandre 163193232Sbzstatic __inline struct radix_node_head ** 164193232Sbzrt_tables_get_rnh_ptr(int table, int fam) 165193232Sbz{ 166193232Sbz struct radix_node_head **rnh; 167193232Sbz 168193232Sbz KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", 169193232Sbz __func__)); 170193232Sbz KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.", 171193232Sbz __func__)); 172193232Sbz 173193232Sbz /* rnh is [fib=0][af=0]. */ 174193232Sbz rnh = (struct radix_node_head **)V_rt_tables; 175193232Sbz /* Get the offset to the requested table and fam. */ 176193232Sbz rnh += table * (AF_MAX+1) + fam; 177193232Sbz 178193232Sbz return (rnh); 179193232Sbz} 180193232Sbz 181193232Sbzstruct radix_node_head * 182193232Sbzrt_tables_get_rnh(int table, int fam) 183193232Sbz{ 184193232Sbz 185193232Sbz return (*rt_tables_get_rnh_ptr(table, fam)); 186193232Sbz} 187193232Sbz 188195837Srwatson/* 189195837Srwatson * route initialization must occur before ip6_init2(), which happenas at 190195837Srwatson * SI_ORDER_MIDDLE. 191195837Srwatson */ 192128357Sluigistatic void 193128357Sluigiroute_init(void) 1941541Srgrimes{ 195200537Sluigi struct domain *dom; 196200537Sluigi int max_keylen = 0; 197178888Sjulian 198178898Sjulian /* whack the tunable ints into line. */ 199178888Sjulian if (rt_numfibs > RT_MAXFIBS) 200178888Sjulian rt_numfibs = RT_MAXFIBS; 201178888Sjulian if (rt_numfibs == 0) 202178888Sjulian rt_numfibs = 1; 203200537Sluigi 204200537Sluigi for (dom = domains; dom; dom = dom->dom_next) 205200537Sluigi if (dom->dom_maxrtkey > max_keylen) 206200537Sluigi max_keylen = dom->dom_maxrtkey; 207200537Sluigi 208200537Sluigi rn_init(max_keylen); /* init all zeroes, all ones, mask table */ 209190787Szec} 210195837SrwatsonSYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); 211190787Szec 212263478Sglebiusstatic int 213263478Sglebiusrtentry_zinit(void *mem, int size, int how) 214263478Sglebius{ 215263478Sglebius struct rtentry *rt = mem; 216263478Sglebius 217263478Sglebius rt->rt_pksent = counter_u64_alloc(how); 218263478Sglebius if (rt->rt_pksent == NULL) 219263478Sglebius return (ENOMEM); 220263478Sglebius 221263478Sglebius RT_LOCK_INIT(rt); 222263478Sglebius 223263478Sglebius return (0); 224263478Sglebius} 225263478Sglebius 226195837Srwatsonstatic void 227263478Sglebiusrtentry_zfini(void *mem, int size) 228263478Sglebius{ 229263478Sglebius struct rtentry *rt = mem; 230263478Sglebius 231263478Sglebius RT_LOCK_DESTROY(rt); 232263478Sglebius counter_u64_free(rt->rt_pksent); 233263478Sglebius} 234263478Sglebius 235263478Sglebiusstatic int 236263478Sglebiusrtentry_ctor(void *mem, int size, void *arg, int how) 237263478Sglebius{ 238263478Sglebius struct rtentry *rt = mem; 239263478Sglebius 240263478Sglebius bzero(rt, offsetof(struct rtentry, rt_endzero)); 241263478Sglebius counter_u64_zero(rt->rt_pksent); 242263478Sglebius 243263478Sglebius return (0); 244263478Sglebius} 245263478Sglebius 246263478Sglebiusstatic void 247263478Sglebiusrtentry_dtor(void *mem, int size, void *arg) 248263478Sglebius{ 249263478Sglebius struct rtentry *rt = mem; 250263478Sglebius 251263478Sglebius RT_UNLOCK_COND(rt); 252263478Sglebius} 253263478Sglebius 254263478Sglebiusstatic void 255195837Srwatsonvnet_route_init(const void *unused __unused) 256190787Szec{ 257193232Sbz struct domain *dom; 258193232Sbz struct radix_node_head **rnh; 259190787Szec int table; 260190787Szec int fam; 261190787Szec 262193232Sbz V_rt_tables = malloc(rt_numfibs * (AF_MAX+1) * 263193232Sbz sizeof(struct radix_node_head *), M_RTABLE, M_WAITOK|M_ZERO); 264193232Sbz 265263478Sglebius V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), 266263478Sglebius rtentry_ctor, rtentry_dtor, 267263478Sglebius rtentry_zinit, rtentry_zfini, UMA_ALIGN_PTR, 0); 268178888Sjulian for (dom = domains; dom; dom = dom->dom_next) { 269231852Sbz if (dom->dom_rtattach == NULL) 270231852Sbz continue; 271231852Sbz 272231852Sbz for (table = 0; table < rt_numfibs; table++) { 273231852Sbz fam = dom->dom_family; 274231852Sbz if (table != 0 && fam != AF_INET6 && fam != AF_INET) 275231852Sbz break; 276231852Sbz 277231852Sbz /* 278231852Sbz * XXX MRT rtattach will be also called from 279231852Sbz * vfs_export.c but the offset will be 0 (only for 280231852Sbz * AF_INET and AF_INET6 which don't need it anyhow). 281231852Sbz */ 282231852Sbz rnh = rt_tables_get_rnh_ptr(table, fam); 283231852Sbz if (rnh == NULL) 284231852Sbz panic("%s: rnh NULL", __func__); 285231852Sbz dom->dom_rtattach((void **)rnh, dom->dom_rtoffset); 286178888Sjulian } 287178888Sjulian } 2881541Srgrimes} 289195837SrwatsonVNET_SYSINIT(vnet_route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 290195837Srwatson vnet_route_init, 0); 2911541Srgrimes 292193731Szec#ifdef VIMAGE 293195837Srwatsonstatic void 294195837Srwatsonvnet_route_uninit(const void *unused __unused) 295193731Szec{ 296193731Szec int table; 297193731Szec int fam; 298193731Szec struct domain *dom; 299193731Szec struct radix_node_head **rnh; 300193731Szec 301193731Szec for (dom = domains; dom; dom = dom->dom_next) { 302231852Sbz if (dom->dom_rtdetach == NULL) 303231852Sbz continue; 304231852Sbz 305231852Sbz for (table = 0; table < rt_numfibs; table++) { 306231852Sbz fam = dom->dom_family; 307231852Sbz 308231852Sbz if (table != 0 && fam != AF_INET6 && fam != AF_INET) 309231852Sbz break; 310231852Sbz 311231852Sbz rnh = rt_tables_get_rnh_ptr(table, fam); 312231852Sbz if (rnh == NULL) 313231852Sbz panic("%s: rnh NULL", __func__); 314231852Sbz dom->dom_rtdetach((void **)rnh, dom->dom_rtoffset); 315193731Szec } 316193731Szec } 317258913Srodrigc 318258913Srodrigc free(V_rt_tables, M_RTABLE); 319258913Srodrigc uma_zdestroy(V_rtzone); 320193731Szec} 321195837SrwatsonVNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, 322195837Srwatson vnet_route_uninit, 0); 323193731Szec#endif 324193731Szec 325178888Sjulian#ifndef _SYS_SYSPROTO_H_ 326178888Sjulianstruct setfib_args { 327178888Sjulian int fibnum; 328178888Sjulian}; 329178888Sjulian#endif 330178888Sjulianint 331225617Skmacysys_setfib(struct thread *td, struct setfib_args *uap) 332178888Sjulian{ 333178888Sjulian if (uap->fibnum < 0 || uap->fibnum >= rt_numfibs) 334178888Sjulian return EINVAL; 335178888Sjulian td->td_proc->p_fibnum = uap->fibnum; 336178888Sjulian return (0); 337178888Sjulian} 338178888Sjulian 3391541Srgrimes/* 3401541Srgrimes * Packet routing routines. 3411541Srgrimes */ 3421541Srgrimesvoid 343120727Ssamrtalloc(struct route *ro) 3441541Srgrimes{ 345231852Sbz 346231852Sbz rtalloc_ign_fib(ro, 0UL, RT_DEFAULT_FIB); 3471541Srgrimes} 3481541Srgrimes 3495104Swollmanvoid 350178888Sjulianrtalloc_fib(struct route *ro, u_int fibnum) 351178888Sjulian{ 352178888Sjulian rtalloc_ign_fib(ro, 0UL, fibnum); 353178888Sjulian} 354178888Sjulian 355178888Sjulianvoid 356120727Ssamrtalloc_ign(struct route *ro, u_long ignore) 3575104Swollman{ 35854369Sjdp struct rtentry *rt; 35954369Sjdp 36054369Sjdp if ((rt = ro->ro_rt) != NULL) { 36154369Sjdp if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 36254369Sjdp return; 36354369Sjdp RTFREE(rt); 36456030Sshin ro->ro_rt = NULL; 36554369Sjdp } 366231852Sbz ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, RT_DEFAULT_FIB); 367120727Ssam if (ro->ro_rt) 368120727Ssam RT_UNLOCK(ro->ro_rt); 3695104Swollman} 3705104Swollman 371178888Sjulianvoid 372178888Sjulianrtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum) 373178888Sjulian{ 374178888Sjulian struct rtentry *rt; 375178888Sjulian 376178888Sjulian if ((rt = ro->ro_rt) != NULL) { 377178888Sjulian if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) 378178888Sjulian return; 379178888Sjulian RTFREE(rt); 380178888Sjulian ro->ro_rt = NULL; 381178888Sjulian } 382178888Sjulian ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, fibnum); 383178888Sjulian if (ro->ro_rt) 384178888Sjulian RT_UNLOCK(ro->ro_rt); 385178888Sjulian} 386178888Sjulian 38718206Sjulian/* 38818206Sjulian * Look up the route that matches the address given 38918206Sjulian * Or, at least try.. Create a cloned route if needed. 390120727Ssam * 391120727Ssam * The returned route, if any, is locked. 39218206Sjulian */ 3931541Srgrimesstruct rtentry * 394120727Ssamrtalloc1(struct sockaddr *dst, int report, u_long ignflags) 3951541Srgrimes{ 396231852Sbz 397231852Sbz return (rtalloc1_fib(dst, report, ignflags, RT_DEFAULT_FIB)); 398178888Sjulian} 399178888Sjulian 400178888Sjulianstruct rtentry * 401178888Sjulianrtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, 402178888Sjulian u_int fibnum) 403178888Sjulian{ 404178888Sjulian struct radix_node_head *rnh; 405120727Ssam struct radix_node *rn; 406120727Ssam struct rtentry *newrt; 4071541Srgrimes struct rt_addrinfo info; 408186119Sqingli int err = 0, msgtype = RTM_MISS; 409185747Skmacy int needlock; 4101541Srgrimes 411178888Sjulian KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); 412231852Sbz switch (dst->sa_family) { 413231852Sbz case AF_INET6: 414231852Sbz case AF_INET: 415231852Sbz /* We support multiple FIBs. */ 416231852Sbz break; 417231852Sbz default: 418231852Sbz fibnum = RT_DEFAULT_FIB; 419231852Sbz break; 420231852Sbz } 421193232Sbz rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 422219786Sdchagin newrt = NULL; 423219783Sdchagin if (rnh == NULL) 424219783Sdchagin goto miss; 425219783Sdchagin 42653541Sshin /* 42718206Sjulian * Look up the address in the table for that Address Family 42818206Sjulian */ 429185747Skmacy needlock = !(ignflags & RTF_RNH_LOCKED); 430185747Skmacy if (needlock) 431185747Skmacy RADIX_NODE_HEAD_RLOCK(rnh); 432185747Skmacy#ifdef INVARIANTS 433185747Skmacy else 434185747Skmacy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 435185747Skmacy#endif 436185747Skmacy rn = rnh->rnh_matchaddr(dst, rnh); 437185747Skmacy if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { 438219776Sdchagin newrt = RNTORT(rn); 439186119Sqingli RT_LOCK(newrt); 440186119Sqingli RT_ADDREF(newrt); 441186119Sqingli if (needlock) 442186119Sqingli RADIX_NODE_HEAD_RUNLOCK(rnh); 443186119Sqingli goto done; 444185747Skmacy 445186119Sqingli } else if (needlock) 446186167Skmacy RADIX_NODE_HEAD_RUNLOCK(rnh); 447186119Sqingli 448185747Skmacy /* 449186119Sqingli * Either we hit the root or couldn't find any match, 450186119Sqingli * Which basically means 451186119Sqingli * "caint get there frm here" 452185747Skmacy */ 453219783Sdchaginmiss: 454186119Sqingli V_rtstat.rts_unreach++; 455219783Sdchagin 456186119Sqingli if (report) { 457185747Skmacy /* 458186119Sqingli * If required, report the failure to the supervising 459186119Sqingli * Authorities. 460186119Sqingli * For a delete, this is not an error. (report == 0) 461185747Skmacy */ 462185747Skmacy bzero(&info, sizeof(info)); 463186119Sqingli info.rti_info[RTAX_DST] = dst; 464225837Sbz rt_missmsg_fib(msgtype, &info, 0, err, fibnum); 465186119Sqingli } 466185747Skmacydone: 467120727Ssam if (newrt) 468120727Ssam RT_LOCK_ASSERT(newrt); 4691541Srgrimes return (newrt); 4701541Srgrimes} 4711541Srgrimes 47223392Sjulian/* 47323392Sjulian * Remove a reference count from an rtentry. 47423392Sjulian * If the count gets low enough, take it out of the routing table 47523392Sjulian */ 4761541Srgrimesvoid 477120727Ssamrtfree(struct rtentry *rt) 4781541Srgrimes{ 479128455Sluigi struct radix_node_head *rnh; 4801541Srgrimes 481169872Sglebius KASSERT(rt != NULL,("%s: NULL rt", __func__)); 482193232Sbz rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 483169872Sglebius KASSERT(rnh != NULL,("%s: NULL rnh", __func__)); 48423392Sjulian 485120727Ssam RT_LOCK_ASSERT(rt); 486120727Ssam 48723392Sjulian /* 488169872Sglebius * The callers should use RTFREE_LOCKED() or RTFREE(), so 489169872Sglebius * we should come here exactly with the last reference. 49023392Sjulian */ 491122334Ssam RT_REMREF(rt); 492169872Sglebius if (rt->rt_refcnt > 0) { 493186705Sqingli log(LOG_DEBUG, "%s: %p has %d refs\n", __func__, rt, rt->rt_refcnt); 494120727Ssam goto done; 495169872Sglebius } 496121770Ssam 497121770Ssam /* 498121770Ssam * On last reference give the "close method" a chance 499121770Ssam * to cleanup private state. This also permits (for 500121770Ssam * IPv4 and IPv6) a chance to decide if the routing table 501121770Ssam * entry should be purged immediately or at a later time. 502121770Ssam * When an immediate purge is to happen the close routine 503121770Ssam * typically calls rtexpunge which clears the RTF_UP flag 504121770Ssam * on the entry so that the code below reclaims the storage. 505121770Ssam */ 506120727Ssam if (rt->rt_refcnt == 0 && rnh->rnh_close) 5074073Swollman rnh->rnh_close((struct radix_node *)rt, rnh); 50823392Sjulian 50923392Sjulian /* 51023392Sjulian * If we are no longer "up" (and ref == 0) 51123392Sjulian * then we can free the resources associated 51223392Sjulian * with the route. 51323392Sjulian */ 514120727Ssam if ((rt->rt_flags & RTF_UP) == 0) { 5151541Srgrimes if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 516169872Sglebius panic("rtfree 2"); 51753541Sshin /* 51823392Sjulian * the rtentry must have been removed from the routing table 51923392Sjulian * so it is represented in rttrash.. remove that now. 52023392Sjulian */ 521181803Sbz V_rttrash--; 52223392Sjulian#ifdef DIAGNOSTIC 5231541Srgrimes if (rt->rt_refcnt < 0) { 5243311Sphk printf("rtfree: %p not freed (neg refs)\n", rt); 525120727Ssam goto done; 5261541Srgrimes } 52723392Sjulian#endif 52853541Sshin /* 52923392Sjulian * release references on items we hold them on.. 53023392Sjulian * e.g other routes and ifaddrs. 53123392Sjulian */ 532108033Shsu if (rt->rt_ifa) 533194602Srwatson ifa_free(rt->rt_ifa); 53423392Sjulian /* 53523392Sjulian * The key is separatly alloc'd so free it (see rt_setgate()). 53623392Sjulian * This also frees the gateway, as they are always malloc'd 53723392Sjulian * together. 53823392Sjulian */ 5391541Srgrimes Free(rt_key(rt)); 54023392Sjulian 54123392Sjulian /* 54223392Sjulian * and the rtentry itself of course 54323392Sjulian */ 544190787Szec uma_zfree(V_rtzone, rt); 545120727Ssam return; 5461541Srgrimes } 547120727Ssamdone: 548120727Ssam RT_UNLOCK(rt); 5491541Srgrimes} 5501541Srgrimes 5511541Srgrimes 5521541Srgrimes/* 5531541Srgrimes * Force a routing table entry to the specified 5541541Srgrimes * destination to go through the given gateway. 5551541Srgrimes * Normally called as a result of a routing redirect 5561541Srgrimes * message from the network layer. 5571541Srgrimes */ 5581549Srgrimesvoid 559120727Ssamrtredirect(struct sockaddr *dst, 560120727Ssam struct sockaddr *gateway, 561120727Ssam struct sockaddr *netmask, 562120727Ssam int flags, 563120727Ssam struct sockaddr *src) 5641541Srgrimes{ 565231852Sbz 566231852Sbz rtredirect_fib(dst, gateway, netmask, flags, src, RT_DEFAULT_FIB); 567178888Sjulian} 568178888Sjulian 569178888Sjulianvoid 570178888Sjulianrtredirect_fib(struct sockaddr *dst, 571178888Sjulian struct sockaddr *gateway, 572178888Sjulian struct sockaddr *netmask, 573178888Sjulian int flags, 574178888Sjulian struct sockaddr *src, 575178888Sjulian u_int fibnum) 576178888Sjulian{ 577174559Skmacy struct rtentry *rt, *rt0 = NULL; 5781541Srgrimes int error = 0; 579128455Sluigi short *stat = NULL; 5801541Srgrimes struct rt_addrinfo info; 5811541Srgrimes struct ifaddr *ifa; 582193232Sbz struct radix_node_head *rnh; 5831541Srgrimes 584194760Srwatson ifa = NULL; 585193232Sbz rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 586193232Sbz if (rnh == NULL) { 587193232Sbz error = EAFNOSUPPORT; 588193232Sbz goto out; 589193232Sbz } 590193232Sbz 5911541Srgrimes /* verify the gateway is directly reachable */ 592267186Sasomers if ((ifa = ifa_ifwithnet_fib(gateway, 0, fibnum)) == NULL) { 5931541Srgrimes error = ENETUNREACH; 5941541Srgrimes goto out; 5951541Srgrimes } 596178888Sjulian rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ 5971541Srgrimes /* 5981541Srgrimes * If the redirect isn't from our current router for this dst, 5991541Srgrimes * it's either old or wrong. If it redirects us to ourselves, 6001541Srgrimes * we have a routing loop, perhaps as a result of an interface 6011541Srgrimes * going down recently. 6021541Srgrimes */ 6031541Srgrimes if (!(flags & RTF_DONE) && rt && 604108250Shsu (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) 6051541Srgrimes error = EINVAL; 606194622Srwatson else if (ifa_ifwithaddr_check(gateway)) 6071541Srgrimes error = EHOSTUNREACH; 6081541Srgrimes if (error) 6091541Srgrimes goto done; 6101541Srgrimes /* 6111541Srgrimes * Create a new entry if we just got back a wildcard entry 612218909Sbrucec * or the lookup failed. This is necessary for hosts 6131541Srgrimes * which use routing redirects generated by smart gateways 6141541Srgrimes * to dynamically build the routing tables. 6151541Srgrimes */ 616128455Sluigi if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) 6171541Srgrimes goto create; 6181541Srgrimes /* 6191541Srgrimes * Don't listen to the redirect if it's 6208876Srgrimes * for a route to an interface. 6211541Srgrimes */ 6221541Srgrimes if (rt->rt_flags & RTF_GATEWAY) { 6231541Srgrimes if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { 6241541Srgrimes /* 6251541Srgrimes * Changing from route to net => route to host. 6261541Srgrimes * Create new route, rather than smashing route to net. 6271541Srgrimes */ 6281541Srgrimes create: 629174559Skmacy rt0 = rt; 630174559Skmacy rt = NULL; 631174559Skmacy 6321541Srgrimes flags |= RTF_GATEWAY | RTF_DYNAMIC; 63385074Sru bzero((caddr_t)&info, sizeof(info)); 63485074Sru info.rti_info[RTAX_DST] = dst; 63585074Sru info.rti_info[RTAX_GATEWAY] = gateway; 63685074Sru info.rti_info[RTAX_NETMASK] = netmask; 63785074Sru info.rti_ifa = ifa; 63885074Sru info.rti_flags = flags; 639185747Skmacy if (rt0 != NULL) 640185747Skmacy RT_UNLOCK(rt0); /* drop lock to avoid LOR with RNH */ 641178888Sjulian error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); 642120727Ssam if (rt != NULL) { 643120820Ssam RT_LOCK(rt); 644185747Skmacy if (rt0 != NULL) 645185747Skmacy EVENTHANDLER_INVOKE(route_redirect_event, rt0, rt, dst); 64685074Sru flags = rt->rt_flags; 647120727Ssam } 648185747Skmacy if (rt0 != NULL) 649185747Skmacy RTFREE(rt0); 650174559Skmacy 651181803Sbz stat = &V_rtstat.rts_dynamic; 6521541Srgrimes } else { 653174559Skmacy struct rtentry *gwrt; 654174559Skmacy 6551541Srgrimes /* 6561541Srgrimes * Smash the current notion of the gateway to 6571541Srgrimes * this destination. Should check about netmask!!! 6581541Srgrimes */ 6591541Srgrimes rt->rt_flags |= RTF_MODIFIED; 6601541Srgrimes flags |= RTF_MODIFIED; 661181803Sbz stat = &V_rtstat.rts_newgateway; 66223392Sjulian /* 66323392Sjulian * add the key and gateway (in one malloc'd chunk). 66423392Sjulian */ 665185747Skmacy RT_UNLOCK(rt); 666185747Skmacy RADIX_NODE_HEAD_LOCK(rnh); 667185747Skmacy RT_LOCK(rt); 6681541Srgrimes rt_setgate(rt, rt_key(rt), gateway); 669185747Skmacy gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED); 670185747Skmacy RADIX_NODE_HEAD_UNLOCK(rnh); 671174703Skmacy EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst); 672174559Skmacy RTFREE_LOCKED(gwrt); 6731541Srgrimes } 6741541Srgrimes } else 6751541Srgrimes error = EHOSTUNREACH; 6761541Srgrimesdone: 677120727Ssam if (rt) 678176244Sjhb RTFREE_LOCKED(rt); 6791541Srgrimesout: 6801541Srgrimes if (error) 681181803Sbz V_rtstat.rts_badredirect++; 6821541Srgrimes else if (stat != NULL) 6831541Srgrimes (*stat)++; 6841541Srgrimes bzero((caddr_t)&info, sizeof(info)); 6851541Srgrimes info.rti_info[RTAX_DST] = dst; 6861541Srgrimes info.rti_info[RTAX_GATEWAY] = gateway; 6871541Srgrimes info.rti_info[RTAX_NETMASK] = netmask; 6881541Srgrimes info.rti_info[RTAX_AUTHOR] = src; 689225837Sbz rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); 690194760Srwatson if (ifa != NULL) 691194760Srwatson ifa_free(ifa); 6921541Srgrimes} 6931541Srgrimes 694178888Sjulianint 695178888Sjulianrtioctl(u_long req, caddr_t data) 696178888Sjulian{ 697231852Sbz 698231852Sbz return (rtioctl_fib(req, data, RT_DEFAULT_FIB)); 699178888Sjulian} 700178888Sjulian 7011541Srgrimes/* 702108033Shsu * Routing table ioctl interface. 703108033Shsu */ 7041541Srgrimesint 705178888Sjulianrtioctl_fib(u_long req, caddr_t data, u_int fibnum) 7061541Srgrimes{ 707134122Scsjp 708134122Scsjp /* 709134122Scsjp * If more ioctl commands are added here, make sure the proper 710134122Scsjp * super-user checks are being performed because it is possible for 711134122Scsjp * prison-root to make it this far if raw sockets have been enabled 712134122Scsjp * in jails. 713134122Scsjp */ 7143311Sphk#ifdef INET 7152531Swollman /* Multicast goop, grrr... */ 716178888Sjulian return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 7173311Sphk#else /* INET */ 7183311Sphk return ENXIO; 7193311Sphk#endif /* INET */ 7201541Srgrimes} 7211541Srgrimes 722194760Srwatson/* 723194760Srwatson * For both ifa_ifwithroute() routines, 'ifa' is returned referenced. 724194760Srwatson */ 7251541Srgrimesstruct ifaddr * 726120727Ssamifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway) 7271541Srgrimes{ 728231852Sbz 729231852Sbz return (ifa_ifwithroute_fib(flags, dst, gateway, RT_DEFAULT_FIB)); 730178888Sjulian} 731178888Sjulian 732178888Sjulianstruct ifaddr * 733178888Sjulianifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway, 734178888Sjulian u_int fibnum) 735178888Sjulian{ 7361541Srgrimes register struct ifaddr *ifa; 737158661Sqingli int not_found = 0; 738120727Ssam 7391541Srgrimes if ((flags & RTF_GATEWAY) == 0) { 7401541Srgrimes /* 7411541Srgrimes * If we are adding a route to an interface, 7421541Srgrimes * and the interface is a pt to pt link 7431541Srgrimes * we should search for the destination 7441541Srgrimes * as our clue to the interface. Otherwise 7451541Srgrimes * we can use the local address. 7461541Srgrimes */ 747128455Sluigi ifa = NULL; 748128455Sluigi if (flags & RTF_HOST) 749267186Sasomers ifa = ifa_ifwithdstaddr_fib(dst, fibnum); 750128455Sluigi if (ifa == NULL) 7511541Srgrimes ifa = ifa_ifwithaddr(gateway); 7521541Srgrimes } else { 7531541Srgrimes /* 7541541Srgrimes * If we are adding a route to a remote net 7551541Srgrimes * or host, the gateway may still be on the 7561541Srgrimes * other end of a pt to pt link. 7571541Srgrimes */ 758267186Sasomers ifa = ifa_ifwithdstaddr_fib(gateway, fibnum); 7591541Srgrimes } 760128455Sluigi if (ifa == NULL) 761267186Sasomers ifa = ifa_ifwithnet_fib(gateway, 0, fibnum); 762128455Sluigi if (ifa == NULL) { 763185849Skmacy struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum); 764128455Sluigi if (rt == NULL) 765128455Sluigi return (NULL); 766158661Sqingli /* 767158661Sqingli * dismiss a gateway that is reachable only 768158661Sqingli * through the default router 769158661Sqingli */ 770158661Sqingli switch (gateway->sa_family) { 771158661Sqingli case AF_INET: 772158661Sqingli if (satosin(rt_key(rt))->sin_addr.s_addr == INADDR_ANY) 773158661Sqingli not_found = 1; 774158661Sqingli break; 775158661Sqingli case AF_INET6: 776158661Sqingli if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(rt_key(rt))->sin6_addr)) 777158661Sqingli not_found = 1; 778158661Sqingli break; 779158661Sqingli default: 780158661Sqingli break; 781158661Sqingli } 782194760Srwatson if (!not_found && rt->rt_ifa != NULL) { 783194760Srwatson ifa = rt->rt_ifa; 784194760Srwatson ifa_ref(ifa); 785194760Srwatson } 786122334Ssam RT_REMREF(rt); 787120727Ssam RT_UNLOCK(rt); 788194760Srwatson if (not_found || ifa == NULL) 789158661Sqingli return (NULL); 7901541Srgrimes } 7911541Srgrimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 7921541Srgrimes struct ifaddr *oifa = ifa; 7931541Srgrimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 794128455Sluigi if (ifa == NULL) 7951541Srgrimes ifa = oifa; 796194760Srwatson else 797194760Srwatson ifa_free(oifa); 7981541Srgrimes } 7991541Srgrimes return (ifa); 8001541Srgrimes} 8011541Srgrimes 80218206Sjulian/* 80318206Sjulian * Do appropriate manipulations of a routing tree given 80418206Sjulian * all the bits of info needed 80518206Sjulian */ 8061541Srgrimesint 807120727Ssamrtrequest(int req, 808120727Ssam struct sockaddr *dst, 809120727Ssam struct sockaddr *gateway, 810120727Ssam struct sockaddr *netmask, 811120727Ssam int flags, 812120727Ssam struct rtentry **ret_nrt) 8131541Srgrimes{ 814231852Sbz 815231852Sbz return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 816231852Sbz RT_DEFAULT_FIB)); 817178888Sjulian} 818178888Sjulian 819178888Sjulianint 820178888Sjulianrtrequest_fib(int req, 821178888Sjulian struct sockaddr *dst, 822178888Sjulian struct sockaddr *gateway, 823178888Sjulian struct sockaddr *netmask, 824178888Sjulian int flags, 825178888Sjulian struct rtentry **ret_nrt, 826178888Sjulian u_int fibnum) 827178888Sjulian{ 82885074Sru struct rt_addrinfo info; 82985074Sru 830158294Sbz if (dst->sa_len == 0) 831158294Sbz return(EINVAL); 832158294Sbz 83385074Sru bzero((caddr_t)&info, sizeof(info)); 83485074Sru info.rti_flags = flags; 83585074Sru info.rti_info[RTAX_DST] = dst; 83685074Sru info.rti_info[RTAX_GATEWAY] = gateway; 83785074Sru info.rti_info[RTAX_NETMASK] = netmask; 838178888Sjulian return rtrequest1_fib(req, &info, ret_nrt, fibnum); 83985074Sru} 84085074Sru 84185074Sru/* 84285074Sru * These (questionable) definitions of apparent local variables apply 84385074Sru * to the next two functions. XXXXXX!!! 84485074Sru */ 84585074Sru#define dst info->rti_info[RTAX_DST] 84685074Sru#define gateway info->rti_info[RTAX_GATEWAY] 84785074Sru#define netmask info->rti_info[RTAX_NETMASK] 84885074Sru#define ifaaddr info->rti_info[RTAX_IFA] 84985074Sru#define ifpaddr info->rti_info[RTAX_IFP] 85085074Sru#define flags info->rti_flags 85185074Sru 85285074Sruint 853120727Ssamrt_getifa(struct rt_addrinfo *info) 85485074Sru{ 855231852Sbz 856231852Sbz return (rt_getifa_fib(info, RT_DEFAULT_FIB)); 857178888Sjulian} 858178888Sjulian 859194760Srwatson/* 860194760Srwatson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 861194760Srwatson * it will be referenced so the caller must free it. 862194760Srwatson */ 863178888Sjulianint 864178888Sjulianrt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 865178888Sjulian{ 86685074Sru struct ifaddr *ifa; 86785074Sru int error = 0; 86885074Sru 86985074Sru /* 87085074Sru * ifp may be specified by sockaddr_dl 87185074Sru * when protocol address is ambiguous. 87285074Sru */ 87385074Sru if (info->rti_ifp == NULL && ifpaddr != NULL && 87485074Sru ifpaddr->sa_family == AF_LINK && 875267186Sasomers (ifa = ifa_ifwithnet_fib(ifpaddr, 0, fibnum)) != NULL) { 87685074Sru info->rti_ifp = ifa->ifa_ifp; 877194760Srwatson ifa_free(ifa); 878194760Srwatson } 87985074Sru if (info->rti_ifa == NULL && ifaaddr != NULL) 88085074Sru info->rti_ifa = ifa_ifwithaddr(ifaaddr); 88185074Sru if (info->rti_ifa == NULL) { 88285074Sru struct sockaddr *sa; 88385074Sru 88485074Sru sa = ifaaddr != NULL ? ifaaddr : 88585074Sru (gateway != NULL ? gateway : dst); 88685074Sru if (sa != NULL && info->rti_ifp != NULL) 88785074Sru info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 88885074Sru else if (dst != NULL && gateway != NULL) 889178888Sjulian info->rti_ifa = ifa_ifwithroute_fib(flags, dst, gateway, 890178888Sjulian fibnum); 89185074Sru else if (sa != NULL) 892178888Sjulian info->rti_ifa = ifa_ifwithroute_fib(flags, sa, sa, 893178888Sjulian fibnum); 89485074Sru } 89585074Sru if ((ifa = info->rti_ifa) != NULL) { 89685074Sru if (info->rti_ifp == NULL) 89785074Sru info->rti_ifp = ifa->ifa_ifp; 89885074Sru } else 89985074Sru error = ENETUNREACH; 90085074Sru return (error); 90185074Sru} 90285074Sru 903121770Ssam/* 904121770Ssam * Expunges references to a route that's about to be reclaimed. 905121770Ssam * The route must be locked. 906121770Ssam */ 90785074Sruint 908121770Ssamrtexpunge(struct rtentry *rt) 909121770Ssam{ 910204902Sqingli#if !defined(RADIX_MPATH) 911121770Ssam struct radix_node *rn; 912204902Sqingli#else 913204902Sqingli struct rt_addrinfo info; 914204902Sqingli int fib; 915204902Sqingli struct rtentry *rt0; 916204902Sqingli#endif 917121770Ssam struct radix_node_head *rnh; 918121770Ssam struct ifaddr *ifa; 919121770Ssam int error = 0; 920121770Ssam 921186119Sqingli /* 922186119Sqingli * Find the correct routing tree to use for this Address Family 923186119Sqingli */ 924193232Sbz rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); 925121770Ssam RT_LOCK_ASSERT(rt); 926186119Sqingli if (rnh == NULL) 927186119Sqingli return (EAFNOSUPPORT); 928185747Skmacy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 929204902Sqingli 930204902Sqingli#ifdef RADIX_MPATH 931204902Sqingli fib = rt->rt_fibnum; 932204902Sqingli bzero(&info, sizeof(info)); 933204902Sqingli info.rti_ifp = rt->rt_ifp; 934204902Sqingli info.rti_flags = RTF_RNH_LOCKED; 935204902Sqingli info.rti_info[RTAX_DST] = rt_key(rt); 936204902Sqingli info.rti_info[RTAX_GATEWAY] = rt->rt_ifa->ifa_addr; 937204902Sqingli 938204902Sqingli RT_UNLOCK(rt); 939204902Sqingli error = rtrequest1_fib(RTM_DELETE, &info, &rt0, fib); 940204902Sqingli 941204902Sqingli if (error == 0 && rt0 != NULL) { 942204902Sqingli rt = rt0; 943204902Sqingli RT_LOCK(rt); 944204902Sqingli } else if (error != 0) { 945204902Sqingli RT_LOCK(rt); 946204902Sqingli return (error); 947204902Sqingli } 948204902Sqingli#else 949121770Ssam /* 950121770Ssam * Remove the item from the tree; it should be there, 951121770Ssam * but when callers invoke us blindly it may not (sigh). 952121770Ssam */ 953121770Ssam rn = rnh->rnh_deladdr(rt_key(rt), rt_mask(rt), rnh); 954128455Sluigi if (rn == NULL) { 955121770Ssam error = ESRCH; 956121770Ssam goto bad; 957121770Ssam } 958121770Ssam KASSERT((rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) == 0, 959121770Ssam ("unexpected flags 0x%x", rn->rn_flags)); 960128524Sluigi KASSERT(rt == RNTORT(rn), 961121770Ssam ("lookup mismatch, rt %p rn %p", rt, rn)); 962204902Sqingli#endif /* RADIX_MPATH */ 963121770Ssam 964121770Ssam rt->rt_flags &= ~RTF_UP; 965121770Ssam 966121770Ssam /* 967121770Ssam * Give the protocol a chance to keep things in sync. 968121770Ssam */ 969121770Ssam if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) { 970121770Ssam struct rt_addrinfo info; 971121770Ssam 972121770Ssam bzero((caddr_t)&info, sizeof(info)); 973121770Ssam info.rti_flags = rt->rt_flags; 974121770Ssam info.rti_info[RTAX_DST] = rt_key(rt); 975121770Ssam info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 976121770Ssam info.rti_info[RTAX_NETMASK] = rt_mask(rt); 977121770Ssam ifa->ifa_rtrequest(RTM_DELETE, rt, &info); 978121770Ssam } 979121770Ssam 980121770Ssam /* 981121770Ssam * one more rtentry floating around that is not 982121770Ssam * linked to the routing table. 983121770Ssam */ 984181803Sbz V_rttrash++; 985204902Sqingli#if !defined(RADIX_MPATH) 986121770Ssambad: 987204902Sqingli#endif 988121770Ssam return (error); 989121770Ssam} 990121770Ssam 991265708Smelifaro#if 0 992265708Smelifaroint p_sockaddr(char *buf, int buflen, struct sockaddr *s); 993265708Smelifaroint rt_print(char *buf, int buflen, struct rtentry *rt); 994265708Smelifaro 995265708Smelifaroint 996265708Smelifarop_sockaddr(char *buf, int buflen, struct sockaddr *s) 997265708Smelifaro{ 998265708Smelifaro void *paddr = NULL; 999265708Smelifaro 1000265708Smelifaro switch (s->sa_family) { 1001265708Smelifaro case AF_INET: 1002265708Smelifaro paddr = &((struct sockaddr_in *)s)->sin_addr; 1003265708Smelifaro break; 1004265708Smelifaro case AF_INET6: 1005265708Smelifaro paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 1006265708Smelifaro break; 1007265708Smelifaro } 1008265708Smelifaro 1009265708Smelifaro if (paddr == NULL) 1010265708Smelifaro return (0); 1011265708Smelifaro 1012265708Smelifaro if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 1013265708Smelifaro return (0); 1014265708Smelifaro 1015265708Smelifaro return (strlen(buf)); 1016265708Smelifaro} 1017265708Smelifaro 1018265708Smelifaroint 1019265708Smelifarort_print(char *buf, int buflen, struct rtentry *rt) 1020265708Smelifaro{ 1021265708Smelifaro struct sockaddr *addr, *mask; 1022265708Smelifaro int i = 0; 1023265708Smelifaro 1024265708Smelifaro addr = rt_key(rt); 1025265708Smelifaro mask = rt_mask(rt); 1026265708Smelifaro 1027265708Smelifaro i = p_sockaddr(buf, buflen, addr); 1028265708Smelifaro if (!(rt->rt_flags & RTF_HOST)) { 1029265708Smelifaro buf[i++] = '/'; 1030265708Smelifaro i += p_sockaddr(buf + i, buflen - i, mask); 1031265708Smelifaro } 1032265708Smelifaro 1033265708Smelifaro if (rt->rt_flags & RTF_GATEWAY) { 1034265708Smelifaro buf[i++] = '>'; 1035265708Smelifaro i += p_sockaddr(buf + i, buflen - i, rt->rt_gateway); 1036265708Smelifaro } 1037265708Smelifaro 1038265708Smelifaro return (i); 1039265708Smelifaro} 1040265708Smelifaro#endif 1041265708Smelifaro 1042191080Skmacy#ifdef RADIX_MPATH 1043191080Skmacystatic int 1044191080Skmacyrn_mpath_update(int req, struct rt_addrinfo *info, 1045191080Skmacy struct radix_node_head *rnh, struct rtentry **ret_nrt) 1046191080Skmacy{ 1047191080Skmacy /* 1048191080Skmacy * if we got multipath routes, we require users to specify 1049191080Skmacy * a matching RTAX_GATEWAY. 1050191080Skmacy */ 1051191080Skmacy struct rtentry *rt, *rto = NULL; 1052191080Skmacy register struct radix_node *rn; 1053191080Skmacy int error = 0; 1054191080Skmacy 1055265708Smelifaro rn = rnh->rnh_lookup(dst, netmask, rnh); 1056191080Skmacy if (rn == NULL) 1057191080Skmacy return (ESRCH); 1058191080Skmacy rto = rt = RNTORT(rn); 1059265708Smelifaro 1060191080Skmacy rt = rt_mpath_matchgate(rt, gateway); 1061191080Skmacy if (rt == NULL) 1062191080Skmacy return (ESRCH); 1063191080Skmacy /* 1064191080Skmacy * this is the first entry in the chain 1065191080Skmacy */ 1066191080Skmacy if (rto == rt) { 1067191080Skmacy rn = rn_mpath_next((struct radix_node *)rt); 1068191080Skmacy /* 1069191080Skmacy * there is another entry, now it's active 1070191080Skmacy */ 1071191080Skmacy if (rn) { 1072191080Skmacy rto = RNTORT(rn); 1073191080Skmacy RT_LOCK(rto); 1074191080Skmacy rto->rt_flags |= RTF_UP; 1075191080Skmacy RT_UNLOCK(rto); 1076191080Skmacy } else if (rt->rt_flags & RTF_GATEWAY) { 1077191080Skmacy /* 1078191080Skmacy * For gateway routes, we need to 1079191080Skmacy * make sure that we we are deleting 1080191080Skmacy * the correct gateway. 1081191080Skmacy * rt_mpath_matchgate() does not 1082191080Skmacy * check the case when there is only 1083191080Skmacy * one route in the chain. 1084191080Skmacy */ 1085191080Skmacy if (gateway && 1086191080Skmacy (rt->rt_gateway->sa_len != gateway->sa_len || 1087191080Skmacy memcmp(rt->rt_gateway, gateway, gateway->sa_len))) 1088191080Skmacy error = ESRCH; 1089195624Skmacy else { 1090195624Skmacy /* 1091195624Skmacy * remove from tree before returning it 1092195624Skmacy * to the caller 1093195624Skmacy */ 1094195624Skmacy rn = rnh->rnh_deladdr(dst, netmask, rnh); 1095195624Skmacy KASSERT(rt == RNTORT(rn), ("radix node disappeared")); 1096195624Skmacy goto gwdelete; 1097195624Skmacy } 1098195624Skmacy 1099191080Skmacy } 1100191080Skmacy /* 1101191080Skmacy * use the normal delete code to remove 1102191080Skmacy * the first entry 1103191080Skmacy */ 1104191080Skmacy if (req != RTM_DELETE) 1105191080Skmacy goto nondelete; 1106191080Skmacy 1107191080Skmacy error = ENOENT; 1108191080Skmacy goto done; 1109191080Skmacy } 1110191080Skmacy 1111191080Skmacy /* 1112191080Skmacy * if the entry is 2nd and on up 1113191080Skmacy */ 1114191080Skmacy if ((req == RTM_DELETE) && !rt_mpath_deldup(rto, rt)) 1115191080Skmacy panic ("rtrequest1: rt_mpath_deldup"); 1116195624Skmacygwdelete: 1117191080Skmacy RT_LOCK(rt); 1118191080Skmacy RT_ADDREF(rt); 1119191080Skmacy if (req == RTM_DELETE) { 1120191080Skmacy rt->rt_flags &= ~RTF_UP; 1121191080Skmacy /* 1122191080Skmacy * One more rtentry floating around that is not 1123191080Skmacy * linked to the routing table. rttrash will be decremented 1124191080Skmacy * when RTFREE(rt) is eventually called. 1125191080Skmacy */ 1126191080Skmacy V_rttrash++; 1127191080Skmacy } 1128191080Skmacy 1129191080Skmacynondelete: 1130191080Skmacy if (req != RTM_DELETE) 1131191080Skmacy panic("unrecognized request %d", req); 1132191080Skmacy 1133191080Skmacy 1134191080Skmacy /* 1135191080Skmacy * If the caller wants it, then it can have it, 1136191080Skmacy * but it's up to it to free the rtentry as we won't be 1137191080Skmacy * doing it. 1138191080Skmacy */ 1139191080Skmacy if (ret_nrt) { 1140191080Skmacy *ret_nrt = rt; 1141191080Skmacy RT_UNLOCK(rt); 1142191080Skmacy } else 1143191080Skmacy RTFREE_LOCKED(rt); 1144191080Skmacydone: 1145191080Skmacy return (error); 1146191080Skmacy} 1147191080Skmacy#endif 1148191080Skmacy 1149121770Ssamint 1150178888Sjulianrtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, 1151178888Sjulian u_int fibnum) 1152178888Sjulian{ 1153185747Skmacy int error = 0, needlock = 0; 11541541Srgrimes register struct rtentry *rt; 1155197687Sqingli#ifdef FLOWTABLE 1156197687Sqingli register struct rtentry *rt0; 1157197687Sqingli#endif 11581541Srgrimes register struct radix_node *rn; 11591541Srgrimes register struct radix_node_head *rnh; 11601541Srgrimes struct ifaddr *ifa; 11611541Srgrimes struct sockaddr *ndst; 1162226710Sqingli struct sockaddr_storage mdst; 11631541Srgrimes#define senderr(x) { error = x ; goto bad; } 11641541Srgrimes 1165178888Sjulian KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); 1166231852Sbz switch (dst->sa_family) { 1167231852Sbz case AF_INET6: 1168231852Sbz case AF_INET: 1169231852Sbz /* We support multiple FIBs. */ 1170231852Sbz break; 1171231852Sbz default: 1172231852Sbz fibnum = RT_DEFAULT_FIB; 1173231852Sbz break; 1174231852Sbz } 1175231852Sbz 117618206Sjulian /* 117718206Sjulian * Find the correct routing tree to use for this Address Family 117818206Sjulian */ 1179193232Sbz rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1180128455Sluigi if (rnh == NULL) 1181113428Shsu return (EAFNOSUPPORT); 1182185747Skmacy needlock = ((flags & RTF_RNH_LOCKED) == 0); 1183185747Skmacy flags &= ~RTF_RNH_LOCKED; 1184185747Skmacy if (needlock) 1185185747Skmacy RADIX_NODE_HEAD_LOCK(rnh); 1186185774Skmacy else 1187185774Skmacy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 118818206Sjulian /* 118918206Sjulian * If we are adding a host route then we don't want to put 119084971Sru * a netmask in the tree, nor do we want to clone it. 119118206Sjulian */ 1192186119Sqingli if (flags & RTF_HOST) 1193128455Sluigi netmask = NULL; 1194186119Sqingli 11951541Srgrimes switch (req) { 11961541Srgrimes case RTM_DELETE: 1197226710Sqingli if (netmask) { 1198226710Sqingli rt_maskedcopy(dst, (struct sockaddr *)&mdst, netmask); 1199226710Sqingli dst = (struct sockaddr *)&mdst; 1200226710Sqingli } 1201178167Sqingli#ifdef RADIX_MPATH 1202178167Sqingli if (rn_mpath_capable(rnh)) { 1203191080Skmacy error = rn_mpath_update(req, info, rnh, ret_nrt); 1204178167Sqingli /* 1205191080Skmacy * "bad" holds true for the success case 1206191080Skmacy * as well 1207178167Sqingli */ 1208191080Skmacy if (error != ENOENT) 1209191080Skmacy goto bad; 1210204902Sqingli error = 0; 1211178167Sqingli } 1212178176Sbz#endif 1213248070Smelifaro if ((flags & RTF_PINNED) == 0) { 1214248070Smelifaro /* Check if target route can be deleted */ 1215248070Smelifaro rt = (struct rtentry *)rnh->rnh_lookup(dst, 1216248070Smelifaro netmask, rnh); 1217248070Smelifaro if ((rt != NULL) && (rt->rt_flags & RTF_PINNED)) 1218248070Smelifaro senderr(EADDRINUSE); 1219248070Smelifaro } 1220248070Smelifaro 1221178167Sqingli /* 122218206Sjulian * Remove the item from the tree and return it. 122318206Sjulian * Complain if it is not there and do no more processing. 122418206Sjulian */ 1225120727Ssam rn = rnh->rnh_deladdr(dst, netmask, rnh); 1226128455Sluigi if (rn == NULL) 12271541Srgrimes senderr(ESRCH); 12281541Srgrimes if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) 12291541Srgrimes panic ("rtrequest delete"); 1230128524Sluigi rt = RNTORT(rn); 1231120727Ssam RT_LOCK(rt); 1232122334Ssam RT_ADDREF(rt); 1233108269Sru rt->rt_flags &= ~RTF_UP; 12347197Swollman 12357197Swollman /* 123623392Sjulian * give the protocol a chance to keep things in sync. 123718206Sjulian */ 12381541Srgrimes if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) 123985074Sru ifa->ifa_rtrequest(RTM_DELETE, rt, info); 124023392Sjulian 124123392Sjulian /* 1242128524Sluigi * One more rtentry floating around that is not 1243128524Sluigi * linked to the routing table. rttrash will be decremented 1244128524Sluigi * when RTFREE(rt) is eventually called. 124523392Sjulian */ 1246181803Sbz V_rttrash++; 124723392Sjulian 124818206Sjulian /* 124923392Sjulian * If the caller wants it, then it can have it, 125023392Sjulian * but it's up to it to free the rtentry as we won't be 125123392Sjulian * doing it. 125218206Sjulian */ 1253120727Ssam if (ret_nrt) { 12541541Srgrimes *ret_nrt = rt; 1255120727Ssam RT_UNLOCK(rt); 1256120727Ssam } else 1257120727Ssam RTFREE_LOCKED(rt); 12581541Srgrimes break; 12591541Srgrimes case RTM_RESOLVE: 1260186119Sqingli /* 1261186119Sqingli * resolve was only used for route cloning 1262186119Sqingli * here for compat 1263186119Sqingli */ 1264186119Sqingli break; 12651541Srgrimes case RTM_ADD: 12663514Swollman if ((flags & RTF_GATEWAY) && !gateway) 1267147650Sqingli senderr(EINVAL); 1268147650Sqingli if (dst && gateway && (dst->sa_family != gateway->sa_family) && 1269147650Sqingli (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) 1270147650Sqingli senderr(EINVAL); 12713514Swollman 1272194760Srwatson if (info->rti_ifa == NULL) { 1273194760Srwatson error = rt_getifa_fib(info, fibnum); 1274194760Srwatson if (error) 1275194760Srwatson senderr(error); 1276194760Srwatson } else 1277194760Srwatson ifa_ref(info->rti_ifa); 127885074Sru ifa = info->rti_ifa; 1279263478Sglebius rt = uma_zalloc(V_rtzone, M_NOWAIT); 1280194760Srwatson if (rt == NULL) { 1281228532Sglebius ifa_free(ifa); 12821541Srgrimes senderr(ENOBUFS); 1283194760Srwatson } 12841541Srgrimes rt->rt_flags = RTF_UP | flags; 1285178888Sjulian rt->rt_fibnum = fibnum; 128623392Sjulian /* 1287231852Sbz * Add the gateway. Possibly re-malloc-ing the storage for it. 128823392Sjulian */ 1289120727Ssam RT_LOCK(rt); 129043305Sdillon if ((error = rt_setgate(rt, dst, gateway)) != 0) { 1291228532Sglebius ifa_free(ifa); 1292190787Szec uma_zfree(V_rtzone, rt); 129317997Sfenner senderr(error); 12941541Srgrimes } 129523392Sjulian 129623392Sjulian /* 129723392Sjulian * point to the (possibly newly malloc'd) dest address. 129823392Sjulian */ 1299120727Ssam ndst = (struct sockaddr *)rt_key(rt); 130023392Sjulian 130123392Sjulian /* 130223392Sjulian * make sure it contains the value we want (masked if needed). 130323392Sjulian */ 13041541Srgrimes if (netmask) { 13051541Srgrimes rt_maskedcopy(dst, ndst, netmask); 13061541Srgrimes } else 1307128399Sluigi bcopy(dst, ndst, dst->sa_len); 13089469Swollman 13099469Swollman /* 1310194760Srwatson * We use the ifa reference returned by rt_getifa_fib(). 13119469Swollman * This moved from below so that rnh->rnh_addaddr() can 131223392Sjulian * examine the ifa and ifa->ifa_ifp if it so desires. 13139469Swollman */ 13149469Swollman rt->rt_ifa = ifa; 13159469Swollman rt->rt_ifp = ifa->ifa_ifp; 1316263478Sglebius rt->rt_weight = 1; 1317120727Ssam 1318178167Sqingli#ifdef RADIX_MPATH 1319178167Sqingli /* do not permit exactly the same dst/mask/gw pair */ 1320178167Sqingli if (rn_mpath_capable(rnh) && 1321178167Sqingli rt_mpath_conflict(rnh, rt, netmask)) { 1322228532Sglebius ifa_free(rt->rt_ifa); 1323178167Sqingli Free(rt_key(rt)); 1324190787Szec uma_zfree(V_rtzone, rt); 1325178167Sqingli senderr(EEXIST); 1326178167Sqingli } 1327178167Sqingli#endif 1328178167Sqingli 1329197687Sqingli#ifdef FLOWTABLE 1330197687Sqingli rt0 = NULL; 1331231852Sbz /* "flow-table" only supports IPv6 and IPv4 at the moment. */ 1332231852Sbz switch (dst->sa_family) { 1333231852Sbz#ifdef INET6 1334231852Sbz case AF_INET6: 1335231852Sbz#endif 1336197727Sbz#ifdef INET 1337231852Sbz case AF_INET: 1338231852Sbz#endif 1339231852Sbz#if defined(INET6) || defined(INET) 1340197687Sqingli rn = rnh->rnh_matchaddr(dst, rnh); 1341197687Sqingli if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { 1342197687Sqingli struct sockaddr *mask; 1343197687Sqingli u_char *m, *n; 1344197687Sqingli int len; 1345197687Sqingli 1346197687Sqingli /* 1347197687Sqingli * compare mask to see if the new route is 1348197687Sqingli * more specific than the existing one 1349197687Sqingli */ 1350197687Sqingli rt0 = RNTORT(rn); 1351197687Sqingli RT_LOCK(rt0); 1352197687Sqingli RT_ADDREF(rt0); 1353197687Sqingli RT_UNLOCK(rt0); 1354197687Sqingli /* 1355197687Sqingli * A host route is already present, so 1356197687Sqingli * leave the flow-table entries as is. 1357197687Sqingli */ 1358197687Sqingli if (rt0->rt_flags & RTF_HOST) { 1359197687Sqingli RTFREE(rt0); 1360197687Sqingli rt0 = NULL; 1361197687Sqingli } else if (!(flags & RTF_HOST) && netmask) { 1362197687Sqingli mask = rt_mask(rt0); 1363197687Sqingli len = mask->sa_len; 1364197687Sqingli m = (u_char *)mask; 1365197687Sqingli n = (u_char *)netmask; 1366197687Sqingli while (len-- > 0) { 1367197687Sqingli if (*n != *m) 1368197687Sqingli break; 1369197687Sqingli n++; 1370197687Sqingli m++; 1371197687Sqingli } 1372197687Sqingli if (len == 0 || (*n < *m)) { 1373197687Sqingli RTFREE(rt0); 1374197687Sqingli rt0 = NULL; 1375197687Sqingli } 1376197687Sqingli } 1377197687Sqingli } 1378231852Sbz#endif/* INET6 || INET */ 1379197687Sqingli } 1380231852Sbz#endif /* FLOWTABLE */ 1381197687Sqingli 138253541Sshin /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ 1383120727Ssam rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); 138423392Sjulian /* 138523392Sjulian * If it still failed to go into the tree, 138623392Sjulian * then un-make it (this should be a function) 138723392Sjulian */ 1388128455Sluigi if (rn == NULL) { 1389228532Sglebius ifa_free(rt->rt_ifa); 13901541Srgrimes Free(rt_key(rt)); 1391190787Szec uma_zfree(V_rtzone, rt); 1392197687Sqingli#ifdef FLOWTABLE 1393197687Sqingli if (rt0 != NULL) 1394197687Sqingli RTFREE(rt0); 1395197687Sqingli#endif 13961541Srgrimes senderr(EEXIST); 1397197687Sqingli } 1398197687Sqingli#ifdef FLOWTABLE 1399197687Sqingli else if (rt0 != NULL) { 1400262743Sglebius flowtable_route_flush(dst->sa_family, rt0); 1401197687Sqingli RTFREE(rt0); 14021541Srgrimes } 1403197687Sqingli#endif 140423392Sjulian 140553541Sshin /* 1406169872Sglebius * If this protocol has something to add to this then 140723392Sjulian * allow it to do that as well. 140823392Sjulian */ 14091541Srgrimes if (ifa->ifa_rtrequest) 141085074Sru ifa->ifa_rtrequest(req, rt, info); 141123392Sjulian 14128070Swollman /* 141323392Sjulian * actually return a resultant rtentry and 141423392Sjulian * give the caller a single reference. 141523392Sjulian */ 14161541Srgrimes if (ret_nrt) { 14171541Srgrimes *ret_nrt = rt; 1418122334Ssam RT_ADDREF(rt); 14191541Srgrimes } 1420120727Ssam RT_UNLOCK(rt); 14211541Srgrimes break; 142285074Sru default: 142385074Sru error = EOPNOTSUPP; 14241541Srgrimes } 14251541Srgrimesbad: 1426185747Skmacy if (needlock) 1427185747Skmacy RADIX_NODE_HEAD_UNLOCK(rnh); 14281541Srgrimes return (error); 1429120727Ssam#undef senderr 1430120727Ssam} 1431120727Ssam 143285074Sru#undef dst 143385074Sru#undef gateway 143485074Sru#undef netmask 143585074Sru#undef ifaaddr 143685074Sru#undef ifpaddr 143785074Sru#undef flags 14381541Srgrimes 14391541Srgrimesint 1440120727Ssamrt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) 14411541Srgrimes{ 1442120727Ssam /* XXX dst may be overwritten, can we move this to below */ 1443186119Sqingli int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); 1444186119Sqingli#ifdef INVARIANTS 1445193232Sbz struct radix_node_head *rnh; 1446193232Sbz 1447193232Sbz rnh = rt_tables_get_rnh(rt->rt_fibnum, dst->sa_family); 1448186119Sqingli#endif 14491541Srgrimes 1450120727Ssam RT_LOCK_ASSERT(rt); 1451185747Skmacy RADIX_NODE_HEAD_LOCK_ASSERT(rnh); 1452185747Skmacy 145317052Sfenner /* 1454128455Sluigi * Prepare to store the gateway in rt->rt_gateway. 1455128455Sluigi * Both dst and gateway are stored one after the other in the same 1456128455Sluigi * malloc'd chunk. If we have room, we can reuse the old buffer, 1457128455Sluigi * rt_gateway already points to the right place. 1458128455Sluigi * Otherwise, malloc a new block and update the 'dst' address. 145923392Sjulian */ 1460128455Sluigi if (rt->rt_gateway == NULL || glen > SA_SIZE(rt->rt_gateway)) { 1461128455Sluigi caddr_t new; 1462128455Sluigi 14631541Srgrimes R_Malloc(new, caddr_t, dlen + glen); 1464128455Sluigi if (new == NULL) 146517052Sfenner return ENOBUFS; 146623392Sjulian /* 1467128455Sluigi * XXX note, we copy from *dst and not *rt_key(rt) because 1468128455Sluigi * rt_setgate() can be called to initialize a newly 1469128455Sluigi * allocated route entry, in which case rt_key(rt) == NULL 1470128455Sluigi * (and also rt->rt_gateway == NULL). 1471128455Sluigi * Free()/free() handle a NULL argument just fine. 147223392Sjulian */ 1473128455Sluigi bcopy(dst, new, dlen); 1474128455Sluigi Free(rt_key(rt)); /* free old block, if any */ 1475132780Skan rt_key(rt) = (struct sockaddr *)new; 1476128455Sluigi rt->rt_gateway = (struct sockaddr *)(new + dlen); 14771541Srgrimes } 147823392Sjulian 147923392Sjulian /* 1480128455Sluigi * Copy the new gateway value into the memory chunk. 148123392Sjulian */ 1482128455Sluigi bcopy(gate, rt->rt_gateway, glen); 148323392Sjulian 1484186119Sqingli return (0); 14851541Srgrimes} 14861541Srgrimes 1487201282Sqinglivoid 1488120727Ssamrt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 14891541Srgrimes{ 14901541Srgrimes register u_char *cp1 = (u_char *)src; 14911541Srgrimes register u_char *cp2 = (u_char *)dst; 14921541Srgrimes register u_char *cp3 = (u_char *)netmask; 14931541Srgrimes u_char *cplim = cp2 + *cp3; 14941541Srgrimes u_char *cplim2 = cp2 + *cp1; 14951541Srgrimes 14961541Srgrimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 14971541Srgrimes cp3 += 2; 14981541Srgrimes if (cplim > cplim2) 14991541Srgrimes cplim = cplim2; 15001541Srgrimes while (cp2 < cplim) 15011541Srgrimes *cp2++ = *cp1++ & *cp3++; 15021541Srgrimes if (cp2 < cplim2) 15031541Srgrimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 15041541Srgrimes} 15051541Srgrimes 15061541Srgrimes/* 15071541Srgrimes * Set up a routing table entry, normally 15081541Srgrimes * for an interface. 15091541Srgrimes */ 1510178888Sjulian#define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 1511178888Sjulianstatic inline int 1512178888Sjulianrtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 15131541Srgrimes{ 1514128167Sluigi struct sockaddr *dst; 151585074Sru struct sockaddr *netmask; 1516128455Sluigi struct rtentry *rt = NULL; 1517128167Sluigi struct rt_addrinfo info; 1518178888Sjulian int error = 0; 1519178888Sjulian int startfib, endfib; 1520178888Sjulian char tempbuf[_SOCKADDR_TMPSIZE]; 1521178888Sjulian int didwork = 0; 1522178888Sjulian int a_failure = 0; 1523186119Sqingli static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1524248070Smelifaro struct radix_node_head *rnh; 15251541Srgrimes 152685074Sru if (flags & RTF_HOST) { 152785074Sru dst = ifa->ifa_dstaddr; 152885074Sru netmask = NULL; 152985074Sru } else { 153085074Sru dst = ifa->ifa_addr; 153185074Sru netmask = ifa->ifa_netmask; 153285074Sru } 1533231852Sbz if (dst->sa_len == 0) 1534231852Sbz return(EINVAL); 1535231852Sbz switch (dst->sa_family) { 1536231852Sbz case AF_INET6: 1537231852Sbz case AF_INET: 1538231852Sbz /* We support multiple FIBs. */ 1539231852Sbz break; 1540231852Sbz default: 1541231852Sbz fibnum = RT_DEFAULT_FIB; 1542231852Sbz break; 1543231852Sbz } 1544265711Smelifaro if (fibnum == RT_ALL_FIBS) { 1545180840Sjulian if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) { 1546267193Sasomers startfib = endfib = ifa->ifa_ifp->if_fib; 1547180840Sjulian } else { 1548180840Sjulian startfib = 0; 1549180840Sjulian endfib = rt_numfibs - 1; 1550180840Sjulian } 1551178888Sjulian } else { 1552178888Sjulian KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 1553178888Sjulian startfib = fibnum; 1554178888Sjulian endfib = fibnum; 1555178888Sjulian } 1556158294Sbz 155718206Sjulian /* 1558178888Sjulian * If it's a delete, check that if it exists, 1559178888Sjulian * it's on the correct interface or we might scrub 1560178888Sjulian * a route to another ifa which would 156118206Sjulian * be confusing at best and possibly worse. 156218206Sjulian */ 15631541Srgrimes if (cmd == RTM_DELETE) { 156453541Sshin /* 156518206Sjulian * It's a delete, so it should already exist.. 156618206Sjulian * If it's a net, mask off the host bits 156718206Sjulian * (Assuming we have a mask) 1568178888Sjulian * XXX this is kinda inet specific.. 156918206Sjulian */ 157085074Sru if (netmask != NULL) { 1571178888Sjulian rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 1572178888Sjulian dst = (struct sockaddr *)tempbuf; 15731541Srgrimes } 1574178888Sjulian } 1575178888Sjulian /* 1576178888Sjulian * Now go through all the requested tables (fibs) and do the 1577178888Sjulian * requested action. Realistically, this will either be fib 0 1578178888Sjulian * for protocols that don't do multiple tables or all the 1579231852Sbz * tables for those that do. 1580178888Sjulian */ 1581178888Sjulian for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 1582178888Sjulian if (cmd == RTM_DELETE) { 1583178888Sjulian struct radix_node *rn; 1584178888Sjulian /* 1585178888Sjulian * Look up an rtentry that is in the routing tree and 1586178888Sjulian * contains the correct info. 1587178888Sjulian */ 1588193232Sbz rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1589193232Sbz if (rnh == NULL) 1590178888Sjulian /* this table doesn't exist but others might */ 1591178888Sjulian continue; 1592247842Smelifaro RADIX_NODE_HEAD_RLOCK(rnh); 1593265711Smelifaro rn = rnh->rnh_lookup(dst, netmask, rnh); 1594178167Sqingli#ifdef RADIX_MPATH 1595178888Sjulian if (rn_mpath_capable(rnh)) { 1596178167Sqingli 1597178888Sjulian if (rn == NULL) 1598178167Sqingli error = ESRCH; 1599178888Sjulian else { 1600178888Sjulian rt = RNTORT(rn); 1601178888Sjulian /* 1602178888Sjulian * for interface route the 1603178888Sjulian * rt->rt_gateway is sockaddr_intf 1604178888Sjulian * for cloning ARP entries, so 1605178888Sjulian * rt_mpath_matchgate must use the 1606178888Sjulian * interface address 1607178888Sjulian */ 1608178888Sjulian rt = rt_mpath_matchgate(rt, 1609178888Sjulian ifa->ifa_addr); 1610265711Smelifaro if (rt == NULL) 1611178888Sjulian error = ESRCH; 1612178888Sjulian } 1613178167Sqingli } 1614178167Sqingli#endif 1615178888Sjulian error = (rn == NULL || 1616178888Sjulian (rn->rn_flags & RNF_ROOT) || 1617265708Smelifaro RNTORT(rn)->rt_ifa != ifa); 1618247842Smelifaro RADIX_NODE_HEAD_RUNLOCK(rnh); 1619178888Sjulian if (error) { 1620178888Sjulian /* this is only an error if bad on ALL tables */ 1621178888Sjulian continue; 1622178888Sjulian } 16231541Srgrimes } 162418206Sjulian /* 1625178888Sjulian * Do the actual request 162618206Sjulian */ 1627178888Sjulian bzero((caddr_t)&info, sizeof(info)); 1628178888Sjulian info.rti_ifa = ifa; 1629248070Smelifaro info.rti_flags = flags | 1630248070Smelifaro (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; 1631178888Sjulian info.rti_info[RTAX_DST] = dst; 1632186119Sqingli /* 1633186119Sqingli * doing this for compatibility reasons 1634186119Sqingli */ 1635186119Sqingli if (cmd == RTM_ADD) 1636186119Sqingli info.rti_info[RTAX_GATEWAY] = 1637186119Sqingli (struct sockaddr *)&null_sdl; 1638186119Sqingli else 1639186119Sqingli info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 1640178888Sjulian info.rti_info[RTAX_NETMASK] = netmask; 1641178888Sjulian error = rtrequest1_fib(cmd, &info, &rt, fibnum); 1642248070Smelifaro 1643248070Smelifaro if ((error == EEXIST) && (cmd == RTM_ADD)) { 1644248070Smelifaro /* 1645248070Smelifaro * Interface route addition failed. 1646248070Smelifaro * Atomically delete current prefix generating 1647248070Smelifaro * RTM_DELETE message, and retry adding 1648248070Smelifaro * interface prefix. 1649248070Smelifaro */ 1650248070Smelifaro rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 1651248070Smelifaro RADIX_NODE_HEAD_LOCK(rnh); 1652248070Smelifaro 1653248070Smelifaro /* Delete old prefix */ 1654248070Smelifaro info.rti_ifa = NULL; 1655248070Smelifaro info.rti_flags = RTF_RNH_LOCKED; 1656248070Smelifaro 1657250764Smelifaro error = rtrequest1_fib(RTM_DELETE, &info, NULL, fibnum); 1658248070Smelifaro if (error == 0) { 1659248070Smelifaro info.rti_ifa = ifa; 1660248070Smelifaro info.rti_flags = flags | RTF_RNH_LOCKED | 1661248070Smelifaro (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; 1662248070Smelifaro error = rtrequest1_fib(cmd, &info, &rt, fibnum); 1663248070Smelifaro } 1664248070Smelifaro 1665248070Smelifaro RADIX_NODE_HEAD_UNLOCK(rnh); 1666248070Smelifaro } 1667248070Smelifaro 1668248070Smelifaro 1669178888Sjulian if (error == 0 && rt != NULL) { 1670178888Sjulian /* 1671178888Sjulian * notify any listening routing agents of the change 1672178888Sjulian */ 1673178888Sjulian RT_LOCK(rt); 1674178167Sqingli#ifdef RADIX_MPATH 167518206Sjulian /* 1676178888Sjulian * in case address alias finds the first address 1677230510Sbz * e.g. ifconfig bge0 192.0.2.246/24 1678230510Sbz * e.g. ifconfig bge0 192.0.2.247/24 1679230510Sbz * the address set in the route is 192.0.2.246 1680230510Sbz * so we need to replace it with 192.0.2.247 168118206Sjulian */ 1682178888Sjulian if (memcmp(rt->rt_ifa->ifa_addr, 1683178888Sjulian ifa->ifa_addr, ifa->ifa_addr->sa_len)) { 1684194602Srwatson ifa_free(rt->rt_ifa); 1685194602Srwatson ifa_ref(ifa); 1686178888Sjulian rt->rt_ifp = ifa->ifa_ifp; 1687178888Sjulian rt->rt_ifa = ifa; 1688178888Sjulian } 1689178888Sjulian#endif 1690186119Sqingli /* 1691186119Sqingli * doing this for compatibility reasons 1692186119Sqingli */ 1693186119Sqingli if (cmd == RTM_ADD) { 1694186119Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 1695186119Sqingli rt->rt_ifp->if_type; 1696186119Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 1697186119Sqingli rt->rt_ifp->if_index; 1698186119Sqingli } 1699199365Stuexen RT_ADDREF(rt); 1700199365Stuexen RT_UNLOCK(rt); 1701225837Sbz rt_newaddrmsg_fib(cmd, ifa, error, rt, fibnum); 1702199365Stuexen RT_LOCK(rt); 1703199365Stuexen RT_REMREF(rt); 1704178888Sjulian if (cmd == RTM_DELETE) { 1705120727Ssam /* 1706178888Sjulian * If we are deleting, and we found an entry, 1707178888Sjulian * then it's been removed from the tree.. 1708178888Sjulian * now throw it away. 1709120727Ssam */ 1710178888Sjulian RTFREE_LOCKED(rt); 1711178888Sjulian } else { 1712178888Sjulian if (cmd == RTM_ADD) { 1713178888Sjulian /* 1714178888Sjulian * We just wanted to add it.. 1715178888Sjulian * we don't actually need a reference. 1716178888Sjulian */ 1717178888Sjulian RT_REMREF(rt); 1718178888Sjulian } 1719178888Sjulian RT_UNLOCK(rt); 1720120727Ssam } 1721178888Sjulian didwork = 1; 17221541Srgrimes } 1723178888Sjulian if (error) 1724178888Sjulian a_failure = error; 17251541Srgrimes } 1726178888Sjulian if (cmd == RTM_DELETE) { 1727178888Sjulian if (didwork) { 1728178888Sjulian error = 0; 1729178888Sjulian } else { 1730178888Sjulian /* we only give an error if it wasn't in any table */ 1731178888Sjulian error = ((flags & RTF_HOST) ? 1732178888Sjulian EHOSTUNREACH : ENETUNREACH); 1733178888Sjulian } 1734178888Sjulian } else { 1735178888Sjulian if (a_failure) { 1736178888Sjulian /* return an error if any of them failed */ 1737178888Sjulian error = a_failure; 1738178888Sjulian } 1739178888Sjulian } 17405801Sdg return (error); 17415801Sdg} 174246161Sluoqi 1743120727Ssam/* 1744178888Sjulian * Set up a routing table entry, normally 1745178888Sjulian * for an interface. 1746178888Sjulian */ 1747178888Sjulianint 1748178888Sjulianrtinit(struct ifaddr *ifa, int cmd, int flags) 1749178888Sjulian{ 1750178888Sjulian struct sockaddr *dst; 1751231852Sbz int fib = RT_DEFAULT_FIB; 1752178888Sjulian 1753178888Sjulian if (flags & RTF_HOST) { 1754178888Sjulian dst = ifa->ifa_dstaddr; 1755178888Sjulian } else { 1756178888Sjulian dst = ifa->ifa_addr; 1757178888Sjulian } 1758178888Sjulian 1759231852Sbz switch (dst->sa_family) { 1760231852Sbz case AF_INET6: 1761231852Sbz case AF_INET: 1762231852Sbz /* We do support multiple FIBs. */ 1763265711Smelifaro fib = RT_ALL_FIBS; 1764231852Sbz break; 1765231852Sbz } 1766178888Sjulian return (rtinit1(ifa, cmd, flags, fib)); 1767178888Sjulian} 1768265717Smelifaro 1769265717Smelifaro/* 1770265717Smelifaro * Announce interface address arrival/withdraw 1771265717Smelifaro * Returns 0 on success. 1772265717Smelifaro */ 1773265717Smelifaroint 1774265717Smelifarort_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 1775265717Smelifaro{ 1776265717Smelifaro 1777265717Smelifaro KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 1778265717Smelifaro ("unexpected cmd %d", cmd)); 1779265717Smelifaro 1780265717Smelifaro KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1781265717Smelifaro ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 1782265717Smelifaro 1783267728Stuexen#if defined(INET) || defined(INET6) 1784267728Stuexen#ifdef SCTP 1785267728Stuexen /* 1786267728Stuexen * notify the SCTP stack 1787267728Stuexen * this will only get called when an address is added/deleted 1788267728Stuexen * XXX pass the ifaddr struct instead if ifa->ifa_addr... 1789267728Stuexen */ 1790267728Stuexen sctp_addr_change(ifa, cmd); 1791267728Stuexen#endif /* SCTP */ 1792267728Stuexen#endif 1793265717Smelifaro return (rtsock_addrmsg(cmd, ifa, fibnum)); 1794265717Smelifaro} 1795265717Smelifaro 1796265717Smelifaro/* 1797265717Smelifaro * Announce route addition/removal. 1798265717Smelifaro * Users of this function MUST validate input data BEFORE calling. 1799265717Smelifaro * However we have to be able to handle invalid data: 1800265717Smelifaro * if some userland app sends us "invalid" route message (invalid mask, 1801265717Smelifaro * no dst, wrong address families, etc...) we need to pass it back 1802265717Smelifaro * to app (and any other rtsock consumers) with rtm_errno field set to 1803265717Smelifaro * non-zero value. 1804265717Smelifaro * Returns 0 on success. 1805265717Smelifaro */ 1806265717Smelifaroint 1807265717Smelifarort_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt, 1808265717Smelifaro int fibnum) 1809265717Smelifaro{ 1810265717Smelifaro 1811265717Smelifaro KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 1812265717Smelifaro ("unexpected cmd %d", cmd)); 1813265717Smelifaro 1814265717Smelifaro KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1815265717Smelifaro ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 1816265717Smelifaro 1817265717Smelifaro KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 1818265717Smelifaro 1819265717Smelifaro return (rtsock_routemsg(cmd, ifp, error, rt, fibnum)); 1820265717Smelifaro} 1821265717Smelifaro 1822265717Smelifarovoid 1823265717Smelifarort_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) 1824265717Smelifaro{ 1825265717Smelifaro 1826265717Smelifaro rt_newaddrmsg_fib(cmd, ifa, error, rt, RT_ALL_FIBS); 1827265717Smelifaro} 1828265717Smelifaro 1829265717Smelifaro/* 1830265717Smelifaro * This is called to generate messages from the routing socket 1831265717Smelifaro * indicating a network interface has had addresses associated with it. 1832265717Smelifaro */ 1833265717Smelifarovoid 1834265717Smelifarort_newaddrmsg_fib(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt, 1835265717Smelifaro int fibnum) 1836265717Smelifaro{ 1837265717Smelifaro 1838265717Smelifaro KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 1839265717Smelifaro ("unexpected cmd %u", cmd)); 1840265717Smelifaro KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1841265717Smelifaro ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 1842265717Smelifaro 1843265717Smelifaro if (cmd == RTM_ADD) { 1844265717Smelifaro rt_addrmsg(cmd, ifa, fibnum); 1845265717Smelifaro if (rt != NULL) 1846265717Smelifaro rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum); 1847265717Smelifaro } else { 1848265717Smelifaro if (rt != NULL) 1849265717Smelifaro rt_routemsg(cmd, ifa->ifa_ifp, error, rt, fibnum); 1850265717Smelifaro rt_addrmsg(cmd, ifa, fibnum); 1851265717Smelifaro } 1852265717Smelifaro} 1853265717Smelifaro 1854