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> 53a7581946SRozhuk 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> 71a7581946SRozhuk 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); 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 { 191*6d4f6e4cSAlexander V. Chernikov struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; 192e1c05fd2SAlexander V. Chernikov struct rib_cmd_info rc; 193df8bae1dSRodney W. Grimes struct ifaddr *ifa; 194*6d4f6e4cSAlexander V. Chernikov int error; 195c2c2a7c1SBjoern A. Zeeb 196b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 197b8a6e03fSGleb Smirnoff 19834a5582cSAlexander V. Chernikov if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 19934a5582cSAlexander V. Chernikov return (EAFNOSUPPORT); 2008e7e854cSKip Macy 20134a5582cSAlexander V. Chernikov /* Verify the allowed flag mask. */ 20234a5582cSAlexander V. Chernikov KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 20334a5582cSAlexander V. Chernikov ("invalid redirect flags: %x", flags)); 204592d300eSAlexander V. Chernikov flags |= RTF_HOST | RTF_DYNAMIC; 20534a5582cSAlexander V. Chernikov 20634a5582cSAlexander V. Chernikov /* Get the best ifa for the given interface and gateway. */ 20734a5582cSAlexander V. Chernikov if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 20834a5582cSAlexander V. Chernikov return (ENETUNREACH); 20934a5582cSAlexander V. Chernikov 210*6d4f6e4cSAlexander V. Chernikov struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); 211*6d4f6e4cSAlexander V. Chernikov if (nh == NULL) 212*6d4f6e4cSAlexander V. Chernikov return (ENOMEM); 21334a5582cSAlexander V. Chernikov 214*6d4f6e4cSAlexander V. Chernikov nhop_set_gw(nh, gateway, flags & RTF_GATEWAY); 215*6d4f6e4cSAlexander V. Chernikov nhop_set_transmit_ifp(nh, ifp); 216*6d4f6e4cSAlexander V. Chernikov nhop_set_src(nh, ifa); 217*6d4f6e4cSAlexander V. Chernikov nhop_set_pxtype_flag(nh, NHF_HOST); 218*6d4f6e4cSAlexander V. Chernikov nhop_set_expire(nh, lifetime_sec + time_uptime); 219*6d4f6e4cSAlexander V. Chernikov nhop_set_redirect(nh, true); 220*6d4f6e4cSAlexander V. Chernikov rnd.rnd_nhop = nhop_get_nhop(nh, &error); 221*6d4f6e4cSAlexander V. Chernikov if (error == 0) { 222*6d4f6e4cSAlexander V. Chernikov error = rib_add_route_px(fibnum, dst, -1, 223*6d4f6e4cSAlexander V. Chernikov &rnd, RTM_F_CREATE, &rc); 224*6d4f6e4cSAlexander V. Chernikov } 22534a5582cSAlexander V. Chernikov 22634a5582cSAlexander V. Chernikov if (error != 0) { 22734a5582cSAlexander V. Chernikov /* TODO: add per-fib redirect stats. */ 22834a5582cSAlexander V. Chernikov return (error); 22934a5582cSAlexander V. Chernikov } 23034a5582cSAlexander V. Chernikov 23134a5582cSAlexander V. Chernikov RTSTAT_INC(rts_dynamic); 23234a5582cSAlexander V. Chernikov 23334a5582cSAlexander V. Chernikov /* Send notification of a route addition to userland. */ 234*6d4f6e4cSAlexander V. Chernikov struct rt_addrinfo info = { 235*6d4f6e4cSAlexander V. Chernikov .rti_info[RTAX_DST] = dst, 236*6d4f6e4cSAlexander V. Chernikov .rti_info[RTAX_GATEWAY] = gateway, 237*6d4f6e4cSAlexander V. Chernikov .rti_info[RTAX_AUTHOR] = author, 238*6d4f6e4cSAlexander V. Chernikov }; 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 2488e8f1cc9SMark Johnston 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 /* 3194bdf0b6aSAlexander V. Chernikov * Delete Routes for a Network Interface 3204bdf0b6aSAlexander V. Chernikov * 3214bdf0b6aSAlexander V. Chernikov * Called for each routing entry via the rnh->rnh_walktree() call above 3224bdf0b6aSAlexander V. Chernikov * to delete all route entries referencing a detaching network interface. 3234bdf0b6aSAlexander V. Chernikov * 3244bdf0b6aSAlexander V. Chernikov * Arguments: 3254bdf0b6aSAlexander V. Chernikov * rt pointer to rtentry 326539642a2SAlexander V. Chernikov * nh pointer to nhop 3274bdf0b6aSAlexander V. Chernikov * arg argument passed to rnh->rnh_walktree() - detaching interface 3284bdf0b6aSAlexander V. Chernikov * 3294bdf0b6aSAlexander V. Chernikov * Returns: 3304bdf0b6aSAlexander V. Chernikov * 0 successful 3314bdf0b6aSAlexander V. Chernikov * errno failed - reason indicated 3324bdf0b6aSAlexander V. Chernikov */ 3334bdf0b6aSAlexander V. Chernikov static int 334539642a2SAlexander V. Chernikov rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 3354bdf0b6aSAlexander V. Chernikov { 3364bdf0b6aSAlexander V. Chernikov struct ifnet *ifp = arg; 3374bdf0b6aSAlexander V. Chernikov 338539642a2SAlexander V. Chernikov if (nh->nh_ifp != ifp) 3394bdf0b6aSAlexander V. Chernikov return (0); 3404bdf0b6aSAlexander V. Chernikov 3414bdf0b6aSAlexander V. Chernikov /* 3424bdf0b6aSAlexander V. Chernikov * Protect (sorta) against walktree recursion problems 3434bdf0b6aSAlexander V. Chernikov * with cloned routes 3444bdf0b6aSAlexander V. Chernikov */ 34593bfd365SAlexander V. Chernikov if ((rt->rte_flags & RTF_UP) == 0) 3464bdf0b6aSAlexander V. Chernikov return (0); 3474bdf0b6aSAlexander V. Chernikov 348e8b0643eSAlexander V. Chernikov return (1); 3494bdf0b6aSAlexander V. Chernikov } 3504bdf0b6aSAlexander V. Chernikov 35180ae8d60SBjoern A. Zeeb void 3524bdf0b6aSAlexander V. Chernikov rt_flushifroutes(struct ifnet *ifp) 3534bdf0b6aSAlexander V. Chernikov { 3544bdf0b6aSAlexander V. Chernikov 3557511a638SAlexander V. Chernikov rib_foreach_table_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 3564bdf0b6aSAlexander V. Chernikov } 3574bdf0b6aSAlexander V. Chernikov 3588071913dSRuslan Ermilov /* 359d98954e2SAlexander V. Chernikov * Tries to extract interface from RTAX_IFP passed in rt_addrinfo. 360d98954e2SAlexander V. Chernikov * Interface can be specified ether as interface index (sdl_index) or 361d98954e2SAlexander V. Chernikov * the interface name (sdl_data). 362d98954e2SAlexander V. Chernikov * 363d98954e2SAlexander V. Chernikov * Returns found ifp or NULL 364d98954e2SAlexander V. Chernikov */ 365d98954e2SAlexander V. Chernikov static struct ifnet * 366d98954e2SAlexander V. Chernikov info_get_ifp(struct rt_addrinfo *info) 367d98954e2SAlexander V. Chernikov { 368d98954e2SAlexander V. Chernikov const struct sockaddr_dl *sdl; 369d98954e2SAlexander V. Chernikov 370d98954e2SAlexander V. Chernikov sdl = (const struct sockaddr_dl *)info->rti_info[RTAX_IFP]; 371d98954e2SAlexander V. Chernikov if (sdl->sdl_family != AF_LINK) 372d98954e2SAlexander V. Chernikov return (NULL); 373d98954e2SAlexander V. Chernikov 374d98954e2SAlexander V. Chernikov if (sdl->sdl_index != 0) 375d98954e2SAlexander V. Chernikov return (ifnet_byindex(sdl->sdl_index)); 376d98954e2SAlexander V. Chernikov if (sdl->sdl_nlen > 0) { 377d98954e2SAlexander V. Chernikov char if_name[IF_NAMESIZE]; 378d98954e2SAlexander V. Chernikov if (sdl->sdl_nlen + offsetof(struct sockaddr_dl, sdl_data) > sdl->sdl_len) 379d98954e2SAlexander V. Chernikov return (NULL); 380d98954e2SAlexander V. Chernikov if (sdl->sdl_nlen >= IF_NAMESIZE) 381d98954e2SAlexander V. Chernikov return (NULL); 382d98954e2SAlexander V. Chernikov bzero(if_name, sizeof(if_name)); 383d98954e2SAlexander V. Chernikov memcpy(if_name, sdl->sdl_data, sdl->sdl_nlen); 384d98954e2SAlexander V. Chernikov return (ifunit(if_name)); 385d98954e2SAlexander V. Chernikov } 386d98954e2SAlexander V. Chernikov 387d98954e2SAlexander V. Chernikov return (NULL); 388d98954e2SAlexander V. Chernikov } 389d98954e2SAlexander V. Chernikov 390d98954e2SAlexander V. Chernikov /* 3914b631fc8SAlexander V. Chernikov * Calculates proper ifa/ifp for the cases when gateway AF is different 3924b631fc8SAlexander V. Chernikov * from dst AF. 3934b631fc8SAlexander V. Chernikov * 3944b631fc8SAlexander V. Chernikov * Returns 0 on success. 3954b631fc8SAlexander V. Chernikov */ 3964b631fc8SAlexander V. Chernikov __noinline static int 3974b631fc8SAlexander V. Chernikov rt_getifa_family(struct rt_addrinfo *info, uint32_t fibnum) 3984b631fc8SAlexander V. Chernikov { 3994b631fc8SAlexander V. Chernikov if (info->rti_ifp == NULL) { 4004b631fc8SAlexander V. Chernikov struct ifaddr *ifa = NULL; 4014b631fc8SAlexander V. Chernikov /* 4024b631fc8SAlexander V. Chernikov * No transmit interface specified. Guess it by checking gw sa. 4034b631fc8SAlexander V. Chernikov */ 4044b631fc8SAlexander V. Chernikov const struct sockaddr *gw = info->rti_info[RTAX_GATEWAY]; 4054b631fc8SAlexander V. Chernikov ifa = ifa_ifwithroute(RTF_GATEWAY, gw, gw, fibnum); 4064b631fc8SAlexander V. Chernikov if (ifa == NULL) 4074b631fc8SAlexander V. Chernikov return (ENETUNREACH); 4084b631fc8SAlexander V. Chernikov info->rti_ifp = ifa->ifa_ifp; 4094b631fc8SAlexander V. Chernikov } 4104b631fc8SAlexander V. Chernikov 4114b631fc8SAlexander V. Chernikov /* Prefer address from outgoing interface */ 4124b631fc8SAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(info->rti_info[RTAX_DST], info->rti_ifp); 4134b631fc8SAlexander V. Chernikov #ifdef INET 4144b631fc8SAlexander V. Chernikov if (info->rti_ifa == NULL) { 4154b631fc8SAlexander V. Chernikov /* Use first found IPv4 address */ 4164b631fc8SAlexander V. Chernikov bool loopback_ok = info->rti_ifp->if_flags & IFF_LOOPBACK; 4174b631fc8SAlexander V. Chernikov info->rti_ifa = (struct ifaddr *)in_findlocal(fibnum, loopback_ok); 4184b631fc8SAlexander V. Chernikov } 4194b631fc8SAlexander V. Chernikov #endif 4204b631fc8SAlexander V. Chernikov if (info->rti_ifa == NULL) 4214b631fc8SAlexander V. Chernikov return (ENETUNREACH); 4224b631fc8SAlexander V. Chernikov return (0); 4234b631fc8SAlexander V. Chernikov } 4244b631fc8SAlexander V. Chernikov 4254b631fc8SAlexander V. Chernikov /* 426800c6846SAlexander V. Chernikov * Fills in rti_ifp and rti_ifa for the provided fib. 4272ad7ed6eSAlexander V. Chernikov * 4282ad7ed6eSAlexander V. Chernikov * Assume basic consistency checks are executed by callers: 4292ad7ed6eSAlexander V. Chernikov * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 4308c0fec80SRobert Watson */ 4318b07e49aSJulian Elischer int 4328b07e49aSJulian Elischer rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 4338b07e49aSJulian Elischer { 434d98954e2SAlexander V. Chernikov const struct sockaddr *dst, *gateway, *ifaaddr; 43559641728SAlexander V. Chernikov int error, flags; 4364d2c2509SAlexander V. Chernikov 4374d2c2509SAlexander V. Chernikov dst = info->rti_info[RTAX_DST]; 4384d2c2509SAlexander V. Chernikov gateway = info->rti_info[RTAX_GATEWAY]; 4394d2c2509SAlexander V. Chernikov ifaaddr = info->rti_info[RTAX_IFA]; 4404d2c2509SAlexander V. Chernikov flags = info->rti_flags; 4418071913dSRuslan Ermilov 4428071913dSRuslan Ermilov /* 4438071913dSRuslan Ermilov * ifp may be specified by sockaddr_dl 4448071913dSRuslan Ermilov * when protocol address is ambiguous. 4458071913dSRuslan Ermilov */ 4461ebec5faSMatt Macy error = 0; 4472ad7ed6eSAlexander V. Chernikov 448d98954e2SAlexander V. Chernikov /* If we have interface specified by RTAX_IFP address, try to use it */ 449d98954e2SAlexander V. Chernikov if ((info->rti_ifp == NULL) && (info->rti_info[RTAX_IFP] != NULL)) 450d98954e2SAlexander V. Chernikov info->rti_ifp = info_get_ifp(info); 4512ad7ed6eSAlexander V. Chernikov /* 4522ad7ed6eSAlexander V. Chernikov * If we have source address specified, try to find it 4532ad7ed6eSAlexander V. Chernikov * TODO: avoid enumerating all ifas on all interfaces. 4542ad7ed6eSAlexander V. Chernikov */ 4558071913dSRuslan Ermilov if (info->rti_ifa == NULL && ifaaddr != NULL) 4568071913dSRuslan Ermilov info->rti_ifa = ifa_ifwithaddr(ifaaddr); 4574b631fc8SAlexander V. Chernikov if ((info->rti_ifa == NULL) && ((info->rti_flags & RTF_GATEWAY) != 0) && 4584b631fc8SAlexander V. Chernikov (gateway->sa_family != dst->sa_family)) 4594b631fc8SAlexander V. Chernikov return (rt_getifa_family(info, fibnum)); 4608071913dSRuslan Ermilov if (info->rti_ifa == NULL) { 4614d2c2509SAlexander V. Chernikov const struct sockaddr *sa; 4628071913dSRuslan Ermilov 4632ad7ed6eSAlexander V. Chernikov /* 4642ad7ed6eSAlexander V. Chernikov * Most common use case for the userland-supplied routes. 4652ad7ed6eSAlexander V. Chernikov * 4662ad7ed6eSAlexander V. Chernikov * Choose sockaddr to select ifa. 4672ad7ed6eSAlexander V. Chernikov * -- if ifp is set -- 4682ad7ed6eSAlexander V. Chernikov * Order of preference: 4692ad7ed6eSAlexander V. Chernikov * 1) IFA address 4702ad7ed6eSAlexander V. Chernikov * 2) gateway address 4712ad7ed6eSAlexander V. Chernikov * Note: for interface routes link-level gateway address 4722ad7ed6eSAlexander V. Chernikov * is specified to indicate the interface index without 4732ad7ed6eSAlexander V. Chernikov * specifying RTF_GATEWAY. In this case, ignore gateway 4742ad7ed6eSAlexander V. Chernikov * Note: gateway AF may be different from dst AF. In this case, 4752ad7ed6eSAlexander V. Chernikov * ignore gateway 4762ad7ed6eSAlexander V. Chernikov * 3) final destination. 4772ad7ed6eSAlexander V. Chernikov * 4) if all of these fails, try to get at least link-level ifa. 4782ad7ed6eSAlexander V. Chernikov * -- else -- 4792ad7ed6eSAlexander V. Chernikov * try to lookup gateway or dst in the routing table to get ifa 4802ad7ed6eSAlexander V. Chernikov */ 4812ad7ed6eSAlexander V. Chernikov if (info->rti_info[RTAX_IFA] != NULL) 4822ad7ed6eSAlexander V. Chernikov sa = info->rti_info[RTAX_IFA]; 4832ad7ed6eSAlexander V. Chernikov else if ((info->rti_flags & RTF_GATEWAY) != 0 && 4842ad7ed6eSAlexander V. Chernikov gateway->sa_family == dst->sa_family) 4852ad7ed6eSAlexander V. Chernikov sa = gateway; 4862ad7ed6eSAlexander V. Chernikov else 4872ad7ed6eSAlexander V. Chernikov sa = dst; 4882ad7ed6eSAlexander V. Chernikov if (info->rti_ifp != NULL) { 4898071913dSRuslan Ermilov info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 4902ad7ed6eSAlexander V. Chernikov /* Case 4 */ 4912ad7ed6eSAlexander V. Chernikov if (info->rti_ifa == NULL && gateway != NULL) 4922ad7ed6eSAlexander V. Chernikov info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 4932ad7ed6eSAlexander V. Chernikov } else if (dst != NULL && gateway != NULL) 4944f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 4958b07e49aSJulian Elischer fibnum); 4968071913dSRuslan Ermilov else if (sa != NULL) 4974f8585e0SAlan Somers info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 4988b07e49aSJulian Elischer fibnum); 4998071913dSRuslan Ermilov } 50059641728SAlexander V. Chernikov if (info->rti_ifa != NULL) { 5018071913dSRuslan Ermilov if (info->rti_ifp == NULL) 502134804c8SMatt Macy info->rti_ifp = info->rti_ifa->ifa_ifp; 5038071913dSRuslan Ermilov } else 5048071913dSRuslan Ermilov error = ENETUNREACH; 5058071913dSRuslan Ermilov return (error); 5068071913dSRuslan Ermilov } 5078071913dSRuslan Ermilov 5087f948f12SAlexander V. Chernikov void 5097f948f12SAlexander V. Chernikov rt_updatemtu(struct ifnet *ifp) 5107f948f12SAlexander V. Chernikov { 51161eee0e2SAlexander V. Chernikov struct rib_head *rnh; 5129e022295SAlexander V. Chernikov int mtu; 5137f948f12SAlexander V. Chernikov int i, j; 5147f948f12SAlexander V. Chernikov 5157f948f12SAlexander V. Chernikov /* 5167f948f12SAlexander V. Chernikov * Try to update rt_mtu for all routes using this interface 5177f948f12SAlexander V. Chernikov * Unfortunately the only way to do this is to traverse all 5187f948f12SAlexander V. Chernikov * routing tables in all fibs/domains. 5197f948f12SAlexander V. Chernikov */ 5207f948f12SAlexander V. Chernikov for (i = 1; i <= AF_MAX; i++) { 5219e022295SAlexander V. Chernikov mtu = if_getmtu_family(ifp, i); 5227f948f12SAlexander V. Chernikov for (j = 0; j < rt_numfibs; j++) { 5237f948f12SAlexander V. Chernikov rnh = rt_tables_get_rnh(j, i); 5247f948f12SAlexander V. Chernikov if (rnh == NULL) 5257f948f12SAlexander V. Chernikov continue; 5269e022295SAlexander V. Chernikov nhops_update_ifmtu(rnh, ifp, mtu); 5277f948f12SAlexander V. Chernikov } 5287f948f12SAlexander V. Chernikov } 5297f948f12SAlexander V. Chernikov } 5307f948f12SAlexander V. Chernikov 5315a2f4cbdSAlexander V. Chernikov #if 0 5325a2f4cbdSAlexander V. Chernikov int p_sockaddr(char *buf, int buflen, struct sockaddr *s); 5335a2f4cbdSAlexander V. Chernikov int rt_print(char *buf, int buflen, struct rtentry *rt); 5345a2f4cbdSAlexander V. Chernikov 5355a2f4cbdSAlexander V. Chernikov int 5365a2f4cbdSAlexander V. Chernikov p_sockaddr(char *buf, int buflen, struct sockaddr *s) 5375a2f4cbdSAlexander V. Chernikov { 5385a2f4cbdSAlexander V. Chernikov void *paddr = NULL; 5395a2f4cbdSAlexander V. Chernikov 5405a2f4cbdSAlexander V. Chernikov switch (s->sa_family) { 5415a2f4cbdSAlexander V. Chernikov case AF_INET: 5425a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in *)s)->sin_addr; 5435a2f4cbdSAlexander V. Chernikov break; 5445a2f4cbdSAlexander V. Chernikov case AF_INET6: 5455a2f4cbdSAlexander V. Chernikov paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 5465a2f4cbdSAlexander V. Chernikov break; 5475a2f4cbdSAlexander V. Chernikov } 5485a2f4cbdSAlexander V. Chernikov 5495a2f4cbdSAlexander V. Chernikov if (paddr == NULL) 5505a2f4cbdSAlexander V. Chernikov return (0); 5515a2f4cbdSAlexander V. Chernikov 5525a2f4cbdSAlexander V. Chernikov if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 5535a2f4cbdSAlexander V. Chernikov return (0); 5545a2f4cbdSAlexander V. Chernikov 5555a2f4cbdSAlexander V. Chernikov return (strlen(buf)); 5565a2f4cbdSAlexander V. Chernikov } 5575a2f4cbdSAlexander V. Chernikov 5585a2f4cbdSAlexander V. Chernikov int 5595a2f4cbdSAlexander V. Chernikov rt_print(char *buf, int buflen, struct rtentry *rt) 5605a2f4cbdSAlexander V. Chernikov { 5615a2f4cbdSAlexander V. Chernikov struct sockaddr *addr, *mask; 5625a2f4cbdSAlexander V. Chernikov int i = 0; 5635a2f4cbdSAlexander V. Chernikov 5645a2f4cbdSAlexander V. Chernikov addr = rt_key(rt); 5655a2f4cbdSAlexander V. Chernikov mask = rt_mask(rt); 5665a2f4cbdSAlexander V. Chernikov 5675a2f4cbdSAlexander V. Chernikov i = p_sockaddr(buf, buflen, addr); 5685a2f4cbdSAlexander V. Chernikov if (!(rt->rt_flags & RTF_HOST)) { 5695a2f4cbdSAlexander V. Chernikov buf[i++] = '/'; 5705a2f4cbdSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, mask); 5715a2f4cbdSAlexander V. Chernikov } 5725a2f4cbdSAlexander V. Chernikov 5735a2f4cbdSAlexander V. Chernikov if (rt->rt_flags & RTF_GATEWAY) { 5745a2f4cbdSAlexander V. Chernikov buf[i++] = '>'; 575aaad3c4fSAlexander V. Chernikov i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 5765a2f4cbdSAlexander V. Chernikov } 5775a2f4cbdSAlexander V. Chernikov 5785a2f4cbdSAlexander V. Chernikov return (i); 5795a2f4cbdSAlexander V. Chernikov } 5805a2f4cbdSAlexander V. Chernikov #endif 5815a2f4cbdSAlexander V. Chernikov 5824d2c2509SAlexander V. Chernikov void 58366230639SAlexander V. Chernikov rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst, 58466230639SAlexander V. Chernikov const struct sockaddr *netmask) 585df8bae1dSRodney W. Grimes { 58666230639SAlexander V. Chernikov const u_char *cp1 = (const u_char *)src; 587f59c6cb0SAlexander V. Chernikov u_char *cp2 = (u_char *)dst; 58866230639SAlexander V. Chernikov const u_char *cp3 = (const u_char *)netmask; 589df8bae1dSRodney W. Grimes u_char *cplim = cp2 + *cp3; 590df8bae1dSRodney W. Grimes u_char *cplim2 = cp2 + *cp1; 591df8bae1dSRodney W. Grimes 592df8bae1dSRodney W. Grimes *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 593df8bae1dSRodney W. Grimes cp3 += 2; 594df8bae1dSRodney W. Grimes if (cplim > cplim2) 595df8bae1dSRodney W. Grimes cplim = cplim2; 596df8bae1dSRodney W. Grimes while (cp2 < cplim) 597df8bae1dSRodney W. Grimes *cp2++ = *cp1++ & *cp3++; 598df8bae1dSRodney W. Grimes if (cp2 < cplim2) 599df8bae1dSRodney W. Grimes bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 600df8bae1dSRodney W. Grimes } 601df8bae1dSRodney W. Grimes 602df8bae1dSRodney W. Grimes /* 6034cbac30bSAlexander V. Chernikov * Announce interface address arrival/withdraw 6044cbac30bSAlexander V. Chernikov * Returns 0 on success. 6054cbac30bSAlexander V. Chernikov */ 6064cbac30bSAlexander V. Chernikov int 6074cbac30bSAlexander V. Chernikov rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 6084cbac30bSAlexander V. Chernikov { 609a7581946SRozhuk Ivan #if defined(INET) || defined(INET6) 610a7581946SRozhuk Ivan struct sockaddr *sa = ifa->ifa_addr; 611a7581946SRozhuk Ivan struct ifnet *ifp = ifa->ifa_ifp; 612a7581946SRozhuk Ivan #endif 6134cbac30bSAlexander V. Chernikov 6144cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 615d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 616d68cf57bSAlexander V. Chernikov KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 617d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 6184cbac30bSAlexander V. Chernikov 619d6e23cf0SMichael Tuexen EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 620d68cf57bSAlexander V. Chernikov 621a7581946SRozhuk Ivan #ifdef INET 622a7581946SRozhuk Ivan if (sa->sa_family == AF_INET) { 623a7581946SRozhuk Ivan char addrstr[INET_ADDRSTRLEN]; 624a7581946SRozhuk Ivan char strbuf[INET_ADDRSTRLEN + 12]; 625a7581946SRozhuk Ivan 626a7581946SRozhuk Ivan inet_ntoa_r(((struct sockaddr_in *)sa)->sin_addr, addrstr); 627a7581946SRozhuk Ivan snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 628a7581946SRozhuk Ivan devctl_notify("IFNET", ifp->if_xname, 629a7581946SRozhuk Ivan (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 630a7581946SRozhuk Ivan } 631a7581946SRozhuk Ivan #endif 632a7581946SRozhuk Ivan #ifdef INET6 633a7581946SRozhuk Ivan if (sa->sa_family == AF_INET6) { 634a7581946SRozhuk Ivan char addrstr[INET6_ADDRSTRLEN]; 635a7581946SRozhuk Ivan char strbuf[INET6_ADDRSTRLEN + 12]; 636a7581946SRozhuk Ivan 637a7581946SRozhuk Ivan ip6_sprintf(addrstr, IFA_IN6(ifa)); 638a7581946SRozhuk Ivan snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 639a7581946SRozhuk Ivan devctl_notify("IFNET", ifp->if_xname, 640a7581946SRozhuk Ivan (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 641a7581946SRozhuk Ivan } 642a7581946SRozhuk Ivan #endif 643a7581946SRozhuk Ivan 644d68cf57bSAlexander V. Chernikov if (V_rt_add_addr_allfibs) 645d68cf57bSAlexander V. Chernikov fibnum = RT_ALL_FIBS; 6464cbac30bSAlexander V. Chernikov return (rtsock_addrmsg(cmd, ifa, fibnum)); 6474cbac30bSAlexander V. Chernikov } 6484cbac30bSAlexander V. Chernikov 6494cbac30bSAlexander V. Chernikov /* 650e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 651e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 652e02d3fe7SAlexander V. Chernikov * @rt: valid rtentry 653d68cf57bSAlexander V. Chernikov * @nh: nhop object to announce 654e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 655e02d3fe7SAlexander V. Chernikov * 6564cbac30bSAlexander V. Chernikov * Returns 0 on success. 6574cbac30bSAlexander V. Chernikov */ 6584cbac30bSAlexander V. Chernikov int 659d68cf57bSAlexander V. Chernikov rt_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, 6604cbac30bSAlexander V. Chernikov int fibnum) 6614cbac30bSAlexander V. Chernikov { 6624cbac30bSAlexander V. Chernikov 6634cbac30bSAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 664d375edc9SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 6654cbac30bSAlexander V. Chernikov 666d375edc9SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 667d375edc9SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 6684cbac30bSAlexander V. Chernikov 6694cbac30bSAlexander V. Chernikov KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 6704cbac30bSAlexander V. Chernikov 671d68cf57bSAlexander V. Chernikov return (rtsock_routemsg(cmd, rt, nh, fibnum)); 6724cbac30bSAlexander V. Chernikov } 6734cbac30bSAlexander V. Chernikov 674e02d3fe7SAlexander V. Chernikov /* 675e02d3fe7SAlexander V. Chernikov * Announce kernel-originated route addition/removal to rtsock based on @rt data. 676e02d3fe7SAlexander V. Chernikov * cmd: RTM_ cmd 677e02d3fe7SAlexander V. Chernikov * @info: addrinfo structure with valid data. 678e02d3fe7SAlexander V. Chernikov * @fibnum: fib id or RT_ALL_FIBS 679e02d3fe7SAlexander V. Chernikov * 680e02d3fe7SAlexander V. Chernikov * Returns 0 on success. 681e02d3fe7SAlexander V. Chernikov */ 682e02d3fe7SAlexander V. Chernikov int 683e02d3fe7SAlexander V. Chernikov rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 6844cbac30bSAlexander V. Chernikov { 6854cbac30bSAlexander V. Chernikov 686e02d3fe7SAlexander V. Chernikov KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 687e02d3fe7SAlexander V. Chernikov ("unexpected cmd %d", cmd)); 688e02d3fe7SAlexander V. Chernikov 689e02d3fe7SAlexander V. Chernikov KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 690e02d3fe7SAlexander V. Chernikov ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 691e02d3fe7SAlexander V. Chernikov 692e02d3fe7SAlexander V. Chernikov KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 693e02d3fe7SAlexander V. Chernikov 694e02d3fe7SAlexander V. Chernikov return (rtsock_routemsg_info(cmd, info, fibnum)); 6954cbac30bSAlexander V. Chernikov } 696