2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2020 Alexander V. Chernikov
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include "opt_inet6.h"
33 #include <sys/param.h>
34 #include <sys/kernel.h>
36 #include <sys/rmlock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
45 #include <net/if_var.h>
47 #include <netinet/in.h>
48 #include <netinet/in_fib.h>
49 #include <netinet/ip.h>
51 #include <netinet6/in6_fib.h>
53 #include <net/route.h>
54 #include <net/route/nhop.h>
55 #include <net/route/route_ctl.h>
56 #include <net/route/route_var.h>
57 #include <net/route/fib_algo.h>
59 #define CHUNK_SIZE 10000
61 VNET_DEFINE_STATIC(struct in_addr *, inet_addr_list);
62 #define V_inet_addr_list VNET(inet_addr_list)
63 VNET_DEFINE_STATIC(int, inet_list_size);
64 #define V_inet_list_size VNET(inet_list_size)
66 VNET_DEFINE_STATIC(struct in6_addr *, inet6_addr_list);
67 #define V_inet6_addr_list VNET(inet6_addr_list)
68 VNET_DEFINE_STATIC(int, inet6_list_size);
69 #define V_inet6_list_size VNET(inet6_list_size)
71 SYSCTL_DECL(_net_route);
72 SYSCTL_NODE(_net_route, OID_AUTO, test, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
73 "Route algorithm lookups");
76 add_addr(int family, char *addr_str)
79 if (family == AF_INET) {
80 struct in_addr *paddr_old = V_inet_addr_list;
81 int size_old = V_inet_list_size;
84 if (inet_pton(AF_INET, addr_str, &addr) != 1)
87 struct in_addr *paddr = mallocarray(size_old + 1,
88 sizeof(struct in_addr), M_TEMP, M_ZERO | M_WAITOK);
90 if (paddr_old != NULL) {
91 memcpy(paddr, paddr_old, size_old * sizeof(struct in_addr));
92 free(paddr_old, M_TEMP);
94 paddr[size_old] = addr;
96 V_inet_addr_list = paddr;
97 V_inet_list_size = size_old + 1;
98 inet_ntop(AF_INET, &addr, addr_str, sizeof(addr_str));
99 } else if (family == AF_INET6) {
100 struct in6_addr *paddr_old = V_inet6_addr_list;
101 int size_old = V_inet6_list_size;
102 struct in6_addr addr6;
104 if (inet_pton(AF_INET6, addr_str, &addr6) != 1)
107 struct in6_addr *paddr = mallocarray(size_old + 1,
108 sizeof(struct in6_addr), M_TEMP, M_ZERO | M_WAITOK);
110 if (paddr_old != NULL) {
111 memcpy(paddr, paddr_old, size_old * sizeof(struct in6_addr));
112 free(paddr_old, M_TEMP);
114 paddr[size_old] = addr6;
116 V_inet6_addr_list = paddr;
117 V_inet6_list_size = size_old + 1;
118 inet_ntop(AF_INET6, &addr6, addr_str, sizeof(addr_str));
125 add_addr_sysctl_handler(struct sysctl_oid *oidp, struct sysctl_req *req, int family)
127 char addr_str[INET6_ADDRSTRLEN];
130 bzero(addr_str, sizeof(addr_str));
132 error = sysctl_handle_string(oidp, addr_str, sizeof(addr_str), req);
133 if (error != 0 || req->newptr == NULL)
136 error = add_addr(family, addr_str);
142 add_inet_addr_sysctl_handler(SYSCTL_HANDLER_ARGS)
145 return (add_addr_sysctl_handler(oidp, req, AF_INET));
147 SYSCTL_PROC(_net_route_test, OID_AUTO, add_inet_addr,
148 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
149 add_inet_addr_sysctl_handler, "A", "Set");
152 add_inet6_addr_sysctl_handler(SYSCTL_HANDLER_ARGS)
155 return (add_addr_sysctl_handler(oidp, req, AF_INET6));
157 SYSCTL_PROC(_net_route_test, OID_AUTO, add_inet6_addr,
158 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
159 add_inet6_addr_sysctl_handler, "A", "Set");
162 run_test_inet_one_pass(uint32_t fibnum)
165 int sz = V_inet_list_size;
166 int tries = CHUNK_SIZE / sz;
167 const struct in_addr *a = V_inet_addr_list;
170 for (int pass = 0; pass < tries; pass++) {
171 for (int i = 0; i < sz; i++) {
172 fib4_lookup(fibnum, a[i], 0, NHR_NONE, 0);
180 run_test_inet(SYSCTL_HANDLER_ARGS)
182 struct epoch_tracker et;
185 int error = sysctl_handle_int(oidp, &count, 0, req);
192 if (V_inet_list_size <= 0)
195 printf("run: %d packets vnet %p\n", count, curvnet);
196 if (count < CHUNK_SIZE)
199 struct timespec ts_pre, ts_post;
200 int64_t pass_diff, total_diff = 0;
201 uint64_t pass_packets, total_packets = 0;
202 uint32_t fibnum = curthread->td_proc->p_fibnum;
204 for (int pass = 0; pass < count / CHUNK_SIZE; pass++) {
207 pass_packets = run_test_inet_one_pass(fibnum);
208 nanouptime(&ts_post);
211 pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
212 (ts_post.tv_nsec - ts_pre.tv_nsec);
213 total_diff += pass_diff;
214 total_packets += pass_packets;
217 printf("%zu packets in %zu nanoseconds, %zu pps\n",
218 total_packets, total_diff, total_packets * 1000000000 / total_diff);
222 SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet,
223 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
224 0, 0, run_test_inet, "I", "Execute fib4_lookup test");
227 run_test_inet6_one_pass(uint32_t fibnum)
230 int sz = V_inet6_list_size;
231 int tries = CHUNK_SIZE / sz;
232 const struct in6_addr *a = V_inet6_addr_list;
235 for (int pass = 0; pass < tries; pass++) {
236 for (int i = 0; i < sz; i++) {
237 fib6_lookup(fibnum, &a[i], 0, NHR_NONE, 0);
245 run_test_inet6(SYSCTL_HANDLER_ARGS)
247 struct epoch_tracker et;
250 int error = sysctl_handle_int(oidp, &count, 0, req);
257 if (V_inet6_list_size <= 0)
260 printf("run: %d packets vnet %p\n", count, curvnet);
261 if (count < CHUNK_SIZE)
264 struct timespec ts_pre, ts_post;
265 int64_t pass_diff, total_diff = 0;
266 uint64_t pass_packets, total_packets = 0;
267 uint32_t fibnum = curthread->td_proc->p_fibnum;
269 for (int pass = 0; pass < count / CHUNK_SIZE; pass++) {
272 pass_packets = run_test_inet6_one_pass(fibnum);
273 nanouptime(&ts_post);
276 pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
277 (ts_post.tv_nsec - ts_pre.tv_nsec);
278 total_diff += pass_diff;
279 total_packets += pass_packets;
282 printf("%zu packets in %zu nanoseconds, %zu pps\n",
283 total_packets, total_diff, total_packets * 1000000000 / total_diff);
287 SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet6,
288 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
289 0, 0, run_test_inet6, "I", "Execute fib6_lookup test");
292 cmp_dst(uint32_t fibnum, struct in_addr a)
294 struct nhop_object *nh_fib;
296 struct route_nhop_data rnd = {};
298 nh_fib = fib4_lookup(fibnum, a, 0, NHR_NONE, 0);
299 rt = fib4_lookup_rt(fibnum, a, 0, NHR_NONE, &rnd);
301 if (nh_fib == NULL && rt == NULL) {
303 } else if (nh_fib == nhop_select(rnd.rnd_nhop, 0)) {
310 char key_str[INET_ADDRSTRLEN], dst_str[INET_ADDRSTRLEN];
312 inet_ntop(AF_INET, &a, key_str, sizeof(key_str));
313 if (rnd.rnd_nhop == NULL) {
314 printf("[RT BUG] lookup for %s: RIB: ENOENT FIB: nh=%u\n",
315 key_str, nhop_get_idx(nh_fib));
317 rt_get_inet_prefix_plen(rt, &dst, &plen, &scopeid);
318 inet_ntop(AF_INET, &dst, dst_str, sizeof(dst_str));
319 printf("[RT BUG] lookup for %s: RIB: %s/%d,nh=%u FIB: nh=%u\n",
320 key_str, dst_str, plen,
321 nhop_get_idx(nhop_select(rnd.rnd_nhop, 0)),
322 nh_fib ? nhop_get_idx(nh_fib) : 0);
329 cmp_dst6(uint32_t fibnum, const struct in6_addr *a)
331 struct nhop_object *nh_fib;
333 struct route_nhop_data rnd = {};
335 nh_fib = fib6_lookup(fibnum, a, 0, NHR_NONE, 0);
336 rt = fib6_lookup_rt(fibnum, a, 0, NHR_NONE, &rnd);
338 if (nh_fib == NULL && rt == NULL) {
340 } else if (nh_fib == nhop_select(rnd.rnd_nhop, 0)) {
347 char key_str[INET6_ADDRSTRLEN], dst_str[INET6_ADDRSTRLEN];
349 inet_ntop(AF_INET6, a, key_str, sizeof(key_str));
350 if (rnd.rnd_nhop == NULL) {
351 printf("[RT BUG] lookup for %s: RIB: ENOENT FIB: nh=%u\n",
352 key_str, nhop_get_idx(nh_fib));
354 rt_get_inet6_prefix_plen(rt, &dst, &plen, &scopeid);
355 inet_ntop(AF_INET6, &dst, dst_str, sizeof(dst_str));
356 printf("[RT BUG] lookup for %s: RIB: %s/%d,nh=%u FIB: nh=%u\n",
357 key_str, dst_str, plen,
358 nhop_get_idx(nhop_select(rnd.rnd_nhop, 0)),
359 nh_fib ? nhop_get_idx(nh_fib) : 0);
365 /* Random lookups: correctness verification */
367 run_test_inet_one_pass_random(uint32_t fibnum)
370 struct in_addr a[64];
374 for (int pass = 0; pass < CHUNK_SIZE / sz; pass++) {
375 arc4random_buf(a, sizeof(a));
376 for (int i = 0; i < sz; i++) {
377 if (!cmp_dst(fibnum, a[i]))
386 run_test_inet_random(SYSCTL_HANDLER_ARGS)
388 struct epoch_tracker et;
391 int error = sysctl_handle_int(oidp, &count, 0, req);
398 if (count < CHUNK_SIZE)
401 struct timespec ts_pre, ts_post;
402 int64_t pass_diff, total_diff = 1;
403 uint64_t pass_packets, total_packets = 0;
404 uint32_t fibnum = curthread->td_proc->p_fibnum;
406 for (int pass = 0; pass < count / CHUNK_SIZE; pass++) {
409 pass_packets = run_test_inet_one_pass_random(fibnum);
410 nanouptime(&ts_post);
413 pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
414 (ts_post.tv_nsec - ts_pre.tv_nsec);
415 total_diff += pass_diff;
416 total_packets += pass_packets;
418 if (pass_packets == 0)
422 /* Signal error to userland */
423 if (pass_packets == 0)
426 printf("%zu packets in %zu nanoseconds, %zu pps\n",
427 total_packets, total_diff, total_packets * 1000000000 / total_diff);
431 SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_random,
432 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
433 0, 0, run_test_inet_random, "I", "Execute fib4_lookup random check tests");
437 uint32_t alloc_items;
439 uint32_t rnh_prefixes;
445 * For each prefix, add the following records to the lookup array:
446 * * prefix-1, prefix, prefix + 1, prefix_end, prefix_end + 1
449 add_prefix(struct rtentry *rt, void *_data)
451 struct inet_array *pa = (struct inet_array *)_data;
454 uint32_t scopeid, haddr;
458 if (pa->num_items + 5 >= pa->alloc_items) {
464 rt_get_inet_prefix_plen(rt, &addr, &plen, &scopeid);
466 pa->arr[pa->num_items++] = addr;
467 haddr = ntohl(addr.s_addr);
469 pa->arr[pa->num_items++].s_addr = htonl(haddr - 1);
470 pa->arr[pa->num_items++].s_addr = htonl(haddr + 1);
471 /* assume mask != 0 */
472 uint32_t mlen = (1 << (32 - plen)) - 1;
473 pa->arr[pa->num_items++].s_addr = htonl(haddr + mlen);
474 /* can overflow, but who cares */
475 pa->arr[pa->num_items++].s_addr = htonl(haddr + mlen + 1);
482 prepare_list(uint32_t fibnum, struct inet_array *pa)
486 rh = rt_tables_get_rnh(fibnum, AF_INET);
488 uint32_t num_prefixes = rh->rnh_prefixes;
489 bzero(pa, sizeof(struct inet_array));
490 pa->alloc_items = (num_prefixes + 10) * 5;
491 pa->arr = mallocarray(pa->alloc_items, sizeof(struct in_addr),
492 M_TEMP, M_ZERO | M_WAITOK);
494 rib_walk(fibnum, AF_INET, false, add_prefix, pa);
496 if (pa->error != 0) {
497 printf("prefixes: old: %u, current: %u, walked: %u, allocated: %u\n",
498 num_prefixes, rh->rnh_prefixes, pa->rnh_prefixes, pa->alloc_items);
501 return (pa->error == 0);
505 run_test_inet_scan(SYSCTL_HANDLER_ARGS)
507 struct epoch_tracker et;
510 int error = sysctl_handle_int(oidp, &count, 0, req);
517 struct inet_array pa = {};
518 uint32_t fibnum = curthread->td_proc->p_fibnum;
520 if (!prepare_list(fibnum, &pa))
523 struct timespec ts_pre, ts_post;
524 int64_t total_diff = 1;
525 uint64_t total_packets = 0;
526 int failure_count = 0;
530 for (int i = 0; i < pa.num_items; i++) {
531 if (!cmp_dst(fibnum, pa.arr[i])) {
536 nanouptime(&ts_post);
540 free(pa.arr, M_TEMP);
542 /* Signal error to userland */
543 if (failure_count > 0) {
544 printf("[RT ERROR] total failures: %d\n", failure_count);
548 total_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
549 (ts_post.tv_nsec - ts_pre.tv_nsec);
550 printf("%zu packets in %zu nanoseconds, %zu pps\n",
551 total_packets, total_diff, total_packets * 1000000000 / total_diff);
555 SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_scan,
556 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
557 0, 0, run_test_inet_scan, "I", "Execute fib4_lookup scan tests");
560 uint32_t alloc_items;
562 uint32_t rnh_prefixes;
564 struct in6_addr *arr;
568 safe_add(uint32_t *v, uint32_t inc)
570 if (*v < (UINT32_MAX - inc)) {
574 *v -= (UINT32_MAX - inc + 1);
580 safe_dec(uint32_t *v, uint32_t inc)
586 *v += (UINT32_MAX - inc + 1);
592 inc_prefix6(struct in6_addr *addr, int inc)
594 for (int i = 0; i < 4; i++) {
595 uint32_t v = ntohl(addr->s6_addr32[3 - i]);
596 bool ret = safe_add(&v, inc);
597 addr->s6_addr32[3 - i] = htonl(v);
605 dec_prefix6(struct in6_addr *addr, int dec)
607 for (int i = 0; i < 4; i++) {
608 uint32_t v = ntohl(addr->s6_addr32[3 - i]);
609 bool ret = safe_dec(&v, dec);
610 addr->s6_addr32[3 - i] = htonl(v);
618 ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
622 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
625 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
629 * For each prefix, add the following records to the lookup array:
630 * * prefix-1, prefix, prefix + 1, prefix_end, prefix_end + 1
633 add_prefix6(struct rtentry *rt, void *_data)
635 struct inet6_array *pa = (struct inet6_array *)_data;
636 struct in6_addr addr, naddr;
642 if (pa->num_items + 5 >= pa->alloc_items) {
648 rt_get_inet6_prefix_plen(rt, &addr, &plen, &scopeid);
650 pa->arr[pa->num_items++] = addr;
651 if (!IN6_ARE_ADDR_EQUAL(&addr, &in6addr_any)) {
653 dec_prefix6(&naddr, 1);
654 pa->arr[pa->num_items++] = naddr;
656 inc_prefix6(&naddr, 1);
657 pa->arr[pa->num_items++] = naddr;
659 /* assume mask != 0 */
660 struct in6_addr mask6;
661 ipv6_writemask(&mask6, plen);
663 for (int i = 0; i < 3; i++)
664 naddr.s6_addr32[i] = htonl(ntohl(naddr.s6_addr32[i]) | ~ntohl(mask6.s6_addr32[i]));
666 pa->arr[pa->num_items++] = naddr;
667 inc_prefix6(&naddr, 1);
668 pa->arr[pa->num_items++] = naddr;
675 prepare_list6(uint32_t fibnum, struct inet6_array *pa)
679 rh = rt_tables_get_rnh(fibnum, AF_INET6);
681 uint32_t num_prefixes = rh->rnh_prefixes;
682 bzero(pa, sizeof(struct inet6_array));
683 pa->alloc_items = (num_prefixes + 10) * 5;
684 pa->arr = mallocarray(pa->alloc_items, sizeof(struct in6_addr),
685 M_TEMP, M_ZERO | M_WAITOK);
687 rib_walk(fibnum, AF_INET6, false, add_prefix6, pa);
689 if (pa->error != 0) {
690 printf("prefixes: old: %u, current: %u, walked: %u, allocated: %u\n",
691 num_prefixes, rh->rnh_prefixes, pa->rnh_prefixes, pa->alloc_items);
694 return (pa->error == 0);
698 run_test_inet6_scan(SYSCTL_HANDLER_ARGS)
700 struct epoch_tracker et;
703 int error = sysctl_handle_int(oidp, &count, 0, req);
710 struct inet6_array pa = {};
711 uint32_t fibnum = curthread->td_proc->p_fibnum;
713 if (!prepare_list6(fibnum, &pa))
716 struct timespec ts_pre, ts_post;
717 int64_t total_diff = 1;
718 uint64_t total_packets = 0;
719 int failure_count = 0;
723 for (int i = 0; i < pa.num_items; i++) {
724 if (!cmp_dst6(fibnum, &pa.arr[i])) {
729 nanouptime(&ts_post);
733 free(pa.arr, M_TEMP);
735 /* Signal error to userland */
736 if (failure_count > 0) {
737 printf("[RT ERROR] total failures: %d\n", failure_count);
741 total_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
742 (ts_post.tv_nsec - ts_pre.tv_nsec);
743 printf("%zu packets in %zu nanoseconds, %zu pps\n",
744 total_packets, total_diff, total_packets * 1000000000 / total_diff);
748 SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet6_scan,
749 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
750 0, 0, run_test_inet6_scan, "I", "Execute fib6_lookup scan tests");
756 struct lps_walk_state {
763 reduce_keys(struct rtentry *rt, void *_data)
765 struct lps_walk_state *wa = (struct lps_walk_state *) _data;
770 rt_get_inet_prefix_plen(rt, &addr, &plen, &scopeid);
771 wa->keys[wa->pos] = ntohl(addr.s_addr) |
772 (wa->keys[wa->pos] & ~(0xffffffffU << (32 - plen)));
775 return (wa->pos == wa->lim);
779 rnd_lps(SYSCTL_HANDLER_ARGS)
781 struct epoch_tracker et;
783 struct lps_walk_state wa;
784 struct timespec ts_pre, ts_post;
785 struct nhop_object *nh_fib;
786 uint64_t total_diff, lps;
787 uint32_t *keys, fibnum;
790 int i, pos, count = 0;
791 int seq = 0, rep = 0;
794 error = sysctl_handle_int(oidp, &count, 0, req);
799 fibnum = curthread->td_proc->p_fibnum;
801 keys = malloc(sizeof(*keys) * count, M_TEMP, M_NOWAIT);
804 printf("Preparing %d random keys...\n", count);
805 arc4random_buf(keys, sizeof(*keys) * count);
806 if (arg2 & LPS_ANN) {
810 printf("Reducing keys to announced address space...\n");
812 rib_walk(fibnum, AF_INET, false, reduce_keys,
814 } while (wa.pos < wa.lim);
815 printf("Reshuffling keys...\n");
816 for (int i = 0; i < count; i++) {
817 p = random() % count;
824 if (arg2 & LPS_REP) {
828 if (arg2 & LPS_SEQ) {
831 } else if (arg2 & LPS_ANN)
835 printf(" LPS test starting...\n");
839 for (i = 0, pos = 0; i < count; i++) {
840 key.s_addr = keys[pos++] ^ ((acc >> 10) & 0xff);
841 nh_fib = fib4_lookup(fibnum, key, 0, NHR_NONE, 0);
843 if (nh_fib != NULL) {
844 acc += (uintptr_t) nh_fib + 123;
846 acc += (uintptr_t) nh_fib->nh_ifp;
848 acc -= (uintptr_t) nh_fib->nh_ifp;
850 acc ^= (acc >> 3) + (acc << 2) + i;
856 if (rep && ((i & 0xf) == 0xf)) {
862 nanouptime(&ts_post);
867 total_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 +
868 (ts_post.tv_nsec - ts_pre.tv_nsec);
869 lps = 1000000000ULL * count / total_diff;
870 printf("%d lookups in %zu.%06zu milliseconds, %lu.%06lu MLPS\n",
871 count, total_diff / 1000000, total_diff % 1000000,
872 lps / 1000000, lps % 1000000);
876 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd,
877 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
879 "Measure lookups per second, uniformly random keys, independent lookups");
880 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_ann,
881 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
882 0, LPS_ANN, rnd_lps, "I",
883 "Measure lookups per second, random keys from announced address space, "
884 "independent lookups");
885 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq,
886 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
887 0, LPS_SEQ, rnd_lps, "I",
888 "Measure lookups per second, uniformly random keys, "
889 "artificial dependencies between lookups");
890 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_ann,
891 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
892 0, LPS_SEQ | LPS_ANN, rnd_lps, "I",
893 "Measure lookups per second, random keys from announced address space, "
894 "artificial dependencies between lookups");
895 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_rep,
896 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
897 0, LPS_REP, rnd_lps, "I",
898 "Measure lookups per second, uniformly random keys, independent lookups, "
900 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_ann_rep,
901 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
902 0, LPS_ANN | LPS_REP, rnd_lps, "I",
903 "Measure lookups per second, random keys from announced address space, "
904 "independent lookups, repeated keys");
905 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_rep,
906 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
907 0, LPS_SEQ | LPS_REP, rnd_lps, "I",
908 "Measure lookups per second, uniformly random keys, "
909 "artificial dependencies between lookups, repeated keys");
910 SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_ann_rep,
911 CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
912 0, LPS_SEQ | LPS_ANN | LPS_REP, rnd_lps, "I",
913 "Measure lookups per second, random keys from announced address space, "
914 "artificial dependencies between lookups, repeated keys");
917 test_fib_lookup_modevent(module_t mod, int type, void *unused)
925 if (V_inet_addr_list != NULL)
926 free(V_inet_addr_list, M_TEMP);
927 if (V_inet6_addr_list != NULL)
928 free(V_inet6_addr_list, M_TEMP);
937 static moduledata_t testfiblookupmod = {
939 test_fib_lookup_modevent,
943 DECLARE_MODULE(testfiblookupmod, testfiblookupmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
944 MODULE_VERSION(testfiblookup, 1);