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> 53*a7581946SRozhuk Ivan #include <sys/devctl.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> 67530c0060SRobert Watson #include <net/vnet.h> 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes #include <netinet/in.h> 70b5e8ce9fSBruce Evans #include <netinet/ip_mroute.h> 71*a7581946SRozhuk Ivan #include <netinet6/in6_var.h> 72df8bae1dSRodney W. Grimes 73a6663252SAlexander V. Chernikov VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); 74185c3d2bSGleb Smirnoff 75185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSINIT(rtstat); 76185c3d2bSGleb Smirnoff #ifdef VIMAGE 77185c3d2bSGleb Smirnoff VNET_PCPUSTAT_SYSUNINIT(rtstat); 78185c3d2bSGleb Smirnoff #endif 79b58ea5f3SBjoern A. Zeeb 80d6e23cf0SMichael Tuexen EVENTHANDLER_LIST_DEFINE(rt_addrmsg); 81d6e23cf0SMichael Tuexen 82539642a2SAlexander V. Chernikov static int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *, 83539642a2SAlexander V. Chernikov void *arg); 84cb984c62SAlexander V. Chernikov static int rt_exportinfo(struct rtentry *rt, struct nhop_object *nh, 85cb984c62SAlexander V. Chernikov struct rt_addrinfo *info, int flags); 86c77462ddSAlexander V. Chernikov 878b07e49aSJulian Elischer /* 88d0728d71SRobert Watson * route initialization must occur before ip6_init2(), which happenas at 89d0728d71SRobert Watson * SI_ORDER_MIDDLE. 90d0728d71SRobert Watson */ 912eb5613fSLuigi Rizzo static void 922eb5613fSLuigi Rizzo route_init(void) 93df8bae1dSRodney W. Grimes { 948b07e49aSJulian Elischer 95a6663252SAlexander V. Chernikov nhops_init(); 961ed81b73SMarko Zec } 97891cf3edSEd Maste SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); 981ed81b73SMarko Zec 9961eee0e2SAlexander V. Chernikov struct rib_head * 100ead85fe4SAlexander V. Chernikov rt_table_init(int offset, int family, u_int fibnum) 10161eee0e2SAlexander V. Chernikov { 10261eee0e2SAlexander V. Chernikov struct rib_head *rh; 10361eee0e2SAlexander V. Chernikov 10461eee0e2SAlexander V. Chernikov rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); 10561eee0e2SAlexander V. Chernikov 10661eee0e2SAlexander V. Chernikov /* TODO: These details should be hidded inside radix.c */ 10761eee0e2SAlexander V. Chernikov /* Init masks tree */ 10861eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); 10961eee0e2SAlexander V. Chernikov rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); 11061eee0e2SAlexander V. Chernikov rh->head.rnh_masks = &rh->rmhead; 11161eee0e2SAlexander V. Chernikov 112ead85fe4SAlexander V. Chernikov /* Save metadata associated with this routing table. */ 113ead85fe4SAlexander V. Chernikov rh->rib_family = family; 114ead85fe4SAlexander V. Chernikov rh->rib_fibnum = fibnum; 115ead85fe4SAlexander V. Chernikov #ifdef VIMAGE 116ead85fe4SAlexander V. Chernikov rh->rib_vnet = curvnet; 117ead85fe4SAlexander V. Chernikov #endif 118ead85fe4SAlexander V. Chernikov 11934a5582cSAlexander V. Chernikov tmproutes_init(rh); 12034a5582cSAlexander V. Chernikov 12161eee0e2SAlexander V. Chernikov /* Init locks */ 122abe95d87SAndrey V. Elsukov RIB_LOCK_INIT(rh); 12361eee0e2SAlexander V. Chernikov 124a6663252SAlexander V. Chernikov nhops_init_rib(rh); 125a6663252SAlexander V. Chernikov 126da187ddbSAlexander V. Chernikov /* Init subscription system */ 127edc37a66SAlexander V. Chernikov rib_init_subscriptions(rh); 128da187ddbSAlexander V. Chernikov 12961eee0e2SAlexander V. Chernikov /* Finally, set base callbacks */ 13061eee0e2SAlexander V. Chernikov rh->rnh_addaddr = rn_addroute; 13161eee0e2SAlexander V. Chernikov rh->rnh_deladdr = rn_delete; 13261eee0e2SAlexander V. Chernikov rh->rnh_matchaddr = rn_match; 13361eee0e2SAlexander V. Chernikov rh->rnh_lookup = rn_lookup; 13461eee0e2SAlexander V. Chernikov rh->rnh_walktree = rn_walktree; 13561eee0e2SAlexander V. Chernikov rh->rnh_walktree_from = rn_walktree_from; 13661eee0e2SAlexander V. Chernikov 13761eee0e2SAlexander V. Chernikov return (rh); 13861eee0e2SAlexander V. Chernikov } 13961eee0e2SAlexander V. Chernikov 140a5243af2SBjoern A. Zeeb static int 141a5243af2SBjoern A. Zeeb rt_freeentry(struct radix_node *rn, void *arg) 142a5243af2SBjoern A. Zeeb { 143a5243af2SBjoern A. Zeeb struct radix_head * const rnh = arg; 144a5243af2SBjoern A. Zeeb struct radix_node *x; 145a5243af2SBjoern A. Zeeb 146a5243af2SBjoern A. Zeeb x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); 147a5243af2SBjoern A. Zeeb if (x != NULL) 148a5243af2SBjoern A. Zeeb R_Free(x); 149a5243af2SBjoern A. Zeeb return (0); 150a5243af2SBjoern A. Zeeb } 151a5243af2SBjoern A. Zeeb 15261eee0e2SAlexander V. Chernikov void 15361eee0e2SAlexander V. Chernikov rt_table_destroy(struct rib_head *rh) 15461eee0e2SAlexander V. Chernikov { 15561eee0e2SAlexander V. Chernikov 156f5baf8bbSAlexander V. Chernikov RIB_WLOCK(rh); 157f5baf8bbSAlexander V. Chernikov rh->rib_dying = true; 158f5baf8bbSAlexander V. Chernikov RIB_WUNLOCK(rh); 159f5baf8bbSAlexander V. Chernikov 160f5baf8bbSAlexander V. Chernikov #ifdef FIB_ALGO 161f5baf8bbSAlexander V. Chernikov fib_destroy_rib(rh); 162f5baf8bbSAlexander V. Chernikov #endif 163f5baf8bbSAlexander V. Chernikov 16434a5582cSAlexander V. Chernikov tmproutes_destroy(rh); 16534a5582cSAlexander V. Chernikov 166a5243af2SBjoern A. Zeeb rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); 167a5243af2SBjoern A. Zeeb 168a6663252SAlexander V. Chernikov nhops_destroy_rib(rh); 169a6663252SAlexander V. Chernikov 170edc37a66SAlexander V. Chernikov rib_destroy_subscriptions(rh); 171edc37a66SAlexander V. Chernikov 17261eee0e2SAlexander V. Chernikov /* Assume table is already empty */ 173abe95d87SAndrey V. Elsukov RIB_LOCK_DESTROY(rh); 17461eee0e2SAlexander V. Chernikov free(rh, M_RTABLE); 17561eee0e2SAlexander V. Chernikov } 17661eee0e2SAlexander V. Chernikov 177df8bae1dSRodney W. Grimes /* 17834a5582cSAlexander V. Chernikov * Adds a temporal redirect entry to the routing table. 17934a5582cSAlexander V. Chernikov * @fibnum: fib number 18034a5582cSAlexander V. Chernikov * @dst: destination to install redirect to 18134a5582cSAlexander V. Chernikov * @gateway: gateway to go via 18234a5582cSAlexander V. Chernikov * @author: sockaddr of originating router, can be NULL 18334a5582cSAlexander V. Chernikov * @ifp: interface to use for the redirected route 18434a5582cSAlexander V. Chernikov * @flags: set of flags to add. Allowed: RTF_GATEWAY 18534a5582cSAlexander V. Chernikov * @lifetime_sec: time in seconds to expire this redirect. 18634a5582cSAlexander V. Chernikov * 18734a5582cSAlexander V. Chernikov * Retuns 0 on success, errno otherwise. 188df8bae1dSRodney W. Grimes */ 18934a5582cSAlexander V. Chernikov int 19034a5582cSAlexander V. Chernikov rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, 19134a5582cSAlexander V. Chernikov struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) 1928b07e49aSJulian Elischer { 193e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc; 19434a5582cSAlexander V. Chernikov int error; 195df8bae1dSRodney W. Grimes struct rt_addrinfo info; 19634a5582cSAlexander V. Chernikov struct rt_metrics rti_rmx; 197df8bae1dSRodney W. Grimes struct ifaddr *ifa; 198c2c2a7c1SBjoern A. Zeeb 199b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 200b8a6e03fSGleb Smirnoff 20134a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 20234a5582cSAlexander V. Chernikov return (EAFNOSUPPORT); 2038e7e854cSKip Macy 20434a5582cSAlexander V. Chernikov /* Verify the allowed flag mask. */ 20534a5582cSAlexander V. Chernikov KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 20634a5582cSAlexander V. Chernikov ("invalid redirect flags: %x", flags)); 207592d300eSAlexander V. Chernikov flags |= RTF_HOST | RTF_DYNAMIC; 20834a5582cSAlexander V. Chernikov 20934a5582cSAlexander V. Chernikov /* Get the best ifa for the given interface and gateway. */ 21034a5582cSAlexander V. Chernikov if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 21134a5582cSAlexander V. Chernikov return (ENETUNREACH); 21234a5582cSAlexander V. Chernikov 21334a5582cSAlexander V. Chernikov bzero(&info, sizeof(info)); 2148071913dSRuslan Ermilov info.rti_info[RTAX_DST] = dst; 2158071913dSRuslan Ermilov info.rti_info[RTAX_GATEWAY] = gateway; 2168071913dSRuslan Ermilov info.rti_ifa = ifa; 21734a5582cSAlexander V. Chernikov info.rti_ifp = ifp; 218592d300eSAlexander V. Chernikov info.rti_flags = flags; 21934a5582cSAlexander V. Chernikov 22034a5582cSAlexander V. Chernikov /* Setup route metrics to define expire time. */ 22134a5582cSAlexander V. Chernikov bzero(&rti_rmx, sizeof(rti_rmx)); 22234a5582cSAlexander V. Chernikov /* Set expire time as absolute. */ 22334a5582cSAlexander V. Chernikov rti_rmx.rmx_expire = lifetime_sec + time_second; 22434a5582cSAlexander V. Chernikov info.rti_mflags |= RTV_EXPIRE; 22534a5582cSAlexander V. Chernikov info.rti_rmx = &rti_rmx; 22634a5582cSAlexander V. Chernikov 227e1c05fd2SAlexander V. Chernikov error = rib_action(fibnum, RTM_ADD, &info, &rc); 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 2508e8f1cc9SMark Johnston 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 */ 333cb984c62SAlexander V. Chernikov static int 334cb984c62SAlexander V. Chernikov rt_exportinfo(struct rtentry *rt, struct nhop_object *nh, 335cb984c62SAlexander V. Chernikov struct rt_addrinfo *info, int flags) 3369a1b64d5SAlexander V. Chernikov { 3379a1b64d5SAlexander V. Chernikov struct rt_metrics *rmx; 3389a1b64d5SAlexander V. Chernikov struct sockaddr *src, *dst; 3399a1b64d5SAlexander V. Chernikov int sa_len; 3409a1b64d5SAlexander V. Chernikov 3419a1b64d5SAlexander V. Chernikov if (flags & NHR_COPY) { 3429a1b64d5SAlexander V. Chernikov /* Copy destination if dst is non-zero */ 3439a1b64d5SAlexander V. Chernikov src = rt_key(rt); 3449a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 3459a1b64d5SAlexander V. Chernikov sa_len = src->sa_len; 34616703ea8SAlexander V. Chernikov if (dst != NULL) { 3479a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3489a1b64d5SAlexander V. Chernikov return (ENOMEM); 3499a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3509a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3519a1b64d5SAlexander V. Chernikov } 3529a1b64d5SAlexander V. Chernikov 3539a1b64d5SAlexander V. Chernikov /* Copy mask if set && dst is non-zero */ 3549a1b64d5SAlexander V. Chernikov src = rt_mask(rt); 3559a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_NETMASK]; 3569a1b64d5SAlexander V. Chernikov if (src != NULL && dst != NULL) { 3579a1b64d5SAlexander V. Chernikov /* 3589a1b64d5SAlexander V. Chernikov * Radix stores different value in sa_len, 3599a1b64d5SAlexander V. Chernikov * assume rt_mask() to have the same length 3609a1b64d5SAlexander V. Chernikov * as rt_key() 3619a1b64d5SAlexander V. Chernikov */ 3629a1b64d5SAlexander V. Chernikov if (sa_len > dst->sa_len) 3639a1b64d5SAlexander V. Chernikov return (ENOMEM); 3649a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3659a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3669a1b64d5SAlexander V. Chernikov } 3679a1b64d5SAlexander V. Chernikov 3689a1b64d5SAlexander V. Chernikov /* Copy gateway is set && dst is non-zero */ 36993bfd365SAlexander V. Chernikov src = &nh->gw_sa; 3709a1b64d5SAlexander V. Chernikov dst = info->rti_info[RTAX_GATEWAY]; 37193bfd365SAlexander V. Chernikov if ((nhop_get_rtflags(nh) & RTF_GATEWAY) && 37293bfd365SAlexander V. Chernikov src != NULL && dst != NULL) { 3739a1b64d5SAlexander V. Chernikov if (src->sa_len > dst->sa_len) 3749a1b64d5SAlexander V. Chernikov return (ENOMEM); 3759a1b64d5SAlexander V. Chernikov memcpy(dst, src, src->sa_len); 3769a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3779a1b64d5SAlexander V. Chernikov } 3789a1b64d5SAlexander V. Chernikov } else { 3799a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_DST] = rt_key(rt); 3809a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_DST; 3819a1b64d5SAlexander V. Chernikov if (rt_mask(rt) != NULL) { 3829a1b64d5SAlexander V. Chernikov info->rti_info[RTAX_NETMASK] = rt_mask(rt); 3839a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_NETMASK; 3849a1b64d5SAlexander V. Chernikov } 38593bfd365SAlexander V. Chernikov if (nhop_get_rtflags(nh) & RTF_GATEWAY) { 38693bfd365SAlexander V. Chernikov info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; 3879a1b64d5SAlexander V. Chernikov info->rti_addrs |= RTA_GATEWAY; 3889a1b64d5SAlexander V. Chernikov } 3899a1b64d5SAlexander V. Chernikov } 3909a1b64d5SAlexander V. Chernikov 3919a1b64d5SAlexander V. Chernikov rmx = info->rti_rmx; 3929a1b64d5SAlexander V. Chernikov if (rmx != NULL) { 3939a1b64d5SAlexander V. Chernikov info->rti_mflags |= RTV_MTU; 394aaad3c4fSAlexander V. Chernikov rmx->rmx_mtu = nh->nh_mtu; 3959a1b64d5SAlexander V. Chernikov } 3969a1b64d5SAlexander V. Chernikov 39793bfd365SAlexander V. Chernikov info->rti_flags = rt->rte_flags | nhop_get_rtflags(nh); 398aaad3c4fSAlexander V. Chernikov info->rti_ifp = nh->nh_ifp; 399aaad3c4fSAlexander V. Chernikov info->rti_ifa = nh->nh_ifa; 4009a1b64d5SAlexander V. Chernikov if (flags & NHR_REF) { 4019a1b64d5SAlexander V. Chernikov if_ref(info->rti_ifp); 4026b5d8e30SMark Johnston ifa_ref(info->rti_ifa); 4039a1b64d5SAlexander V. Chernikov } 4049a1b64d5SAlexander V. Chernikov 4059a1b64d5SAlexander V. Chernikov return (0); 4069a1b64d5SAlexander V. Chernikov } 4079a1b64d5SAlexander V. Chernikov 4089a1b64d5SAlexander V. Chernikov /* 4099a1b64d5SAlexander V. Chernikov * Lookups up route entry for @dst in RIB database for fib @fibnum. 4109a1b64d5SAlexander V. Chernikov * Exports entry data to @info using rt_exportinfo(). 4119a1b64d5SAlexander V. Chernikov * 4126b5d8e30SMark Johnston * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa. 4136b5d8e30SMark Johnston * All references can be released later by calling rib_free_info(). 4149a1b64d5SAlexander V. Chernikov * 4159a1b64d5SAlexander V. Chernikov * Returns 0 on success. 4169a1b64d5SAlexander V. Chernikov * Returns ENOENT for lookup failure, ENOMEM for export failure. 4179a1b64d5SAlexander V. Chernikov */ 4189a1b64d5SAlexander V. Chernikov int 4199a1b64d5SAlexander V. Chernikov rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags, 4209a1b64d5SAlexander V. Chernikov uint32_t flowid, struct rt_addrinfo *info) 4219a1b64d5SAlexander V. Chernikov { 42220efcfc6SAndrey V. Elsukov RIB_RLOCK_TRACKER; 42361eee0e2SAlexander V. Chernikov struct rib_head *rh; 4249a1b64d5SAlexander V. Chernikov struct radix_node *rn; 4259a1b64d5SAlexander V. Chernikov struct rtentry *rt; 426cb984c62SAlexander V. Chernikov struct nhop_object *nh; 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); 438cb984c62SAlexander V. Chernikov nh = nhop_select(rt->rt_nhop, flowid); 4399a1b64d5SAlexander V. Chernikov /* Ensure route & ifp is UP */ 440cb984c62SAlexander V. Chernikov if (RT_LINK_IS_UP(nh->nh_ifp)) { 4419a1b64d5SAlexander V. Chernikov flags = (flags & NHR_REF) | NHR_COPY; 442cb984c62SAlexander V. Chernikov error = rt_exportinfo(rt, nh, info, flags); 44361eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4449a1b64d5SAlexander V. Chernikov 4459a1b64d5SAlexander V. Chernikov return (error); 4469a1b64d5SAlexander V. Chernikov } 4479a1b64d5SAlexander V. Chernikov } 44861eee0e2SAlexander V. Chernikov RIB_RUNLOCK(rh); 4499a1b64d5SAlexander V. Chernikov 4509a1b64d5SAlexander V. Chernikov return (ENOENT); 4519a1b64d5SAlexander V. Chernikov } 4529a1b64d5SAlexander V. Chernikov 4539a1b64d5SAlexander V. Chernikov /* 4549a1b64d5SAlexander V. Chernikov * Releases all references acquired by rib_lookup_info() when 4559a1b64d5SAlexander V. Chernikov * called with NHR_REF flags. 4569a1b64d5SAlexander V. Chernikov */ 4579a1b64d5SAlexander V. Chernikov void 4589a1b64d5SAlexander V. Chernikov rib_free_info(struct rt_addrinfo *info) 4599a1b64d5SAlexander V. Chernikov { 4609a1b64d5SAlexander V. Chernikov 4616b5d8e30SMark Johnston ifa_free(info->rti_ifa); 4629a1b64d5SAlexander V. Chernikov if_rele(info->rti_ifp); 4639a1b64d5SAlexander V. Chernikov } 4649a1b64d5SAlexander V. Chernikov 4659a1b64d5SAlexander V. Chernikov /* 4664bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 4674bdf0b6aSAlexander V. Chernikov * 4684bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 4694bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 4704bdf0b6aSAlexander V. Chernikov * 4714bdf0b6aSAlexander V. Chernikov * Arguments: 4724bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 473539642a2SAlexander V. Chernikov * nh pointer to nhop 4744bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 4754bdf0b6aSAlexander V. Chernikov * 4764bdf0b6aSAlexander V. Chernikov * Returns: 4774bdf0b6aSAlexander V. Chernikov * 0 successful 4784bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 4794bdf0b6aSAlexander V. Chernikov */ 4804bdf0b6aSAlexander V. Chernikov static int 481539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 4824bdf0b6aSAlexander V. Chernikov { 4834bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 4844bdf0b6aSAlexander V. Chernikov 485539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 4864bdf0b6aSAlexander V. Chernikov return (0); 4874bdf0b6aSAlexander V. Chernikov 4884bdf0b6aSAlexander V. Chernikov /* 4894bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 4904bdf0b6aSAlexander V. Chernikov * with cloned routes 4914bdf0b6aSAlexander V. Chernikov */ 49293bfd365SAlexander V. Chernikov if ((rt->rte_flags & RTF_UP) == 0) 4934bdf0b6aSAlexander V. Chernikov return (0); 4944bdf0b6aSAlexander V. Chernikov 495e8b0643eSAlexander V. Chernikov return (1); 4964bdf0b6aSAlexander V. Chernikov } 4974bdf0b6aSAlexander V. Chernikov 49880ae8d60SBjoern A. Zeeb void 4994bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 5004bdf0b6aSAlexander V. Chernikov { 5014bdf0b6aSAlexander V. Chernikov 5027511a638SAlexander V. Chernikov rib_foreach_table_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 5034bdf0b6aSAlexander V. Chernikov } 5044bdf0b6aSAlexander V. Chernikov 5058071913dSRuslan Ermilov /* 50659641728SAlexander V. Chernikov * Look up rt_addrinfo for a specific fib. 5072ad7ed6eSAlexander V. Chernikov * 5082ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 5092ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 5108c0fec80SRobert Watson */ 5118b07e49aSJulian Elischer int 5128b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 5138b07e49aSJulian Elischer { 5144d2c2509SAlexander V. Chernikov const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr; 51559641728SAlexander V. Chernikov int error, flags; 5164d2c2509SAlexander V. Chernikov 5174d2c2509SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 5184d2c2509SAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 5194d2c2509SAlexander V. Chernikov ifpaddr = info->rti_info[RTAX_IFP]; 5204d2c2509SAlexander V. Chernikov ifaaddr = info->rti_info[RTAX_IFA]; 5214d2c2509SAlexander V. Chernikov flags = info->rti_flags; 5228071913dSRuslan Ermilov 5238071913dSRuslan Ermilov /* 5248071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 5258071913dSRuslan Ermilov * when protocol address is ambiguous. 5268071913dSRuslan Ermilov */ 5271ebec5faSMatt Macy error = 0; 5282ad7ed6eSAlexander V. Chernikov 5292ad7ed6eSAlexander V. Chernikov /* If we have interface specified by the ifindex in the address, use it */ 5308071913dSRuslan Ermilov if (info->rti_ifp == NULL && ifpaddr != NULL && 5312ad7ed6eSAlexander V. Chernikov ifpaddr->sa_family == AF_LINK) { 5322ad7ed6eSAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr; 5332ad7ed6eSAlexander V. Chernikov if (sdl->sdl_index != 0) 534270b83b9SHans Petter Selasky info->rti_ifp = ifnet_byindex(sdl->sdl_index); 5358c0fec80SRobert Watson } 5362ad7ed6eSAlexander V. Chernikov /* 5372ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 5382ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 5392ad7ed6eSAlexander V. Chernikov */ 5408071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 5418071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 5428071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 5434d2c2509SAlexander V. Chernikov const struct sockaddr *sa; 5448071913dSRuslan Ermilov 5452ad7ed6eSAlexander V. Chernikov /* 5462ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 5472ad7ed6eSAlexander V. Chernikov * 5482ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 5492ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 5502ad7ed6eSAlexander V. Chernikov * Order of preference: 5512ad7ed6eSAlexander V. Chernikov * 1) IFA address 5522ad7ed6eSAlexander V. Chernikov * 2) gateway address 5532ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 5542ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 5552ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 5562ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 5572ad7ed6eSAlexander V. Chernikov * ignore gateway 5582ad7ed6eSAlexander V. Chernikov * 3) final destination. 5592ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 5602ad7ed6eSAlexander V. Chernikov * -- else -- 5612ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 5622ad7ed6eSAlexander V. Chernikov */ 5632ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 5642ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 5652ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 5662ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 5672ad7ed6eSAlexander V. Chernikov sa = gateway; 5682ad7ed6eSAlexander V. Chernikov else 5692ad7ed6eSAlexander V. Chernikov sa = dst; 5702ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 5718071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 5722ad7ed6eSAlexander V. Chernikov /* Case 4 */ 5732ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 5742ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 5752ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 5764f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 5778b07e49aSJulian Elischer fibnum); 5788071913dSRuslan Ermilov else if (sa != NULL) 5794f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 5808b07e49aSJulian Elischer fibnum); 5818071913dSRuslan Ermilov } 58259641728SAlexander V. Chernikov if (info->rti_ifa != NULL) { 5838071913dSRuslan Ermilov if (info->rti_ifp == NULL) 584134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 5858071913dSRuslan Ermilov } else 5868071913dSRuslan Ermilov error = ENETUNREACH; 5878071913dSRuslan Ermilov return (error); 5888071913dSRuslan Ermilov } 5898071913dSRuslan Ermilov 5907f948f12SAlexander V. Chernikov void 5917f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 5927f948f12SAlexander V. Chernikov { 59361eee0e2SAlexander V. Chernikov struct rib_head *rnh; 5949e022295SAlexander V. Chernikov int mtu; 5957f948f12SAlexander V. Chernikov int i, j; 5967f948f12SAlexander V. Chernikov 5977f948f12SAlexander V. Chernikov /* 5987f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 5997f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 6007f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 6017f948f12SAlexander V. Chernikov */ 6027f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 6039e022295SAlexander V. Chernikov mtu = if_getmtu_family(ifp, i); 6047f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 6057f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 6067f948f12SAlexander V. Chernikov if (rnh == NULL) 6077f948f12SAlexander V. Chernikov continue; 6089e022295SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, mtu); 6097f948f12SAlexander V. Chernikov } 6107f948f12SAlexander V. Chernikov } 6117f948f12SAlexander V. Chernikov } 6127f948f12SAlexander V. Chernikov 6135a2f4cbdSAlexander V. Chernikov #if 0 6145a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 6155a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 6165a2f4cbdSAlexander V. Chernikov 6175a2f4cbdSAlexander V. Chernikov int 6185a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 6195a2f4cbdSAlexander V. Chernikov { 6205a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 6215a2f4cbdSAlexander V. Chernikov 6225a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 6235a2f4cbdSAlexander V. Chernikov case AF_INET: 6245a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 6255a2f4cbdSAlexander V. Chernikov break; 6265a2f4cbdSAlexander V. Chernikov case AF_INET6: 6275a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 6285a2f4cbdSAlexander V. Chernikov break; 6295a2f4cbdSAlexander V. Chernikov } 6305a2f4cbdSAlexander V. Chernikov 6315a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 6325a2f4cbdSAlexander V. Chernikov return (0); 6335a2f4cbdSAlexander V. Chernikov 6345a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 6355a2f4cbdSAlexander V. Chernikov return (0); 6365a2f4cbdSAlexander V. Chernikov 6375a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 6385a2f4cbdSAlexander V. Chernikov } 6395a2f4cbdSAlexander V. Chernikov 6405a2f4cbdSAlexander V. Chernikov int 6415a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 6425a2f4cbdSAlexander V. Chernikov { 6435a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 6445a2f4cbdSAlexander V. Chernikov int i = 0; 6455a2f4cbdSAlexander V. Chernikov 6465a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 6475a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 6485a2f4cbdSAlexander V. Chernikov 6495a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 6505a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 6515a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 6525a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 6535a2f4cbdSAlexander V. Chernikov } 6545a2f4cbdSAlexander V. Chernikov 6555a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 6565a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 657aaad3c4fSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 6585a2f4cbdSAlexander V. Chernikov } 6595a2f4cbdSAlexander V. Chernikov 6605a2f4cbdSAlexander V. Chernikov return (i); 6615a2f4cbdSAlexander V. Chernikov } 6625a2f4cbdSAlexander V. Chernikov #endif 6635a2f4cbdSAlexander V. Chernikov 6644d2c2509SAlexander V. Chernikov void 665d1dd20beSSam Leffler rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask) 666df8bae1dSRodney W. Grimes { 667f59c6cb0SAlexander V. Chernikov u_char *cp1 = (u_char *)src; 668f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 669f59c6cb0SAlexander V. Chernikov u_char *cp3 = (u_char *)netmask; 670df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 671df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 672df8bae1dSRodney W. Grimes 673df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 674df8bae1dSRodney W. Grimes cp3 += 2; 675df8bae1dSRodney W. Grimes if (cplim > cplim2) 676df8bae1dSRodney W. Grimes cplim = cplim2; 677df8bae1dSRodney W. Grimes while (cp2 < cplim) 678df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 679df8bae1dSRodney W. Grimes if (cp2 < cplim2) 680df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 681df8bae1dSRodney W. Grimes } 682df8bae1dSRodney W. Grimes 683df8bae1dSRodney W. Grimes /* 6844cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 6854cbac30bSAlexander V. Chernikov * Returns 0 on success. 6864cbac30bSAlexander V. Chernikov */ 6874cbac30bSAlexander V. Chernikov int 6884cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 6894cbac30bSAlexander V. Chernikov { 690*a7581946SRozhuk Ivan #if defined(INET) || defined(INET6) 691*a7581946SRozhuk Ivan struct sockaddr *sa = ifa->ifa_addr; 692*a7581946SRozhuk Ivan struct ifnet *ifp = ifa->ifa_ifp; 693*a7581946SRozhuk Ivan #endif 6944cbac30bSAlexander V. Chernikov 6954cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 696d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 697d68cf57bSAlexander V. Chernikov KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 698d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 6994cbac30bSAlexander V. Chernikov 700d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 701d68cf57bSAlexander V. Chernikov 702*a7581946SRozhuk Ivan #ifdef INET 703*a7581946SRozhuk Ivan if (sa->sa_family == AF_INET) { 704*a7581946SRozhuk Ivan char addrstr[INET_ADDRSTRLEN]; 705*a7581946SRozhuk Ivan char strbuf[INET_ADDRSTRLEN + 12]; 706*a7581946SRozhuk Ivan 707*a7581946SRozhuk Ivan inet_ntoa_r(((struct sockaddr_in *)sa)->sin_addr, addrstr); 708*a7581946SRozhuk Ivan snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 709*a7581946SRozhuk Ivan devctl_notify("IFNET", ifp->if_xname, 710*a7581946SRozhuk Ivan (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 711*a7581946SRozhuk Ivan } 712*a7581946SRozhuk Ivan #endif 713*a7581946SRozhuk Ivan #ifdef INET6 714*a7581946SRozhuk Ivan if (sa->sa_family == AF_INET6) { 715*a7581946SRozhuk Ivan char addrstr[INET6_ADDRSTRLEN]; 716*a7581946SRozhuk Ivan char strbuf[INET6_ADDRSTRLEN + 12]; 717*a7581946SRozhuk Ivan 718*a7581946SRozhuk Ivan ip6_sprintf(addrstr, IFA_IN6(ifa)); 719*a7581946SRozhuk Ivan snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 720*a7581946SRozhuk Ivan devctl_notify("IFNET", ifp->if_xname, 721*a7581946SRozhuk Ivan (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 722*a7581946SRozhuk Ivan } 723*a7581946SRozhuk Ivan #endif 724*a7581946SRozhuk Ivan 725d68cf57bSAlexander V. Chernikov if (V_rt_add_addr_allfibs) 726d68cf57bSAlexander V. Chernikov fibnum = RT_ALL_FIBS; 7274cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 7284cbac30bSAlexander V. Chernikov } 7294cbac30bSAlexander V. Chernikov 7304cbac30bSAlexander V. Chernikov /* 731e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 732e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 733e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 734d68cf57bSAlexander V. Chernikov * @nh: nhop object to announce 735e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 736e02d3fe7SAlexander V. Chernikov * 7374cbac30bSAlexander V. Chernikov * Returns 0 on success. 7384cbac30bSAlexander V. Chernikov */ 7394cbac30bSAlexander V. Chernikov int 740d68cf57bSAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, 7414cbac30bSAlexander V. Chernikov int fibnum) 7424cbac30bSAlexander V. Chernikov { 7434cbac30bSAlexander V. Chernikov 7444cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 745d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 7464cbac30bSAlexander V. Chernikov 747d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 748d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 7494cbac30bSAlexander V. Chernikov 7504cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 7514cbac30bSAlexander V. Chernikov 752d68cf57bSAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, nh, fibnum)); 7534cbac30bSAlexander V. Chernikov } 7544cbac30bSAlexander V. Chernikov 755e02d3fe7SAlexander V. Chernikov /* 756e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 757e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 758e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 759e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 760e02d3fe7SAlexander V. Chernikov * 761e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 762e02d3fe7SAlexander V. Chernikov */ 763e02d3fe7SAlexander V. Chernikov int 764e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 7654cbac30bSAlexander V. Chernikov { 7664cbac30bSAlexander V. Chernikov 767e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 768e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 769e02d3fe7SAlexander V. Chernikov 770e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 771e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 772e02d3fe7SAlexander V. Chernikov 773e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 774e02d3fe7SAlexander V. Chernikov 775e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 7764cbac30bSAlexander V. Chernikov } 777