xref: /freebsd/sys/netinet6/in6_fib_algo.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1f5baf8bbSAlexander V. Chernikov /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3f5baf8bbSAlexander V. Chernikov  *
4f5baf8bbSAlexander V. Chernikov  * Copyright (c) 2020 Alexander V. Chernikov
5f5baf8bbSAlexander V. Chernikov  *
6f5baf8bbSAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
7f5baf8bbSAlexander V. Chernikov  * modification, are permitted provided that the following conditions
8f5baf8bbSAlexander V. Chernikov  * are met:
9f5baf8bbSAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
10f5baf8bbSAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
11f5baf8bbSAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
12f5baf8bbSAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
13f5baf8bbSAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
14f5baf8bbSAlexander V. Chernikov  *
15f5baf8bbSAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16f5baf8bbSAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17f5baf8bbSAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f5baf8bbSAlexander V. Chernikov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19f5baf8bbSAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f5baf8bbSAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21f5baf8bbSAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22f5baf8bbSAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23f5baf8bbSAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24f5baf8bbSAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25f5baf8bbSAlexander V. Chernikov  * SUCH DAMAGE.
26f5baf8bbSAlexander V. Chernikov  */
27f5baf8bbSAlexander V. Chernikov 
28f5baf8bbSAlexander V. Chernikov #include <sys/cdefs.h>
29f5baf8bbSAlexander V. Chernikov #include "opt_inet6.h"
30f5baf8bbSAlexander V. Chernikov 
31f5baf8bbSAlexander V. Chernikov #include <sys/param.h>
32f5baf8bbSAlexander V. Chernikov #include <sys/eventhandler.h>
33f5baf8bbSAlexander V. Chernikov #include <sys/kernel.h>
34f5baf8bbSAlexander V. Chernikov #include <sys/lock.h>
35f5baf8bbSAlexander V. Chernikov #include <sys/rmlock.h>
36f5baf8bbSAlexander V. Chernikov #include <sys/malloc.h>
37f5baf8bbSAlexander V. Chernikov #include <sys/mbuf.h>
38f5baf8bbSAlexander V. Chernikov #include <sys/module.h>
39f5baf8bbSAlexander V. Chernikov #include <sys/kernel.h>
40f5baf8bbSAlexander V. Chernikov #include <sys/priv.h>
41f5baf8bbSAlexander V. Chernikov #include <sys/proc.h>
42f5baf8bbSAlexander V. Chernikov #include <sys/socket.h>
43f5baf8bbSAlexander V. Chernikov #include <sys/socketvar.h>
44f5baf8bbSAlexander V. Chernikov #include <sys/sysctl.h>
45f5baf8bbSAlexander V. Chernikov #include <net/vnet.h>
46f5baf8bbSAlexander V. Chernikov 
47f5baf8bbSAlexander V. Chernikov #include <net/if.h>
48f5baf8bbSAlexander V. Chernikov #include <net/if_var.h>
49f5baf8bbSAlexander V. Chernikov 
50f5baf8bbSAlexander V. Chernikov #include <netinet/in.h>
51f5baf8bbSAlexander V. Chernikov #include <netinet/in_var.h>
52f5baf8bbSAlexander V. Chernikov #include <netinet/ip.h>
53f5baf8bbSAlexander V. Chernikov #include <netinet/ip_var.h>
54f5baf8bbSAlexander V. Chernikov #include <netinet/ip6.h>
55f5baf8bbSAlexander V. Chernikov #include <netinet6/ip6_var.h>
56f5baf8bbSAlexander V. Chernikov #include <netinet6/in6_fib.h>
57f5baf8bbSAlexander V. Chernikov 
58f5baf8bbSAlexander V. Chernikov #include <net/route.h>
59f5baf8bbSAlexander V. Chernikov #include <net/route/nhop.h>
60f5baf8bbSAlexander V. Chernikov #include <net/route/route_ctl.h>
61f5baf8bbSAlexander V. Chernikov #include <net/route/route_var.h>
62f5baf8bbSAlexander V. Chernikov #include <net/route/fib_algo.h>
63f5baf8bbSAlexander V. Chernikov 
64f5baf8bbSAlexander V. Chernikov /*
65f5baf8bbSAlexander V. Chernikov  * Lockless radix lookup algo.
66f5baf8bbSAlexander V. Chernikov  *
67f5baf8bbSAlexander V. Chernikov  * Compiles immutable radix from the current routing table.
68f5baf8bbSAlexander V. Chernikov  * Used with small amount of routes (<1000).
69f5baf8bbSAlexander V. Chernikov  * As datastructure is immutable, it gets rebuild on each rtable change.
70f5baf8bbSAlexander V. Chernikov  *
71f5baf8bbSAlexander V. Chernikov  */
72f5baf8bbSAlexander V. Chernikov 
73f5baf8bbSAlexander V. Chernikov #define KEY_LEN_INET6	(offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
74f5baf8bbSAlexander V. Chernikov #define OFF_LEN_INET6	(8 * offsetof(struct sa_in6, sin6_addr))
75f5baf8bbSAlexander V. Chernikov struct sa_in6 {
76f5baf8bbSAlexander V. Chernikov 	uint8_t			sin6_len;
77f5baf8bbSAlexander V. Chernikov 	uint8_t			sin6_family;
78f5baf8bbSAlexander V. Chernikov 	uint8_t			pad[6];
79f5baf8bbSAlexander V. Chernikov 	struct in6_addr		sin6_addr;
80f5baf8bbSAlexander V. Chernikov };
81f5baf8bbSAlexander V. Chernikov struct radix6_addr_entry {
82f5baf8bbSAlexander V. Chernikov 	struct radix_node	rn[2];
83f5baf8bbSAlexander V. Chernikov 	struct sa_in6		addr;
84f5baf8bbSAlexander V. Chernikov 	struct nhop_object	*nhop;
85f5baf8bbSAlexander V. Chernikov };
86f5baf8bbSAlexander V. Chernikov #define	LRADIX6_ITEM_SZ	roundup2(sizeof(struct radix6_addr_entry), CACHE_LINE_SIZE)
87f5baf8bbSAlexander V. Chernikov 
88f5baf8bbSAlexander V. Chernikov struct lradix6_data {
89f5baf8bbSAlexander V. Chernikov 	struct radix_node_head	*rnh;
90f5baf8bbSAlexander V. Chernikov 	struct fib_data		*fd;
91f5baf8bbSAlexander V. Chernikov 	void			*mem; // raw radix_mem pointer to free
92f5baf8bbSAlexander V. Chernikov 	void			*radix_mem;
93f5baf8bbSAlexander V. Chernikov 	uint32_t		alloc_items;
94f5baf8bbSAlexander V. Chernikov 	uint32_t		num_items;
95f5baf8bbSAlexander V. Chernikov };
96f5baf8bbSAlexander V. Chernikov 
97f5baf8bbSAlexander V. Chernikov static struct nhop_object *
lradix6_lookup(void * algo_data,const struct flm_lookup_key key,uint32_t scopeid)98f5baf8bbSAlexander V. Chernikov lradix6_lookup(void *algo_data, const struct flm_lookup_key key, uint32_t scopeid)
99f5baf8bbSAlexander V. Chernikov {
100f5baf8bbSAlexander V. Chernikov 	struct radix_node_head *rnh = (struct radix_node_head *)algo_data;
101f5baf8bbSAlexander V. Chernikov 	struct radix6_addr_entry *ent;
102f5baf8bbSAlexander V. Chernikov 	struct sa_in6 addr6 = {
103f5baf8bbSAlexander V. Chernikov 		.sin6_len = KEY_LEN_INET6,
104f5baf8bbSAlexander V. Chernikov 		.sin6_addr = *key.addr6,
105f5baf8bbSAlexander V. Chernikov 	};
106f5baf8bbSAlexander V. Chernikov 	if (IN6_IS_SCOPE_LINKLOCAL(key.addr6))
107f5baf8bbSAlexander V. Chernikov 		addr6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff);
1082defbe9fSAlexander V. Chernikov 	ent = (struct radix6_addr_entry *)(rn_match(&addr6, &rnh->rh));
109f5baf8bbSAlexander V. Chernikov 	if (ent != NULL)
110f5baf8bbSAlexander V. Chernikov 		return (ent->nhop);
111f5baf8bbSAlexander V. Chernikov 	return (NULL);
112f5baf8bbSAlexander V. Chernikov }
113f5baf8bbSAlexander V. Chernikov 
114f5baf8bbSAlexander V. Chernikov static uint8_t
lradix6_get_pref(const struct rib_rtable_info * rinfo)115f5baf8bbSAlexander V. Chernikov lradix6_get_pref(const struct rib_rtable_info *rinfo)
116f5baf8bbSAlexander V. Chernikov {
117f5baf8bbSAlexander V. Chernikov 
118f5baf8bbSAlexander V. Chernikov 	if (rinfo->num_prefixes < 10)
119f5baf8bbSAlexander V. Chernikov 		return (255);
120d5be41beSAlexander V. Chernikov 	else if (rinfo->num_prefixes < 10000)
121d5be41beSAlexander V. Chernikov 		return (255 - rinfo->num_prefixes / 40);
122f5baf8bbSAlexander V. Chernikov 	else
123f5baf8bbSAlexander V. Chernikov 		return (1);
124f5baf8bbSAlexander V. Chernikov }
125f5baf8bbSAlexander V. Chernikov 
126f5baf8bbSAlexander V. Chernikov static enum flm_op_result
lradix6_init(uint32_t fibnum,struct fib_data * fd,void * _old_data,void ** _data)127f5baf8bbSAlexander V. Chernikov lradix6_init(uint32_t fibnum, struct fib_data *fd, void *_old_data, void **_data)
128f5baf8bbSAlexander V. Chernikov {
129f5baf8bbSAlexander V. Chernikov 	struct lradix6_data *lr;
130f5baf8bbSAlexander V. Chernikov 	struct rib_rtable_info rinfo;
131f5baf8bbSAlexander V. Chernikov 	uint32_t count;
132f5baf8bbSAlexander V. Chernikov 	void *mem;
133f5baf8bbSAlexander V. Chernikov 
134f5baf8bbSAlexander V. Chernikov 	lr = malloc(sizeof(struct lradix6_data), M_RTABLE, M_NOWAIT | M_ZERO);
135f5baf8bbSAlexander V. Chernikov 	if (lr == NULL || !rn_inithead((void **)&lr->rnh, OFF_LEN_INET6))
136f5baf8bbSAlexander V. Chernikov 		return (FLM_REBUILD);
137f5baf8bbSAlexander V. Chernikov 	fib_get_rtable_info(fib_get_rh(fd), &rinfo);
138f5baf8bbSAlexander V. Chernikov 
139f5baf8bbSAlexander V. Chernikov 	count = rinfo.num_prefixes * 11 / 10;
140f5baf8bbSAlexander V. Chernikov 	// count+1 adds at least 1 cache line
141f5baf8bbSAlexander V. Chernikov 	mem = malloc((count + 1) * LRADIX6_ITEM_SZ, M_RTABLE, M_NOWAIT | M_ZERO);
142f5baf8bbSAlexander V. Chernikov 	if (mem == NULL)
143f5baf8bbSAlexander V. Chernikov 		return (FLM_REBUILD);
144f5baf8bbSAlexander V. Chernikov 	lr->mem = mem;
145f5baf8bbSAlexander V. Chernikov 	lr->radix_mem = (void *)roundup2((uintptr_t)mem, CACHE_LINE_SIZE);
146f5baf8bbSAlexander V. Chernikov 	lr->alloc_items = count;
147f5baf8bbSAlexander V. Chernikov 	lr->fd = fd;
148f5baf8bbSAlexander V. Chernikov 
149f5baf8bbSAlexander V. Chernikov 	*_data = lr;
150f5baf8bbSAlexander V. Chernikov 
151f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
152f5baf8bbSAlexander V. Chernikov }
153f5baf8bbSAlexander V. Chernikov 
154f5baf8bbSAlexander V. Chernikov static void
lradix6_destroy(void * _data)155f5baf8bbSAlexander V. Chernikov lradix6_destroy(void *_data)
156f5baf8bbSAlexander V. Chernikov {
157f5baf8bbSAlexander V. Chernikov 	struct lradix6_data *lr = (struct lradix6_data *)_data;
158f5baf8bbSAlexander V. Chernikov 
159f5baf8bbSAlexander V. Chernikov 	if (lr->rnh != NULL)
160f5baf8bbSAlexander V. Chernikov 		rn_detachhead((void **)&lr->rnh);
161f5baf8bbSAlexander V. Chernikov 	if (lr->mem != NULL)
162f5baf8bbSAlexander V. Chernikov 		free(lr->mem, M_RTABLE);
163f5baf8bbSAlexander V. Chernikov 	free(lr, M_RTABLE);
164f5baf8bbSAlexander V. Chernikov }
165f5baf8bbSAlexander V. Chernikov 
166f5baf8bbSAlexander V. Chernikov static enum flm_op_result
lradix6_add_route_cb(struct rtentry * rt,void * _data)167f5baf8bbSAlexander V. Chernikov lradix6_add_route_cb(struct rtentry *rt, void *_data)
168f5baf8bbSAlexander V. Chernikov {
169f5baf8bbSAlexander V. Chernikov 	struct lradix6_data *lr = (struct lradix6_data *)_data;
170f5baf8bbSAlexander V. Chernikov 	struct radix6_addr_entry *ae;
171f5baf8bbSAlexander V. Chernikov 	struct sockaddr_in6 *rt_dst, *rt_mask;
172f5baf8bbSAlexander V. Chernikov 	struct sa_in6 mask;
173f5baf8bbSAlexander V. Chernikov 	struct radix_node *rn;
174f5baf8bbSAlexander V. Chernikov 	struct nhop_object *nh;
175f5baf8bbSAlexander V. Chernikov 
176f5baf8bbSAlexander V. Chernikov 	nh = rt_get_raw_nhop(rt);
177f5baf8bbSAlexander V. Chernikov 
178f5baf8bbSAlexander V. Chernikov 	if (lr->num_items >= lr->alloc_items)
179f5baf8bbSAlexander V. Chernikov 		return (FLM_REBUILD);
180f5baf8bbSAlexander V. Chernikov 
181f5baf8bbSAlexander V. Chernikov 	ae = (struct radix6_addr_entry *)((char *)lr->radix_mem + lr->num_items * LRADIX6_ITEM_SZ);
182f5baf8bbSAlexander V. Chernikov 	lr->num_items++;
183f5baf8bbSAlexander V. Chernikov 
184f5baf8bbSAlexander V. Chernikov 	ae->nhop = nh;
185f5baf8bbSAlexander V. Chernikov 
186f5baf8bbSAlexander V. Chernikov 	rt_dst = (struct sockaddr_in6 *)rt_key(rt);
187f5baf8bbSAlexander V. Chernikov 	rt_mask = (struct sockaddr_in6 *)rt_mask(rt);
188f5baf8bbSAlexander V. Chernikov 
189f5baf8bbSAlexander V. Chernikov 	ae->addr.sin6_len = KEY_LEN_INET6;
190f5baf8bbSAlexander V. Chernikov 	ae->addr.sin6_addr = rt_dst->sin6_addr;
191f5baf8bbSAlexander V. Chernikov 
192f5baf8bbSAlexander V. Chernikov 	if (rt_mask != NULL) {
193f5baf8bbSAlexander V. Chernikov 		bzero(&mask, sizeof(mask));
194f5baf8bbSAlexander V. Chernikov 		mask.sin6_len = KEY_LEN_INET6;
195f5baf8bbSAlexander V. Chernikov 		mask.sin6_addr = rt_mask->sin6_addr;
196f5baf8bbSAlexander V. Chernikov 		rt_mask = (struct sockaddr_in6 *)&mask;
197f5baf8bbSAlexander V. Chernikov 	}
198f5baf8bbSAlexander V. Chernikov 
199f5baf8bbSAlexander V. Chernikov 	rn = lr->rnh->rnh_addaddr((struct sockaddr *)&ae->addr,
200f5baf8bbSAlexander V. Chernikov 	    (struct sockaddr *)rt_mask, &lr->rnh->rh, ae->rn);
201f5baf8bbSAlexander V. Chernikov 	if (rn == NULL)
202f5baf8bbSAlexander V. Chernikov 		return (FLM_REBUILD);
203f5baf8bbSAlexander V. Chernikov 
204f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
205f5baf8bbSAlexander V. Chernikov }
206f5baf8bbSAlexander V. Chernikov 
207f5baf8bbSAlexander V. Chernikov static enum flm_op_result
lradix6_end_dump(void * _data,struct fib_dp * dp)208f5baf8bbSAlexander V. Chernikov lradix6_end_dump(void *_data, struct fib_dp *dp)
209f5baf8bbSAlexander V. Chernikov {
210f5baf8bbSAlexander V. Chernikov 	struct lradix6_data *lr = (struct lradix6_data *)_data;
211f5baf8bbSAlexander V. Chernikov 
212f5baf8bbSAlexander V. Chernikov 	dp->f = lradix6_lookup;
213f5baf8bbSAlexander V. Chernikov 	dp->arg = lr->rnh;
214f5baf8bbSAlexander V. Chernikov 
215f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
216f5baf8bbSAlexander V. Chernikov }
217f5baf8bbSAlexander V. Chernikov 
218f5baf8bbSAlexander V. Chernikov static enum flm_op_result
lradix6_change_cb(struct rib_head * rnh,struct rib_cmd_info * rc,void * _data)219f5baf8bbSAlexander V. Chernikov lradix6_change_cb(struct rib_head *rnh, struct rib_cmd_info *rc,
220f5baf8bbSAlexander V. Chernikov     void *_data)
221f5baf8bbSAlexander V. Chernikov {
222f5baf8bbSAlexander V. Chernikov 
223f5baf8bbSAlexander V. Chernikov 	return (FLM_REBUILD);
224f5baf8bbSAlexander V. Chernikov }
225f5baf8bbSAlexander V. Chernikov 
226f5baf8bbSAlexander V. Chernikov struct fib_lookup_module flm_radix6_lockless = {
227f5baf8bbSAlexander V. Chernikov 	.flm_name = "radix6_lockless",
228f5baf8bbSAlexander V. Chernikov 	.flm_family = AF_INET6,
229f5baf8bbSAlexander V. Chernikov 	.flm_init_cb = lradix6_init,
230f5baf8bbSAlexander V. Chernikov 	.flm_destroy_cb = lradix6_destroy,
231f5baf8bbSAlexander V. Chernikov 	.flm_dump_rib_item_cb = lradix6_add_route_cb,
232f5baf8bbSAlexander V. Chernikov 	.flm_dump_end_cb = lradix6_end_dump,
233f5baf8bbSAlexander V. Chernikov 	.flm_change_rib_item_cb = lradix6_change_cb,
234f5baf8bbSAlexander V. Chernikov 	.flm_get_pref = lradix6_get_pref,
235f5baf8bbSAlexander V. Chernikov };
236f5baf8bbSAlexander V. Chernikov 
237f5baf8bbSAlexander V. Chernikov /*
238f5baf8bbSAlexander V. Chernikov  * Fallback lookup algorithm.
239f5baf8bbSAlexander V. Chernikov  * This is a simple wrapper around system radix.
240f5baf8bbSAlexander V. Chernikov  */
241f5baf8bbSAlexander V. Chernikov 
242f5baf8bbSAlexander V. Chernikov struct radix6_data {
243f5baf8bbSAlexander V. Chernikov 	struct fib_data *fd;
244f5baf8bbSAlexander V. Chernikov 	struct rib_head *rh;
245f5baf8bbSAlexander V. Chernikov };
246f5baf8bbSAlexander V. Chernikov 
247f5baf8bbSAlexander V. Chernikov static struct nhop_object *
radix6_lookup(void * algo_data,const struct flm_lookup_key key,uint32_t scopeid)248f5baf8bbSAlexander V. Chernikov radix6_lookup(void *algo_data, const struct flm_lookup_key key, uint32_t scopeid)
249f5baf8bbSAlexander V. Chernikov {
250f5baf8bbSAlexander V. Chernikov 	RIB_RLOCK_TRACKER;
251f5baf8bbSAlexander V. Chernikov 	struct rib_head *rh = (struct rib_head *)algo_data;
252f5baf8bbSAlexander V. Chernikov 	struct radix_node *rn;
253f5baf8bbSAlexander V. Chernikov 	struct nhop_object *nh;
254f5baf8bbSAlexander V. Chernikov 
255f5baf8bbSAlexander V. Chernikov 	/* Prepare lookup key */
256f5baf8bbSAlexander V. Chernikov 	struct sockaddr_in6 sin6 = {
257f5baf8bbSAlexander V. Chernikov 		.sin6_family = AF_INET6,
258f5baf8bbSAlexander V. Chernikov 		.sin6_len = sizeof(struct sockaddr_in6),
259f5baf8bbSAlexander V. Chernikov 		.sin6_addr = *key.addr6,
260f5baf8bbSAlexander V. Chernikov 	};
261f5baf8bbSAlexander V. Chernikov 	if (IN6_IS_SCOPE_LINKLOCAL(key.addr6))
262f5baf8bbSAlexander V. Chernikov 		sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff);
263f5baf8bbSAlexander V. Chernikov 
264f5baf8bbSAlexander V. Chernikov 	nh = NULL;
265f5baf8bbSAlexander V. Chernikov 	RIB_RLOCK(rh);
2662defbe9fSAlexander V. Chernikov 	rn = rn_match((void *)&sin6, &rh->head);
267f5baf8bbSAlexander V. Chernikov 	if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0))
268f5baf8bbSAlexander V. Chernikov 		nh = (RNTORT(rn))->rt_nhop;
269f5baf8bbSAlexander V. Chernikov 	RIB_RUNLOCK(rh);
270f5baf8bbSAlexander V. Chernikov 
271f5baf8bbSAlexander V. Chernikov 	return (nh);
272f5baf8bbSAlexander V. Chernikov }
273f5baf8bbSAlexander V. Chernikov 
274f5baf8bbSAlexander V. Chernikov struct nhop_object *
fib6_radix_lookup_nh(uint32_t fibnum,const struct in6_addr * dst6,uint32_t scopeid)275f5baf8bbSAlexander V. Chernikov fib6_radix_lookup_nh(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid)
276f5baf8bbSAlexander V. Chernikov {
277f5baf8bbSAlexander V. Chernikov 	struct rib_head *rh = rh = rt_tables_get_rnh(fibnum, AF_INET6);
278f5baf8bbSAlexander V. Chernikov 	const struct flm_lookup_key key = { .addr6 = dst6 };
279f5baf8bbSAlexander V. Chernikov 
280f5baf8bbSAlexander V. Chernikov 	if (rh == NULL)
281f5baf8bbSAlexander V. Chernikov 		return (NULL);
282f5baf8bbSAlexander V. Chernikov 
283f5baf8bbSAlexander V. Chernikov 	return (radix6_lookup(rh, key, scopeid));
284f5baf8bbSAlexander V. Chernikov }
285f5baf8bbSAlexander V. Chernikov 
286f5baf8bbSAlexander V. Chernikov static uint8_t
radix6_get_pref(const struct rib_rtable_info * rinfo)287f5baf8bbSAlexander V. Chernikov radix6_get_pref(const struct rib_rtable_info *rinfo)
288f5baf8bbSAlexander V. Chernikov {
289f5baf8bbSAlexander V. Chernikov 
290f5baf8bbSAlexander V. Chernikov 	return (50);
291f5baf8bbSAlexander V. Chernikov }
292f5baf8bbSAlexander V. Chernikov 
293f5baf8bbSAlexander V. Chernikov static enum flm_op_result
radix6_init(uint32_t fibnum,struct fib_data * fd,void * _old_data,void ** _data)294f5baf8bbSAlexander V. Chernikov radix6_init(uint32_t fibnum, struct fib_data *fd, void *_old_data, void **_data)
295f5baf8bbSAlexander V. Chernikov {
296f5baf8bbSAlexander V. Chernikov 	struct radix6_data *r6;
297f5baf8bbSAlexander V. Chernikov 
298f5baf8bbSAlexander V. Chernikov 	r6 = malloc(sizeof(struct radix6_data), M_RTABLE, M_NOWAIT | M_ZERO);
299f5baf8bbSAlexander V. Chernikov 	if (r6 == NULL)
300f5baf8bbSAlexander V. Chernikov 		return (FLM_REBUILD);
301f5baf8bbSAlexander V. Chernikov 	r6->fd = fd;
302f5baf8bbSAlexander V. Chernikov 	r6->rh = fib_get_rh(fd);
303f5baf8bbSAlexander V. Chernikov 
304f5baf8bbSAlexander V. Chernikov 	*_data = r6;
305f5baf8bbSAlexander V. Chernikov 
306f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
307f5baf8bbSAlexander V. Chernikov }
308f5baf8bbSAlexander V. Chernikov 
309f5baf8bbSAlexander V. Chernikov static void
radix6_destroy(void * _data)310f5baf8bbSAlexander V. Chernikov radix6_destroy(void *_data)
311f5baf8bbSAlexander V. Chernikov {
312f5baf8bbSAlexander V. Chernikov 
313f5baf8bbSAlexander V. Chernikov 	free(_data, M_RTABLE);
314f5baf8bbSAlexander V. Chernikov }
315f5baf8bbSAlexander V. Chernikov 
316f5baf8bbSAlexander V. Chernikov static enum flm_op_result
radix6_add_route_cb(struct rtentry * rt,void * _data)317f5baf8bbSAlexander V. Chernikov radix6_add_route_cb(struct rtentry *rt, void *_data)
318f5baf8bbSAlexander V. Chernikov {
319f5baf8bbSAlexander V. Chernikov 
320f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
321f5baf8bbSAlexander V. Chernikov }
322f5baf8bbSAlexander V. Chernikov 
323f5baf8bbSAlexander V. Chernikov static enum flm_op_result
radix6_end_dump(void * _data,struct fib_dp * dp)324f5baf8bbSAlexander V. Chernikov radix6_end_dump(void *_data, struct fib_dp *dp)
325f5baf8bbSAlexander V. Chernikov {
326f5baf8bbSAlexander V. Chernikov 	struct radix6_data *r6 = (struct radix6_data *)_data;
327f5baf8bbSAlexander V. Chernikov 
328f5baf8bbSAlexander V. Chernikov 	dp->f = radix6_lookup;
329f5baf8bbSAlexander V. Chernikov 	dp->arg = r6->rh;
330f5baf8bbSAlexander V. Chernikov 
331f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
332f5baf8bbSAlexander V. Chernikov }
333f5baf8bbSAlexander V. Chernikov 
334f5baf8bbSAlexander V. Chernikov static enum flm_op_result
radix6_change_cb(struct rib_head * rnh,struct rib_cmd_info * rc,void * _data)335f5baf8bbSAlexander V. Chernikov radix6_change_cb(struct rib_head *rnh, struct rib_cmd_info *rc,
336f5baf8bbSAlexander V. Chernikov     void *_data)
337f5baf8bbSAlexander V. Chernikov {
338f5baf8bbSAlexander V. Chernikov 
339f5baf8bbSAlexander V. Chernikov 	return (FLM_SUCCESS);
340f5baf8bbSAlexander V. Chernikov }
341f5baf8bbSAlexander V. Chernikov 
342f5baf8bbSAlexander V. Chernikov struct fib_lookup_module flm_radix6 = {
343f5baf8bbSAlexander V. Chernikov 	.flm_name = "radix6",
344f5baf8bbSAlexander V. Chernikov 	.flm_family = AF_INET6,
345f5baf8bbSAlexander V. Chernikov 	.flm_init_cb = radix6_init,
346f5baf8bbSAlexander V. Chernikov 	.flm_destroy_cb = radix6_destroy,
347f5baf8bbSAlexander V. Chernikov 	.flm_dump_rib_item_cb = radix6_add_route_cb,
348f5baf8bbSAlexander V. Chernikov 	.flm_dump_end_cb = radix6_end_dump,
349f5baf8bbSAlexander V. Chernikov 	.flm_change_rib_item_cb = radix6_change_cb,
350f5baf8bbSAlexander V. Chernikov 	.flm_get_pref = radix6_get_pref,
351f5baf8bbSAlexander V. Chernikov };
352f5baf8bbSAlexander V. Chernikov 
353f5baf8bbSAlexander V. Chernikov static void
fib6_algo_init(void)354f5baf8bbSAlexander V. Chernikov fib6_algo_init(void)
355f5baf8bbSAlexander V. Chernikov {
356f5baf8bbSAlexander V. Chernikov 
357f5baf8bbSAlexander V. Chernikov 	fib_module_register(&flm_radix6_lockless);
358f5baf8bbSAlexander V. Chernikov 	fib_module_register(&flm_radix6);
359f5baf8bbSAlexander V. Chernikov }
360f5baf8bbSAlexander V. Chernikov SYSINIT(fib6_algo_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, fib6_algo_init, NULL);
361