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