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" 42d6e23cf0SMichael Tuexen #include "opt_route.h" 434bd49128SPeter Wemm 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 464d1d4912SBruce Evans #include <sys/malloc.h> 47df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 48df8bae1dSRodney W. Grimes #include <sys/socket.h> 498b07e49aSJulian Elischer #include <sys/sysctl.h> 503120b9d4SKip Macy #include <sys/syslog.h> 518b07e49aSJulian Elischer #include <sys/sysproto.h> 528b07e49aSJulian Elischer #include <sys/proc.h> 53df8bae1dSRodney W. Grimes #include <sys/domain.h> 5469104ebeSMichael Tuexen #include <sys/eventhandler.h> 55cb64988fSLuoqi Chen #include <sys/kernel.h> 5620efcfc6SAndrey V. Elsukov #include <sys/lock.h> 5720efcfc6SAndrey V. Elsukov #include <sys/rmlock.h> 58df8bae1dSRodney W. Grimes 59df8bae1dSRodney W. Grimes #include <net/if.h> 6076039bc8SGleb Smirnoff #include <net/if_var.h> 616e6b3f7cSQing Li #include <net/if_dl.h> 62df8bae1dSRodney W. Grimes #include <net/route.h> 63da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h> 64e7d8af4fSAlexander V. Chernikov #include <net/route/route_var.h> 65a6663252SAlexander V. Chernikov #include <net/route/nhop.h> 66530c0060SRobert Watson #include <net/vnet.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #include <netinet/in.h> 69b5e8ce9fSBruce Evans #include <netinet/ip_mroute.h> 70df8bae1dSRodney W. Grimes 71a6663252SAlexander V. Chernikov VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); 72185c3d2bSGleb Smirnoff 73185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSINIT(rtstat); 74185c3d2bSGleb Smirnoff #ifdef VIMAGE 75185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSUNINIT(rtstat); 76185c3d2bSGleb Smirnoff #endif 77b58ea5f3SBjoern A. Zeeb 78d6e23cf0SMichael Tuexen EVENTHANDLER_LIST_DEFINE(rt_addrmsg); 79d6e23cf0SMichael Tuexen 80539642a2SAlexander V. Chernikov static int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *, 81539642a2SAlexander V. Chernikov void *arg); 82cb984c62SAlexander V. Chernikov static int rt_exportinfo(struct rtentry *rt, struct nhop_object *nh, 83cb984c62SAlexander V. Chernikov struct rt_addrinfo *info, int flags); 84c77462ddSAlexander V. Chernikov 858b07e49aSJulian Elischer /* 86d0728d71SRobert Watson * route initialization must occur before ip6_init2(), which happenas at 87d0728d71SRobert Watson * SI_ORDER_MIDDLE. 88d0728d71SRobert Watson */ 892eb5613fSLuigi Rizzo static void 902eb5613fSLuigi Rizzo route_init(void) 91df8bae1dSRodney W. Grimes { 928b07e49aSJulian Elischer 93a6663252SAlexander V. Chernikov nhops_init(); 941ed81b73SMarko Zec } 95891cf3edSEd Maste SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); 961ed81b73SMarko Zec 9761eee0e2SAlexander V. Chernikov struct rib_head * 98ead85fe4SAlexander V. Chernikov rt_table_init(int offset, int family, u_int fibnum) 9961eee0e2SAlexander V. Chernikov { 10061eee0e2SAlexander V. Chernikov struct rib_head *rh; 10161eee0e2SAlexander V. Chernikov 10261eee0e2SAlexander V. Chernikov rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); 10361eee0e2SAlexander V. Chernikov 10461eee0e2SAlexander V. Chernikov /* TODO: These details should be hidded inside radix.c */ 10561eee0e2SAlexander V. Chernikov /* Init masks tree */ 10661eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); 10761eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); 10861eee0e2SAlexander V. Chernikov rh->head.rnh_masks = &rh->rmhead; 10961eee0e2SAlexander V. Chernikov 110ead85fe4SAlexander V. Chernikov /* Save metadata associated with this routing table. */ 111ead85fe4SAlexander V. Chernikov rh->rib_family = family; 112ead85fe4SAlexander V. Chernikov rh->rib_fibnum = fibnum; 113ead85fe4SAlexander V. Chernikov #ifdef VIMAGE 114ead85fe4SAlexander V. Chernikov rh->rib_vnet = curvnet; 115ead85fe4SAlexander V. Chernikov #endif 116ead85fe4SAlexander V. Chernikov 11734a5582cSAlexander V. Chernikov tmproutes_init(rh); 11834a5582cSAlexander V. Chernikov 11961eee0e2SAlexander V. Chernikov /* Init locks */ 120abe95d87SAndrey V. Elsukov RIB_LOCK_INIT(rh); 12161eee0e2SAlexander V. Chernikov 122a6663252SAlexander V. Chernikov nhops_init_rib(rh); 123a6663252SAlexander V. Chernikov 124da187ddbSAlexander V. Chernikov /* Init subscription system */ 125edc37a66SAlexander V. Chernikov rib_init_subscriptions(rh); 126da187ddbSAlexander V. Chernikov 12761eee0e2SAlexander V. Chernikov /* Finally, set base callbacks */ 12861eee0e2SAlexander V. Chernikov rh->rnh_addaddr = rn_addroute; 12961eee0e2SAlexander V. Chernikov rh->rnh_deladdr = rn_delete; 13061eee0e2SAlexander V. Chernikov rh->rnh_matchaddr = rn_match; 13161eee0e2SAlexander V. Chernikov rh->rnh_lookup = rn_lookup; 13261eee0e2SAlexander V. Chernikov rh->rnh_walktree = rn_walktree; 13361eee0e2SAlexander V. Chernikov rh->rnh_walktree_from = rn_walktree_from; 13461eee0e2SAlexander V. Chernikov 13561eee0e2SAlexander V. Chernikov return (rh); 13661eee0e2SAlexander V. Chernikov } 13761eee0e2SAlexander V. Chernikov 138a5243af2SBjoern A. Zeeb static int 139a5243af2SBjoern A. Zeeb rt_freeentry(struct radix_node *rn, void *arg) 140a5243af2SBjoern A. Zeeb { 141a5243af2SBjoern A. Zeeb struct radix_head * const rnh = arg; 142a5243af2SBjoern A. Zeeb struct radix_node *x; 143a5243af2SBjoern A. Zeeb 144a5243af2SBjoern A. Zeeb x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); 145a5243af2SBjoern A. Zeeb if (x != NULL) 146a5243af2SBjoern A. Zeeb R_Free(x); 147a5243af2SBjoern A. Zeeb return (0); 148a5243af2SBjoern A. Zeeb } 149a5243af2SBjoern A. Zeeb 15061eee0e2SAlexander V. Chernikov void 15161eee0e2SAlexander V. Chernikov rt_table_destroy(struct rib_head *rh) 15261eee0e2SAlexander V. Chernikov { 15361eee0e2SAlexander V. Chernikov 154f5baf8bbSAlexander V. Chernikov RIB_WLOCK(rh); 155f5baf8bbSAlexander V. Chernikov rh->rib_dying = true; 156f5baf8bbSAlexander V. Chernikov RIB_WUNLOCK(rh); 157f5baf8bbSAlexander V. Chernikov 158f5baf8bbSAlexander V. Chernikov #ifdef FIB_ALGO 159f5baf8bbSAlexander V. Chernikov fib_destroy_rib(rh); 160f5baf8bbSAlexander V. Chernikov #endif 161f5baf8bbSAlexander V. Chernikov 16234a5582cSAlexander V. Chernikov tmproutes_destroy(rh); 16334a5582cSAlexander V. Chernikov 164a5243af2SBjoern A. Zeeb rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); 165a5243af2SBjoern A. Zeeb 166a6663252SAlexander V. Chernikov nhops_destroy_rib(rh); 167a6663252SAlexander V. Chernikov 168edc37a66SAlexander V. Chernikov rib_destroy_subscriptions(rh); 169edc37a66SAlexander V. Chernikov 17061eee0e2SAlexander V. Chernikov /* Assume table is already empty */ 171abe95d87SAndrey V. Elsukov RIB_LOCK_DESTROY(rh); 17261eee0e2SAlexander V. Chernikov free(rh, M_RTABLE); 17361eee0e2SAlexander V. Chernikov } 17461eee0e2SAlexander V. Chernikov 175df8bae1dSRodney W. Grimes /* 17634a5582cSAlexander V. Chernikov * Adds a temporal redirect entry to the routing table. 17734a5582cSAlexander V. Chernikov * @fibnum: fib number 17834a5582cSAlexander V. Chernikov * @dst: destination to install redirect to 17934a5582cSAlexander V. Chernikov * @gateway: gateway to go via 18034a5582cSAlexander V. Chernikov * @author: sockaddr of originating router, can be NULL 18134a5582cSAlexander V. Chernikov * @ifp: interface to use for the redirected route 18234a5582cSAlexander V. Chernikov * @flags: set of flags to add. Allowed: RTF_GATEWAY 18334a5582cSAlexander V. Chernikov * @lifetime_sec: time in seconds to expire this redirect. 18434a5582cSAlexander V. Chernikov * 18534a5582cSAlexander V. Chernikov * Retuns 0 on success, errno otherwise. 186df8bae1dSRodney W. Grimes */ 18734a5582cSAlexander V. Chernikov int 18834a5582cSAlexander V. Chernikov rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, 18934a5582cSAlexander V. Chernikov struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) 1908b07e49aSJulian Elischer { 191e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc; 19234a5582cSAlexander V. Chernikov int error; 193df8bae1dSRodney W. Grimes struct rt_addrinfo info; 19434a5582cSAlexander V. Chernikov struct rt_metrics rti_rmx; 195df8bae1dSRodney W. Grimes struct ifaddr *ifa; 196c2c2a7c1SBjoern A. Zeeb 197b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 198b8a6e03fSGleb Smirnoff 19934a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 20034a5582cSAlexander V. Chernikov return (EAFNOSUPPORT); 2018e7e854cSKip Macy 20234a5582cSAlexander V. Chernikov /* Verify the allowed flag mask. */ 20334a5582cSAlexander V. Chernikov KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 20434a5582cSAlexander V. Chernikov ("invalid redirect flags: %x", flags)); 205592d300eSAlexander V. Chernikov flags |= RTF_HOST | RTF_DYNAMIC; 20634a5582cSAlexander V. Chernikov 20734a5582cSAlexander V. Chernikov /* Get the best ifa for the given interface and gateway. */ 20834a5582cSAlexander V. Chernikov if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 20934a5582cSAlexander V. Chernikov return (ENETUNREACH); 21034a5582cSAlexander V. Chernikov 21134a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 2128071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 2138071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 2148071913dSRuslan Ermilov info.rti_ifa = ifa; 21534a5582cSAlexander V. Chernikov info.rti_ifp = ifp; 216592d300eSAlexander V. Chernikov info.rti_flags = flags; 21734a5582cSAlexander V. Chernikov 21834a5582cSAlexander V. Chernikov /* Setup route metrics to define expire time. */ 21934a5582cSAlexander V. Chernikov bzero(&rti_rmx, sizeof(rti_rmx)); 22034a5582cSAlexander V. Chernikov /* Set expire time as absolute. */ 22134a5582cSAlexander V. Chernikov rti_rmx.rmx_expire = lifetime_sec + time_second; 22234a5582cSAlexander V. Chernikov info.rti_mflags |= RTV_EXPIRE; 22334a5582cSAlexander V. Chernikov info.rti_rmx = &rti_rmx; 22434a5582cSAlexander V. Chernikov 225e1c05fd2SAlexander V. Chernikov error = rib_action(fibnum, RTM_ADD, &info, &rc); 22634a5582cSAlexander V. Chernikov 22734a5582cSAlexander V. Chernikov if (error != 0) { 22834a5582cSAlexander V. Chernikov /* TODO: add per-fib redirect stats. */ 22934a5582cSAlexander V. Chernikov return (error); 23034a5582cSAlexander V. Chernikov } 23134a5582cSAlexander V. Chernikov 23234a5582cSAlexander V. Chernikov RTSTAT_INC(rts_dynamic); 23334a5582cSAlexander V. Chernikov 23434a5582cSAlexander V. Chernikov /* Send notification of a route addition to userland. */ 23534a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 236df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 237df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 23834a5582cSAlexander V. Chernikov info.rti_info[RTAX_AUTHOR] = author; 239592d300eSAlexander V. Chernikov rt_missmsg_fib(RTM_REDIRECT, &info, flags | RTF_UP, error, fibnum); 24034a5582cSAlexander V. Chernikov 24134a5582cSAlexander V. Chernikov return (0); 242df8bae1dSRodney W. Grimes } 243df8bae1dSRodney W. Grimes 244df8bae1dSRodney W. Grimes /* 245df8bae1dSRodney W. Grimes * Routing table ioctl interface. 246df8bae1dSRodney W. Grimes */ 247df8bae1dSRodney W. Grimes int 2488b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 249df8bae1dSRodney W. Grimes { 2505090559bSChristian S.J. Peron 2515090559bSChristian S.J. Peron /* 2525090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 2535090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 2545090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 2555090559bSChristian S.J. Peron * in jails. 2565090559bSChristian S.J. Peron */ 257623ae52eSPoul-Henning Kamp #ifdef INET 258f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 2598b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 260623ae52eSPoul-Henning Kamp #else /* INET */ 261623ae52eSPoul-Henning Kamp return ENXIO; 262623ae52eSPoul-Henning Kamp #endif /* INET */ 263df8bae1dSRodney W. Grimes } 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes struct ifaddr * 2664d2c2509SAlexander V. Chernikov ifa_ifwithroute(int flags, const struct sockaddr *dst, 2674d2c2509SAlexander V. Chernikov const struct sockaddr *gateway, u_int fibnum) 2688b07e49aSJulian Elischer { 269f59c6cb0SAlexander V. Chernikov struct ifaddr *ifa; 270d1dd20beSSam Leffler 27197168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 272df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 273df8bae1dSRodney W. Grimes /* 274df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 275df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 276df8bae1dSRodney W. Grimes * we should search for the destination 277df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 278df8bae1dSRodney W. Grimes * we can use the local address. 279df8bae1dSRodney W. Grimes */ 28085911824SLuigi Rizzo ifa = NULL; 28185911824SLuigi Rizzo if (flags & RTF_HOST) 2824f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(dst, fibnum); 28385911824SLuigi Rizzo if (ifa == NULL) 284df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 285df8bae1dSRodney W. Grimes } else { 286df8bae1dSRodney W. Grimes /* 287df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 288df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 289df8bae1dSRodney W. Grimes * other end of a pt to pt link. 290df8bae1dSRodney W. Grimes */ 2914f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(gateway, fibnum); 292df8bae1dSRodney W. Grimes } 29385911824SLuigi Rizzo if (ifa == NULL) 2944f8585e0SAlan Somers ifa = ifa_ifwithnet(gateway, 0, fibnum); 29585911824SLuigi Rizzo if (ifa == NULL) { 296682b902dSAlexander V. Chernikov struct nhop_object *nh; 297b83aa367SAndrey V. Elsukov 298682b902dSAlexander V. Chernikov nh = rib_lookup(fibnum, gateway, NHR_NONE, 0); 299682b902dSAlexander V. Chernikov 300e034e82cSQing Li /* 301e034e82cSQing Li * dismiss a gateway that is reachable only 302e034e82cSQing Li * through the default router 303e034e82cSQing Li */ 304682b902dSAlexander V. Chernikov if ((nh == NULL) || (nh->nh_flags & NHF_DEFAULT)) 305682b902dSAlexander V. Chernikov return (NULL); 306682b902dSAlexander V. Chernikov ifa = nh->nh_ifa; 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 309df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 310df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 31185911824SLuigi Rizzo if (ifa == NULL) 312df8bae1dSRodney W. Grimes ifa = oifa; 313df8bae1dSRodney W. Grimes } 314682b902dSAlexander V. Chernikov 315df8bae1dSRodney W. Grimes return (ifa); 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes 3182caee4beSAlexander V. Chernikov /* 3199a1b64d5SAlexander V. Chernikov * Copy most of @rt data into @info. 3209a1b64d5SAlexander V. Chernikov * 3219a1b64d5SAlexander V. Chernikov * If @flags contains NHR_COPY, copies dst,netmask and gw to the 3229a1b64d5SAlexander V. Chernikov * pointers specified by @info structure. Assume such pointers 3239a1b64d5SAlexander V. Chernikov * are zeroed sockaddr-like structures with sa_len field initialized 3249a1b64d5SAlexander V. Chernikov * to reflect size of the provided buffer. if no NHR_COPY is specified, 3259a1b64d5SAlexander V. Chernikov * point dst,netmask and gw @info fields to appropriate @rt values. 3269a1b64d5SAlexander V. Chernikov * 3276b5d8e30SMark Johnston * if @flags contains NHR_REF, do refcouting on rt_ifp and rt_ifa. 3289a1b64d5SAlexander V. Chernikov * 3299a1b64d5SAlexander V. Chernikov * Returns 0 on success. 3309a1b64d5SAlexander V. Chernikov */ 331cb984c62SAlexander V. Chernikov static int 332cb984c62SAlexander V. Chernikov rt_exportinfo(struct rtentry *rt, struct nhop_object *nh, 333cb984c62SAlexander V. Chernikov struct rt_addrinfo *info, int flags) 3349a1b64d5SAlexander V. Chernikov { 3359a1b64d5SAlexander V. Chernikov struct rt_metrics *rmx; 3369a1b64d5SAlexander V. Chernikov struct sockaddr *src, *dst; 3379a1b64d5SAlexander V. Chernikov int sa_len; 3389a1b64d5SAlexander V. Chernikov 3399a1b64d5SAlexander V. Chernikov if (flags & NHR_COPY) { 3409a1b64d5SAlexander V. Chernikov /* Copy destination if dst is non-zero */ 3419a1b64d5SAlexander V. Chernikov src = rt_key(rt); 3429a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 3439a1b64d5SAlexander V. Chernikov sa_len = src->sa_len; 34416703ea8SAlexander V. Chernikov if (dst != NULL) { 3459a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3469a1b64d5SAlexander V. Chernikov return (ENOMEM); 3479a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3489a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3499a1b64d5SAlexander V. Chernikov } 3509a1b64d5SAlexander V. Chernikov 3519a1b64d5SAlexander V. Chernikov /* Copy mask if set && dst is non-zero */ 3529a1b64d5SAlexander V. Chernikov src = rt_mask(rt); 3539a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_NETMASK]; 3549a1b64d5SAlexander V. Chernikov if (src != NULL && dst != NULL) { 3559a1b64d5SAlexander V. Chernikov /* 3569a1b64d5SAlexander V. Chernikov * Radix stores different value in sa_len, 3579a1b64d5SAlexander V. Chernikov * assume rt_mask() to have the same length 3589a1b64d5SAlexander V. Chernikov * as rt_key() 3599a1b64d5SAlexander V. Chernikov */ 3609a1b64d5SAlexander V. Chernikov if (sa_len > dst->sa_len) 3619a1b64d5SAlexander V. Chernikov return (ENOMEM); 3629a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3639a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3649a1b64d5SAlexander V. Chernikov } 3659a1b64d5SAlexander V. Chernikov 3669a1b64d5SAlexander V. Chernikov /* Copy gateway is set && dst is non-zero */ 36793bfd365SAlexander V. Chernikov src = &nh->gw_sa; 3689a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_GATEWAY]; 36993bfd365SAlexander V. Chernikov if ((nhop_get_rtflags(nh) & RTF_GATEWAY) && 37093bfd365SAlexander V. Chernikov src != NULL && dst != NULL) { 3719a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3729a1b64d5SAlexander V. Chernikov return (ENOMEM); 3739a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3749a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3759a1b64d5SAlexander V. Chernikov } 3769a1b64d5SAlexander V. Chernikov } else { 3779a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 3789a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3799a1b64d5SAlexander V. Chernikov if (rt_mask(rt) != NULL) { 3809a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 3819a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3829a1b64d5SAlexander V. Chernikov } 38393bfd365SAlexander V. Chernikov if (nhop_get_rtflags(nh) & RTF_GATEWAY) { 38493bfd365SAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; 3859a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3869a1b64d5SAlexander V. Chernikov } 3879a1b64d5SAlexander V. Chernikov } 3889a1b64d5SAlexander V. Chernikov 3899a1b64d5SAlexander V. Chernikov rmx = info->rti_rmx; 3909a1b64d5SAlexander V. Chernikov if (rmx != NULL) { 3919a1b64d5SAlexander V. Chernikov info->rti_mflags |= RTV_MTU; 392aaad3c4fSAlexander V. Chernikov rmx->rmx_mtu = nh->nh_mtu; 3939a1b64d5SAlexander V. Chernikov } 3949a1b64d5SAlexander V. Chernikov 39593bfd365SAlexander V. Chernikov info->rti_flags = rt->rte_flags | nhop_get_rtflags(nh); 396aaad3c4fSAlexander V. Chernikov info->rti_ifp = nh->nh_ifp; 397aaad3c4fSAlexander V. Chernikov info->rti_ifa = nh->nh_ifa; 3989a1b64d5SAlexander V. Chernikov if (flags & NHR_REF) { 3999a1b64d5SAlexander V. Chernikov if_ref(info->rti_ifp); 4006b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 4019a1b64d5SAlexander V. Chernikov } 4029a1b64d5SAlexander V. Chernikov 4039a1b64d5SAlexander V. Chernikov return (0); 4049a1b64d5SAlexander V. Chernikov } 4059a1b64d5SAlexander V. Chernikov 4069a1b64d5SAlexander V. Chernikov /* 4079a1b64d5SAlexander V. Chernikov * Lookups up route entry for @dst in RIB database for fib @fibnum. 4089a1b64d5SAlexander V. Chernikov * Exports entry data to @info using rt_exportinfo(). 4099a1b64d5SAlexander V. Chernikov * 4106b5d8e30SMark Johnston * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa. 4116b5d8e30SMark Johnston * All references can be released later by calling rib_free_info(). 4129a1b64d5SAlexander V. Chernikov * 4139a1b64d5SAlexander V. Chernikov * Returns 0 on success. 4149a1b64d5SAlexander V. Chernikov * Returns ENOENT for lookup failure, ENOMEM for export failure. 4159a1b64d5SAlexander V. Chernikov */ 4169a1b64d5SAlexander V. Chernikov int 4179a1b64d5SAlexander V. Chernikov rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, 4189a1b64d5SAlexander V. Chernikov uint32_t flowid, struct rt_addrinfo *info) 4199a1b64d5SAlexander V. Chernikov { 42020efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 42161eee0e2SAlexander V. Chernikov struct rib_head *rh; 4229a1b64d5SAlexander V. Chernikov struct radix_node *rn; 4239a1b64d5SAlexander V. Chernikov struct rtentry *rt; 424cb984c62SAlexander V. Chernikov struct nhop_object *nh; 4259a1b64d5SAlexander V. Chernikov int error; 4269a1b64d5SAlexander V. Chernikov 4279a1b64d5SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum")); 4289a1b64d5SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, dst->sa_family); 4299a1b64d5SAlexander V. Chernikov if (rh == NULL) 4309a1b64d5SAlexander V. Chernikov return (ENOENT); 4319a1b64d5SAlexander V. Chernikov 43261eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 43361eee0e2SAlexander V. Chernikov rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head); 4349a1b64d5SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 4359a1b64d5SAlexander V. Chernikov rt = RNTORT(rn); 436cb984c62SAlexander V. Chernikov nh = nhop_select(rt->rt_nhop, flowid); 4379a1b64d5SAlexander V. Chernikov /* Ensure route & ifp is UP */ 438cb984c62SAlexander V. Chernikov if (RT_LINK_IS_UP(nh->nh_ifp)) { 4399a1b64d5SAlexander V. Chernikov flags = (flags & NHR_REF) | NHR_COPY; 440cb984c62SAlexander V. Chernikov error = rt_exportinfo(rt, nh, info, flags); 44161eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4429a1b64d5SAlexander V. Chernikov 4439a1b64d5SAlexander V. Chernikov return (error); 4449a1b64d5SAlexander V. Chernikov } 4459a1b64d5SAlexander V. Chernikov } 44661eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4479a1b64d5SAlexander V. Chernikov 4489a1b64d5SAlexander V. Chernikov return (ENOENT); 4499a1b64d5SAlexander V. Chernikov } 4509a1b64d5SAlexander V. Chernikov 4519a1b64d5SAlexander V. Chernikov /* 4529a1b64d5SAlexander V. Chernikov * Releases all references acquired by rib_lookup_info() when 4539a1b64d5SAlexander V. Chernikov * called with NHR_REF flags. 4549a1b64d5SAlexander V. Chernikov */ 4559a1b64d5SAlexander V. Chernikov void 4569a1b64d5SAlexander V. Chernikov rib_free_info(struct rt_addrinfo *info) 4579a1b64d5SAlexander V. Chernikov { 4589a1b64d5SAlexander V. Chernikov 4596b5d8e30SMark Johnston ifa_free(info->rti_ifa); 4609a1b64d5SAlexander V. Chernikov if_rele(info->rti_ifp); 4619a1b64d5SAlexander V. Chernikov } 4629a1b64d5SAlexander V. Chernikov 4639a1b64d5SAlexander V. Chernikov /* 4644bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 4654bdf0b6aSAlexander V. Chernikov * 4664bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 4674bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 4684bdf0b6aSAlexander V. Chernikov * 4694bdf0b6aSAlexander V. Chernikov * Arguments: 4704bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 471539642a2SAlexander V. Chernikov * nh pointer to nhop 4724bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 4734bdf0b6aSAlexander V. Chernikov * 4744bdf0b6aSAlexander V. Chernikov * Returns: 4754bdf0b6aSAlexander V. Chernikov * 0 successful 4764bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 4774bdf0b6aSAlexander V. Chernikov */ 4784bdf0b6aSAlexander V. Chernikov static int 479539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 4804bdf0b6aSAlexander V. Chernikov { 4814bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 4824bdf0b6aSAlexander V. Chernikov 483539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 4844bdf0b6aSAlexander V. Chernikov return (0); 4854bdf0b6aSAlexander V. Chernikov 4864bdf0b6aSAlexander V. Chernikov /* 4874bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 4884bdf0b6aSAlexander V. Chernikov * with cloned routes 4894bdf0b6aSAlexander V. Chernikov */ 49093bfd365SAlexander V. Chernikov if ((rt->rte_flags & RTF_UP) == 0) 4914bdf0b6aSAlexander V. Chernikov return (0); 4924bdf0b6aSAlexander V. Chernikov 493e8b0643eSAlexander V. Chernikov return (1); 4944bdf0b6aSAlexander V. Chernikov } 4954bdf0b6aSAlexander V. Chernikov 4964bdf0b6aSAlexander V. Chernikov /* 4974bdf0b6aSAlexander V. Chernikov * Delete all remaining routes using this interface 4984bdf0b6aSAlexander V. Chernikov * Unfortuneatly the only way to do this is to slog through 4994bdf0b6aSAlexander V. Chernikov * the entire routing table looking for routes which point 5004bdf0b6aSAlexander V. Chernikov * to this interface...oh well... 5014bdf0b6aSAlexander V. Chernikov */ 5024bdf0b6aSAlexander V. Chernikov void 50380ae8d60SBjoern A. Zeeb rt_flushifroutes_af(struct ifnet *ifp, int af) 50480ae8d60SBjoern A. Zeeb { 50580ae8d60SBjoern A. Zeeb KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d", 50680ae8d60SBjoern A. Zeeb __func__, af, AF_MAX)); 50780ae8d60SBjoern A. Zeeb 5087511a638SAlexander V. Chernikov rib_foreach_table_walk_del(af, rt_ifdelroute, ifp); 50980ae8d60SBjoern A. Zeeb } 51080ae8d60SBjoern A. Zeeb 51180ae8d60SBjoern A. Zeeb void 5124bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 5134bdf0b6aSAlexander V. Chernikov { 5144bdf0b6aSAlexander V. Chernikov 5157511a638SAlexander V. Chernikov rib_foreach_table_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 5164bdf0b6aSAlexander V. Chernikov } 5174bdf0b6aSAlexander V. Chernikov 5188071913dSRuslan Ermilov /* 519*59641728SAlexander V. Chernikov * Look up rt_addrinfo for a specific fib. 5202ad7ed6eSAlexander V. Chernikov * 5212ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 5222ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 5238c0fec80SRobert Watson */ 5248b07e49aSJulian Elischer int 5258b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 5268b07e49aSJulian Elischer { 5274d2c2509SAlexander V. Chernikov const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr; 528*59641728SAlexander V. Chernikov int error, flags; 5294d2c2509SAlexander V. Chernikov 5304d2c2509SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 5314d2c2509SAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 5324d2c2509SAlexander V. Chernikov ifpaddr = info->rti_info[RTAX_IFP]; 5334d2c2509SAlexander V. Chernikov ifaaddr = info->rti_info[RTAX_IFA]; 5344d2c2509SAlexander V. Chernikov flags = info->rti_flags; 5358071913dSRuslan Ermilov 5368071913dSRuslan Ermilov /* 5378071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 5388071913dSRuslan Ermilov * when protocol address is ambiguous. 5398071913dSRuslan Ermilov */ 5401ebec5faSMatt Macy error = 0; 5412ad7ed6eSAlexander V. Chernikov 5422ad7ed6eSAlexander V. Chernikov /* If we have interface specified by the ifindex in the address, use it */ 5438071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 5442ad7ed6eSAlexander V. Chernikov ifpaddr->sa_family == AF_LINK) { 5452ad7ed6eSAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; 5462ad7ed6eSAlexander V. Chernikov if (sdl->sdl_index != 0) 547270b83b9SHans Petter Selasky info->rti_ifp = ifnet_byindex(sdl->sdl_index); 5488c0fec80SRobert Watson } 5492ad7ed6eSAlexander V. Chernikov /* 5502ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 5512ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 5522ad7ed6eSAlexander V. Chernikov */ 5538071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 5548071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 5558071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 5564d2c2509SAlexander V. Chernikov const struct sockaddr *sa; 5578071913dSRuslan Ermilov 5582ad7ed6eSAlexander V. Chernikov /* 5592ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 5602ad7ed6eSAlexander V. Chernikov * 5612ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 5622ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 5632ad7ed6eSAlexander V. Chernikov * Order of preference: 5642ad7ed6eSAlexander V. Chernikov * 1) IFA address 5652ad7ed6eSAlexander V. Chernikov * 2) gateway address 5662ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 5672ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 5682ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 5692ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 5702ad7ed6eSAlexander V. Chernikov * ignore gateway 5712ad7ed6eSAlexander V. Chernikov * 3) final destination. 5722ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 5732ad7ed6eSAlexander V. Chernikov * -- else -- 5742ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 5752ad7ed6eSAlexander V. Chernikov */ 5762ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 5772ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 5782ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 5792ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 5802ad7ed6eSAlexander V. Chernikov sa = gateway; 5812ad7ed6eSAlexander V. Chernikov else 5822ad7ed6eSAlexander V. Chernikov sa = dst; 5832ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 5848071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 5852ad7ed6eSAlexander V. Chernikov /* Case 4 */ 5862ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 5872ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 5882ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 5894f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 5908b07e49aSJulian Elischer fibnum); 5918071913dSRuslan Ermilov else if (sa != NULL) 5924f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 5938b07e49aSJulian Elischer fibnum); 5948071913dSRuslan Ermilov } 595*59641728SAlexander V. Chernikov if (info->rti_ifa != NULL) { 5968071913dSRuslan Ermilov if (info->rti_ifp == NULL) 597134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 5988071913dSRuslan Ermilov } else 5998071913dSRuslan Ermilov error = ENETUNREACH; 6008071913dSRuslan Ermilov return (error); 6018071913dSRuslan Ermilov } 6028071913dSRuslan Ermilov 6037f948f12SAlexander V. Chernikov void 6047f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 6057f948f12SAlexander V. Chernikov { 60661eee0e2SAlexander V. Chernikov struct rib_head *rnh; 6079e022295SAlexander V. Chernikov int mtu; 6087f948f12SAlexander V. Chernikov int i, j; 6097f948f12SAlexander V. Chernikov 6107f948f12SAlexander V. Chernikov /* 6117f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 6127f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 6137f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 6147f948f12SAlexander V. Chernikov */ 6157f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 6169e022295SAlexander V. Chernikov mtu = if_getmtu_family(ifp, i); 6177f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 6187f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 6197f948f12SAlexander V. Chernikov if (rnh == NULL) 6207f948f12SAlexander V. Chernikov continue; 6219e022295SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, mtu); 6227f948f12SAlexander V. Chernikov } 6237f948f12SAlexander V. Chernikov } 6247f948f12SAlexander V. Chernikov } 6257f948f12SAlexander V. Chernikov 6265a2f4cbdSAlexander V. Chernikov #if 0 6275a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 6285a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 6295a2f4cbdSAlexander V. Chernikov 6305a2f4cbdSAlexander V. Chernikov int 6315a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 6325a2f4cbdSAlexander V. Chernikov { 6335a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 6345a2f4cbdSAlexander V. Chernikov 6355a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 6365a2f4cbdSAlexander V. Chernikov case AF_INET: 6375a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 6385a2f4cbdSAlexander V. Chernikov break; 6395a2f4cbdSAlexander V. Chernikov case AF_INET6: 6405a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 6415a2f4cbdSAlexander V. Chernikov break; 6425a2f4cbdSAlexander V. Chernikov } 6435a2f4cbdSAlexander V. Chernikov 6445a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 6455a2f4cbdSAlexander V. Chernikov return (0); 6465a2f4cbdSAlexander V. Chernikov 6475a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 6485a2f4cbdSAlexander V. Chernikov return (0); 6495a2f4cbdSAlexander V. Chernikov 6505a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 6515a2f4cbdSAlexander V. Chernikov } 6525a2f4cbdSAlexander V. Chernikov 6535a2f4cbdSAlexander V. Chernikov int 6545a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 6555a2f4cbdSAlexander V. Chernikov { 6565a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 6575a2f4cbdSAlexander V. Chernikov int i = 0; 6585a2f4cbdSAlexander V. Chernikov 6595a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 6605a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 6615a2f4cbdSAlexander V. Chernikov 6625a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 6635a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 6645a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 6655a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 6665a2f4cbdSAlexander V. Chernikov } 6675a2f4cbdSAlexander V. Chernikov 6685a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 6695a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 670aaad3c4fSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 6715a2f4cbdSAlexander V. Chernikov } 6725a2f4cbdSAlexander V. Chernikov 6735a2f4cbdSAlexander V. Chernikov return (i); 6745a2f4cbdSAlexander V. Chernikov } 6755a2f4cbdSAlexander V. Chernikov #endif 6765a2f4cbdSAlexander V. Chernikov 6774d2c2509SAlexander V. Chernikov void 678d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 679df8bae1dSRodney W. Grimes { 680f59c6cb0SAlexander V. Chernikov u_char *cp1 = (u_char *)src; 681f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 682f59c6cb0SAlexander V. Chernikov u_char *cp3 = (u_char *)netmask; 683df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 684df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 687df8bae1dSRodney W. Grimes cp3 += 2; 688df8bae1dSRodney W. Grimes if (cplim > cplim2) 689df8bae1dSRodney W. Grimes cplim = cplim2; 690df8bae1dSRodney W. Grimes while (cp2 < cplim) 691df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 692df8bae1dSRodney W. Grimes if (cp2 < cplim2) 693df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes 696df8bae1dSRodney W. Grimes /* 6974cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 6984cbac30bSAlexander V. Chernikov * Returns 0 on success. 6994cbac30bSAlexander V. Chernikov */ 7004cbac30bSAlexander V. Chernikov int 7014cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 7024cbac30bSAlexander V. Chernikov { 7034cbac30bSAlexander V. Chernikov 7044cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 705d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 706d68cf57bSAlexander V. Chernikov KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 707d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7084cbac30bSAlexander V. Chernikov 709d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 710d68cf57bSAlexander V. Chernikov 711d68cf57bSAlexander V. Chernikov if (V_rt_add_addr_allfibs) 712d68cf57bSAlexander V. Chernikov fibnum = RT_ALL_FIBS; 7134cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 7144cbac30bSAlexander V. Chernikov } 7154cbac30bSAlexander V. Chernikov 7164cbac30bSAlexander V. Chernikov /* 717e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 718e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 719e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 720d68cf57bSAlexander V. Chernikov * @nh: nhop object to announce 721e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 722e02d3fe7SAlexander V. Chernikov * 7234cbac30bSAlexander V. Chernikov * Returns 0 on success. 7244cbac30bSAlexander V. Chernikov */ 7254cbac30bSAlexander V. Chernikov int 726d68cf57bSAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, 7274cbac30bSAlexander V. Chernikov int fibnum) 7284cbac30bSAlexander V. Chernikov { 7294cbac30bSAlexander V. Chernikov 7304cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 731d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 7324cbac30bSAlexander V. Chernikov 733d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 734d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7354cbac30bSAlexander V. Chernikov 7364cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 7374cbac30bSAlexander V. Chernikov 738d68cf57bSAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, nh, fibnum)); 7394cbac30bSAlexander V. Chernikov } 7404cbac30bSAlexander V. Chernikov 741e02d3fe7SAlexander V. Chernikov /* 742e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 743e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 744e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 745e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 746e02d3fe7SAlexander V. Chernikov * 747e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 748e02d3fe7SAlexander V. Chernikov */ 749e02d3fe7SAlexander V. Chernikov int 750e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 7514cbac30bSAlexander V. Chernikov { 7524cbac30bSAlexander V. Chernikov 753e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 754e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 755e02d3fe7SAlexander V. Chernikov 756e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 757e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 758e02d3fe7SAlexander V. Chernikov 759e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 760e02d3fe7SAlexander V. Chernikov 761e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 7624cbac30bSAlexander V. Chernikov } 763