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