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); 829a1b64d5SAlexander V. Chernikov static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, 839a1b64d5SAlexander V. Chernikov 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 ifa_ref(ifa); 21134a5582cSAlexander V. Chernikov 21234a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 2138071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 2148071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 2158071913dSRuslan Ermilov info.rti_ifa = ifa; 21634a5582cSAlexander V. Chernikov info.rti_ifp = ifp; 217592d300eSAlexander V. Chernikov info.rti_flags = flags; 21834a5582cSAlexander V. Chernikov 21934a5582cSAlexander V. Chernikov /* Setup route metrics to define expire time. */ 22034a5582cSAlexander V. Chernikov bzero(&rti_rmx, sizeof(rti_rmx)); 22134a5582cSAlexander V. Chernikov /* Set expire time as absolute. */ 22234a5582cSAlexander V. Chernikov rti_rmx.rmx_expire = lifetime_sec + time_second; 22334a5582cSAlexander V. Chernikov info.rti_mflags |= RTV_EXPIRE; 22434a5582cSAlexander V. Chernikov info.rti_rmx = &rti_rmx; 22534a5582cSAlexander V. Chernikov 226e1c05fd2SAlexander V. Chernikov error = rib_action(fibnum, RTM_ADD, &info, &rc); 22734a5582cSAlexander V. Chernikov ifa_free(ifa); 22834a5582cSAlexander V. Chernikov 22934a5582cSAlexander V. Chernikov if (error != 0) { 23034a5582cSAlexander V. Chernikov /* TODO: add per-fib redirect stats. */ 23134a5582cSAlexander V. Chernikov return (error); 23234a5582cSAlexander V. Chernikov } 23334a5582cSAlexander V. Chernikov 23434a5582cSAlexander V. Chernikov RTSTAT_INC(rts_dynamic); 23534a5582cSAlexander V. Chernikov 23634a5582cSAlexander V. Chernikov /* Send notification of a route addition to userland. */ 23734a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 238df8bae1dSRodney W. Grimes info.rti_info[RTAX_DST] = dst; 239df8bae1dSRodney W. Grimes info.rti_info[RTAX_GATEWAY] = gateway; 24034a5582cSAlexander V. Chernikov info.rti_info[RTAX_AUTHOR] = author; 241592d300eSAlexander V. Chernikov rt_missmsg_fib(RTM_REDIRECT, &info, flags | RTF_UP, error, fibnum); 24234a5582cSAlexander V. Chernikov 24334a5582cSAlexander V. Chernikov return (0); 244df8bae1dSRodney W. Grimes } 245df8bae1dSRodney W. Grimes 246df8bae1dSRodney W. Grimes /* 247df8bae1dSRodney W. Grimes * Routing table ioctl interface. 248df8bae1dSRodney W. Grimes */ 249df8bae1dSRodney W. Grimes int 2508b07e49aSJulian Elischer rtioctl_fib(u_long req, caddr_t data, u_int fibnum) 251df8bae1dSRodney W. Grimes { 2525090559bSChristian S.J. Peron 2535090559bSChristian S.J. Peron /* 2545090559bSChristian S.J. Peron * If more ioctl commands are added here, make sure the proper 2555090559bSChristian S.J. Peron * super-user checks are being performed because it is possible for 2565090559bSChristian S.J. Peron * prison-root to make it this far if raw sockets have been enabled 2575090559bSChristian S.J. Peron * in jails. 2585090559bSChristian S.J. Peron */ 259623ae52eSPoul-Henning Kamp #ifdef INET 260f0068c4aSGarrett Wollman /* Multicast goop, grrr... */ 2618b07e49aSJulian Elischer return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 262623ae52eSPoul-Henning Kamp #else /* INET */ 263623ae52eSPoul-Henning Kamp return ENXIO; 264623ae52eSPoul-Henning Kamp #endif /* INET */ 265df8bae1dSRodney W. Grimes } 266df8bae1dSRodney W. Grimes 267df8bae1dSRodney W. Grimes struct ifaddr * 2684d2c2509SAlexander V. Chernikov ifa_ifwithroute(int flags, const struct sockaddr *dst, 2694d2c2509SAlexander V. Chernikov const struct sockaddr *gateway, u_int fibnum) 2708b07e49aSJulian Elischer { 271f59c6cb0SAlexander V. Chernikov struct ifaddr *ifa; 272d1dd20beSSam Leffler 27397168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 274df8bae1dSRodney W. Grimes if ((flags & RTF_GATEWAY) == 0) { 275df8bae1dSRodney W. Grimes /* 276df8bae1dSRodney W. Grimes * If we are adding a route to an interface, 277df8bae1dSRodney W. Grimes * and the interface is a pt to pt link 278df8bae1dSRodney W. Grimes * we should search for the destination 279df8bae1dSRodney W. Grimes * as our clue to the interface. Otherwise 280df8bae1dSRodney W. Grimes * we can use the local address. 281df8bae1dSRodney W. Grimes */ 28285911824SLuigi Rizzo ifa = NULL; 28385911824SLuigi Rizzo if (flags & RTF_HOST) 2844f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(dst, fibnum); 28585911824SLuigi Rizzo if (ifa == NULL) 286df8bae1dSRodney W. Grimes ifa = ifa_ifwithaddr(gateway); 287df8bae1dSRodney W. Grimes } else { 288df8bae1dSRodney W. Grimes /* 289df8bae1dSRodney W. Grimes * If we are adding a route to a remote net 290df8bae1dSRodney W. Grimes * or host, the gateway may still be on the 291df8bae1dSRodney W. Grimes * other end of a pt to pt link. 292df8bae1dSRodney W. Grimes */ 2934f8585e0SAlan Somers ifa = ifa_ifwithdstaddr(gateway, fibnum); 294df8bae1dSRodney W. Grimes } 29585911824SLuigi Rizzo if (ifa == NULL) 2964f8585e0SAlan Somers ifa = ifa_ifwithnet(gateway, 0, fibnum); 29785911824SLuigi Rizzo if (ifa == NULL) { 298682b902dSAlexander V. Chernikov struct nhop_object *nh; 299b83aa367SAndrey V. Elsukov 300682b902dSAlexander V. Chernikov nh = rib_lookup(fibnum, gateway, NHR_NONE, 0); 301682b902dSAlexander V. Chernikov 302e034e82cSQing Li /* 303e034e82cSQing Li * dismiss a gateway that is reachable only 304e034e82cSQing Li * through the default router 305e034e82cSQing Li */ 306682b902dSAlexander V. Chernikov if ((nh == NULL) || (nh->nh_flags & NHF_DEFAULT)) 307682b902dSAlexander V. Chernikov return (NULL); 308682b902dSAlexander V. Chernikov ifa = nh->nh_ifa; 309df8bae1dSRodney W. Grimes } 310df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != dst->sa_family) { 311df8bae1dSRodney W. Grimes struct ifaddr *oifa = ifa; 312df8bae1dSRodney W. Grimes ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 31385911824SLuigi Rizzo if (ifa == NULL) 314df8bae1dSRodney W. Grimes ifa = oifa; 315df8bae1dSRodney W. Grimes } 316682b902dSAlexander V. Chernikov 317df8bae1dSRodney W. Grimes return (ifa); 318df8bae1dSRodney W. Grimes } 319df8bae1dSRodney W. Grimes 3202caee4beSAlexander V. Chernikov /* 3219a1b64d5SAlexander V. Chernikov * Copy most of @rt data into @info. 3229a1b64d5SAlexander V. Chernikov * 3239a1b64d5SAlexander V. Chernikov * If @flags contains NHR_COPY, copies dst,netmask and gw to the 3249a1b64d5SAlexander V. Chernikov * pointers specified by @info structure. Assume such pointers 3259a1b64d5SAlexander V. Chernikov * are zeroed sockaddr-like structures with sa_len field initialized 3269a1b64d5SAlexander V. Chernikov * to reflect size of the provided buffer. if no NHR_COPY is specified, 3279a1b64d5SAlexander V. Chernikov * point dst,netmask and gw @info fields to appropriate @rt values. 3289a1b64d5SAlexander V. Chernikov * 3296b5d8e30SMark Johnston * if @flags contains NHR_REF, do refcouting on rt_ifp and rt_ifa. 3309a1b64d5SAlexander V. Chernikov * 3319a1b64d5SAlexander V. Chernikov * Returns 0 on success. 3329a1b64d5SAlexander V. Chernikov */ 3339a1b64d5SAlexander V. Chernikov int 3349a1b64d5SAlexander V. Chernikov rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags) 3359a1b64d5SAlexander V. Chernikov { 3369a1b64d5SAlexander V. Chernikov struct rt_metrics *rmx; 3379a1b64d5SAlexander V. Chernikov struct sockaddr *src, *dst; 338aaad3c4fSAlexander V. Chernikov struct nhop_object *nh; 3399a1b64d5SAlexander V. Chernikov int sa_len; 3409a1b64d5SAlexander V. Chernikov 34193bfd365SAlexander V. Chernikov nh = rt->rt_nhop; 3429a1b64d5SAlexander V. Chernikov if (flags & NHR_COPY) { 3439a1b64d5SAlexander V. Chernikov /* Copy destination if dst is non-zero */ 3449a1b64d5SAlexander V. Chernikov src = rt_key(rt); 3459a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 3469a1b64d5SAlexander V. Chernikov sa_len = src->sa_len; 34716703ea8SAlexander V. Chernikov if (dst != NULL) { 3489a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3499a1b64d5SAlexander V. Chernikov return (ENOMEM); 3509a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3519a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3529a1b64d5SAlexander V. Chernikov } 3539a1b64d5SAlexander V. Chernikov 3549a1b64d5SAlexander V. Chernikov /* Copy mask if set && dst is non-zero */ 3559a1b64d5SAlexander V. Chernikov src = rt_mask(rt); 3569a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_NETMASK]; 3579a1b64d5SAlexander V. Chernikov if (src != NULL && dst != NULL) { 3589a1b64d5SAlexander V. Chernikov /* 3599a1b64d5SAlexander V. Chernikov * Radix stores different value in sa_len, 3609a1b64d5SAlexander V. Chernikov * assume rt_mask() to have the same length 3619a1b64d5SAlexander V. Chernikov * as rt_key() 3629a1b64d5SAlexander V. Chernikov */ 3639a1b64d5SAlexander V. Chernikov if (sa_len > dst->sa_len) 3649a1b64d5SAlexander V. Chernikov return (ENOMEM); 3659a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3669a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3679a1b64d5SAlexander V. Chernikov } 3689a1b64d5SAlexander V. Chernikov 3699a1b64d5SAlexander V. Chernikov /* Copy gateway is set && dst is non-zero */ 37093bfd365SAlexander V. Chernikov src = &nh->gw_sa; 3719a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_GATEWAY]; 37293bfd365SAlexander V. Chernikov if ((nhop_get_rtflags(nh) & RTF_GATEWAY) && 37393bfd365SAlexander V. Chernikov src != NULL && dst != NULL) { 3749a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3759a1b64d5SAlexander V. Chernikov return (ENOMEM); 3769a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3779a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3789a1b64d5SAlexander V. Chernikov } 3799a1b64d5SAlexander V. Chernikov } else { 3809a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 3819a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3829a1b64d5SAlexander V. Chernikov if (rt_mask(rt) != NULL) { 3839a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 3849a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3859a1b64d5SAlexander V. Chernikov } 38693bfd365SAlexander V. Chernikov if (nhop_get_rtflags(nh) & RTF_GATEWAY) { 38793bfd365SAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; 3889a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3899a1b64d5SAlexander V. Chernikov } 3909a1b64d5SAlexander V. Chernikov } 3919a1b64d5SAlexander V. Chernikov 3929a1b64d5SAlexander V. Chernikov rmx = info->rti_rmx; 3939a1b64d5SAlexander V. Chernikov if (rmx != NULL) { 3949a1b64d5SAlexander V. Chernikov info->rti_mflags |= RTV_MTU; 395aaad3c4fSAlexander V. Chernikov rmx->rmx_mtu = nh->nh_mtu; 3969a1b64d5SAlexander V. Chernikov } 3979a1b64d5SAlexander V. Chernikov 39893bfd365SAlexander V. Chernikov info->rti_flags = rt->rte_flags | nhop_get_rtflags(nh); 399aaad3c4fSAlexander V. Chernikov info->rti_ifp = nh->nh_ifp; 400aaad3c4fSAlexander V. Chernikov info->rti_ifa = nh->nh_ifa; 4019a1b64d5SAlexander V. Chernikov if (flags & NHR_REF) { 4029a1b64d5SAlexander V. Chernikov if_ref(info->rti_ifp); 4036b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 4049a1b64d5SAlexander V. Chernikov } 4059a1b64d5SAlexander V. Chernikov 4069a1b64d5SAlexander V. Chernikov return (0); 4079a1b64d5SAlexander V. Chernikov } 4089a1b64d5SAlexander V. Chernikov 4099a1b64d5SAlexander V. Chernikov /* 4109a1b64d5SAlexander V. Chernikov * Lookups up route entry for @dst in RIB database for fib @fibnum. 4119a1b64d5SAlexander V. Chernikov * Exports entry data to @info using rt_exportinfo(). 4129a1b64d5SAlexander V. Chernikov * 4136b5d8e30SMark Johnston * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa. 4146b5d8e30SMark Johnston * All references can be released later by calling rib_free_info(). 4159a1b64d5SAlexander V. Chernikov * 4169a1b64d5SAlexander V. Chernikov * Returns 0 on success. 4179a1b64d5SAlexander V. Chernikov * Returns ENOENT for lookup failure, ENOMEM for export failure. 4189a1b64d5SAlexander V. Chernikov */ 4199a1b64d5SAlexander V. Chernikov int 4209a1b64d5SAlexander V. Chernikov rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, 4219a1b64d5SAlexander V. Chernikov uint32_t flowid, struct rt_addrinfo *info) 4229a1b64d5SAlexander V. Chernikov { 42320efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 42461eee0e2SAlexander V. Chernikov struct rib_head *rh; 4259a1b64d5SAlexander V. Chernikov struct radix_node *rn; 4269a1b64d5SAlexander V. Chernikov struct rtentry *rt; 4279a1b64d5SAlexander V. Chernikov int error; 4289a1b64d5SAlexander V. Chernikov 4299a1b64d5SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum")); 4309a1b64d5SAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, dst->sa_family); 4319a1b64d5SAlexander V. Chernikov if (rh == NULL) 4329a1b64d5SAlexander V. Chernikov return (ENOENT); 4339a1b64d5SAlexander V. Chernikov 43461eee0e2SAlexander V. Chernikov RIB_RLOCK(rh); 43561eee0e2SAlexander V. Chernikov rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head); 4369a1b64d5SAlexander V. Chernikov if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { 4379a1b64d5SAlexander V. Chernikov rt = RNTORT(rn); 4389a1b64d5SAlexander V. Chernikov /* Ensure route & ifp is UP */ 4398c61eb21SAlexander V. Chernikov if (RT_LINK_IS_UP(rt->rt_nhop->nh_ifp)) { 4409a1b64d5SAlexander V. Chernikov flags = (flags & NHR_REF) | NHR_COPY; 4419a1b64d5SAlexander V. Chernikov error = rt_exportinfo(rt, info, flags); 44261eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4439a1b64d5SAlexander V. Chernikov 4449a1b64d5SAlexander V. Chernikov return (error); 4459a1b64d5SAlexander V. Chernikov } 4469a1b64d5SAlexander V. Chernikov } 44761eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4489a1b64d5SAlexander V. Chernikov 4499a1b64d5SAlexander V. Chernikov return (ENOENT); 4509a1b64d5SAlexander V. Chernikov } 4519a1b64d5SAlexander V. Chernikov 4529a1b64d5SAlexander V. Chernikov /* 4539a1b64d5SAlexander V. Chernikov * Releases all references acquired by rib_lookup_info() when 4549a1b64d5SAlexander V. Chernikov * called with NHR_REF flags. 4559a1b64d5SAlexander V. Chernikov */ 4569a1b64d5SAlexander V. Chernikov void 4579a1b64d5SAlexander V. Chernikov rib_free_info(struct rt_addrinfo *info) 4589a1b64d5SAlexander V. Chernikov { 4599a1b64d5SAlexander V. Chernikov 4606b5d8e30SMark Johnston ifa_free(info->rti_ifa); 4619a1b64d5SAlexander V. Chernikov if_rele(info->rti_ifp); 4629a1b64d5SAlexander V. Chernikov } 4639a1b64d5SAlexander V. Chernikov 4649a1b64d5SAlexander V. Chernikov /* 4654bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 4664bdf0b6aSAlexander V. Chernikov * 4674bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 4684bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 4694bdf0b6aSAlexander V. Chernikov * 4704bdf0b6aSAlexander V. Chernikov * Arguments: 4714bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 472539642a2SAlexander V. Chernikov * nh pointer to nhop 4734bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 4744bdf0b6aSAlexander V. Chernikov * 4754bdf0b6aSAlexander V. Chernikov * Returns: 4764bdf0b6aSAlexander V. Chernikov * 0 successful 4774bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 4784bdf0b6aSAlexander V. Chernikov */ 4794bdf0b6aSAlexander V. Chernikov static int 480539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 4814bdf0b6aSAlexander V. Chernikov { 4824bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 4834bdf0b6aSAlexander V. Chernikov 484539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 4854bdf0b6aSAlexander V. Chernikov return (0); 4864bdf0b6aSAlexander V. Chernikov 4874bdf0b6aSAlexander V. Chernikov /* 4884bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 4894bdf0b6aSAlexander V. Chernikov * with cloned routes 4904bdf0b6aSAlexander V. Chernikov */ 49193bfd365SAlexander V. Chernikov if ((rt->rte_flags & RTF_UP) == 0) 4924bdf0b6aSAlexander V. Chernikov return (0); 4934bdf0b6aSAlexander V. Chernikov 494e8b0643eSAlexander V. Chernikov return (1); 4954bdf0b6aSAlexander V. Chernikov } 4964bdf0b6aSAlexander V. Chernikov 4974bdf0b6aSAlexander V. Chernikov /* 4984bdf0b6aSAlexander V. Chernikov * Delete all remaining routes using this interface 4994bdf0b6aSAlexander V. Chernikov * Unfortuneatly the only way to do this is to slog through 5004bdf0b6aSAlexander V. Chernikov * the entire routing table looking for routes which point 5014bdf0b6aSAlexander V. Chernikov * to this interface...oh well... 5024bdf0b6aSAlexander V. Chernikov */ 5034bdf0b6aSAlexander V. Chernikov void 50480ae8d60SBjoern A. Zeeb rt_flushifroutes_af(struct ifnet *ifp, int af) 50580ae8d60SBjoern A. Zeeb { 50680ae8d60SBjoern A. Zeeb KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d", 50780ae8d60SBjoern A. Zeeb __func__, af, AF_MAX)); 50880ae8d60SBjoern A. Zeeb 5097511a638SAlexander V. Chernikov rib_foreach_table_walk_del(af, rt_ifdelroute, ifp); 51080ae8d60SBjoern A. Zeeb } 51180ae8d60SBjoern A. Zeeb 51280ae8d60SBjoern A. Zeeb void 5134bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 5144bdf0b6aSAlexander V. Chernikov { 5154bdf0b6aSAlexander V. Chernikov 5167511a638SAlexander V. Chernikov rib_foreach_table_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 5174bdf0b6aSAlexander V. Chernikov } 5184bdf0b6aSAlexander V. Chernikov 5198071913dSRuslan Ermilov /* 5208c0fec80SRobert Watson * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined, 5218c0fec80SRobert Watson * it will be referenced so the caller must free it. 5222ad7ed6eSAlexander V. Chernikov * 5232ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 5242ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 5258c0fec80SRobert Watson */ 5268b07e49aSJulian Elischer int 5278b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 5288b07e49aSJulian Elischer { 5294d2c2509SAlexander V. Chernikov const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr; 530a68cc388SGleb Smirnoff struct epoch_tracker et; 5314d2c2509SAlexander V. Chernikov int needref, error, flags; 5324d2c2509SAlexander V. Chernikov 5334d2c2509SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 5344d2c2509SAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 5354d2c2509SAlexander V. Chernikov ifpaddr = info->rti_info[RTAX_IFP]; 5364d2c2509SAlexander V. Chernikov ifaaddr = info->rti_info[RTAX_IFA]; 5374d2c2509SAlexander V. Chernikov flags = info->rti_flags; 5388071913dSRuslan Ermilov 5398071913dSRuslan Ermilov /* 5408071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 5418071913dSRuslan Ermilov * when protocol address is ambiguous. 5428071913dSRuslan Ermilov */ 5431ebec5faSMatt Macy error = 0; 5441ebec5faSMatt Macy needref = (info->rti_ifa == NULL); 545a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 5462ad7ed6eSAlexander V. Chernikov 5472ad7ed6eSAlexander V. Chernikov /* If we have interface specified by the ifindex in the address, use it */ 5488071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 5492ad7ed6eSAlexander V. Chernikov ifpaddr->sa_family == AF_LINK) { 5502ad7ed6eSAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; 5512ad7ed6eSAlexander V. Chernikov if (sdl->sdl_index != 0) 552270b83b9SHans Petter Selasky info->rti_ifp = ifnet_byindex(sdl->sdl_index); 5538c0fec80SRobert Watson } 5542ad7ed6eSAlexander V. Chernikov /* 5552ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 5562ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 5572ad7ed6eSAlexander V. Chernikov */ 5588071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 5598071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 5608071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 5614d2c2509SAlexander V. Chernikov const struct sockaddr *sa; 5628071913dSRuslan Ermilov 5632ad7ed6eSAlexander V. Chernikov /* 5642ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 5652ad7ed6eSAlexander V. Chernikov * 5662ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 5672ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 5682ad7ed6eSAlexander V. Chernikov * Order of preference: 5692ad7ed6eSAlexander V. Chernikov * 1) IFA address 5702ad7ed6eSAlexander V. Chernikov * 2) gateway address 5712ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 5722ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 5732ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 5742ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 5752ad7ed6eSAlexander V. Chernikov * ignore gateway 5762ad7ed6eSAlexander V. Chernikov * 3) final destination. 5772ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 5782ad7ed6eSAlexander V. Chernikov * -- else -- 5792ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 5802ad7ed6eSAlexander V. Chernikov */ 5812ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 5822ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 5832ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 5842ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 5852ad7ed6eSAlexander V. Chernikov sa = gateway; 5862ad7ed6eSAlexander V. Chernikov else 5872ad7ed6eSAlexander V. Chernikov sa = dst; 5882ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 5898071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 5902ad7ed6eSAlexander V. Chernikov /* Case 4 */ 5912ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 5922ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 5932ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 5944f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 5958b07e49aSJulian Elischer fibnum); 5968071913dSRuslan Ermilov else if (sa != NULL) 5974f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 5988b07e49aSJulian Elischer fibnum); 5998071913dSRuslan Ermilov } 6001ebec5faSMatt Macy if (needref && info->rti_ifa != NULL) { 6018071913dSRuslan Ermilov if (info->rti_ifp == NULL) 602134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 6034f6c66ccSMatt Macy ifa_ref(info->rti_ifa); 6048071913dSRuslan Ermilov } else 6058071913dSRuslan Ermilov error = ENETUNREACH; 606a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 6078071913dSRuslan Ermilov return (error); 6088071913dSRuslan Ermilov } 6098071913dSRuslan Ermilov 6107f948f12SAlexander V. Chernikov void 6117f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 6127f948f12SAlexander V. Chernikov { 61361eee0e2SAlexander V. Chernikov struct rib_head *rnh; 6149e022295SAlexander V. Chernikov int mtu; 6157f948f12SAlexander V. Chernikov int i, j; 6167f948f12SAlexander V. Chernikov 6177f948f12SAlexander V. Chernikov /* 6187f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 6197f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 6207f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 6217f948f12SAlexander V. Chernikov */ 6227f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 6239e022295SAlexander V. Chernikov mtu = if_getmtu_family(ifp, i); 6247f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 6257f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 6267f948f12SAlexander V. Chernikov if (rnh == NULL) 6277f948f12SAlexander V. Chernikov continue; 6289e022295SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, mtu); 6297f948f12SAlexander V. Chernikov } 6307f948f12SAlexander V. Chernikov } 6317f948f12SAlexander V. Chernikov } 6327f948f12SAlexander V. Chernikov 6335a2f4cbdSAlexander V. Chernikov #if 0 6345a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 6355a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 6365a2f4cbdSAlexander V. Chernikov 6375a2f4cbdSAlexander V. Chernikov int 6385a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 6395a2f4cbdSAlexander V. Chernikov { 6405a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 6415a2f4cbdSAlexander V. Chernikov 6425a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 6435a2f4cbdSAlexander V. Chernikov case AF_INET: 6445a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 6455a2f4cbdSAlexander V. Chernikov break; 6465a2f4cbdSAlexander V. Chernikov case AF_INET6: 6475a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 6485a2f4cbdSAlexander V. Chernikov break; 6495a2f4cbdSAlexander V. Chernikov } 6505a2f4cbdSAlexander V. Chernikov 6515a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 6525a2f4cbdSAlexander V. Chernikov return (0); 6535a2f4cbdSAlexander V. Chernikov 6545a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 6555a2f4cbdSAlexander V. Chernikov return (0); 6565a2f4cbdSAlexander V. Chernikov 6575a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 6585a2f4cbdSAlexander V. Chernikov } 6595a2f4cbdSAlexander V. Chernikov 6605a2f4cbdSAlexander V. Chernikov int 6615a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 6625a2f4cbdSAlexander V. Chernikov { 6635a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 6645a2f4cbdSAlexander V. Chernikov int i = 0; 6655a2f4cbdSAlexander V. Chernikov 6665a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 6675a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 6685a2f4cbdSAlexander V. Chernikov 6695a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 6705a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 6715a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 6725a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 6735a2f4cbdSAlexander V. Chernikov } 6745a2f4cbdSAlexander V. Chernikov 6755a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 6765a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 677aaad3c4fSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 6785a2f4cbdSAlexander V. Chernikov } 6795a2f4cbdSAlexander V. Chernikov 6805a2f4cbdSAlexander V. Chernikov return (i); 6815a2f4cbdSAlexander V. Chernikov } 6825a2f4cbdSAlexander V. Chernikov #endif 6835a2f4cbdSAlexander V. Chernikov 6844d2c2509SAlexander V. Chernikov void 685d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 686df8bae1dSRodney W. Grimes { 687f59c6cb0SAlexander V. Chernikov u_char *cp1 = (u_char *)src; 688f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 689f59c6cb0SAlexander V. Chernikov u_char *cp3 = (u_char *)netmask; 690df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 691df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 692df8bae1dSRodney W. Grimes 693df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 694df8bae1dSRodney W. Grimes cp3 += 2; 695df8bae1dSRodney W. Grimes if (cplim > cplim2) 696df8bae1dSRodney W. Grimes cplim = cplim2; 697df8bae1dSRodney W. Grimes while (cp2 < cplim) 698df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 699df8bae1dSRodney W. Grimes if (cp2 < cplim2) 700df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 701df8bae1dSRodney W. Grimes } 702df8bae1dSRodney W. Grimes 703df8bae1dSRodney W. Grimes /* 7044cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 7054cbac30bSAlexander V. Chernikov * Returns 0 on success. 7064cbac30bSAlexander V. Chernikov */ 7074cbac30bSAlexander V. Chernikov int 7084cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 7094cbac30bSAlexander V. Chernikov { 7104cbac30bSAlexander V. Chernikov 7114cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 712d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 713*d68cf57bSAlexander V. Chernikov KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 714d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7154cbac30bSAlexander V. Chernikov 716d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 717*d68cf57bSAlexander V. Chernikov 718*d68cf57bSAlexander V. Chernikov if (V_rt_add_addr_allfibs) 719*d68cf57bSAlexander V. Chernikov fibnum = RT_ALL_FIBS; 7204cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 7214cbac30bSAlexander V. Chernikov } 7224cbac30bSAlexander V. Chernikov 7234cbac30bSAlexander V. Chernikov /* 724e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 725e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 726e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 727*d68cf57bSAlexander V. Chernikov * @nh: nhop object to announce 728e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 729e02d3fe7SAlexander V. Chernikov * 7304cbac30bSAlexander V. Chernikov * Returns 0 on success. 7314cbac30bSAlexander V. Chernikov */ 7324cbac30bSAlexander V. Chernikov int 733*d68cf57bSAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, 7344cbac30bSAlexander V. Chernikov int fibnum) 7354cbac30bSAlexander V. Chernikov { 7364cbac30bSAlexander V. Chernikov 7374cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 738d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 7394cbac30bSAlexander V. Chernikov 740d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 741d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7424cbac30bSAlexander V. Chernikov 7434cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 7444cbac30bSAlexander V. Chernikov 745*d68cf57bSAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, nh, fibnum)); 7464cbac30bSAlexander V. Chernikov } 7474cbac30bSAlexander V. Chernikov 748e02d3fe7SAlexander V. Chernikov /* 749e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 750e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 751e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 752e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 753e02d3fe7SAlexander V. Chernikov * 754e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 755e02d3fe7SAlexander V. Chernikov */ 756e02d3fe7SAlexander V. Chernikov int 757e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 7584cbac30bSAlexander V. Chernikov { 7594cbac30bSAlexander V. Chernikov 760e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 761e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 762e02d3fe7SAlexander V. Chernikov 763e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 764e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 765e02d3fe7SAlexander V. Chernikov 766e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 767e02d3fe7SAlexander V. Chernikov 768e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 7694cbac30bSAlexander V. Chernikov } 7704cbac30bSAlexander V. Chernikov 7714cbac30bSAlexander V. Chernikov /* 7724cbac30bSAlexander V. Chernikov * This is called to generate messages from the routing socket 7734cbac30bSAlexander V. Chernikov * indicating a network interface has had addresses associated with it. 7744cbac30bSAlexander V. Chernikov */ 7754cbac30bSAlexander V. Chernikov void 776e02d3fe7SAlexander V. Chernikov rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum) 7774cbac30bSAlexander V. Chernikov { 7784cbac30bSAlexander V. Chernikov 7794cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 7804cbac30bSAlexander V. Chernikov ("unexpected cmd %u", cmd)); 781*d68cf57bSAlexander V. Chernikov KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 782d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7834cbac30bSAlexander V. Chernikov 7844cbac30bSAlexander V. Chernikov if (cmd == RTM_ADD) { 7854cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 7864cbac30bSAlexander V. Chernikov if (rt != NULL) 787*d68cf57bSAlexander V. Chernikov rt_routemsg(cmd, rt, nhop_select(rt->rt_nhop, 0), fibnum); 7884cbac30bSAlexander V. Chernikov } else { 7894cbac30bSAlexander V. Chernikov if (rt != NULL) 790*d68cf57bSAlexander V. Chernikov rt_routemsg(cmd, rt, nhop_select(rt->rt_nhop, 0), fibnum); 7914cbac30bSAlexander V. Chernikov rt_addrmsg(cmd, ifa, fibnum); 7924cbac30bSAlexander V. Chernikov } 7934cbac30bSAlexander V. Chernikov } 794