xref: /freebsd-src/sys/net/route/route_rtentry.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
15c4d2252SAlexander V. Chernikov /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35c4d2252SAlexander V. Chernikov  *
45c4d2252SAlexander V. Chernikov  * Copyright (c) 2021-2022 Alexander V. Chernikov
55c4d2252SAlexander V. Chernikov  *
65c4d2252SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
75c4d2252SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
85c4d2252SAlexander V. Chernikov  * are met:
95c4d2252SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
105c4d2252SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
115c4d2252SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
125c4d2252SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
135c4d2252SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
145c4d2252SAlexander V. Chernikov  *
155c4d2252SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165c4d2252SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175c4d2252SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185c4d2252SAlexander V. Chernikov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195c4d2252SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205c4d2252SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215c4d2252SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225c4d2252SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235c4d2252SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245c4d2252SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255c4d2252SAlexander V. Chernikov  * SUCH DAMAGE.
265c4d2252SAlexander V. Chernikov  */
275c4d2252SAlexander V. Chernikov 
285c4d2252SAlexander V. Chernikov #include <sys/cdefs.h>
295c4d2252SAlexander V. Chernikov #include "opt_inet.h"
305c4d2252SAlexander V. Chernikov #include "opt_inet6.h"
315c4d2252SAlexander V. Chernikov #include "opt_route.h"
325c4d2252SAlexander V. Chernikov 
335c4d2252SAlexander V. Chernikov #include <sys/param.h>
345c4d2252SAlexander V. Chernikov #include <sys/systm.h>
355c4d2252SAlexander V. Chernikov #include <sys/malloc.h>
365c4d2252SAlexander V. Chernikov #include <sys/socket.h>
372cda6a2fSAlexander V. Chernikov #include <sys/jail.h>
385c4d2252SAlexander V. Chernikov #include <sys/kernel.h>
395c4d2252SAlexander V. Chernikov #include <sys/lock.h>
405c4d2252SAlexander V. Chernikov #include <sys/rmlock.h>
415c4d2252SAlexander V. Chernikov 
425c4d2252SAlexander V. Chernikov #include <net/if.h>
435c4d2252SAlexander V. Chernikov #include <net/if_var.h>
445c4d2252SAlexander V. Chernikov #include <net/vnet.h>
455c4d2252SAlexander V. Chernikov #include <net/route.h>
465c4d2252SAlexander V. Chernikov #include <net/route/route_ctl.h>
475c4d2252SAlexander V. Chernikov #include <net/route/route_var.h>
485c4d2252SAlexander V. Chernikov #include <net/route/nhop.h>
495c4d2252SAlexander V. Chernikov #include <netinet/in.h>
505c4d2252SAlexander V. Chernikov #include <netinet6/scope6_var.h>
515c4d2252SAlexander V. Chernikov 
525c4d2252SAlexander V. Chernikov #include <vm/uma.h>
535c4d2252SAlexander V. Chernikov 
545c4d2252SAlexander V. Chernikov /* Routing table UMA zone */
555c4d2252SAlexander V. Chernikov VNET_DEFINE_STATIC(uma_zone_t, rtzone);
565c4d2252SAlexander V. Chernikov #define	V_rtzone	VNET(rtzone)
575c4d2252SAlexander V. Chernikov 
585c4d2252SAlexander V. Chernikov void
vnet_rtzone_init(void)595c4d2252SAlexander V. Chernikov vnet_rtzone_init(void)
605c4d2252SAlexander V. Chernikov {
615c4d2252SAlexander V. Chernikov 
625c4d2252SAlexander V. Chernikov 	V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry),
635c4d2252SAlexander V. Chernikov 		NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
645c4d2252SAlexander V. Chernikov }
655c4d2252SAlexander V. Chernikov 
665c4d2252SAlexander V. Chernikov #ifdef VIMAGE
675c4d2252SAlexander V. Chernikov void
vnet_rtzone_destroy(void)685c4d2252SAlexander V. Chernikov vnet_rtzone_destroy(void)
695c4d2252SAlexander V. Chernikov {
705c4d2252SAlexander V. Chernikov 
715c4d2252SAlexander V. Chernikov 	uma_zdestroy(V_rtzone);
725c4d2252SAlexander V. Chernikov }
735c4d2252SAlexander V. Chernikov #endif
745c4d2252SAlexander V. Chernikov 
755c4d2252SAlexander V. Chernikov /*
765c4d2252SAlexander V. Chernikov  * Creates rtentry and based on @dst/@netmask data.
775c4d2252SAlexander V. Chernikov  * Return 0 and fills in rtentry into @prt on success,
785c4d2252SAlexander V. Chernikov  * Note: rtentry mask ptr will be set to @netmask , thus its pointer is required
795c4d2252SAlexander V. Chernikov  *  to be stable till the end of the operation (radix rt insertion/change/removal).
805c4d2252SAlexander V. Chernikov  */
815c4d2252SAlexander V. Chernikov struct rtentry *
rt_alloc(struct rib_head * rnh,const struct sockaddr * dst,struct sockaddr * netmask)825c4d2252SAlexander V. Chernikov rt_alloc(struct rib_head *rnh, const struct sockaddr *dst,
835c4d2252SAlexander V. Chernikov     struct sockaddr *netmask)
845c4d2252SAlexander V. Chernikov {
855c4d2252SAlexander V. Chernikov 	MPASS(dst->sa_len <= sizeof(((struct rtentry *)NULL)->rt_dstb));
865c4d2252SAlexander V. Chernikov 
875c4d2252SAlexander V. Chernikov 	struct rtentry *rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO);
885c4d2252SAlexander V. Chernikov 	if (rt == NULL)
895c4d2252SAlexander V. Chernikov 		return (NULL);
905c4d2252SAlexander V. Chernikov 	rt->rte_flags = RTF_UP | (netmask == NULL ? RTF_HOST : 0);
915c4d2252SAlexander V. Chernikov 
925c4d2252SAlexander V. Chernikov 	/* Fill in dst, ensuring it's masked if needed. */
935c4d2252SAlexander V. Chernikov 	if (netmask != NULL) {
945c4d2252SAlexander V. Chernikov 		rt_maskedcopy(dst, &rt->rt_dst, netmask);
955c4d2252SAlexander V. Chernikov 	} else
965c4d2252SAlexander V. Chernikov 		bcopy(dst, &rt->rt_dst, dst->sa_len);
975c4d2252SAlexander V. Chernikov 	rt_key(rt) = &rt->rt_dst;
985c4d2252SAlexander V. Chernikov 	/* Set netmask to the storage from info. It will be updated upon insertion */
995c4d2252SAlexander V. Chernikov 	rt_mask(rt) = netmask;
1005c4d2252SAlexander V. Chernikov 
1015c4d2252SAlexander V. Chernikov 	return (rt);
1025c4d2252SAlexander V. Chernikov }
1035c4d2252SAlexander V. Chernikov 
1045c4d2252SAlexander V. Chernikov static void
destroy_rtentry(struct rtentry * rt)1055c4d2252SAlexander V. Chernikov destroy_rtentry(struct rtentry *rt)
1065c4d2252SAlexander V. Chernikov {
1075c4d2252SAlexander V. Chernikov #ifdef VIMAGE
1085c4d2252SAlexander V. Chernikov 	struct nhop_object *nh = rt->rt_nhop;
1095c4d2252SAlexander V. Chernikov 
1105c4d2252SAlexander V. Chernikov 	/*
1115c4d2252SAlexander V. Chernikov 	 * At this moment rnh, nh_control may be already freed.
1125c4d2252SAlexander V. Chernikov 	 * nhop interface may have been migrated to a different vnet.
1135c4d2252SAlexander V. Chernikov 	 * Use vnet stored in the nexthop to delete the entry.
1145c4d2252SAlexander V. Chernikov 	 */
1155c4d2252SAlexander V. Chernikov #ifdef ROUTE_MPATH
1165c4d2252SAlexander V. Chernikov 	if (NH_IS_NHGRP(nh)) {
1175c4d2252SAlexander V. Chernikov 		const struct weightened_nhop *wn;
1185c4d2252SAlexander V. Chernikov 		uint32_t num_nhops;
1195c4d2252SAlexander V. Chernikov 		wn = nhgrp_get_nhops((struct nhgrp_object *)nh, &num_nhops);
1205c4d2252SAlexander V. Chernikov 		nh = wn[0].nh;
1215c4d2252SAlexander V. Chernikov 	}
1225c4d2252SAlexander V. Chernikov #endif
1235c4d2252SAlexander V. Chernikov 	CURVNET_SET(nhop_get_vnet(nh));
1245c4d2252SAlexander V. Chernikov #endif
1255c4d2252SAlexander V. Chernikov 
1265c4d2252SAlexander V. Chernikov 	/* Unreference nexthop */
1275c4d2252SAlexander V. Chernikov 	nhop_free_any(rt->rt_nhop);
1285c4d2252SAlexander V. Chernikov 
1295c4d2252SAlexander V. Chernikov 	rt_free_immediate(rt);
1305c4d2252SAlexander V. Chernikov 
1315c4d2252SAlexander V. Chernikov 	CURVNET_RESTORE();
1325c4d2252SAlexander V. Chernikov }
1335c4d2252SAlexander V. Chernikov 
1345c4d2252SAlexander V. Chernikov /*
1355c4d2252SAlexander V. Chernikov  * Epoch callback indicating rtentry is safe to destroy
1365c4d2252SAlexander V. Chernikov  */
1375c4d2252SAlexander V. Chernikov static void
destroy_rtentry_epoch(epoch_context_t ctx)1385c4d2252SAlexander V. Chernikov destroy_rtentry_epoch(epoch_context_t ctx)
1395c4d2252SAlexander V. Chernikov {
1405c4d2252SAlexander V. Chernikov 	struct rtentry *rt;
1415c4d2252SAlexander V. Chernikov 
1425c4d2252SAlexander V. Chernikov 	rt = __containerof(ctx, struct rtentry, rt_epoch_ctx);
1435c4d2252SAlexander V. Chernikov 
1445c4d2252SAlexander V. Chernikov 	destroy_rtentry(rt);
1455c4d2252SAlexander V. Chernikov }
1465c4d2252SAlexander V. Chernikov 
1475c4d2252SAlexander V. Chernikov /*
1485c4d2252SAlexander V. Chernikov  * Schedule rtentry deletion
1495c4d2252SAlexander V. Chernikov  */
1505c4d2252SAlexander V. Chernikov void
rt_free(struct rtentry * rt)1515c4d2252SAlexander V. Chernikov rt_free(struct rtentry *rt)
1525c4d2252SAlexander V. Chernikov {
1535c4d2252SAlexander V. Chernikov 
1545c4d2252SAlexander V. Chernikov 	KASSERT(rt != NULL, ("%s: NULL rt", __func__));
1555c4d2252SAlexander V. Chernikov 
15673336a6fSZhenlei Huang 	NET_EPOCH_CALL(destroy_rtentry_epoch, &rt->rt_epoch_ctx);
1575c4d2252SAlexander V. Chernikov }
1585c4d2252SAlexander V. Chernikov 
1595c4d2252SAlexander V. Chernikov void
rt_free_immediate(struct rtentry * rt)1605c4d2252SAlexander V. Chernikov rt_free_immediate(struct rtentry *rt)
1615c4d2252SAlexander V. Chernikov {
1625c4d2252SAlexander V. Chernikov 	uma_zfree(V_rtzone, rt);
1635c4d2252SAlexander V. Chernikov }
1645c4d2252SAlexander V. Chernikov 
1655c4d2252SAlexander V. Chernikov bool
rt_is_host(const struct rtentry * rt)1665c4d2252SAlexander V. Chernikov rt_is_host(const struct rtentry *rt)
1675c4d2252SAlexander V. Chernikov {
1685c4d2252SAlexander V. Chernikov 
1695c4d2252SAlexander V. Chernikov 	return (rt->rte_flags & RTF_HOST);
1705c4d2252SAlexander V. Chernikov }
1715c4d2252SAlexander V. Chernikov 
1725c4d2252SAlexander V. Chernikov sa_family_t
rt_get_family(const struct rtentry * rt)1735c4d2252SAlexander V. Chernikov rt_get_family(const struct rtentry *rt)
1745c4d2252SAlexander V. Chernikov {
1755c4d2252SAlexander V. Chernikov 	const struct sockaddr *dst;
1765c4d2252SAlexander V. Chernikov 
1775c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr *)rt_key_const(rt);
1785c4d2252SAlexander V. Chernikov 
1795c4d2252SAlexander V. Chernikov 	return (dst->sa_family);
1805c4d2252SAlexander V. Chernikov }
1815c4d2252SAlexander V. Chernikov 
1825c4d2252SAlexander V. Chernikov /*
1835c4d2252SAlexander V. Chernikov  * Returns pointer to nexthop or nexthop group
1845c4d2252SAlexander V. Chernikov  * associated with @rt
1855c4d2252SAlexander V. Chernikov  */
1865c4d2252SAlexander V. Chernikov struct nhop_object *
rt_get_raw_nhop(const struct rtentry * rt)1875c4d2252SAlexander V. Chernikov rt_get_raw_nhop(const struct rtentry *rt)
1885c4d2252SAlexander V. Chernikov {
1895c4d2252SAlexander V. Chernikov 
1905c4d2252SAlexander V. Chernikov 	return (rt->rt_nhop);
1915c4d2252SAlexander V. Chernikov }
1925c4d2252SAlexander V. Chernikov 
193fe05d1ddSAlexander V. Chernikov void
rt_get_rnd(const struct rtentry * rt,struct route_nhop_data * rnd)194fe05d1ddSAlexander V. Chernikov rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd)
195fe05d1ddSAlexander V. Chernikov {
196fe05d1ddSAlexander V. Chernikov 	rnd->rnd_nhop = rt->rt_nhop;
197fe05d1ddSAlexander V. Chernikov 	rnd->rnd_weight = rt->rt_weight;
198fe05d1ddSAlexander V. Chernikov }
199fe05d1ddSAlexander V. Chernikov 
2002cda6a2fSAlexander V. Chernikov /*
2012cda6a2fSAlexander V. Chernikov  * If the process in in jail w/o VNET, export only host routes for the
2022cda6a2fSAlexander V. Chernikov  *  addresses assigned to the jail.
2032cda6a2fSAlexander V. Chernikov  * Otherwise, allow exporting the entire table.
2042cda6a2fSAlexander V. Chernikov  */
2052cda6a2fSAlexander V. Chernikov bool
rt_is_exportable(const struct rtentry * rt,struct ucred * cred)2062cda6a2fSAlexander V. Chernikov rt_is_exportable(const struct rtentry *rt, struct ucred *cred)
2072cda6a2fSAlexander V. Chernikov {
2082cda6a2fSAlexander V. Chernikov 	if (!rt_is_host(rt)) {
2092cda6a2fSAlexander V. Chernikov 		/*
2102cda6a2fSAlexander V. Chernikov 		 * Performance optimisation: only host routes are allowed
2112cda6a2fSAlexander V. Chernikov 		 * in the jail w/o vnet.
2122cda6a2fSAlexander V. Chernikov 		 */
2132cda6a2fSAlexander V. Chernikov 		if (jailed_without_vnet(cred))
2142cda6a2fSAlexander V. Chernikov 			return (false);
2152cda6a2fSAlexander V. Chernikov 	} else {
2162cda6a2fSAlexander V. Chernikov 		if (prison_if(cred, rt_key_const(rt)) != 0)
2172cda6a2fSAlexander V. Chernikov 			return (false);
2182cda6a2fSAlexander V. Chernikov 	}
2192cda6a2fSAlexander V. Chernikov 
2202cda6a2fSAlexander V. Chernikov 	return (true);
2212cda6a2fSAlexander V. Chernikov }
2222cda6a2fSAlexander V. Chernikov 
2235c4d2252SAlexander V. Chernikov #ifdef INET
2245c4d2252SAlexander V. Chernikov /*
2255c4d2252SAlexander V. Chernikov  * Stores IPv4 address and prefix length of @rt inside
2265c4d2252SAlexander V. Chernikov  *  @paddr and @plen.
2275c4d2252SAlexander V. Chernikov  * @pscopeid is currently always set to 0.
2285c4d2252SAlexander V. Chernikov  */
2295c4d2252SAlexander V. Chernikov void
rt_get_inet_prefix_plen(const struct rtentry * rt,struct in_addr * paddr,int * plen,uint32_t * pscopeid)2305c4d2252SAlexander V. Chernikov rt_get_inet_prefix_plen(const struct rtentry *rt, struct in_addr *paddr,
2315c4d2252SAlexander V. Chernikov     int *plen, uint32_t *pscopeid)
2325c4d2252SAlexander V. Chernikov {
2335c4d2252SAlexander V. Chernikov 	const struct sockaddr_in *dst;
2345c4d2252SAlexander V. Chernikov 
2355c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in *)rt_key_const(rt);
2365c4d2252SAlexander V. Chernikov 	KASSERT((dst->sin_family == AF_INET),
2375c4d2252SAlexander V. Chernikov 	    ("rt family is %d, not inet", dst->sin_family));
2385c4d2252SAlexander V. Chernikov 	*paddr = dst->sin_addr;
2395c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in *)rt_mask_const(rt);
2405c4d2252SAlexander V. Chernikov 	if (dst == NULL)
2415c4d2252SAlexander V. Chernikov 		*plen = 32;
2425c4d2252SAlexander V. Chernikov 	else
2435c4d2252SAlexander V. Chernikov 		*plen = bitcount32(dst->sin_addr.s_addr);
2445c4d2252SAlexander V. Chernikov 	*pscopeid = 0;
2455c4d2252SAlexander V. Chernikov }
2465c4d2252SAlexander V. Chernikov 
2475c4d2252SAlexander V. Chernikov /*
2485c4d2252SAlexander V. Chernikov  * Stores IPv4 address and prefix mask of @rt inside
2495c4d2252SAlexander V. Chernikov  *  @paddr and @pmask. Sets mask to INADDR_ANY for host routes.
2505c4d2252SAlexander V. Chernikov  * @pscopeid is currently always set to 0.
2515c4d2252SAlexander V. Chernikov  */
2525c4d2252SAlexander V. Chernikov void
rt_get_inet_prefix_pmask(const struct rtentry * rt,struct in_addr * paddr,struct in_addr * pmask,uint32_t * pscopeid)2535c4d2252SAlexander V. Chernikov rt_get_inet_prefix_pmask(const struct rtentry *rt, struct in_addr *paddr,
2545c4d2252SAlexander V. Chernikov     struct in_addr *pmask, uint32_t *pscopeid)
2555c4d2252SAlexander V. Chernikov {
2565c4d2252SAlexander V. Chernikov 	const struct sockaddr_in *dst;
2575c4d2252SAlexander V. Chernikov 
2585c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in *)rt_key_const(rt);
2595c4d2252SAlexander V. Chernikov 	KASSERT((dst->sin_family == AF_INET),
2605c4d2252SAlexander V. Chernikov 	    ("rt family is %d, not inet", dst->sin_family));
2615c4d2252SAlexander V. Chernikov 	*paddr = dst->sin_addr;
2625c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in *)rt_mask_const(rt);
2635c4d2252SAlexander V. Chernikov 	if (dst == NULL)
2645c4d2252SAlexander V. Chernikov 		pmask->s_addr = INADDR_BROADCAST;
2655c4d2252SAlexander V. Chernikov 	else
2665c4d2252SAlexander V. Chernikov 		*pmask = dst->sin_addr;
2675c4d2252SAlexander V. Chernikov 	*pscopeid = 0;
2685c4d2252SAlexander V. Chernikov }
2695c4d2252SAlexander V. Chernikov #endif
2705c4d2252SAlexander V. Chernikov 
2715c4d2252SAlexander V. Chernikov #ifdef INET6
2725c4d2252SAlexander V. Chernikov static int
inet6_get_plen(const struct in6_addr * addr)2735c4d2252SAlexander V. Chernikov inet6_get_plen(const struct in6_addr *addr)
2745c4d2252SAlexander V. Chernikov {
2755c4d2252SAlexander V. Chernikov 
2765c4d2252SAlexander V. Chernikov 	return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) +
2775c4d2252SAlexander V. Chernikov 	    bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3]));
2785c4d2252SAlexander V. Chernikov }
2795c4d2252SAlexander V. Chernikov 
2805c4d2252SAlexander V. Chernikov /*
2815c4d2252SAlexander V. Chernikov  * Stores IPv6 address and prefix length of @rt inside
2825c4d2252SAlexander V. Chernikov  *  @paddr and @plen. Addresses are returned in de-embedded form.
2835c4d2252SAlexander V. Chernikov  * Scopeid is set to 0 for non-LL addresses.
2845c4d2252SAlexander V. Chernikov  */
2855c4d2252SAlexander V. Chernikov void
rt_get_inet6_prefix_plen(const struct rtentry * rt,struct in6_addr * paddr,int * plen,uint32_t * pscopeid)2865c4d2252SAlexander V. Chernikov rt_get_inet6_prefix_plen(const struct rtentry *rt, struct in6_addr *paddr,
2875c4d2252SAlexander V. Chernikov     int *plen, uint32_t *pscopeid)
2885c4d2252SAlexander V. Chernikov {
2895c4d2252SAlexander V. Chernikov 	const struct sockaddr_in6 *dst;
2905c4d2252SAlexander V. Chernikov 
2915c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in6 *)rt_key_const(rt);
2925c4d2252SAlexander V. Chernikov 	KASSERT((dst->sin6_family == AF_INET6),
2935c4d2252SAlexander V. Chernikov 	    ("rt family is %d, not inet6", dst->sin6_family));
2945c4d2252SAlexander V. Chernikov 	if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
2955c4d2252SAlexander V. Chernikov 		in6_splitscope(&dst->sin6_addr, paddr, pscopeid);
2965c4d2252SAlexander V. Chernikov 	else
2975c4d2252SAlexander V. Chernikov 		*paddr = dst->sin6_addr;
2985c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in6 *)rt_mask_const(rt);
2995c4d2252SAlexander V. Chernikov 	if (dst == NULL)
3005c4d2252SAlexander V. Chernikov 		*plen = 128;
3015c4d2252SAlexander V. Chernikov 	else
3025c4d2252SAlexander V. Chernikov 		*plen = inet6_get_plen(&dst->sin6_addr);
3035c4d2252SAlexander V. Chernikov }
3045c4d2252SAlexander V. Chernikov 
3055c4d2252SAlexander V. Chernikov /*
3065c4d2252SAlexander V. Chernikov  * Stores IPv6 address and prefix mask of @rt inside
3075c4d2252SAlexander V. Chernikov  *  @paddr and @pmask. Addresses are returned in de-embedded form.
3085c4d2252SAlexander V. Chernikov  * Scopeid is set to 0 for non-LL addresses.
3095c4d2252SAlexander V. Chernikov  */
3105c4d2252SAlexander V. Chernikov void
rt_get_inet6_prefix_pmask(const struct rtentry * rt,struct in6_addr * paddr,struct in6_addr * pmask,uint32_t * pscopeid)3115c4d2252SAlexander V. Chernikov rt_get_inet6_prefix_pmask(const struct rtentry *rt, struct in6_addr *paddr,
3125c4d2252SAlexander V. Chernikov     struct in6_addr *pmask, uint32_t *pscopeid)
3135c4d2252SAlexander V. Chernikov {
3145c4d2252SAlexander V. Chernikov 	const struct sockaddr_in6 *dst;
3155c4d2252SAlexander V. Chernikov 
3165c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in6 *)rt_key_const(rt);
3175c4d2252SAlexander V. Chernikov 	KASSERT((dst->sin6_family == AF_INET6),
3185c4d2252SAlexander V. Chernikov 	    ("rt family is %d, not inet", dst->sin6_family));
3195c4d2252SAlexander V. Chernikov 	if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr))
3205c4d2252SAlexander V. Chernikov 		in6_splitscope(&dst->sin6_addr, paddr, pscopeid);
3215c4d2252SAlexander V. Chernikov 	else
3225c4d2252SAlexander V. Chernikov 		*paddr = dst->sin6_addr;
3235c4d2252SAlexander V. Chernikov 	dst = (const struct sockaddr_in6 *)rt_mask_const(rt);
3245c4d2252SAlexander V. Chernikov 	if (dst == NULL)
3255c4d2252SAlexander V. Chernikov 		memset(pmask, 0xFF, sizeof(struct in6_addr));
3265c4d2252SAlexander V. Chernikov 	else
3275c4d2252SAlexander V. Chernikov 		*pmask = dst->sin6_addr;
3285c4d2252SAlexander V. Chernikov }
3295c4d2252SAlexander V. Chernikov #endif
3305c4d2252SAlexander V. Chernikov 
3315c4d2252SAlexander V. Chernikov 
332