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> 64da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h> 65e7d8af4fSAlexander V. Chernikov #include <net/route/route_var.h> 66a6663252SAlexander V. Chernikov #include <net/route/nhop.h> 67a6663252SAlexander V. Chernikov #include <net/route/shared.h> 68530c0060SRobert Watson #include <net/vnet.h> 69df8bae1dSRodney W. Grimes 70e440aed9SQing Li #ifdef RADIX_MPATH 71e440aed9SQing Li #include <net/radix_mpath.h> 72e440aed9SQing Li #endif 73e440aed9SQing Li 74df8bae1dSRodney W. Grimes #include <netinet/in.h> 75b5e8ce9fSBruce Evans #include <netinet/ip_mroute.h> 76df8bae1dSRodney W. Grimes 7766e8505fSJulian Elischer /* 7866e8505fSJulian Elischer * By default add routes to all fibs for new interfaces. 7966e8505fSJulian Elischer * Once this is set to 0 then only allocate routes on interface 8066e8505fSJulian Elischer * changes for the FIB of the caller when adding a new set of addresses 8166e8505fSJulian Elischer * to an interface. XXX this is a shotgun aproach to a problem that needs 8266e8505fSJulian Elischer * a more fine grained solution.. that will come. 83a8498625SBjoern A. Zeeb * XXX also has the problems getting the FIB from curthread which will not 84a8498625SBjoern A. Zeeb * always work given the fib can be overridden and prefixes can be added 85a8498625SBjoern A. Zeeb * from the network stack context. 8666e8505fSJulian Elischer */ 87ee0bd4b9SHiroki Sato VNET_DEFINE(u_int, rt_add_addr_allfibs) = 1; 88ee0bd4b9SHiroki Sato SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, 89ee0bd4b9SHiroki Sato &VNET_NAME(rt_add_addr_allfibs), 0, ""); 9066e8505fSJulian Elischer 91a6663252SAlexander V. Chernikov VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); 92185c3d2bSGleb Smirnoff 93185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSINIT(rtstat); 94185c3d2bSGleb Smirnoff #ifdef VIMAGE 95185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSUNINIT(rtstat); 96185c3d2bSGleb Smirnoff #endif 97b58ea5f3SBjoern A. Zeeb 98d6e23cf0SMichael Tuexen EVENTHANDLER_LIST_DEFINE(rt_addrmsg); 99d6e23cf0SMichael Tuexen 100539642a2SAlexander V. Chernikov static int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *, 101539642a2SAlexander V. Chernikov void *arg); 1029a1b64d5SAlexander V. Chernikov static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, 1039a1b64d5SAlexander V. Chernikov int flags); 104c77462ddSAlexander V. Chernikov 1058b07e49aSJulian Elischer /* 106d0728d71SRobert Watson * route initialization must occur before ip6_init2(), which happenas at 107d0728d71SRobert Watson * SI_ORDER_MIDDLE. 108d0728d71SRobert Watson */ 1092eb5613fSLuigi Rizzo static void 1102eb5613fSLuigi Rizzo route_init(void) 111df8bae1dSRodney W. Grimes { 1128b07e49aSJulian Elischer 113a6663252SAlexander V. Chernikov nhops_init(); 1141ed81b73SMarko Zec } 115891cf3edSEd Maste SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); 1161ed81b73SMarko Zec 11761eee0e2SAlexander V. Chernikov struct rib_head * 118ead85fe4SAlexander V. Chernikov rt_table_init(int offset, int family, u_int fibnum) 11961eee0e2SAlexander V. Chernikov { 12061eee0e2SAlexander V. Chernikov struct rib_head *rh; 12161eee0e2SAlexander V. Chernikov 12261eee0e2SAlexander V. Chernikov rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); 12361eee0e2SAlexander V. Chernikov 12461eee0e2SAlexander V. Chernikov /* TODO: These details should be hidded inside radix.c */ 12561eee0e2SAlexander V. Chernikov /* Init masks tree */ 12661eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); 12761eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); 12861eee0e2SAlexander V. Chernikov rh->head.rnh_masks = &rh->rmhead; 12961eee0e2SAlexander V. Chernikov 130ead85fe4SAlexander V. Chernikov /* Save metadata associated with this routing table. */ 131ead85fe4SAlexander V. Chernikov rh->rib_family = family; 132ead85fe4SAlexander V. Chernikov rh->rib_fibnum = fibnum; 133ead85fe4SAlexander V. Chernikov #ifdef VIMAGE 134ead85fe4SAlexander V. Chernikov rh->rib_vnet = curvnet; 135ead85fe4SAlexander V. Chernikov #endif 136ead85fe4SAlexander V. Chernikov 13734a5582cSAlexander V. Chernikov tmproutes_init(rh); 13834a5582cSAlexander V. Chernikov 13961eee0e2SAlexander V. Chernikov /* Init locks */ 140abe95d87SAndrey V. Elsukov RIB_LOCK_INIT(rh); 14161eee0e2SAlexander V. Chernikov 142a6663252SAlexander V. Chernikov nhops_init_rib(rh); 143a6663252SAlexander V. Chernikov 144da187ddbSAlexander V. Chernikov /* Init subscription system */ 145edc37a66SAlexander V. Chernikov rib_init_subscriptions(rh); 146da187ddbSAlexander V. Chernikov 14761eee0e2SAlexander V. Chernikov /* Finally, set base callbacks */ 14861eee0e2SAlexander V. Chernikov rh->rnh_addaddr = rn_addroute; 14961eee0e2SAlexander V. Chernikov rh->rnh_deladdr = rn_delete; 15061eee0e2SAlexander V. Chernikov rh->rnh_matchaddr = rn_match; 15161eee0e2SAlexander V. Chernikov rh->rnh_lookup = rn_lookup; 15261eee0e2SAlexander V. Chernikov rh->rnh_walktree = rn_walktree; 15361eee0e2SAlexander V. Chernikov rh->rnh_walktree_from = rn_walktree_from; 15461eee0e2SAlexander V. Chernikov 15561eee0e2SAlexander V. Chernikov return (rh); 15661eee0e2SAlexander V. Chernikov } 15761eee0e2SAlexander V. Chernikov 158a5243af2SBjoern A. Zeeb static int 159a5243af2SBjoern A. Zeeb rt_freeentry(struct radix_node *rn, void *arg) 160a5243af2SBjoern A. Zeeb { 161a5243af2SBjoern A. Zeeb struct radix_head * const rnh = arg; 162a5243af2SBjoern A. Zeeb struct radix_node *x; 163a5243af2SBjoern A. Zeeb 164a5243af2SBjoern A. Zeeb x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); 165a5243af2SBjoern A. Zeeb if (x != NULL) 166a5243af2SBjoern A. Zeeb R_Free(x); 167a5243af2SBjoern A. Zeeb return (0); 168a5243af2SBjoern A. Zeeb } 169a5243af2SBjoern A. Zeeb 17061eee0e2SAlexander V. Chernikov void 17161eee0e2SAlexander V. Chernikov rt_table_destroy(struct rib_head *rh) 17261eee0e2SAlexander V. Chernikov { 17361eee0e2SAlexander V. Chernikov 17434a5582cSAlexander V. Chernikov tmproutes_destroy(rh); 17534a5582cSAlexander V. Chernikov 176a5243af2SBjoern A. Zeeb rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); 177a5243af2SBjoern A. Zeeb 178a6663252SAlexander V. Chernikov nhops_destroy_rib(rh); 179a6663252SAlexander V. Chernikov 180edc37a66SAlexander V. Chernikov rib_destroy_subscriptions(rh); 181edc37a66SAlexander V. Chernikov 18261eee0e2SAlexander V. Chernikov /* Assume table is already empty */ 183abe95d87SAndrey V. Elsukov RIB_LOCK_DESTROY(rh); 18461eee0e2SAlexander V. Chernikov free(rh, M_RTABLE); 18561eee0e2SAlexander V. Chernikov } 18661eee0e2SAlexander V. Chernikov 187df8bae1dSRodney W. Grimes /* 18834a5582cSAlexander V. Chernikov * Adds a temporal redirect entry to the routing table. 18934a5582cSAlexander V. Chernikov * @fibnum: fib number 19034a5582cSAlexander V. Chernikov * @dst: destination to install redirect to 19134a5582cSAlexander V. Chernikov * @gateway: gateway to go via 19234a5582cSAlexander V. Chernikov * @author: sockaddr of originating router, can be NULL 19334a5582cSAlexander V. Chernikov * @ifp: interface to use for the redirected route 19434a5582cSAlexander V. Chernikov * @flags: set of flags to add. Allowed: RTF_GATEWAY 19534a5582cSAlexander V. Chernikov * @lifetime_sec: time in seconds to expire this redirect. 19634a5582cSAlexander V. Chernikov * 19734a5582cSAlexander V. Chernikov * Retuns 0 on success, errno otherwise. 198df8bae1dSRodney W. Grimes */ 19934a5582cSAlexander V. Chernikov int 20034a5582cSAlexander V. Chernikov rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, 20134a5582cSAlexander V. Chernikov struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) 2028b07e49aSJulian Elischer { 203e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc; 20434a5582cSAlexander V. Chernikov int error; 205df8bae1dSRodney W. Grimes struct rt_addrinfo info; 20634a5582cSAlexander V. Chernikov struct rt_metrics rti_rmx; 207df8bae1dSRodney W. Grimes struct ifaddr *ifa; 208c2c2a7c1SBjoern A. Zeeb 209b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 210b8a6e03fSGleb Smirnoff 21134a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 21234a5582cSAlexander V. Chernikov return (EAFNOSUPPORT); 2138e7e854cSKip Macy 21434a5582cSAlexander V. Chernikov /* Verify the allowed flag mask. */ 21534a5582cSAlexander V. Chernikov KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 21634a5582cSAlexander V. Chernikov ("invalid redirect flags: %x", flags)); 217*592d300eSAlexander V. Chernikov flags |= RTF_HOST | RTF_DYNAMIC; 21834a5582cSAlexander V. Chernikov 21934a5582cSAlexander V. Chernikov /* Get the best ifa for the given interface and gateway. */ 22034a5582cSAlexander V. Chernikov if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 22134a5582cSAlexander V. Chernikov return (ENETUNREACH); 22234a5582cSAlexander V. Chernikov ifa_ref(ifa); 22334a5582cSAlexander V. Chernikov 22434a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 2258071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 2268071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 2278071913dSRuslan Ermilov info.rti_ifa = ifa; 22834a5582cSAlexander V. Chernikov info.rti_ifp = ifp; 229*592d300eSAlexander V. Chernikov info.rti_flags = flags; 23034a5582cSAlexander V. Chernikov 23134a5582cSAlexander V. Chernikov /* Setup route metrics to define expire time. */ 23234a5582cSAlexander V. Chernikov bzero(&rti_rmx, sizeof(rti_rmx)); 23334a5582cSAlexander V. Chernikov /* Set expire time as absolute. */ 23434a5582cSAlexander V. Chernikov rti_rmx.rmx_expire = lifetime_sec + time_second; 23534a5582cSAlexander V. Chernikov info.rti_mflags |= RTV_EXPIRE; 23634a5582cSAlexander V. Chernikov info.rti_rmx = &rti_rmx; 23734a5582cSAlexander V. Chernikov 238e1c05fd2SAlexander V. Chernikov error = rib_action(fibnum, RTM_ADD, &info, &rc); 23934a5582cSAlexander V. Chernikov ifa_free(ifa); 24034a5582cSAlexander V. Chernikov 24134a5582cSAlexander V. Chernikov if (error != 0) { 24234a5582cSAlexander V. Chernikov /* TODO: add per-fib redirect stats. */ 24334a5582cSAlexander V. Chernikov return (error); 24434a5582cSAlexander V. Chernikov } 24534a5582cSAlexander V. Chernikov 24634a5582cSAlexander V. Chernikov RTSTAT_INC(rts_dynamic); 24734a5582cSAlexander V. Chernikov 24834a5582cSAlexander V. Chernikov /* Send notification of a route addition to userland. */ 24934a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 250df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 251df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 25234a5582cSAlexander V. Chernikov info.rti_info[RTAX_AUTHOR] = author; 253*592d300eSAlexander V. Chernikov rt_missmsg_fib(RTM_REDIRECT, &info, flags | RTF_UP, error, fibnum); 25434a5582cSAlexander V. Chernikov 25534a5582cSAlexander V. Chernikov return (0); 256df8bae1dSRodney W. Grimes } 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes /* 259df8bae1dSRodney W. Grimes * Routing table ioctl interface. 260df8bae1dSRodney W. Grimes */ 261df8bae1dSRodney W. Grimes int 2628b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 263df8bae1dSRodney W. Grimes { 2645090559bSChristian S.J. Peron 2655090559bSChristian S.J. Peron /* 2665090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 2675090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 2685090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 2695090559bSChristian S.J. Peron * in jails. 2705090559bSChristian S.J. Peron */ 271623ae52eSPoul-Henning Kamp #ifdef INET 272f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 2738b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 274623ae52eSPoul-Henning Kamp #else /* INET */ 275623ae52eSPoul-Henning Kamp return ENXIO; 276623ae52eSPoul-Henning Kamp #endif /* INET */ 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes struct ifaddr * 2804d2c2509SAlexander V. Chernikov ifa_ifwithroute(int flags, const struct sockaddr *dst, 2814d2c2509SAlexander V. Chernikov const struct sockaddr *gateway, u_int fibnum) 2828b07e49aSJulian Elischer { 283f59c6cb0SAlexander V. Chernikov struct ifaddr *ifa; 284d1dd20beSSam Leffler 28597168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 286df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 287df8bae1dSRodney W. Grimes /* 288df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 289df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 290df8bae1dSRodney W. Grimes * we should search for the destination 291df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 292df8bae1dSRodney W. Grimes * we can use the local address. 293df8bae1dSRodney W. Grimes */ 29485911824SLuigi Rizzo ifa = NULL; 29585911824SLuigi Rizzo if (flags & RTF_HOST) 2964f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(dst, fibnum); 29785911824SLuigi Rizzo if (ifa == NULL) 298df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 299df8bae1dSRodney W. Grimes } else { 300df8bae1dSRodney W. Grimes /* 301df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 302df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 303df8bae1dSRodney W. Grimes * other end of a pt to pt link. 304df8bae1dSRodney W. Grimes */ 3054f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(gateway, fibnum); 306df8bae1dSRodney W. Grimes } 30785911824SLuigi Rizzo if (ifa == NULL) 3084f8585e0SAlan Somers ifa = ifa_ifwithnet(gateway, 0, fibnum); 30985911824SLuigi Rizzo if (ifa == NULL) { 310682b902dSAlexander V. Chernikov struct nhop_object *nh; 311b83aa367SAndrey V. Elsukov 312682b902dSAlexander V. Chernikov nh = rib_lookup(fibnum, gateway, NHR_NONE, 0); 313682b902dSAlexander V. Chernikov 314e034e82cSQing Li /* 315e034e82cSQing Li * dismiss a gateway that is reachable only 316e034e82cSQing Li * through the default router 317e034e82cSQing Li */ 318682b902dSAlexander V. Chernikov if ((nh == NULL) || (nh->nh_flags & NHF_DEFAULT)) 319682b902dSAlexander V. Chernikov return (NULL); 320682b902dSAlexander V. Chernikov ifa = nh->nh_ifa; 321df8bae1dSRodney W. Grimes } 322df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 323df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 324df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 32585911824SLuigi Rizzo if (ifa == NULL) 326df8bae1dSRodney W. Grimes ifa = oifa; 327df8bae1dSRodney W. Grimes } 328682b902dSAlexander V. Chernikov 329df8bae1dSRodney W. Grimes return (ifa); 330df8bae1dSRodney W. Grimes } 331df8bae1dSRodney W. Grimes 3324bdf0b6aSAlexander V. Chernikov 3332caee4beSAlexander V. Chernikov /* 3349a1b64d5SAlexander V. Chernikov * Copy most of @rt data into @info. 3359a1b64d5SAlexander V. Chernikov * 3369a1b64d5SAlexander V. Chernikov * If @flags contains NHR_COPY, copies dst,netmask and gw to the 3379a1b64d5SAlexander V. Chernikov * pointers specified by @info structure. Assume such pointers 3389a1b64d5SAlexander V. Chernikov * are zeroed sockaddr-like structures with sa_len field initialized 3399a1b64d5SAlexander V. Chernikov * to reflect size of the provided buffer. if no NHR_COPY is specified, 3409a1b64d5SAlexander V. Chernikov * point dst,netmask and gw @info fields to appropriate @rt values. 3419a1b64d5SAlexander V. Chernikov * 3426b5d8e30SMark Johnston * if @flags contains NHR_REF, do refcouting on rt_ifp and rt_ifa. 3439a1b64d5SAlexander V. Chernikov * 3449a1b64d5SAlexander V. Chernikov * Returns 0 on success. 3459a1b64d5SAlexander V. Chernikov */ 3469a1b64d5SAlexander V. Chernikov int 3479a1b64d5SAlexander V. Chernikov rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags) 3489a1b64d5SAlexander V. Chernikov { 3499a1b64d5SAlexander V. Chernikov struct rt_metrics *rmx; 3509a1b64d5SAlexander V. Chernikov struct sockaddr *src, *dst; 351aaad3c4fSAlexander V. Chernikov struct nhop_object *nh; 3529a1b64d5SAlexander V. Chernikov int sa_len; 3539a1b64d5SAlexander V. Chernikov 35493bfd365SAlexander V. Chernikov nh = rt->rt_nhop; 3559a1b64d5SAlexander V. Chernikov if (flags & NHR_COPY) { 3569a1b64d5SAlexander V. Chernikov /* Copy destination if dst is non-zero */ 3579a1b64d5SAlexander V. Chernikov src = rt_key(rt); 3589a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 3599a1b64d5SAlexander V. Chernikov sa_len = src->sa_len; 36016703ea8SAlexander V. Chernikov if (dst != NULL) { 3619a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3629a1b64d5SAlexander V. Chernikov return (ENOMEM); 3639a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3649a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3659a1b64d5SAlexander V. Chernikov } 3669a1b64d5SAlexander V. Chernikov 3679a1b64d5SAlexander V. Chernikov /* Copy mask if set && dst is non-zero */ 3689a1b64d5SAlexander V. Chernikov src = rt_mask(rt); 3699a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_NETMASK]; 3709a1b64d5SAlexander V. Chernikov if (src != NULL && dst != NULL) { 3719a1b64d5SAlexander V. Chernikov 3729a1b64d5SAlexander V. Chernikov /* 3739a1b64d5SAlexander V. Chernikov * Radix stores different value in sa_len, 3749a1b64d5SAlexander V. Chernikov * assume rt_mask() to have the same length 3759a1b64d5SAlexander V. Chernikov * as rt_key() 3769a1b64d5SAlexander V. Chernikov */ 3779a1b64d5SAlexander V. Chernikov if (sa_len > dst->sa_len) 3789a1b64d5SAlexander V. Chernikov return (ENOMEM); 3799a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3809a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3819a1b64d5SAlexander V. Chernikov } 3829a1b64d5SAlexander V. Chernikov 3839a1b64d5SAlexander V. Chernikov /* Copy gateway is set && dst is non-zero */ 38493bfd365SAlexander V. Chernikov src = &nh->gw_sa; 3859a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_GATEWAY]; 38693bfd365SAlexander V. Chernikov if ((nhop_get_rtflags(nh) & RTF_GATEWAY) && 38793bfd365SAlexander V. Chernikov src != NULL && dst != NULL) { 3889a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3899a1b64d5SAlexander V. Chernikov return (ENOMEM); 3909a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3919a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3929a1b64d5SAlexander V. Chernikov } 3939a1b64d5SAlexander V. Chernikov } else { 3949a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 3959a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3969a1b64d5SAlexander V. Chernikov if (rt_mask(rt) != NULL) { 3979a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 3989a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3999a1b64d5SAlexander V. Chernikov } 40093bfd365SAlexander V. Chernikov if (nhop_get_rtflags(nh) & RTF_GATEWAY) { 40193bfd365SAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; 4029a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 4039a1b64d5SAlexander V. Chernikov } 4049a1b64d5SAlexander V. Chernikov } 4059a1b64d5SAlexander V. Chernikov 4069a1b64d5SAlexander V. Chernikov rmx = info->rti_rmx; 4079a1b64d5SAlexander V. Chernikov if (rmx != NULL) { 4089a1b64d5SAlexander V. Chernikov info->rti_mflags |= RTV_MTU; 409aaad3c4fSAlexander V. Chernikov rmx->rmx_mtu = nh->nh_mtu; 4109a1b64d5SAlexander V. Chernikov } 4119a1b64d5SAlexander V. Chernikov 41293bfd365SAlexander V. Chernikov info->rti_flags = rt->rte_flags | nhop_get_rtflags(nh); 413aaad3c4fSAlexander V. Chernikov info->rti_ifp = nh->nh_ifp; 414aaad3c4fSAlexander V. Chernikov info->rti_ifa = nh->nh_ifa; 4159a1b64d5SAlexander V. Chernikov if (flags & NHR_REF) { 4169a1b64d5SAlexander V. Chernikov if_ref(info->rti_ifp); 4176b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 4189a1b64d5SAlexander V. Chernikov } 4199a1b64d5SAlexander V. Chernikov 4209a1b64d5SAlexander V. Chernikov return (0); 4219a1b64d5SAlexander V. Chernikov } 4229a1b64d5SAlexander V. Chernikov 4239a1b64d5SAlexander V. Chernikov /* 4249a1b64d5SAlexander V. Chernikov * Lookups up route entry for @dst in RIB database for fib @fibnum. 4259a1b64d5SAlexander V. Chernikov * Exports entry data to @info using rt_exportinfo(). 4269a1b64d5SAlexander V. Chernikov * 4276b5d8e30SMark Johnston * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa. 4286b5d8e30SMark Johnston * All references can be released later by calling rib_free_info(). 4299a1b64d5SAlexander V. Chernikov * 4309a1b64d5SAlexander V. Chernikov * Returns 0 on success. 4319a1b64d5SAlexander V. Chernikov * Returns ENOENT for lookup failure, ENOMEM for export failure. 4329a1b64d5SAlexander V. Chernikov */ 4339a1b64d5SAlexander V. Chernikov int 4349a1b64d5SAlexander V. Chernikov rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, 4359a1b64d5SAlexander V. Chernikov uint32_t flowid, struct rt_addrinfo *info) 4369a1b64d5SAlexander V. Chernikov { 43720efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 43861eee0e2SAlexander V. Chernikov struct rib_head *rh; 4399a1b64d5SAlexander V. Chernikov struct radix_node *rn; 4409a1b64d5SAlexander V. Chernikov struct rtentry *rt; 4419a1b64d5SAlexander V. Chernikov int error; 4429a1b64d5SAlexander V. Chernikov 4439a1b64d5SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum")); 4449a1b64d5SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, dst->sa_family); 4459a1b64d5SAlexander V. Chernikov if (rh == NULL) 4469a1b64d5SAlexander V. Chernikov return (ENOENT); 4479a1b64d5SAlexander V. Chernikov 44861eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 44961eee0e2SAlexander V. Chernikov rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head); 4509a1b64d5SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 4519a1b64d5SAlexander V. Chernikov rt = RNTORT(rn); 4529a1b64d5SAlexander V. Chernikov /* Ensure route & ifp is UP */ 4538c61eb21SAlexander V. Chernikov if (RT_LINK_IS_UP(rt->rt_nhop->nh_ifp)) { 4549a1b64d5SAlexander V. Chernikov flags = (flags & NHR_REF) | NHR_COPY; 4559a1b64d5SAlexander V. Chernikov error = rt_exportinfo(rt, info, flags); 45661eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4579a1b64d5SAlexander V. Chernikov 4589a1b64d5SAlexander V. Chernikov return (error); 4599a1b64d5SAlexander V. Chernikov } 4609a1b64d5SAlexander V. Chernikov } 46161eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4629a1b64d5SAlexander V. Chernikov 4639a1b64d5SAlexander V. Chernikov return (ENOENT); 4649a1b64d5SAlexander V. Chernikov } 4659a1b64d5SAlexander V. Chernikov 4669a1b64d5SAlexander V. Chernikov /* 4679a1b64d5SAlexander V. Chernikov * Releases all references acquired by rib_lookup_info() when 4689a1b64d5SAlexander V. Chernikov * called with NHR_REF flags. 4699a1b64d5SAlexander V. Chernikov */ 4709a1b64d5SAlexander V. Chernikov void 4719a1b64d5SAlexander V. Chernikov rib_free_info(struct rt_addrinfo *info) 4729a1b64d5SAlexander V. Chernikov { 4739a1b64d5SAlexander V. Chernikov 4746b5d8e30SMark Johnston ifa_free(info->rti_ifa); 4759a1b64d5SAlexander V. Chernikov if_rele(info->rti_ifp); 4769a1b64d5SAlexander V. Chernikov } 4779a1b64d5SAlexander V. Chernikov 4789a1b64d5SAlexander V. Chernikov /* 4792caee4beSAlexander V. Chernikov * Iterates over all existing fibs in system calling 4802caee4beSAlexander V. Chernikov * @setwa_f function prior to traversing each fib. 4812caee4beSAlexander V. Chernikov * Calls @wa_f function for each element in current fib. 4822caee4beSAlexander V. Chernikov * If af is not AF_UNSPEC, iterates over fibs in particular 4832caee4beSAlexander V. Chernikov * address family. 4842caee4beSAlexander V. Chernikov */ 4854bdf0b6aSAlexander V. Chernikov void 4862caee4beSAlexander V. Chernikov rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, 4872caee4beSAlexander V. Chernikov void *arg) 4884bdf0b6aSAlexander V. Chernikov { 48961eee0e2SAlexander V. Chernikov struct rib_head *rnh; 4904bdf0b6aSAlexander V. Chernikov uint32_t fibnum; 4914bdf0b6aSAlexander V. Chernikov int i; 4924bdf0b6aSAlexander V. Chernikov 4934bdf0b6aSAlexander V. Chernikov for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 4944bdf0b6aSAlexander V. Chernikov /* Do we want some specific family? */ 4954bdf0b6aSAlexander V. Chernikov if (af != AF_UNSPEC) { 4964bdf0b6aSAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, af); 4974bdf0b6aSAlexander V. Chernikov if (rnh == NULL) 4984bdf0b6aSAlexander V. Chernikov continue; 4994bdf0b6aSAlexander V. Chernikov if (setwa_f != NULL) 500e4790abfSAlexander V. Chernikov setwa_f(rnh, fibnum, af, arg); 5014bdf0b6aSAlexander V. Chernikov 50261eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 50361eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); 50461eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 5054bdf0b6aSAlexander V. Chernikov continue; 5064bdf0b6aSAlexander V. Chernikov } 5074bdf0b6aSAlexander V. Chernikov 5084bdf0b6aSAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 5094bdf0b6aSAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, i); 5104bdf0b6aSAlexander V. Chernikov if (rnh == NULL) 5114bdf0b6aSAlexander V. Chernikov continue; 5124bdf0b6aSAlexander V. Chernikov if (setwa_f != NULL) 5134bdf0b6aSAlexander V. Chernikov setwa_f(rnh, fibnum, i, arg); 5144bdf0b6aSAlexander V. Chernikov 51561eee0e2SAlexander V. Chernikov RIB_WLOCK(rnh); 51661eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg); 51761eee0e2SAlexander V. Chernikov RIB_WUNLOCK(rnh); 5184bdf0b6aSAlexander V. Chernikov } 5194bdf0b6aSAlexander V. Chernikov } 5204bdf0b6aSAlexander V. Chernikov } 5214bdf0b6aSAlexander V. Chernikov 52234a5582cSAlexander V. Chernikov /* 52334a5582cSAlexander V. Chernikov * Iterates over all existing fibs in system and deletes each element 52434a5582cSAlexander V. Chernikov * for which @filter_f function returns non-zero value. 52534a5582cSAlexander V. Chernikov * If @family is not AF_UNSPEC, iterates over fibs in particular 52634a5582cSAlexander V. Chernikov * address family. 52734a5582cSAlexander V. Chernikov */ 52834a5582cSAlexander V. Chernikov void 52934a5582cSAlexander V. Chernikov rt_foreach_fib_walk_del(int family, rt_filter_f_t *filter_f, void *arg) 53034a5582cSAlexander V. Chernikov { 53134a5582cSAlexander V. Chernikov u_int fibnum; 53234a5582cSAlexander V. Chernikov int i, start, end; 53334a5582cSAlexander V. Chernikov 53434a5582cSAlexander V. Chernikov for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 53534a5582cSAlexander V. Chernikov /* Do we want some specific family? */ 53634a5582cSAlexander V. Chernikov if (family != AF_UNSPEC) { 53734a5582cSAlexander V. Chernikov start = family; 53834a5582cSAlexander V. Chernikov end = family; 53934a5582cSAlexander V. Chernikov } else { 54034a5582cSAlexander V. Chernikov start = 1; 54134a5582cSAlexander V. Chernikov end = AF_MAX; 54234a5582cSAlexander V. Chernikov } 54334a5582cSAlexander V. Chernikov 54434a5582cSAlexander V. Chernikov for (i = start; i <= end; i++) { 54534a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, i) == NULL) 54634a5582cSAlexander V. Chernikov continue; 54734a5582cSAlexander V. Chernikov 54834a5582cSAlexander V. Chernikov rib_walk_del(fibnum, i, filter_f, arg, 0); 549e8b0643eSAlexander V. Chernikov } 550e8b0643eSAlexander V. Chernikov } 551e8b0643eSAlexander V. Chernikov } 552e8b0643eSAlexander V. Chernikov 5534bdf0b6aSAlexander V. Chernikov /* 5544bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 5554bdf0b6aSAlexander V. Chernikov * 5564bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 5574bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 5584bdf0b6aSAlexander V. Chernikov * 5594bdf0b6aSAlexander V. Chernikov * Arguments: 5604bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 561539642a2SAlexander V. Chernikov * nh pointer to nhop 5624bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 5634bdf0b6aSAlexander V. Chernikov * 5644bdf0b6aSAlexander V. Chernikov * Returns: 5654bdf0b6aSAlexander V. Chernikov * 0 successful 5664bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 5674bdf0b6aSAlexander V. Chernikov */ 5684bdf0b6aSAlexander V. Chernikov static int 569539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 5704bdf0b6aSAlexander V. Chernikov { 5714bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 5724bdf0b6aSAlexander V. Chernikov 573539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 5744bdf0b6aSAlexander V. Chernikov return (0); 5754bdf0b6aSAlexander V. Chernikov 5764bdf0b6aSAlexander V. Chernikov /* 5774bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 5784bdf0b6aSAlexander V. Chernikov * with cloned routes 5794bdf0b6aSAlexander V. Chernikov */ 58093bfd365SAlexander V. Chernikov if ((rt->rte_flags & RTF_UP) == 0) 5814bdf0b6aSAlexander V. Chernikov return (0); 5824bdf0b6aSAlexander V. Chernikov 583e8b0643eSAlexander V. Chernikov return (1); 5844bdf0b6aSAlexander V. Chernikov } 5854bdf0b6aSAlexander V. Chernikov 5864bdf0b6aSAlexander V. Chernikov /* 5874bdf0b6aSAlexander V. Chernikov * Delete all remaining routes using this interface 5884bdf0b6aSAlexander V. Chernikov * Unfortuneatly the only way to do this is to slog through 5894bdf0b6aSAlexander V. Chernikov * the entire routing table looking for routes which point 5904bdf0b6aSAlexander V. Chernikov * to this interface...oh well... 5914bdf0b6aSAlexander V. Chernikov */ 5924bdf0b6aSAlexander V. Chernikov void 59380ae8d60SBjoern A. Zeeb rt_flushifroutes_af(struct ifnet *ifp, int af) 59480ae8d60SBjoern A. Zeeb { 59580ae8d60SBjoern A. Zeeb KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d", 59680ae8d60SBjoern A. Zeeb __func__, af, AF_MAX)); 59780ae8d60SBjoern A. Zeeb 59880ae8d60SBjoern A. Zeeb rt_foreach_fib_walk_del(af, rt_ifdelroute, ifp); 59980ae8d60SBjoern A. Zeeb } 60080ae8d60SBjoern A. Zeeb 60180ae8d60SBjoern A. Zeeb void 6024bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 6034bdf0b6aSAlexander V. Chernikov { 6044bdf0b6aSAlexander V. Chernikov 605e8b0643eSAlexander V. Chernikov rt_foreach_fib_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 6064bdf0b6aSAlexander V. Chernikov } 6074bdf0b6aSAlexander V. Chernikov 6088071913dSRuslan Ermilov /* 6098c0fec80SRobert Watson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 6108c0fec80SRobert Watson * it will be referenced so the caller must free it. 6112ad7ed6eSAlexander V. Chernikov * 6122ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 6132ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 6148c0fec80SRobert Watson */ 6158b07e49aSJulian Elischer int 6168b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 6178b07e49aSJulian Elischer { 6184d2c2509SAlexander V. Chernikov const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr; 619a68cc388SGleb Smirnoff struct epoch_tracker et; 6204d2c2509SAlexander V. Chernikov int needref, error, flags; 6214d2c2509SAlexander V. Chernikov 6224d2c2509SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 6234d2c2509SAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 6244d2c2509SAlexander V. Chernikov ifpaddr = info->rti_info[RTAX_IFP]; 6254d2c2509SAlexander V. Chernikov ifaaddr = info->rti_info[RTAX_IFA]; 6264d2c2509SAlexander V. Chernikov flags = info->rti_flags; 6278071913dSRuslan Ermilov 6288071913dSRuslan Ermilov /* 6298071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 6308071913dSRuslan Ermilov * when protocol address is ambiguous. 6318071913dSRuslan Ermilov */ 6321ebec5faSMatt Macy error = 0; 6331ebec5faSMatt Macy needref = (info->rti_ifa == NULL); 634a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 6352ad7ed6eSAlexander V. Chernikov 6362ad7ed6eSAlexander V. Chernikov /* If we have interface specified by the ifindex in the address, use it */ 6378071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 6382ad7ed6eSAlexander V. Chernikov ifpaddr->sa_family == AF_LINK) { 6392ad7ed6eSAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; 6402ad7ed6eSAlexander V. Chernikov if (sdl->sdl_index != 0) 641270b83b9SHans Petter Selasky info->rti_ifp = ifnet_byindex(sdl->sdl_index); 6428c0fec80SRobert Watson } 6432ad7ed6eSAlexander V. Chernikov /* 6442ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 6452ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 6462ad7ed6eSAlexander V. Chernikov */ 6478071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 6488071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 6498071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 6504d2c2509SAlexander V. Chernikov const struct sockaddr *sa; 6518071913dSRuslan Ermilov 6522ad7ed6eSAlexander V. Chernikov /* 6532ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 6542ad7ed6eSAlexander V. Chernikov * 6552ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 6562ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 6572ad7ed6eSAlexander V. Chernikov * Order of preference: 6582ad7ed6eSAlexander V. Chernikov * 1) IFA address 6592ad7ed6eSAlexander V. Chernikov * 2) gateway address 6602ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 6612ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 6622ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 6632ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 6642ad7ed6eSAlexander V. Chernikov * ignore gateway 6652ad7ed6eSAlexander V. Chernikov * 3) final destination. 6662ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 6672ad7ed6eSAlexander V. Chernikov * -- else -- 6682ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 6692ad7ed6eSAlexander V. Chernikov */ 6702ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 6712ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 6722ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 6732ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 6742ad7ed6eSAlexander V. Chernikov sa = gateway; 6752ad7ed6eSAlexander V. Chernikov else 6762ad7ed6eSAlexander V. Chernikov sa = dst; 6772ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 6788071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 6792ad7ed6eSAlexander V. Chernikov /* Case 4 */ 6802ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 6812ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 6822ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 6834f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 6848b07e49aSJulian Elischer fibnum); 6858071913dSRuslan Ermilov else if (sa != NULL) 6864f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 6878b07e49aSJulian Elischer fibnum); 6888071913dSRuslan Ermilov } 6891ebec5faSMatt Macy if (needref && info->rti_ifa != NULL) { 6908071913dSRuslan Ermilov if (info->rti_ifp == NULL) 691134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 6924f6c66ccSMatt Macy ifa_ref(info->rti_ifa); 6938071913dSRuslan Ermilov } else 6948071913dSRuslan Ermilov error = ENETUNREACH; 695a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 6968071913dSRuslan Ermilov return (error); 6978071913dSRuslan Ermilov } 6988071913dSRuslan Ermilov 6997f948f12SAlexander V. Chernikov void 7007f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 7017f948f12SAlexander V. Chernikov { 70261eee0e2SAlexander V. Chernikov struct rib_head *rnh; 7039e022295SAlexander V. Chernikov int mtu; 7047f948f12SAlexander V. Chernikov int i, j; 7057f948f12SAlexander V. Chernikov 7067f948f12SAlexander V. Chernikov /* 7077f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 7087f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 7097f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 7107f948f12SAlexander V. Chernikov */ 7117f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 7129e022295SAlexander V. Chernikov mtu = if_getmtu_family(ifp, i); 7137f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 7147f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 7157f948f12SAlexander V. Chernikov if (rnh == NULL) 7167f948f12SAlexander V. Chernikov continue; 7179e022295SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, mtu); 7187f948f12SAlexander V. Chernikov } 7197f948f12SAlexander V. Chernikov } 7207f948f12SAlexander V. Chernikov } 7217f948f12SAlexander V. Chernikov 7227f948f12SAlexander V. Chernikov 7235a2f4cbdSAlexander V. Chernikov #if 0 7245a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 7255a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 7265a2f4cbdSAlexander V. Chernikov 7275a2f4cbdSAlexander V. Chernikov int 7285a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 7295a2f4cbdSAlexander V. Chernikov { 7305a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 7315a2f4cbdSAlexander V. Chernikov 7325a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 7335a2f4cbdSAlexander V. Chernikov case AF_INET: 7345a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 7355a2f4cbdSAlexander V. Chernikov break; 7365a2f4cbdSAlexander V. Chernikov case AF_INET6: 7375a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 7385a2f4cbdSAlexander V. Chernikov break; 7395a2f4cbdSAlexander V. Chernikov } 7405a2f4cbdSAlexander V. Chernikov 7415a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 7425a2f4cbdSAlexander V. Chernikov return (0); 7435a2f4cbdSAlexander V. Chernikov 7445a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 7455a2f4cbdSAlexander V. Chernikov return (0); 7465a2f4cbdSAlexander V. Chernikov 7475a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 7485a2f4cbdSAlexander V. Chernikov } 7495a2f4cbdSAlexander V. Chernikov 7505a2f4cbdSAlexander V. Chernikov int 7515a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 7525a2f4cbdSAlexander V. Chernikov { 7535a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 7545a2f4cbdSAlexander V. Chernikov int i = 0; 7555a2f4cbdSAlexander V. Chernikov 7565a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 7575a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 7585a2f4cbdSAlexander V. Chernikov 7595a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 7605a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 7615a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 7625a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 7635a2f4cbdSAlexander V. Chernikov } 7645a2f4cbdSAlexander V. Chernikov 7655a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 7665a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 767aaad3c4fSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 7685a2f4cbdSAlexander V. Chernikov } 7695a2f4cbdSAlexander V. Chernikov 7705a2f4cbdSAlexander V. Chernikov return (i); 7715a2f4cbdSAlexander V. Chernikov } 7725a2f4cbdSAlexander V. Chernikov #endif 7735a2f4cbdSAlexander V. Chernikov 774427ac07fSKip Macy #ifdef RADIX_MPATH 775e8b0643eSAlexander V. Chernikov /* 776e8b0643eSAlexander V. Chernikov * Deletes key for single-path routes, unlinks rtentry with 777e8b0643eSAlexander V. Chernikov * gateway specified in @info from multi-path routes. 778e8b0643eSAlexander V. Chernikov * 779e8b0643eSAlexander V. Chernikov * Returnes unlinked entry. In case of failure, returns NULL 780e8b0643eSAlexander V. Chernikov * and sets @perror to ESRCH. 781e8b0643eSAlexander V. Chernikov */ 7824d2c2509SAlexander V. Chernikov struct radix_node * 78361eee0e2SAlexander V. Chernikov rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, 784e8b0643eSAlexander V. Chernikov struct rtentry *rto, int *perror) 785427ac07fSKip Macy { 786427ac07fSKip Macy /* 787427ac07fSKip Macy * if we got multipath routes, we require users to specify 788427ac07fSKip Macy * a matching RTAX_GATEWAY. 789427ac07fSKip Macy */ 790e8b0643eSAlexander V. Chernikov struct rtentry *rt; // *rto = NULL; 791f59c6cb0SAlexander V. Chernikov struct radix_node *rn; 792e8b0643eSAlexander V. Chernikov struct sockaddr *gw; 793427ac07fSKip Macy 794e8b0643eSAlexander V. Chernikov gw = info->rti_info[RTAX_GATEWAY]; 795e8b0643eSAlexander V. Chernikov rt = rt_mpath_matchgate(rto, gw); 796e8b0643eSAlexander V. Chernikov if (rt == NULL) { 797e8b0643eSAlexander V. Chernikov *perror = ESRCH; 798e8b0643eSAlexander V. Chernikov return (NULL); 799e8b0643eSAlexander V. Chernikov } 8005a2f4cbdSAlexander V. Chernikov 801427ac07fSKip Macy /* 802427ac07fSKip Macy * this is the first entry in the chain 803427ac07fSKip Macy */ 804427ac07fSKip Macy if (rto == rt) { 805427ac07fSKip Macy rn = rn_mpath_next((struct radix_node *)rt); 806427ac07fSKip Macy /* 807427ac07fSKip Macy * there is another entry, now it's active 808427ac07fSKip Macy */ 809427ac07fSKip Macy if (rn) { 810427ac07fSKip Macy rto = RNTORT(rn); 811eb1c7adbSAlexander V. Chernikov rto->rte_flags |= RTF_UP; 812eb1c7adbSAlexander V. Chernikov } else if (rt->rte_flags & RTF_GATEWAY) { 813427ac07fSKip Macy /* 814427ac07fSKip Macy * For gateway routes, we need to 815427ac07fSKip Macy * make sure that we we are deleting 816427ac07fSKip Macy * the correct gateway. 817427ac07fSKip Macy * rt_mpath_matchgate() does not 818427ac07fSKip Macy * check the case when there is only 819427ac07fSKip Macy * one route in the chain. 820427ac07fSKip Macy */ 821e8b0643eSAlexander V. Chernikov if (gw && 822aaad3c4fSAlexander V. Chernikov (rt->rt_nhop->gw_sa.sa_len != gw->sa_len || 823aaad3c4fSAlexander V. Chernikov memcmp(&rt->rt_nhop->gw_sa, gw, gw->sa_len))) { 824e8b0643eSAlexander V. Chernikov *perror = ESRCH; 825e8b0643eSAlexander V. Chernikov return (NULL); 826e8b0643eSAlexander V. Chernikov } 8276a7bff2cSKip Macy } 8286a7bff2cSKip Macy 829427ac07fSKip Macy /* 830427ac07fSKip Macy * use the normal delete code to remove 831427ac07fSKip Macy * the first entry 832427ac07fSKip Macy */ 8334d2c2509SAlexander V. Chernikov rn = rnh->rnh_deladdr(info->rti_info[RTAX_DST], 8344d2c2509SAlexander V. Chernikov info->rti_info[RTAX_NETMASK], 8354d2c2509SAlexander V. Chernikov &rnh->head); 836f7d79f6cSMitchell Horne if (rn != NULL) { 837e8b0643eSAlexander V. Chernikov *perror = 0; 838f7d79f6cSMitchell Horne } else { 839f7d79f6cSMitchell Horne *perror = ESRCH; 840f7d79f6cSMitchell Horne } 841e8b0643eSAlexander V. Chernikov return (rn); 842427ac07fSKip Macy } 843427ac07fSKip Macy 844427ac07fSKip Macy /* 845427ac07fSKip Macy * if the entry is 2nd and on up 846427ac07fSKip Macy */ 847e8b0643eSAlexander V. Chernikov if (rt_mpath_deldup(rto, rt) == 0) 848427ac07fSKip Macy panic ("rtrequest1: rt_mpath_deldup"); 849e8b0643eSAlexander V. Chernikov *perror = 0; 850e8b0643eSAlexander V. Chernikov rn = (struct radix_node *)rt; 851e8b0643eSAlexander V. Chernikov return (rn); 852427ac07fSKip Macy } 853427ac07fSKip Macy #endif 854427ac07fSKip Macy 8554d2c2509SAlexander V. Chernikov void 8560fb9298dSAlexander V. Chernikov rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) 8570fb9298dSAlexander V. Chernikov { 8580fb9298dSAlexander V. Chernikov 8590fb9298dSAlexander V. Chernikov if (info->rti_mflags & RTV_WEIGHT) 8600fb9298dSAlexander V. Chernikov rt->rt_weight = info->rti_rmx->rmx_weight; 8610fb9298dSAlexander V. Chernikov /* Kernel -> userland timebase conversion. */ 8620fb9298dSAlexander V. Chernikov if (info->rti_mflags & RTV_EXPIRE) 8630fb9298dSAlexander V. Chernikov rt->rt_expire = info->rti_rmx->rmx_expire ? 8640fb9298dSAlexander V. Chernikov info->rti_rmx->rmx_expire - time_second + time_uptime : 0; 8650fb9298dSAlexander V. Chernikov } 8660fb9298dSAlexander V. Chernikov 867c7ab6602SQing Li void 868d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 869df8bae1dSRodney W. Grimes { 870f59c6cb0SAlexander V. Chernikov u_char *cp1 = (u_char *)src; 871f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 872f59c6cb0SAlexander V. Chernikov u_char *cp3 = (u_char *)netmask; 873df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 874df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 875df8bae1dSRodney W. Grimes 876df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 877df8bae1dSRodney W. Grimes cp3 += 2; 878df8bae1dSRodney W. Grimes if (cplim > cplim2) 879df8bae1dSRodney W. Grimes cplim = cplim2; 880df8bae1dSRodney W. Grimes while (cp2 < cplim) 881df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 882df8bae1dSRodney W. Grimes if (cp2 < cplim2) 883df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 884df8bae1dSRodney W. Grimes } 885df8bae1dSRodney W. Grimes 886df8bae1dSRodney W. Grimes /* 887df8bae1dSRodney W. Grimes * Set up a routing table entry, normally 888df8bae1dSRodney W. Grimes * for an interface. 889df8bae1dSRodney W. Grimes */ 8908b07e49aSJulian Elischer #define _SOCKADDR_TMPSIZE 128 /* Not too big.. kernel stack size is limited */ 8918b07e49aSJulian Elischer static inline int 8928b07e49aSJulian Elischer rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) 893df8bae1dSRodney W. Grimes { 89420efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 8952bbab0afSAlexander V. Chernikov struct epoch_tracker et; 8965aca0b30SLuigi Rizzo struct sockaddr *dst; 8978071913dSRuslan Ermilov struct sockaddr *netmask; 898e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc; 8998071913dSRuslan Ermilov struct rt_addrinfo info; 900e440aed9SQing Li int error = 0; 9018b07e49aSJulian Elischer int startfib, endfib; 9028b07e49aSJulian Elischer char tempbuf[_SOCKADDR_TMPSIZE]; 9038b07e49aSJulian Elischer int didwork = 0; 9048b07e49aSJulian Elischer int a_failure = 0; 905aaad3c4fSAlexander V. Chernikov struct sockaddr_dl_short *sdl = NULL; 90661eee0e2SAlexander V. Chernikov struct rib_head *rnh; 907df8bae1dSRodney W. Grimes 9088071913dSRuslan Ermilov if (flags & RTF_HOST) { 9098071913dSRuslan Ermilov dst = ifa->ifa_dstaddr; 9108071913dSRuslan Ermilov netmask = NULL; 9118071913dSRuslan Ermilov } else { 9128071913dSRuslan Ermilov dst = ifa->ifa_addr; 9138071913dSRuslan Ermilov netmask = ifa->ifa_netmask; 9148071913dSRuslan Ermilov } 915b3dd0771SBjoern A. Zeeb if (dst->sa_len == 0) 916b3dd0771SBjoern A. Zeeb return(EINVAL); 917b680a383SBjoern A. Zeeb switch (dst->sa_family) { 918b680a383SBjoern A. Zeeb case AF_INET6: 919b680a383SBjoern A. Zeeb case AF_INET: 920b680a383SBjoern A. Zeeb /* We support multiple FIBs. */ 921b680a383SBjoern A. Zeeb break; 922b680a383SBjoern A. Zeeb default: 923b680a383SBjoern A. Zeeb fibnum = RT_DEFAULT_FIB; 924b680a383SBjoern A. Zeeb break; 925b680a383SBjoern A. Zeeb } 9267d9b6df1SAlexander V. Chernikov if (fibnum == RT_ALL_FIBS) { 927ee0bd4b9SHiroki Sato if (V_rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) 9280489b891SAlan Somers startfib = endfib = ifa->ifa_ifp->if_fib; 929ee0bd4b9SHiroki Sato else { 9308b07e49aSJulian Elischer startfib = 0; 9318b07e49aSJulian Elischer endfib = rt_numfibs - 1; 93266e8505fSJulian Elischer } 9338b07e49aSJulian Elischer } else { 9348b07e49aSJulian Elischer KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum")); 9358b07e49aSJulian Elischer startfib = fibnum; 9368b07e49aSJulian Elischer endfib = fibnum; 9378b07e49aSJulian Elischer } 938ac4a76ebSBjoern A. Zeeb 939b0a76b88SJulian Elischer /* 9408b07e49aSJulian Elischer * If it's a delete, check that if it exists, 9418b07e49aSJulian Elischer * it's on the correct interface or we might scrub 9428b07e49aSJulian Elischer * a route to another ifa which would 943b0a76b88SJulian Elischer * be confusing at best and possibly worse. 944b0a76b88SJulian Elischer */ 945df8bae1dSRodney W. Grimes if (cmd == RTM_DELETE) { 946b0a76b88SJulian Elischer /* 947b0a76b88SJulian Elischer * It's a delete, so it should already exist.. 948b0a76b88SJulian Elischer * If it's a net, mask off the host bits 949b0a76b88SJulian Elischer * (Assuming we have a mask) 9508b07e49aSJulian Elischer * XXX this is kinda inet specific.. 951b0a76b88SJulian Elischer */ 9528071913dSRuslan Ermilov if (netmask != NULL) { 9538b07e49aSJulian Elischer rt_maskedcopy(dst, (struct sockaddr *)tempbuf, netmask); 9548b07e49aSJulian Elischer dst = (struct sockaddr *)tempbuf; 955df8bae1dSRodney W. Grimes } 956563ab4e4SAlexander V. Chernikov } else if (cmd == RTM_ADD) { 957aaad3c4fSAlexander V. Chernikov sdl = (struct sockaddr_dl_short *)tempbuf; 958aaad3c4fSAlexander V. Chernikov bzero(sdl, sizeof(struct sockaddr_dl_short)); 959563ab4e4SAlexander V. Chernikov sdl->sdl_family = AF_LINK; 960aaad3c4fSAlexander V. Chernikov sdl->sdl_len = sizeof(struct sockaddr_dl_short); 961563ab4e4SAlexander V. Chernikov sdl->sdl_type = ifa->ifa_ifp->if_type; 962563ab4e4SAlexander V. Chernikov sdl->sdl_index = ifa->ifa_ifp->if_index; 9638b07e49aSJulian Elischer } 9648b07e49aSJulian Elischer /* 9658b07e49aSJulian Elischer * Now go through all the requested tables (fibs) and do the 9668b07e49aSJulian Elischer * requested action. Realistically, this will either be fib 0 9678b07e49aSJulian Elischer * for protocols that don't do multiple tables or all the 968a8498625SBjoern A. Zeeb * tables for those that do. 9698b07e49aSJulian Elischer */ 9708b07e49aSJulian Elischer for ( fibnum = startfib; fibnum <= endfib; fibnum++) { 9718b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 9728b07e49aSJulian Elischer struct radix_node *rn; 973b0a76b88SJulian Elischer /* 9748071913dSRuslan Ermilov * Look up an rtentry that is in the routing tree and 9758071913dSRuslan Ermilov * contains the correct info. 976b0a76b88SJulian Elischer */ 977c2c2a7c1SBjoern A. Zeeb rnh = rt_tables_get_rnh(fibnum, dst->sa_family); 978c2c2a7c1SBjoern A. Zeeb if (rnh == NULL) 9798b07e49aSJulian Elischer /* this table doesn't exist but others might */ 9808b07e49aSJulian Elischer continue; 98161eee0e2SAlexander V. Chernikov RIB_RLOCK(rnh); 98261eee0e2SAlexander V. Chernikov rn = rnh->rnh_lookup(dst, netmask, &rnh->head); 983e440aed9SQing Li #ifdef RADIX_MPATH 98461eee0e2SAlexander V. Chernikov if (rt_mpath_capable(rnh)) { 985e440aed9SQing Li 986e440aed9SQing Li if (rn == NULL) 987e440aed9SQing Li error = ESRCH; 988e440aed9SQing Li else { 989e1c05fd2SAlexander V. Chernikov struct rtentry *rt = RNTORT(rn); 990e440aed9SQing Li /* 9919e022295SAlexander V. Chernikov * for interface route the gateway 9929e022295SAlexander V. Chernikov * gateway is sockaddr_dl, so 9938b07e49aSJulian Elischer * rt_mpath_matchgate must use the 9948b07e49aSJulian Elischer * interface address 995e440aed9SQing Li */ 9968b07e49aSJulian Elischer rt = rt_mpath_matchgate(rt, 9978b07e49aSJulian Elischer ifa->ifa_addr); 998034c09ffSAlexander V. Chernikov if (rt == NULL) 999e440aed9SQing Li error = ESRCH; 1000e440aed9SQing Li } 1001e440aed9SQing Li } 1002e440aed9SQing Li #endif 10038b07e49aSJulian Elischer error = (rn == NULL || 10048071913dSRuslan Ermilov (rn->rn_flags & RNF_ROOT) || 10058c61eb21SAlexander V. Chernikov RNTORT(rn)->rt_nhop->nh_ifa != ifa); 100661eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rnh); 1007956b0b65SJeffrey Hsu if (error) { 10088b07e49aSJulian Elischer /* this is only an error if bad on ALL tables */ 10098b07e49aSJulian Elischer continue; 1010df8bae1dSRodney W. Grimes } 1011b0a76b88SJulian Elischer } 1012b0a76b88SJulian Elischer /* 1013b0a76b88SJulian Elischer * Do the actual request 1014b0a76b88SJulian Elischer */ 10158071913dSRuslan Ermilov bzero((caddr_t)&info, sizeof(info)); 10168071913dSRuslan Ermilov info.rti_ifa = ifa; 10173034f43fSAlexander V. Chernikov info.rti_flags = flags | 10183034f43fSAlexander V. Chernikov (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; 10198071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 10206e6b3f7cSQing Li /* 10216e6b3f7cSQing Li * doing this for compatibility reasons 10226e6b3f7cSQing Li */ 10236e6b3f7cSQing Li if (cmd == RTM_ADD) 1024563ab4e4SAlexander V. Chernikov info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)sdl; 10256e6b3f7cSQing Li else 10268071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; 10278071913dSRuslan Ermilov info.rti_info[RTAX_NETMASK] = netmask; 10282bbab0afSAlexander V. Chernikov NET_EPOCH_ENTER(et); 1029e1c05fd2SAlexander V. Chernikov error = rib_action(fibnum, cmd, &info, &rc); 1030e1c05fd2SAlexander V. Chernikov if (error == 0 && rc.rc_rt != NULL) { 10318071913dSRuslan Ermilov /* 10326f99b44cSBrian Somers * notify any listening routing agents of the change 10338071913dSRuslan Ermilov */ 10349e022295SAlexander V. Chernikov 10359e022295SAlexander V. Chernikov /* TODO: interface routes/aliases */ 1036e1c05fd2SAlexander V. Chernikov rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum); 10378b07e49aSJulian Elischer didwork = 1; 1038df8bae1dSRodney W. Grimes } 10392bbab0afSAlexander V. Chernikov NET_EPOCH_EXIT(et); 10408b07e49aSJulian Elischer if (error) 10418b07e49aSJulian Elischer a_failure = error; 10428b07e49aSJulian Elischer } 10438b07e49aSJulian Elischer if (cmd == RTM_DELETE) { 10448b07e49aSJulian Elischer if (didwork) { 10458b07e49aSJulian Elischer error = 0; 10468b07e49aSJulian Elischer } else { 10478b07e49aSJulian Elischer /* we only give an error if it wasn't in any table */ 10488b07e49aSJulian Elischer error = ((flags & RTF_HOST) ? 10498b07e49aSJulian Elischer EHOSTUNREACH : ENETUNREACH); 10508b07e49aSJulian Elischer } 10518b07e49aSJulian Elischer } else { 10528b07e49aSJulian Elischer if (a_failure) { 10538b07e49aSJulian Elischer /* return an error if any of them failed */ 10548b07e49aSJulian Elischer error = a_failure; 10558b07e49aSJulian Elischer } 10568b07e49aSJulian Elischer } 10573ec66d6cSDavid Greenman return (error); 10583ec66d6cSDavid Greenman } 1059cb64988fSLuoqi Chen 10608b07e49aSJulian Elischer /* 10618b07e49aSJulian Elischer * Set up a routing table entry, normally 10628b07e49aSJulian Elischer * for an interface. 10638b07e49aSJulian Elischer */ 10648b07e49aSJulian Elischer int 10658b07e49aSJulian Elischer rtinit(struct ifaddr *ifa, int cmd, int flags) 10668b07e49aSJulian Elischer { 10678b07e49aSJulian Elischer struct sockaddr *dst; 1068a8498625SBjoern A. Zeeb int fib = RT_DEFAULT_FIB; 10698b07e49aSJulian Elischer 10708b07e49aSJulian Elischer if (flags & RTF_HOST) { 10718b07e49aSJulian Elischer dst = ifa->ifa_dstaddr; 10728b07e49aSJulian Elischer } else { 10738b07e49aSJulian Elischer dst = ifa->ifa_addr; 10748b07e49aSJulian Elischer } 10758b07e49aSJulian Elischer 1076b680a383SBjoern A. Zeeb switch (dst->sa_family) { 1077b680a383SBjoern A. Zeeb case AF_INET6: 1078b680a383SBjoern A. Zeeb case AF_INET: 1079b680a383SBjoern A. Zeeb /* We do support multiple FIBs. */ 10807d9b6df1SAlexander V. Chernikov fib = RT_ALL_FIBS; 1081b680a383SBjoern A. Zeeb break; 1082b680a383SBjoern A. Zeeb } 10838b07e49aSJulian Elischer return (rtinit1(ifa, cmd, flags, fib)); 10848b07e49aSJulian Elischer } 10854cbac30bSAlexander V. Chernikov 10864cbac30bSAlexander V. Chernikov /* 10874cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 10884cbac30bSAlexander V. Chernikov * Returns 0 on success. 10894cbac30bSAlexander V. Chernikov */ 10904cbac30bSAlexander V. Chernikov int 10914cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 10924cbac30bSAlexander V. Chernikov { 10934cbac30bSAlexander V. Chernikov 10944cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 1095d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 1096d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1097d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 10984cbac30bSAlexander V. Chernikov 1099d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 11004cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 11014cbac30bSAlexander V. Chernikov } 11024cbac30bSAlexander V. Chernikov 11034cbac30bSAlexander V. Chernikov /* 1104e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 1105e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 1106e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 1107e02d3fe7SAlexander V. Chernikov * @ifp: target route interface 1108e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 1109e02d3fe7SAlexander V. Chernikov * 11104cbac30bSAlexander V. Chernikov * Returns 0 on success. 11114cbac30bSAlexander V. Chernikov */ 11124cbac30bSAlexander V. Chernikov int 1113e02d3fe7SAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int rti_addrs, 11144cbac30bSAlexander V. Chernikov int fibnum) 11154cbac30bSAlexander V. Chernikov { 11164cbac30bSAlexander V. Chernikov 11174cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 1118d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 11194cbac30bSAlexander V. Chernikov 1120d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1121d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 11224cbac30bSAlexander V. Chernikov 11234cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 11244cbac30bSAlexander V. Chernikov 1125e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, ifp, 0, fibnum)); 11264cbac30bSAlexander V. Chernikov } 11274cbac30bSAlexander V. Chernikov 1128e02d3fe7SAlexander V. Chernikov /* 1129e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 1130e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 1131e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 1132e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 1133e02d3fe7SAlexander V. Chernikov * 1134e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 1135e02d3fe7SAlexander V. Chernikov */ 1136e02d3fe7SAlexander V. Chernikov int 1137e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 11384cbac30bSAlexander V. Chernikov { 11394cbac30bSAlexander V. Chernikov 1140e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 1141e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 1142e02d3fe7SAlexander V. Chernikov 1143e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1144e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 1145e02d3fe7SAlexander V. Chernikov 1146e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 1147e02d3fe7SAlexander V. Chernikov 1148e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 11494cbac30bSAlexander V. Chernikov } 11504cbac30bSAlexander V. Chernikov 1151e02d3fe7SAlexander V. Chernikov 11524cbac30bSAlexander V. Chernikov /* 11534cbac30bSAlexander V. Chernikov * This is called to generate messages from the routing socket 11544cbac30bSAlexander V. Chernikov * indicating a network interface has had addresses associated with it. 11554cbac30bSAlexander V. Chernikov */ 11564cbac30bSAlexander V. Chernikov void 1157e02d3fe7SAlexander V. Chernikov rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum) 11584cbac30bSAlexander V. Chernikov { 11594cbac30bSAlexander V. Chernikov 11604cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 11614cbac30bSAlexander V. Chernikov ("unexpected cmd %u", cmd)); 1162d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 1163d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 11644cbac30bSAlexander V. Chernikov 11654cbac30bSAlexander V. Chernikov if (cmd == RTM_ADD) { 11664cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 11674cbac30bSAlexander V. Chernikov if (rt != NULL) 1168e02d3fe7SAlexander V. Chernikov rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum); 11694cbac30bSAlexander V. Chernikov } else { 11704cbac30bSAlexander V. Chernikov if (rt != NULL) 1171e02d3fe7SAlexander V. Chernikov rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum); 11724cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 11734cbac30bSAlexander V. Chernikov } 11744cbac30bSAlexander V. Chernikov } 11754cbac30bSAlexander V. Chernikov 1176