150397Sobrien/*- 290075Sobrien * SPDX-License-Identifier: BSD-3-Clause 3169689Skan * 450397Sobrien * Copyright (c) 1980, 1986, 1991, 1993 5132718Skan * The Regents of the University of California. All rights reserved. 650397Sobrien * 750397Sobrien * Redistribution and use in source and binary forms, with or without 8132718Skan * modification, are permitted provided that the following conditions 950397Sobrien * are met: 10132718Skan * 1. Redistributions of source code must retain the above copyright 1150397Sobrien * notice, this list of conditions and the following disclaimer. 1250397Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1350397Sobrien * notice, this list of conditions and the following disclaimer in the 1450397Sobrien * documentation and/or other materials provided with the distribution. 15132718Skan * 3. Neither the name of the University nor the names of its contributors 1650397Sobrien * may be used to endorse or promote products derived from this software 1750397Sobrien * without specific prior written permission. 1850397Sobrien * 1950397Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2050397Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2450397Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2550397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2650397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2750397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29169689Skan * SUCH DAMAGE. 30169689Skan */ 31169689Skan/************************************************************************ 32169689Skan * Note: In this file a 'fib' is a "forwarding information base" * 33169689Skan * Which is the new name for an in kernel routing (next hop) table. * 34169689Skan ***********************************************************************/ 35169689Skan 36169689Skan#include "opt_inet.h" 37169689Skan#include "opt_inet6.h" 38169689Skan#include "opt_mrouting.h" 39169689Skan#include "opt_route.h" 40169689Skan 41169689Skan#include <sys/param.h> 42169689Skan#include <sys/systm.h> 43169689Skan#include <sys/malloc.h> 44169689Skan#include <sys/mbuf.h> 45169689Skan#include <sys/socket.h> 46169689Skan#include <sys/sysctl.h> 47169689Skan#include <sys/syslog.h> 48169689Skan#include <sys/sysproto.h> 49169689Skan#include <sys/proc.h> 50169689Skan#include <sys/devctl.h> 51169689Skan#include <sys/domain.h> 52169689Skan#include <sys/eventhandler.h> 53169689Skan#include <sys/kernel.h> 54169689Skan#include <sys/lock.h> 55169689Skan#include <sys/rmlock.h> 56169689Skan 57169689Skan#include <net/if.h> 58169689Skan#include <net/if_var.h> 59169689Skan#include <net/if_private.h> 60169689Skan#include <net/if_dl.h> 61169689Skan#include <net/route.h> 62169689Skan#include <net/route/route_ctl.h> 63169689Skan#include <net/route/route_var.h> 64169689Skan#include <net/route/nhop.h> 65169689Skan#include <net/vnet.h> 66169689Skan 67169689Skan#include <netinet/in.h> 68169689Skan#include <netinet/ip_mroute.h> 69169689Skan#include <netinet6/in6_var.h> 70169689Skan 71169689SkanVNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); 72169689Skan 73169689SkanVNET_PCPUSTAT_SYSINIT(rtstat); 74169689Skan#ifdef VIMAGE 75169689SkanVNET_PCPUSTAT_SYSUNINIT(rtstat); 76169689Skan#endif 77169689Skan 78169689SkanEVENTHANDLER_LIST_DEFINE(rt_addrmsg); 79169689Skan 80169689Skanstatic int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *, 81169689Skan void *arg); 82169689Skan 83169689Skan/* 84169689Skan * route initialization must occur before ip6_init2(), which happenas at 85169689Skan * SI_ORDER_MIDDLE. 86169689Skan */ 87169689Skanstatic void 88169689Skanroute_init(void) 89169689Skan{ 90169689Skan 91169689Skan nhops_init(); 92169689Skan} 93169689SkanSYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); 94169689Skan 95169689Skanstruct rib_head * 96169689Skanrt_table_init(int offset, int family, u_int fibnum) 97169689Skan{ 98169689Skan struct rib_head *rh; 99169689Skan 100169689Skan rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO); 101169689Skan 102169689Skan /* TODO: These details should be hidded inside radix.c */ 103169689Skan /* Init masks tree */ 104169689Skan rn_inithead_internal(&rh->head, rh->rnh_nodes, offset); 105169689Skan rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); 106132718Skan rh->head.rnh_masks = &rh->rmhead; 107132718Skan 108132718Skan /* Save metadata associated with this routing table. */ 109132718Skan rh->rib_family = family; 110132718Skan rh->rib_fibnum = fibnum; 111132718Skan#ifdef VIMAGE 112132718Skan rh->rib_vnet = curvnet; 113132718Skan#endif 114132718Skan 115132718Skan tmproutes_init(rh); 116132718Skan 117132718Skan /* Init locks */ 118132718Skan RIB_LOCK_INIT(rh); 119132718Skan 120132718Skan nhops_init_rib(rh); 121132718Skan 122132718Skan /* Init subscription system */ 123132718Skan rib_init_subscriptions(rh); 124132718Skan 125132718Skan /* Finally, set base callbacks */ 12650397Sobrien rh->rnh_addaddr = rn_addroute; 12750397Sobrien rh->rnh_deladdr = rn_delete; 12850397Sobrien rh->rnh_matchaddr = rn_match; 12950397Sobrien rh->rnh_lookup = rn_lookup; 13050397Sobrien rh->rnh_walktree = rn_walktree; 13150397Sobrien rh->rnh_walktree_from = rn_walktree_from; 13250397Sobrien 13350397Sobrien return (rh); 13450397Sobrien} 13552284Sobrien 13690075Sobrienstatic int 13752284Sobrienrt_freeentry(struct radix_node *rn, void *arg) 13852284Sobrien{ 13952284Sobrien struct radix_head * const rnh = arg; 14090075Sobrien struct radix_node *x; 14152284Sobrien 14290075Sobrien x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh); 14350397Sobrien if (x != NULL) 14450397Sobrien R_Free(x); 14550397Sobrien return (0); 14652284Sobrien} 14790075Sobrien 14850397Sobrienvoid 14950397Sobrienrt_table_destroy(struct rib_head *rh) 150132718Skan{ 15150397Sobrien 152132718Skan RIB_WLOCK(rh); 15350397Sobrien rh->rib_dying = true; 154132718Skan RIB_WUNLOCK(rh); 155132718Skan 15650397Sobrien#ifdef FIB_ALGO 157132718Skan fib_destroy_rib(rh); 15850397Sobrien#endif 159132718Skan 160132718Skan tmproutes_destroy(rh); 161132718Skan 162132718Skan rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); 16350397Sobrien 164132718Skan nhops_destroy_rib(rh); 165132718Skan 166132718Skan rib_destroy_subscriptions(rh); 167132718Skan 168132718Skan /* Assume table is already empty */ 169132718Skan RIB_LOCK_DESTROY(rh); 17050397Sobrien free(rh, M_RTABLE); 171132718Skan} 172132718Skan 173132718Skan/* 174132718Skan * Adds a temporal redirect entry to the routing table. 175132718Skan * @fibnum: fib number 176132718Skan * @dst: destination to install redirect to 177132718Skan * @gateway: gateway to go via 178132718Skan * @author: sockaddr of originating router, can be NULL 179132718Skan * @ifp: interface to use for the redirected route 180132718Skan * @flags: set of flags to add. Allowed: RTF_GATEWAY 181132718Skan * @lifetime_sec: time in seconds to expire this redirect. 182132718Skan * 183132718Skan * Retuns 0 on success, errno otherwise. 184132718Skan */ 185132718Skanint 18650397Sobrienrib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, 18750397Sobrien struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) 18850397Sobrien{ 18950397Sobrien struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; 19050397Sobrien struct rib_cmd_info rc; 19150397Sobrien struct ifaddr *ifa; 19250397Sobrien int error; 19350397Sobrien 19450397Sobrien NET_EPOCH_ASSERT(); 19550397Sobrien 19650397Sobrien if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) 19750397Sobrien return (EAFNOSUPPORT); 19850397Sobrien 19950397Sobrien /* Verify the allowed flag mask. */ 20050397Sobrien KASSERT(((flags & ~(RTF_GATEWAY)) == 0), 20150397Sobrien ("invalid redirect flags: %x", flags)); 20250397Sobrien flags |= RTF_HOST | RTF_DYNAMIC; 20390075Sobrien 20450397Sobrien /* Get the best ifa for the given interface and gateway. */ 205169689Skan if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) 206169689Skan return (ENETUNREACH); 207169689Skan 208169689Skan struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); 209169689Skan if (nh == NULL) 210169689Skan return (ENOMEM); 211169689Skan 212169689Skan nhop_set_gw(nh, gateway, flags & RTF_GATEWAY); 213169689Skan nhop_set_transmit_ifp(nh, ifp); 214169689Skan nhop_set_src(nh, ifa); 215169689Skan nhop_set_pxtype_flag(nh, NHF_HOST); 216169689Skan nhop_set_expire(nh, lifetime_sec + time_uptime); 217169689Skan nhop_set_redirect(nh, true); 21850397Sobrien nhop_set_origin(nh, NH_ORIGIN_REDIRECT); 21950397Sobrien rnd.rnd_nhop = nhop_get_nhop(nh, &error); 22050397Sobrien if (error == 0) { 22150397Sobrien error = rib_add_route_px(fibnum, dst, -1, 22250397Sobrien &rnd, RTM_F_CREATE, &rc); 22350397Sobrien } 22450397Sobrien 225117395Skan if (error != 0) { 22652284Sobrien /* TODO: add per-fib redirect stats. */ 22750397Sobrien return (error); 22850397Sobrien } 22950397Sobrien 23050397Sobrien RTSTAT_INC(rts_dynamic); 23150397Sobrien 23250397Sobrien /* Send notification of a route addition to userland. */ 23352284Sobrien struct rt_addrinfo info = { 23452284Sobrien .rti_info[RTAX_DST] = dst, 23552284Sobrien .rti_info[RTAX_GATEWAY] = gateway, 23652284Sobrien .rti_info[RTAX_AUTHOR] = author, 23752284Sobrien }; 23852284Sobrien rt_missmsg_fib(RTM_REDIRECT, &info, flags | RTF_UP, error, fibnum); 23952284Sobrien 240117395Skan return (0); 241169689Skan} 24250397Sobrien 24352284Sobrien/* 244117395Skan * Routing table ioctl interface. 245169689Skan */ 246169689Skanint 24752284Sobrienrtioctl_fib(u_long req, caddr_t data, u_int fibnum) 24852284Sobrien{ 24952284Sobrien 25052284Sobrien /* 25150397Sobrien * If more ioctl commands are added here, make sure the proper 25250397Sobrien * super-user checks are being performed because it is possible for 25352284Sobrien * prison-root to make it this far if raw sockets have been enabled 25450397Sobrien * in jails. 25550397Sobrien */ 25650397Sobrien#ifdef INET 25752284Sobrien /* Multicast goop, grrr... */ 25850397Sobrien return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; 25950397Sobrien#else /* INET */ 26052284Sobrien return ENXIO; 26152284Sobrien#endif /* INET */ 26250397Sobrien} 263117395Skan 264117395Skanstruct ifaddr * 265117395Skanifa_ifwithroute(int flags, const struct sockaddr *dst, 266117395Skan const struct sockaddr *gateway, u_int fibnum) 267169689Skan{ 268169689Skan struct ifaddr *ifa; 269169689Skan 270169689Skan NET_EPOCH_ASSERT(); 27152284Sobrien if ((flags & RTF_GATEWAY) == 0) { 27252284Sobrien /* 27352284Sobrien * If we are adding a route to an interface, 27452284Sobrien * and the interface is a pt to pt link 27552284Sobrien * we should search for the destination 27652284Sobrien * as our clue to the interface. Otherwise 27752284Sobrien * we can use the local address. 27852284Sobrien */ 27952284Sobrien ifa = NULL; 28052284Sobrien if (flags & RTF_HOST) 28152284Sobrien ifa = ifa_ifwithdstaddr(dst, fibnum); 28252284Sobrien if (ifa == NULL) 28352284Sobrien ifa = ifa_ifwithaddr(gateway); 28452284Sobrien } else { 28552284Sobrien /* 28652284Sobrien * If we are adding a route to a remote net 28752284Sobrien * or host, the gateway may still be on the 28852284Sobrien * other end of a pt to pt link. 28952284Sobrien */ 29052284Sobrien ifa = ifa_ifwithdstaddr(gateway, fibnum); 29152284Sobrien } 29252284Sobrien if (ifa == NULL) 29352284Sobrien ifa = ifa_ifwithnet(gateway, 0, fibnum); 29452284Sobrien if (ifa == NULL) { 29552284Sobrien struct nhop_object *nh; 29652284Sobrien 29752284Sobrien nh = rib_lookup(fibnum, gateway, NHR_NONE, 0); 29852284Sobrien 29952284Sobrien /* 30052284Sobrien * dismiss a gateway that is reachable only 30152284Sobrien * through the default router 30252284Sobrien */ 30352284Sobrien if ((nh == NULL) || (nh->nh_flags & NHF_DEFAULT)) 30490075Sobrien return (NULL); 30590075Sobrien ifa = nh->nh_ifa; 30652284Sobrien } 30752284Sobrien if (ifa->ifa_addr->sa_family != dst->sa_family) { 30852284Sobrien struct ifaddr *oifa = ifa; 30952284Sobrien ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); 31052284Sobrien if (ifa == NULL) 311117395Skan ifa = oifa; 31250397Sobrien } 31350397Sobrien 31452284Sobrien return (ifa); 31552284Sobrien} 31652284Sobrien 31752284Sobrien/* 31852284Sobrien * Delete Routes for a Network Interface 31952284Sobrien * 32052284Sobrien * Called for each routing entry via the rnh->rnh_walktree() call above 32152284Sobrien * to delete all route entries referencing a detaching network interface. 32252284Sobrien * 32352284Sobrien * Arguments: 32452284Sobrien * rt pointer to rtentry 32552284Sobrien * nh pointer to nhop 32652284Sobrien * arg argument passed to rnh->rnh_walktree() - detaching interface 32752284Sobrien * 32852284Sobrien * Returns: 32952284Sobrien * 0 successful 33052284Sobrien * errno failed - reason indicated 33152284Sobrien */ 33252284Sobrienstatic int 33352284Sobrienrt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg) 33452284Sobrien{ 33552284Sobrien struct ifnet *ifp = arg; 33652284Sobrien 33752284Sobrien if (nh->nh_ifp != ifp) 33852284Sobrien return (0); 33952284Sobrien 34050397Sobrien /* 34150397Sobrien * Protect (sorta) against walktree recursion problems 34250397Sobrien * with cloned routes 34350397Sobrien */ 34450397Sobrien if ((rt->rte_flags & RTF_UP) == 0) 34590075Sobrien return (0); 34650397Sobrien 34750397Sobrien return (1); 34850397Sobrien} 34950397Sobrien 35050397Sobrienvoid 35150397Sobrienrt_flushifroutes(struct ifnet *ifp) 35250397Sobrien{ 35350397Sobrien 35450397Sobrien rib_foreach_table_walk_del(AF_UNSPEC, rt_ifdelroute, ifp); 35550397Sobrien} 35652284Sobrien 35790075Sobrien/* 35850397Sobrien * Tries to extract interface from RTAX_IFP passed in rt_addrinfo. 35950397Sobrien * Interface can be specified ether as interface index (sdl_index) or 360117395Skan * the interface name (sdl_data). 361169689Skan * 36250397Sobrien * Returns found ifp or NULL 36350397Sobrien */ 364132718Skanstatic struct ifnet * 365132718Skaninfo_get_ifp(struct rt_addrinfo *info) 36650397Sobrien{ 36750397Sobrien const struct sockaddr_dl *sdl; 36850397Sobrien 36950397Sobrien sdl = (const struct sockaddr_dl *)info->rti_info[RTAX_IFP]; 37050397Sobrien if (sdl->sdl_family != AF_LINK) 37150397Sobrien return (NULL); 37250397Sobrien 37350397Sobrien if (sdl->sdl_index != 0) 37450397Sobrien return (ifnet_byindex(sdl->sdl_index)); 37550397Sobrien if (sdl->sdl_nlen > 0) { 37650397Sobrien char if_name[IF_NAMESIZE]; 37752284Sobrien if (sdl->sdl_nlen + offsetof(struct sockaddr_dl, sdl_data) > sdl->sdl_len) 37852284Sobrien return (NULL); 37952284Sobrien if (sdl->sdl_nlen >= IF_NAMESIZE) 38050397Sobrien return (NULL); 38150397Sobrien bzero(if_name, sizeof(if_name)); 38250397Sobrien memcpy(if_name, sdl->sdl_data, sdl->sdl_nlen); 38350397Sobrien return (ifunit(if_name)); 38450397Sobrien } 38550397Sobrien 38650397Sobrien return (NULL); 38750397Sobrien} 38850397Sobrien 38950397Sobrien/* 39050397Sobrien * Calculates proper ifa/ifp for the cases when gateway AF is different 39150397Sobrien * from dst AF. 39250397Sobrien * 39350397Sobrien * Returns 0 on success. 39450397Sobrien */ 39550397Sobrien__noinline static int 39650397Sobrienrt_getifa_family(struct rt_addrinfo *info, uint32_t fibnum) 39750397Sobrien{ 39850397Sobrien if (info->rti_ifp == NULL) { 39950397Sobrien struct ifaddr *ifa = NULL; 40050397Sobrien /* 40150397Sobrien * No transmit interface specified. Guess it by checking gw sa. 40250397Sobrien */ 40350397Sobrien const struct sockaddr *gw = info->rti_info[RTAX_GATEWAY]; 40450397Sobrien ifa = ifa_ifwithroute(RTF_GATEWAY, gw, gw, fibnum); 40590075Sobrien if (ifa == NULL) 40650397Sobrien return (ENETUNREACH); 40750397Sobrien info->rti_ifp = ifa->ifa_ifp; 40850397Sobrien } 40950397Sobrien 410117395Skan /* Prefer address from outgoing interface */ 411169689Skan info->rti_ifa = ifaof_ifpforaddr(info->rti_info[RTAX_DST], info->rti_ifp); 41250397Sobrien#ifdef INET 41350397Sobrien if (info->rti_ifa == NULL) { 41450397Sobrien /* Use first found IPv4 address */ 41550397Sobrien bool loopback_ok = info->rti_ifp->if_flags & IFF_LOOPBACK; 41650397Sobrien info->rti_ifa = (struct ifaddr *)in_findlocal(fibnum, loopback_ok); 41750397Sobrien } 41850397Sobrien#endif 41990075Sobrien if (info->rti_ifa == NULL) 42090075Sobrien return (ENETUNREACH); 42190075Sobrien return (0); 42250397Sobrien} 42390075Sobrien 42450397Sobrien/* 42550397Sobrien * Fills in rti_ifp and rti_ifa for the provided fib. 42650397Sobrien * 42750397Sobrien * Assume basic consistency checks are executed by callers: 42850397Sobrien * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well. 42950397Sobrien */ 43050397Sobrienint 43150397Sobrienrt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) 43250397Sobrien{ 43390075Sobrien const struct sockaddr *dst, *gateway, *ifaaddr; 43490075Sobrien int error, flags; 43590075Sobrien 43690075Sobrien dst = info->rti_info[RTAX_DST]; 43790075Sobrien gateway = info->rti_info[RTAX_GATEWAY]; 43890075Sobrien ifaaddr = info->rti_info[RTAX_IFA]; 43950397Sobrien flags = info->rti_flags; 44050397Sobrien 44150397Sobrien /* 442132718Skan * ifp may be specified by sockaddr_dl 44390075Sobrien * when protocol address is ambiguous. 44450397Sobrien */ 445132718Skan error = 0; 446132718Skan 44750397Sobrien /* If we have interface specified by RTAX_IFP address, try to use it */ 44850397Sobrien if ((info->rti_ifp == NULL) && (info->rti_info[RTAX_IFP] != NULL)) 44950397Sobrien info->rti_ifp = info_get_ifp(info); 45050397Sobrien /* 45150397Sobrien * If we have source address specified, try to find it 452132718Skan * TODO: avoid enumerating all ifas on all interfaces. 45350397Sobrien */ 45450397Sobrien if (info->rti_ifa == NULL && ifaaddr != NULL) 45550397Sobrien info->rti_ifa = ifa_ifwithaddr(ifaaddr); 45650397Sobrien if ((info->rti_ifa == NULL) && ((info->rti_flags & RTF_GATEWAY) != 0) && 45750397Sobrien (gateway->sa_family != dst->sa_family)) 45852284Sobrien return (rt_getifa_family(info, fibnum)); 45952284Sobrien if (info->rti_ifa == NULL) { 46052284Sobrien const struct sockaddr *sa; 46152284Sobrien 46252284Sobrien /* 46352284Sobrien * Most common use case for the userland-supplied routes. 46452284Sobrien * 46552284Sobrien * Choose sockaddr to select ifa. 46652284Sobrien * -- if ifp is set -- 46752284Sobrien * Order of preference: 46852284Sobrien * 1) IFA address 46952284Sobrien * 2) gateway address 47090075Sobrien * Note: for interface routes link-level gateway address 47152284Sobrien * is specified to indicate the interface index without 47252284Sobrien * specifying RTF_GATEWAY. In this case, ignore gateway 47350397Sobrien * Note: gateway AF may be different from dst AF. In this case, 47450397Sobrien * ignore gateway 47550397Sobrien * 3) final destination. 47696263Sobrien * 4) if all of these fails, try to get at least link-level ifa. 47796263Sobrien * -- else -- 47896263Sobrien * try to lookup gateway or dst in the routing table to get ifa 47996263Sobrien */ 48096263Sobrien if (info->rti_info[RTAX_IFA] != NULL) 48150397Sobrien sa = info->rti_info[RTAX_IFA]; 48250397Sobrien else if ((info->rti_flags & RTF_GATEWAY) != 0 && 48350397Sobrien gateway->sa_family == dst->sa_family) 48450397Sobrien sa = gateway; 48550397Sobrien else 48650397Sobrien sa = dst; 48750397Sobrien if (info->rti_ifp != NULL) { 48850397Sobrien info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp); 48950397Sobrien /* Case 4 */ 49050397Sobrien if (info->rti_ifa == NULL && gateway != NULL) 49150397Sobrien info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp); 492169689Skan } else if (dst != NULL && gateway != NULL) 493169689Skan info->rti_ifa = ifa_ifwithroute(flags, dst, gateway, 49496263Sobrien fibnum); 49550397Sobrien else if (sa != NULL) 49650397Sobrien info->rti_ifa = ifa_ifwithroute(flags, sa, sa, 49750397Sobrien fibnum); 49850397Sobrien } 49950397Sobrien if (info->rti_ifa != NULL) { 50050397Sobrien if (info->rti_ifp == NULL) 50150397Sobrien info->rti_ifp = info->rti_ifa->ifa_ifp; 50250397Sobrien } else 50350397Sobrien error = ENETUNREACH; 50450397Sobrien return (error); 50550397Sobrien} 50650397Sobrien 50750397Sobrienvoid 50890075Sobrienrt_updatemtu(struct ifnet *ifp) 50950397Sobrien{ 51050397Sobrien struct rib_head *rnh; 51150397Sobrien int mtu; 512117395Skan int i, j; 51350397Sobrien 51450397Sobrien /* 51550397Sobrien * Try to update rt_mtu for all routes using this interface 51650397Sobrien * Unfortunately the only way to do this is to traverse all 51796263Sobrien * routing tables in all fibs/domains. 51850397Sobrien */ 51950397Sobrien for (i = 1; i <= AF_MAX; i++) { 52050397Sobrien mtu = if_getmtu_family(ifp, i); 52150397Sobrien for (j = 0; j < rt_numfibs; j++) { 52250397Sobrien rnh = rt_tables_get_rnh(j, i); 52350397Sobrien if (rnh == NULL) 52450397Sobrien continue; 52550397Sobrien nhops_update_ifmtu(rnh, ifp, mtu); 52650397Sobrien } 52750397Sobrien } 52850397Sobrien} 52952284Sobrien 53052284Sobrien#if 0 53150397Sobrienint p_sockaddr(char *buf, int buflen, struct sockaddr *s); 53250397Sobrienint rt_print(char *buf, int buflen, struct rtentry *rt); 53350397Sobrien 534117395Skanint 535169689Skanp_sockaddr(char *buf, int buflen, struct sockaddr *s) 536169689Skan{ 53750397Sobrien void *paddr = NULL; 53850397Sobrien 53950397Sobrien switch (s->sa_family) { 54050397Sobrien case AF_INET: 54150397Sobrien paddr = &((struct sockaddr_in *)s)->sin_addr; 54250397Sobrien break; 54350397Sobrien case AF_INET6: 54450397Sobrien paddr = &((struct sockaddr_in6 *)s)->sin6_addr; 54550397Sobrien break; 546132718Skan } 547132718Skan 548132718Skan if (paddr == NULL) 549132718Skan return (0); 550132718Skan 551132718Skan if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL) 552132718Skan return (0); 553132718Skan 554132718Skan return (strlen(buf)); 555132718Skan} 55650397Sobrien 55750397Sobrienint 55850397Sobrienrt_print(char *buf, int buflen, struct rtentry *rt) 55952284Sobrien{ 56090075Sobrien struct sockaddr *addr, *mask; 56190075Sobrien int i = 0; 56290075Sobrien 56350397Sobrien addr = rt_key(rt); 56450397Sobrien mask = rt_mask(rt); 56550397Sobrien 56650397Sobrien i = p_sockaddr(buf, buflen, addr); 56750397Sobrien if (!(rt->rt_flags & RTF_HOST)) { 56850397Sobrien buf[i++] = '/'; 56950397Sobrien i += p_sockaddr(buf + i, buflen - i, mask); 57050397Sobrien } 57150397Sobrien 57250397Sobrien if (rt->rt_flags & RTF_GATEWAY) { 57350397Sobrien buf[i++] = '>'; 57450397Sobrien i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa); 57550397Sobrien } 57650397Sobrien 57750397Sobrien return (i); 57850397Sobrien} 57950397Sobrien#endif 58050397Sobrien 58150397Sobrienvoid 58252284Sobrienrt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst, 58350397Sobrien const struct sockaddr *netmask) 58450397Sobrien{ 58550397Sobrien const u_char *cp1 = (const u_char *)src; 58650397Sobrien u_char *cp2 = (u_char *)dst; 58750397Sobrien const u_char *cp3 = (const u_char *)netmask; 58850397Sobrien u_char *cplim = cp2 + *cp3; 58950397Sobrien u_char *cplim2 = cp2 + *cp1; 59050397Sobrien 59150397Sobrien *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 59296263Sobrien cp3 += 2; 59396263Sobrien if (cplim > cplim2) 59496263Sobrien cplim = cplim2; 59550397Sobrien while (cp2 < cplim) 59696263Sobrien *cp2++ = *cp1++ & *cp3++; 59750397Sobrien if (cp2 < cplim2) 598169689Skan bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); 599169689Skan} 60050397Sobrien 60150397Sobrien/* 60250397Sobrien * Announce interface address arrival/withdraw 60350397Sobrien * Returns 0 on success. 60450397Sobrien */ 60550397Sobrienint 60650397Sobrienrt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) 60750397Sobrien{ 608169689Skan#if defined(INET) || defined(INET6) 609169689Skan struct sockaddr *sa = ifa->ifa_addr; 610169689Skan struct ifnet *ifp = ifa->ifa_ifp; 61150397Sobrien#endif 61250397Sobrien 61350397Sobrien KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE, 61450397Sobrien ("unexpected cmd %d", cmd)); 61550397Sobrien KASSERT((fibnum >= 0 && fibnum < rt_numfibs), 61690075Sobrien ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 61790075Sobrien 61890075Sobrien EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd); 61990075Sobrien 62090075Sobrien#ifdef INET 621169689Skan if (sa->sa_family == AF_INET) { 622169689Skan char addrstr[INET_ADDRSTRLEN]; 623169689Skan char strbuf[INET_ADDRSTRLEN + 12]; 624169689Skan 625169689Skan inet_ntoa_r(((struct sockaddr_in *)sa)->sin_addr, addrstr); 62650397Sobrien snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 62750397Sobrien devctl_notify("IFNET", ifp->if_xname, 62850397Sobrien (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 629169689Skan } 63050397Sobrien#endif 63150397Sobrien#ifdef INET6 63250397Sobrien if (sa->sa_family == AF_INET6) { 63350397Sobrien char addrstr[INET6_ADDRSTRLEN]; 63450397Sobrien char strbuf[INET6_ADDRSTRLEN + 12]; 635132718Skan 636169689Skan ip6_sprintf(addrstr, IFA_IN6(ifa)); 63750397Sobrien snprintf(strbuf, sizeof(strbuf), "address=%s", addrstr); 638169689Skan devctl_notify("IFNET", ifp->if_xname, 639132718Skan (cmd == RTM_ADD) ? "ADDR_ADD" : "ADDR_DEL", strbuf); 64050397Sobrien } 64150397Sobrien#endif 64250397Sobrien 64350397Sobrien if (V_rt_add_addr_allfibs) 64450397Sobrien fibnum = RT_ALL_FIBS; 64550397Sobrien return (rtsock_addrmsg(cmd, ifa, fibnum)); 64650397Sobrien} 64790075Sobrien 64850397Sobrien/* 64950397Sobrien * Announce kernel-originated route addition/removal to rtsock based on @rt data. 65050397Sobrien * cmd: RTM_ cmd 65150397Sobrien * @rt: valid rtentry 65250397Sobrien * @nh: nhop object to announce 65350397Sobrien * @fibnum: fib id or RT_ALL_FIBS 65450397Sobrien * 655117395Skan * Returns 0 on success. 65650397Sobrien */ 65750397Sobrienint 65850397Sobrienrt_routemsg(int cmd, struct rtentry *rt, struct nhop_object *nh, 65950397Sobrien int fibnum) 66050397Sobrien{ 66150397Sobrien 66250397Sobrien KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 66350397Sobrien ("unexpected cmd %d", cmd)); 66490075Sobrien 66590075Sobrien KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 66690075Sobrien ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 66790075Sobrien 66890075Sobrien KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__)); 66990075Sobrien 67090075Sobrien return (rtsock_routemsg(cmd, rt, nh, fibnum)); 67190075Sobrien} 67290075Sobrien 67390075Sobrien/* 67490075Sobrien * Announce kernel-originated route addition/removal to rtsock based on @rt data. 67590075Sobrien * cmd: RTM_ cmd 67690075Sobrien * @info: addrinfo structure with valid data. 67790075Sobrien * @fibnum: fib id or RT_ALL_FIBS 67890075Sobrien * 67990075Sobrien * Returns 0 on success. 68090075Sobrien */ 68150397Sobrienint 68250397Sobrienrt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum) 68350397Sobrien{ 68450397Sobrien 68550397Sobrien KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE, 68650397Sobrien ("unexpected cmd %d", cmd)); 68750397Sobrien 68850397Sobrien KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs), 68950397Sobrien ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs)); 69050397Sobrien 69150397Sobrien KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__)); 69250397Sobrien 69350397Sobrien return (rtsock_routemsg_info(cmd, info, fibnum)); 69450397Sobrien} 69550397Sobrien 69650397Sobrienvoid 69750397Sobrienrt_ifmsg(struct ifnet *ifp, int if_flags_mask) 69850397Sobrien{ 69950397Sobrien rtsock_callback_p->ifmsg_f(ifp, if_flags_mask); 70050397Sobrien netlink_callback_p->ifmsg_f(ifp, if_flags_mask); 70150397Sobrien} 70250397Sobrien 70350397Sobrien