10433870eSAlexander V. Chernikov /*- 20433870eSAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 30433870eSAlexander V. Chernikov * 40433870eSAlexander V. Chernikov * Copyright (c) 2020 Alexander V. Chernikov 50433870eSAlexander V. Chernikov * 60433870eSAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 70433870eSAlexander V. Chernikov * modification, are permitted provided that the following conditions 80433870eSAlexander V. Chernikov * are met: 90433870eSAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 100433870eSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 110433870eSAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 120433870eSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 130433870eSAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 140433870eSAlexander V. Chernikov * 150433870eSAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 160433870eSAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170433870eSAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 180433870eSAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 190433870eSAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 200433870eSAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 210433870eSAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 220433870eSAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 230433870eSAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 240433870eSAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 250433870eSAlexander V. Chernikov * SUCH DAMAGE. 260433870eSAlexander V. Chernikov */ 270433870eSAlexander V. Chernikov 280433870eSAlexander V. Chernikov #include <sys/cdefs.h> 290433870eSAlexander V. Chernikov __FBSDID("$FreeBSD$"); 300433870eSAlexander V. Chernikov #include "opt_inet.h" 310433870eSAlexander V. Chernikov #include "opt_inet6.h" 320433870eSAlexander V. Chernikov 330433870eSAlexander V. Chernikov #include <sys/param.h> 340433870eSAlexander V. Chernikov #include <sys/kernel.h> 350433870eSAlexander V. Chernikov #include <sys/lock.h> 360433870eSAlexander V. Chernikov #include <sys/rmlock.h> 370433870eSAlexander V. Chernikov #include <sys/malloc.h> 380433870eSAlexander V. Chernikov #include <sys/module.h> 390433870eSAlexander V. Chernikov #include <sys/kernel.h> 400433870eSAlexander V. Chernikov #include <sys/socket.h> 410433870eSAlexander V. Chernikov #include <sys/sysctl.h> 420433870eSAlexander V. Chernikov #include <net/vnet.h> 430433870eSAlexander V. Chernikov 440433870eSAlexander V. Chernikov #include <net/if.h> 450433870eSAlexander V. Chernikov #include <net/if_var.h> 460433870eSAlexander V. Chernikov 470433870eSAlexander V. Chernikov #include <netinet/in.h> 480433870eSAlexander V. Chernikov #include <netinet/in_fib.h> 490433870eSAlexander V. Chernikov #include <netinet/ip.h> 500433870eSAlexander V. Chernikov 510433870eSAlexander V. Chernikov #include <netinet6/in6_fib.h> 520433870eSAlexander V. Chernikov 530433870eSAlexander V. Chernikov #include <net/route.h> 540433870eSAlexander V. Chernikov #include <net/route/nhop.h> 550433870eSAlexander V. Chernikov #include <net/route/route_ctl.h> 560433870eSAlexander V. Chernikov #include <net/route/route_var.h> 570433870eSAlexander V. Chernikov #include <net/route/fib_algo.h> 580433870eSAlexander V. Chernikov 590433870eSAlexander V. Chernikov #define CHUNK_SIZE 10000 600433870eSAlexander V. Chernikov 610433870eSAlexander V. Chernikov VNET_DEFINE_STATIC(struct in_addr *, inet_addr_list); 620433870eSAlexander V. Chernikov #define V_inet_addr_list VNET(inet_addr_list) 630433870eSAlexander V. Chernikov VNET_DEFINE_STATIC(int, inet_list_size); 640433870eSAlexander V. Chernikov #define V_inet_list_size VNET(inet_list_size) 650433870eSAlexander V. Chernikov 660433870eSAlexander V. Chernikov VNET_DEFINE_STATIC(struct in6_addr *, inet6_addr_list); 670433870eSAlexander V. Chernikov #define V_inet6_addr_list VNET(inet6_addr_list) 680433870eSAlexander V. Chernikov VNET_DEFINE_STATIC(int, inet6_list_size); 690433870eSAlexander V. Chernikov #define V_inet6_list_size VNET(inet6_list_size) 700433870eSAlexander V. Chernikov 710433870eSAlexander V. Chernikov SYSCTL_DECL(_net_route); 720433870eSAlexander V. Chernikov SYSCTL_NODE(_net_route, OID_AUTO, test, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 730433870eSAlexander V. Chernikov "Route algorithm lookups"); 740433870eSAlexander V. Chernikov 750433870eSAlexander V. Chernikov static int 760433870eSAlexander V. Chernikov add_addr(int family, char *addr_str) 770433870eSAlexander V. Chernikov { 780433870eSAlexander V. Chernikov 790433870eSAlexander V. Chernikov if (family == AF_INET) { 800433870eSAlexander V. Chernikov struct in_addr *paddr_old = V_inet_addr_list; 810433870eSAlexander V. Chernikov int size_old = V_inet_list_size; 820433870eSAlexander V. Chernikov struct in_addr addr; 830433870eSAlexander V. Chernikov 840433870eSAlexander V. Chernikov if (inet_pton(AF_INET, addr_str, &addr) != 1) 850433870eSAlexander V. Chernikov return (EINVAL); 860433870eSAlexander V. Chernikov 870433870eSAlexander V. Chernikov struct in_addr *paddr = mallocarray(size_old + 1, 880433870eSAlexander V. Chernikov sizeof(struct in_addr), M_TEMP, M_ZERO | M_WAITOK); 890433870eSAlexander V. Chernikov 900433870eSAlexander V. Chernikov if (paddr_old != NULL) { 910433870eSAlexander V. Chernikov memcpy(paddr, paddr_old, size_old * sizeof(struct in_addr)); 920433870eSAlexander V. Chernikov free(paddr_old, M_TEMP); 930433870eSAlexander V. Chernikov } 940433870eSAlexander V. Chernikov paddr[size_old] = addr; 950433870eSAlexander V. Chernikov 960433870eSAlexander V. Chernikov V_inet_addr_list = paddr; 970433870eSAlexander V. Chernikov V_inet_list_size = size_old + 1; 980433870eSAlexander V. Chernikov inet_ntop(AF_INET, &addr, addr_str, sizeof(addr_str)); 990433870eSAlexander V. Chernikov } else if (family == AF_INET6) { 1000433870eSAlexander V. Chernikov struct in6_addr *paddr_old = V_inet6_addr_list; 1010433870eSAlexander V. Chernikov int size_old = V_inet6_list_size; 1020433870eSAlexander V. Chernikov struct in6_addr addr6; 1030433870eSAlexander V. Chernikov 1040433870eSAlexander V. Chernikov if (inet_pton(AF_INET6, addr_str, &addr6) != 1) 1050433870eSAlexander V. Chernikov return (EINVAL); 1060433870eSAlexander V. Chernikov 1070433870eSAlexander V. Chernikov struct in6_addr *paddr = mallocarray(size_old + 1, 1080433870eSAlexander V. Chernikov sizeof(struct in6_addr), M_TEMP, M_ZERO | M_WAITOK); 1090433870eSAlexander V. Chernikov 1100433870eSAlexander V. Chernikov if (paddr_old != NULL) { 1110433870eSAlexander V. Chernikov memcpy(paddr, paddr_old, size_old * sizeof(struct in6_addr)); 1120433870eSAlexander V. Chernikov free(paddr_old, M_TEMP); 1130433870eSAlexander V. Chernikov } 1140433870eSAlexander V. Chernikov paddr[size_old] = addr6; 1150433870eSAlexander V. Chernikov 1160433870eSAlexander V. Chernikov V_inet6_addr_list = paddr; 1170433870eSAlexander V. Chernikov V_inet6_list_size = size_old + 1; 1180433870eSAlexander V. Chernikov inet_ntop(AF_INET6, &addr6, addr_str, sizeof(addr_str)); 1190433870eSAlexander V. Chernikov } 1200433870eSAlexander V. Chernikov 1210433870eSAlexander V. Chernikov return (0); 1220433870eSAlexander V. Chernikov } 1230433870eSAlexander V. Chernikov 1240433870eSAlexander V. Chernikov static int 1250433870eSAlexander V. Chernikov add_addr_sysctl_handler(struct sysctl_oid *oidp, struct sysctl_req *req, int family) 1260433870eSAlexander V. Chernikov { 1270433870eSAlexander V. Chernikov char addr_str[INET6_ADDRSTRLEN]; 1280433870eSAlexander V. Chernikov int error; 1290433870eSAlexander V. Chernikov 1300433870eSAlexander V. Chernikov bzero(addr_str, sizeof(addr_str)); 1310433870eSAlexander V. Chernikov 1320433870eSAlexander V. Chernikov error = sysctl_handle_string(oidp, addr_str, sizeof(addr_str), req); 1330433870eSAlexander V. Chernikov if (error != 0 || req->newptr == NULL) 1340433870eSAlexander V. Chernikov return (error); 1350433870eSAlexander V. Chernikov 1360433870eSAlexander V. Chernikov error = add_addr(family, addr_str); 1370433870eSAlexander V. Chernikov 1380433870eSAlexander V. Chernikov return (0); 1390433870eSAlexander V. Chernikov } 1400433870eSAlexander V. Chernikov 1410433870eSAlexander V. Chernikov static int 1420433870eSAlexander V. Chernikov add_inet_addr_sysctl_handler(SYSCTL_HANDLER_ARGS) 1430433870eSAlexander V. Chernikov { 1440433870eSAlexander V. Chernikov 1450433870eSAlexander V. Chernikov return (add_addr_sysctl_handler(oidp, req, AF_INET)); 1460433870eSAlexander V. Chernikov } 1470433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, add_inet_addr, 1480433870eSAlexander V. Chernikov CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, 1490433870eSAlexander V. Chernikov add_inet_addr_sysctl_handler, "A", "Set"); 1500433870eSAlexander V. Chernikov 1510433870eSAlexander V. Chernikov static int 1520433870eSAlexander V. Chernikov add_inet6_addr_sysctl_handler(SYSCTL_HANDLER_ARGS) 1530433870eSAlexander V. Chernikov { 1540433870eSAlexander V. Chernikov 1550433870eSAlexander V. Chernikov return (add_addr_sysctl_handler(oidp, req, AF_INET6)); 1560433870eSAlexander V. Chernikov } 1570433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, add_inet6_addr, 1580433870eSAlexander V. Chernikov CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, 1590433870eSAlexander V. Chernikov add_inet6_addr_sysctl_handler, "A", "Set"); 1600433870eSAlexander V. Chernikov 1610433870eSAlexander V. Chernikov static uint64_t 162*4a77a9b6SAlexander V. Chernikov run_test_inet_one_pass(uint32_t fibnum) 1630433870eSAlexander V. Chernikov { 1640433870eSAlexander V. Chernikov /* Assume epoch */ 1650433870eSAlexander V. Chernikov int sz = V_inet_list_size; 1660433870eSAlexander V. Chernikov int tries = CHUNK_SIZE / sz; 1670433870eSAlexander V. Chernikov const struct in_addr *a = V_inet_addr_list; 1680433870eSAlexander V. Chernikov uint64_t count = 0; 1690433870eSAlexander V. Chernikov 1700433870eSAlexander V. Chernikov for (int pass = 0; pass < tries; pass++) { 1710433870eSAlexander V. Chernikov for (int i = 0; i < sz; i++) { 172*4a77a9b6SAlexander V. Chernikov fib4_lookup(fibnum, a[i], 0, NHR_NONE, 0); 1730433870eSAlexander V. Chernikov count++; 1740433870eSAlexander V. Chernikov } 1750433870eSAlexander V. Chernikov } 1760433870eSAlexander V. Chernikov return (count); 1770433870eSAlexander V. Chernikov } 1780433870eSAlexander V. Chernikov 1790433870eSAlexander V. Chernikov static int 1800433870eSAlexander V. Chernikov run_test_inet(SYSCTL_HANDLER_ARGS) 1810433870eSAlexander V. Chernikov { 1820433870eSAlexander V. Chernikov struct epoch_tracker et; 1830433870eSAlexander V. Chernikov 1840433870eSAlexander V. Chernikov int count = 0; 1850433870eSAlexander V. Chernikov int error = sysctl_handle_int(oidp, &count, 0, req); 1860433870eSAlexander V. Chernikov if (error != 0) 1870433870eSAlexander V. Chernikov return (error); 1880433870eSAlexander V. Chernikov 1890433870eSAlexander V. Chernikov if (count == 0) 1900433870eSAlexander V. Chernikov return (0); 1910433870eSAlexander V. Chernikov 1920433870eSAlexander V. Chernikov if (V_inet_list_size <= 0) 1930433870eSAlexander V. Chernikov return (ENOENT); 1940433870eSAlexander V. Chernikov 1950433870eSAlexander V. Chernikov printf("run: %d packets vnet %p\n", count, curvnet); 1960433870eSAlexander V. Chernikov if (count < CHUNK_SIZE) 1970433870eSAlexander V. Chernikov count = CHUNK_SIZE; 1980433870eSAlexander V. Chernikov 1990433870eSAlexander V. Chernikov struct timespec ts_pre, ts_post; 2000433870eSAlexander V. Chernikov int64_t pass_diff, total_diff = 0; 2010433870eSAlexander V. Chernikov uint64_t pass_packets, total_packets = 0; 202*4a77a9b6SAlexander V. Chernikov uint32_t fibnum = curthread->td_proc->p_fibnum; 2030433870eSAlexander V. Chernikov 2040433870eSAlexander V. Chernikov for (int pass = 0; pass < count / CHUNK_SIZE; pass++) { 2050433870eSAlexander V. Chernikov NET_EPOCH_ENTER(et); 2060433870eSAlexander V. Chernikov nanouptime(&ts_pre); 207*4a77a9b6SAlexander V. Chernikov pass_packets = run_test_inet_one_pass(fibnum); 2080433870eSAlexander V. Chernikov nanouptime(&ts_post); 2090433870eSAlexander V. Chernikov NET_EPOCH_EXIT(et); 2100433870eSAlexander V. Chernikov 2110433870eSAlexander V. Chernikov pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 + 2120433870eSAlexander V. Chernikov (ts_post.tv_nsec - ts_pre.tv_nsec); 2130433870eSAlexander V. Chernikov total_diff += pass_diff; 2140433870eSAlexander V. Chernikov total_packets += pass_packets; 2150433870eSAlexander V. Chernikov } 2160433870eSAlexander V. Chernikov 2170433870eSAlexander V. Chernikov printf("%zu packets in %zu nanoseconds, %zu pps\n", 2180433870eSAlexander V. Chernikov total_packets, total_diff, total_packets * 1000000000 / total_diff); 2190433870eSAlexander V. Chernikov 2200433870eSAlexander V. Chernikov return (0); 2210433870eSAlexander V. Chernikov } 2220433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet, 22374935ce8SAlexander V. Chernikov CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 2240433870eSAlexander V. Chernikov 0, 0, run_test_inet, "I", "Execute fib4_lookup test"); 2250433870eSAlexander V. Chernikov 2260433870eSAlexander V. Chernikov static uint64_t 227*4a77a9b6SAlexander V. Chernikov run_test_inet6_one_pass(uint32_t fibnum) 2280433870eSAlexander V. Chernikov { 2290433870eSAlexander V. Chernikov /* Assume epoch */ 2300433870eSAlexander V. Chernikov int sz = V_inet6_list_size; 2310433870eSAlexander V. Chernikov int tries = CHUNK_SIZE / sz; 2320433870eSAlexander V. Chernikov const struct in6_addr *a = V_inet6_addr_list; 2330433870eSAlexander V. Chernikov uint64_t count = 0; 2340433870eSAlexander V. Chernikov 2350433870eSAlexander V. Chernikov for (int pass = 0; pass < tries; pass++) { 2360433870eSAlexander V. Chernikov for (int i = 0; i < sz; i++) { 237*4a77a9b6SAlexander V. Chernikov fib6_lookup(fibnum, &a[i], 0, NHR_NONE, 0); 2380433870eSAlexander V. Chernikov count++; 2390433870eSAlexander V. Chernikov } 2400433870eSAlexander V. Chernikov } 2410433870eSAlexander V. Chernikov return (count); 2420433870eSAlexander V. Chernikov } 2430433870eSAlexander V. Chernikov 2440433870eSAlexander V. Chernikov static int 2450433870eSAlexander V. Chernikov run_test_inet6(SYSCTL_HANDLER_ARGS) 2460433870eSAlexander V. Chernikov { 2470433870eSAlexander V. Chernikov struct epoch_tracker et; 2480433870eSAlexander V. Chernikov 2490433870eSAlexander V. Chernikov int count = 0; 2500433870eSAlexander V. Chernikov int error = sysctl_handle_int(oidp, &count, 0, req); 2510433870eSAlexander V. Chernikov if (error != 0) 2520433870eSAlexander V. Chernikov return (error); 2530433870eSAlexander V. Chernikov 2540433870eSAlexander V. Chernikov if (count == 0) 2550433870eSAlexander V. Chernikov return (0); 2560433870eSAlexander V. Chernikov 2570433870eSAlexander V. Chernikov if (V_inet6_list_size <= 0) 2580433870eSAlexander V. Chernikov return (ENOENT); 2590433870eSAlexander V. Chernikov 2600433870eSAlexander V. Chernikov printf("run: %d packets vnet %p\n", count, curvnet); 2610433870eSAlexander V. Chernikov if (count < CHUNK_SIZE) 2620433870eSAlexander V. Chernikov count = CHUNK_SIZE; 2630433870eSAlexander V. Chernikov 2640433870eSAlexander V. Chernikov struct timespec ts_pre, ts_post; 2650433870eSAlexander V. Chernikov int64_t pass_diff, total_diff = 0; 2660433870eSAlexander V. Chernikov uint64_t pass_packets, total_packets = 0; 267*4a77a9b6SAlexander V. Chernikov uint32_t fibnum = curthread->td_proc->p_fibnum; 2680433870eSAlexander V. Chernikov 2690433870eSAlexander V. Chernikov for (int pass = 0; pass < count / CHUNK_SIZE; pass++) { 2700433870eSAlexander V. Chernikov NET_EPOCH_ENTER(et); 2710433870eSAlexander V. Chernikov nanouptime(&ts_pre); 272*4a77a9b6SAlexander V. Chernikov pass_packets = run_test_inet6_one_pass(fibnum); 2730433870eSAlexander V. Chernikov nanouptime(&ts_post); 2740433870eSAlexander V. Chernikov NET_EPOCH_EXIT(et); 2750433870eSAlexander V. Chernikov 2760433870eSAlexander V. Chernikov pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 + 2770433870eSAlexander V. Chernikov (ts_post.tv_nsec - ts_pre.tv_nsec); 2780433870eSAlexander V. Chernikov total_diff += pass_diff; 2790433870eSAlexander V. Chernikov total_packets += pass_packets; 2800433870eSAlexander V. Chernikov } 2810433870eSAlexander V. Chernikov 2820433870eSAlexander V. Chernikov printf("%zu packets in %zu nanoseconds, %zu pps\n", 2830433870eSAlexander V. Chernikov total_packets, total_diff, total_packets * 1000000000 / total_diff); 2840433870eSAlexander V. Chernikov 2850433870eSAlexander V. Chernikov return (0); 2860433870eSAlexander V. Chernikov } 2870433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet6, 28874935ce8SAlexander V. Chernikov CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 2890433870eSAlexander V. Chernikov 0, 0, run_test_inet6, "I", "Execute fib6_lookup test"); 2900433870eSAlexander V. Chernikov 2910433870eSAlexander V. Chernikov static bool 2920433870eSAlexander V. Chernikov cmp_dst(uint32_t fibnum, struct in_addr a) 2930433870eSAlexander V. Chernikov { 2940433870eSAlexander V. Chernikov struct nhop_object *nh_fib; 2950433870eSAlexander V. Chernikov struct rtentry *rt; 2960433870eSAlexander V. Chernikov struct route_nhop_data rnd = {}; 2970433870eSAlexander V. Chernikov 2980433870eSAlexander V. Chernikov nh_fib = fib4_lookup(fibnum, a, 0, NHR_NONE, 0); 2990433870eSAlexander V. Chernikov rt = fib4_lookup_rt(fibnum, a, 0, NHR_NONE, &rnd); 3000433870eSAlexander V. Chernikov 3010433870eSAlexander V. Chernikov if (nh_fib == NULL && rt == NULL) { 3020433870eSAlexander V. Chernikov return (true); 3030433870eSAlexander V. Chernikov } else if (nh_fib == nhop_select(rnd.rnd_nhop, 0)) { 3040433870eSAlexander V. Chernikov return (true); 3050433870eSAlexander V. Chernikov } 3060433870eSAlexander V. Chernikov 3070433870eSAlexander V. Chernikov struct in_addr dst; 3080433870eSAlexander V. Chernikov int plen; 3090433870eSAlexander V. Chernikov uint32_t scopeid; 3100433870eSAlexander V. Chernikov char key_str[INET_ADDRSTRLEN], dst_str[INET_ADDRSTRLEN]; 3110433870eSAlexander V. Chernikov 3120433870eSAlexander V. Chernikov inet_ntop(AF_INET, &a, key_str, sizeof(key_str)); 3130433870eSAlexander V. Chernikov if (rnd.rnd_nhop == NULL) { 3140433870eSAlexander V. Chernikov printf("[RT BUG] lookup for %s: RIB: ENOENT FIB: nh=%u\n", 3150433870eSAlexander V. Chernikov key_str, nhop_get_idx(nh_fib)); 3160433870eSAlexander V. Chernikov } else { 3170433870eSAlexander V. Chernikov rt_get_inet_prefix_plen(rt, &dst, &plen, &scopeid); 3180433870eSAlexander V. Chernikov inet_ntop(AF_INET, &dst, dst_str, sizeof(dst_str)); 3190433870eSAlexander V. Chernikov printf("[RT BUG] lookup for %s: RIB: %s/%d,nh=%u FIB: nh=%u\n", 3200433870eSAlexander V. Chernikov key_str, dst_str, plen, 3210433870eSAlexander V. Chernikov nhop_get_idx(nhop_select(rnd.rnd_nhop, 0)), 3220433870eSAlexander V. Chernikov nhop_get_idx(nh_fib)); 3230433870eSAlexander V. Chernikov } 3240433870eSAlexander V. Chernikov 3250433870eSAlexander V. Chernikov return (false); 3260433870eSAlexander V. Chernikov } 3270433870eSAlexander V. Chernikov 3280433870eSAlexander V. Chernikov /* Random lookups: correctness verification */ 3290433870eSAlexander V. Chernikov static uint64_t 330*4a77a9b6SAlexander V. Chernikov run_test_inet_one_pass_random(uint32_t fibnum) 3310433870eSAlexander V. Chernikov { 3320433870eSAlexander V. Chernikov /* Assume epoch */ 3330433870eSAlexander V. Chernikov struct in_addr a[64]; 3340433870eSAlexander V. Chernikov int sz = 64; 3350433870eSAlexander V. Chernikov uint64_t count = 0; 3360433870eSAlexander V. Chernikov 3370433870eSAlexander V. Chernikov for (int pass = 0; pass < CHUNK_SIZE / sz; pass++) { 3380433870eSAlexander V. Chernikov arc4random_buf(a, sizeof(a)); 3390433870eSAlexander V. Chernikov for (int i = 0; i < sz; i++) { 340*4a77a9b6SAlexander V. Chernikov if (!cmp_dst(fibnum, a[i])) 3410433870eSAlexander V. Chernikov return (0); 3420433870eSAlexander V. Chernikov count++; 3430433870eSAlexander V. Chernikov } 3440433870eSAlexander V. Chernikov } 3450433870eSAlexander V. Chernikov return (count); 3460433870eSAlexander V. Chernikov } 3470433870eSAlexander V. Chernikov 3480433870eSAlexander V. Chernikov static int 3490433870eSAlexander V. Chernikov run_test_inet_random(SYSCTL_HANDLER_ARGS) 3500433870eSAlexander V. Chernikov { 3510433870eSAlexander V. Chernikov struct epoch_tracker et; 3520433870eSAlexander V. Chernikov 3530433870eSAlexander V. Chernikov int count = 0; 3540433870eSAlexander V. Chernikov int error = sysctl_handle_int(oidp, &count, 0, req); 3550433870eSAlexander V. Chernikov if (error != 0) 3560433870eSAlexander V. Chernikov return (error); 3570433870eSAlexander V. Chernikov 3580433870eSAlexander V. Chernikov if (count == 0) 3590433870eSAlexander V. Chernikov return (0); 3600433870eSAlexander V. Chernikov 3610433870eSAlexander V. Chernikov if (count < CHUNK_SIZE) 3620433870eSAlexander V. Chernikov count = CHUNK_SIZE; 3630433870eSAlexander V. Chernikov 3640433870eSAlexander V. Chernikov struct timespec ts_pre, ts_post; 3650433870eSAlexander V. Chernikov int64_t pass_diff, total_diff = 1; 3660433870eSAlexander V. Chernikov uint64_t pass_packets, total_packets = 0; 367*4a77a9b6SAlexander V. Chernikov uint32_t fibnum = curthread->td_proc->p_fibnum; 3680433870eSAlexander V. Chernikov 3690433870eSAlexander V. Chernikov for (int pass = 0; pass < count / CHUNK_SIZE; pass++) { 3700433870eSAlexander V. Chernikov NET_EPOCH_ENTER(et); 3710433870eSAlexander V. Chernikov nanouptime(&ts_pre); 372*4a77a9b6SAlexander V. Chernikov pass_packets = run_test_inet_one_pass_random(fibnum); 3730433870eSAlexander V. Chernikov nanouptime(&ts_post); 3740433870eSAlexander V. Chernikov NET_EPOCH_EXIT(et); 3750433870eSAlexander V. Chernikov 3760433870eSAlexander V. Chernikov pass_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 + 3770433870eSAlexander V. Chernikov (ts_post.tv_nsec - ts_pre.tv_nsec); 3780433870eSAlexander V. Chernikov total_diff += pass_diff; 3790433870eSAlexander V. Chernikov total_packets += pass_packets; 3800433870eSAlexander V. Chernikov 3810433870eSAlexander V. Chernikov if (pass_packets == 0) 3820433870eSAlexander V. Chernikov break; 3830433870eSAlexander V. Chernikov } 3840433870eSAlexander V. Chernikov 3850433870eSAlexander V. Chernikov /* Signal error to userland */ 3860433870eSAlexander V. Chernikov if (pass_packets == 0) 3870433870eSAlexander V. Chernikov return (EINVAL); 3880433870eSAlexander V. Chernikov 3890433870eSAlexander V. Chernikov printf("%zu packets in %zu nanoseconds, %zu pps\n", 3900433870eSAlexander V. Chernikov total_packets, total_diff, total_packets * 1000000000 / total_diff); 3910433870eSAlexander V. Chernikov 3920433870eSAlexander V. Chernikov return (0); 3930433870eSAlexander V. Chernikov } 3940433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_random, 39574935ce8SAlexander V. Chernikov CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 3960433870eSAlexander V. Chernikov 0, 0, run_test_inet_random, "I", "Execute fib4_lookup random check tests"); 3970433870eSAlexander V. Chernikov 3980433870eSAlexander V. Chernikov 3990433870eSAlexander V. Chernikov struct inet_array { 4000433870eSAlexander V. Chernikov uint32_t alloc_items; 4010433870eSAlexander V. Chernikov uint32_t num_items; 402*4a77a9b6SAlexander V. Chernikov uint32_t rnh_prefixes; 4030433870eSAlexander V. Chernikov int error; 404*4a77a9b6SAlexander V. Chernikov struct in_addr *arr; 4050433870eSAlexander V. Chernikov }; 4060433870eSAlexander V. Chernikov 4070433870eSAlexander V. Chernikov /* 4080433870eSAlexander V. Chernikov * For each prefix, add the following records to the lookup array: 4090433870eSAlexander V. Chernikov * * prefix-1, prefix, prefix + 1, prefix_end, prefix_end + 1 4100433870eSAlexander V. Chernikov */ 4110433870eSAlexander V. Chernikov static int 4120433870eSAlexander V. Chernikov add_prefix(struct rtentry *rt, void *_data) 4130433870eSAlexander V. Chernikov { 4140433870eSAlexander V. Chernikov struct inet_array *pa = (struct inet_array *)_data; 4150433870eSAlexander V. Chernikov struct in_addr addr; 4160433870eSAlexander V. Chernikov int plen; 4170433870eSAlexander V. Chernikov uint32_t scopeid, haddr; 4180433870eSAlexander V. Chernikov 419*4a77a9b6SAlexander V. Chernikov pa->rnh_prefixes++; 420*4a77a9b6SAlexander V. Chernikov 4210433870eSAlexander V. Chernikov if (pa->num_items + 5 >= pa->alloc_items) { 4220433870eSAlexander V. Chernikov if (pa->error == 0) 423*4a77a9b6SAlexander V. Chernikov pa->error = ENOSPC; 4240433870eSAlexander V. Chernikov return (0); 4250433870eSAlexander V. Chernikov } 4260433870eSAlexander V. Chernikov 4270433870eSAlexander V. Chernikov rt_get_inet_prefix_plen(rt, &addr, &plen, &scopeid); 4280433870eSAlexander V. Chernikov 4290433870eSAlexander V. Chernikov pa->arr[pa->num_items++] = addr; 4300433870eSAlexander V. Chernikov haddr = ntohl(addr.s_addr); 4310433870eSAlexander V. Chernikov if (haddr > 0) { 4320433870eSAlexander V. Chernikov pa->arr[pa->num_items++].s_addr = htonl(haddr - 1); 4330433870eSAlexander V. Chernikov pa->arr[pa->num_items++].s_addr = htonl(haddr + 1); 4340433870eSAlexander V. Chernikov /* assume mask != 0 */ 4350433870eSAlexander V. Chernikov uint32_t mlen = (1 << (32 - plen)) - 1; 4360433870eSAlexander V. Chernikov pa->arr[pa->num_items++].s_addr = htonl(haddr + mlen); 4370433870eSAlexander V. Chernikov /* can overflow, but who cares */ 4380433870eSAlexander V. Chernikov pa->arr[pa->num_items++].s_addr = htonl(haddr + mlen + 1); 4390433870eSAlexander V. Chernikov } 4400433870eSAlexander V. Chernikov 4410433870eSAlexander V. Chernikov return (0); 4420433870eSAlexander V. Chernikov } 4430433870eSAlexander V. Chernikov 4440433870eSAlexander V. Chernikov static bool 4450433870eSAlexander V. Chernikov prepare_list(uint32_t fibnum, struct inet_array *pa) 4460433870eSAlexander V. Chernikov { 4470433870eSAlexander V. Chernikov struct rib_head *rh; 4480433870eSAlexander V. Chernikov 4490433870eSAlexander V. Chernikov rh = rt_tables_get_rnh(fibnum, AF_INET); 4500433870eSAlexander V. Chernikov 451*4a77a9b6SAlexander V. Chernikov uint32_t num_prefixes = rh->rnh_prefixes; 4520433870eSAlexander V. Chernikov bzero(pa, sizeof(struct inet_array)); 453*4a77a9b6SAlexander V. Chernikov pa->alloc_items = (num_prefixes + 10) * 5; 454*4a77a9b6SAlexander V. Chernikov pa->arr = mallocarray(pa->alloc_items, sizeof(struct in_addr), 4550433870eSAlexander V. Chernikov M_TEMP, M_ZERO | M_WAITOK); 4560433870eSAlexander V. Chernikov 457*4a77a9b6SAlexander V. Chernikov rib_walk(fibnum, AF_INET, false, add_prefix, pa); 458*4a77a9b6SAlexander V. Chernikov 459*4a77a9b6SAlexander V. Chernikov if (pa->error != 0) { 460*4a77a9b6SAlexander V. Chernikov printf("prefixes: old: %u, current: %u, walked: %u, allocated: %u\n", 461*4a77a9b6SAlexander V. Chernikov num_prefixes, rh->rnh_prefixes, pa->rnh_prefixes, pa->alloc_items); 462*4a77a9b6SAlexander V. Chernikov } 4630433870eSAlexander V. Chernikov 4640433870eSAlexander V. Chernikov return (pa->error == 0); 4650433870eSAlexander V. Chernikov } 4660433870eSAlexander V. Chernikov 4670433870eSAlexander V. Chernikov static int 4680433870eSAlexander V. Chernikov run_test_inet_scan(SYSCTL_HANDLER_ARGS) 4690433870eSAlexander V. Chernikov { 4700433870eSAlexander V. Chernikov struct epoch_tracker et; 4710433870eSAlexander V. Chernikov 4720433870eSAlexander V. Chernikov int count = 0; 4730433870eSAlexander V. Chernikov int error = sysctl_handle_int(oidp, &count, 0, req); 4740433870eSAlexander V. Chernikov if (error != 0) 4750433870eSAlexander V. Chernikov return (error); 4760433870eSAlexander V. Chernikov 4770433870eSAlexander V. Chernikov if (count == 0) 4780433870eSAlexander V. Chernikov return (0); 4790433870eSAlexander V. Chernikov 4800433870eSAlexander V. Chernikov struct inet_array pa = {}; 481*4a77a9b6SAlexander V. Chernikov uint32_t fibnum = curthread->td_proc->p_fibnum; 4820433870eSAlexander V. Chernikov 483*4a77a9b6SAlexander V. Chernikov if (!prepare_list(fibnum, &pa)) 4840433870eSAlexander V. Chernikov return (pa.error); 4850433870eSAlexander V. Chernikov 4860433870eSAlexander V. Chernikov struct timespec ts_pre, ts_post; 4870433870eSAlexander V. Chernikov int64_t total_diff = 1; 4880433870eSAlexander V. Chernikov uint64_t total_packets = 0; 489*4a77a9b6SAlexander V. Chernikov int failure_count = 0; 4900433870eSAlexander V. Chernikov 4910433870eSAlexander V. Chernikov NET_EPOCH_ENTER(et); 4920433870eSAlexander V. Chernikov nanouptime(&ts_pre); 4930433870eSAlexander V. Chernikov for (int i = 0; i < pa.num_items; i++) { 494*4a77a9b6SAlexander V. Chernikov if (!cmp_dst(fibnum, pa.arr[i])) { 495*4a77a9b6SAlexander V. Chernikov failure_count++; 4960433870eSAlexander V. Chernikov } 4970433870eSAlexander V. Chernikov total_packets++; 4980433870eSAlexander V. Chernikov } 4990433870eSAlexander V. Chernikov nanouptime(&ts_post); 5000433870eSAlexander V. Chernikov NET_EPOCH_EXIT(et); 5010433870eSAlexander V. Chernikov 5020433870eSAlexander V. Chernikov if (pa.arr != NULL) 5030433870eSAlexander V. Chernikov free(pa.arr, M_TEMP); 5040433870eSAlexander V. Chernikov 5050433870eSAlexander V. Chernikov /* Signal error to userland */ 506*4a77a9b6SAlexander V. Chernikov if (failure_count > 0) { 507*4a77a9b6SAlexander V. Chernikov printf("[RT ERROR] total failures: %d\n", failure_count); 508*4a77a9b6SAlexander V. Chernikov return (EINVAL); 509*4a77a9b6SAlexander V. Chernikov } 5100433870eSAlexander V. Chernikov 5110433870eSAlexander V. Chernikov total_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 + 5120433870eSAlexander V. Chernikov (ts_post.tv_nsec - ts_pre.tv_nsec); 5130433870eSAlexander V. Chernikov printf("%zu packets in %zu nanoseconds, %zu pps\n", 5140433870eSAlexander V. Chernikov total_packets, total_diff, total_packets * 1000000000 / total_diff); 5150433870eSAlexander V. Chernikov 5160433870eSAlexander V. Chernikov return (0); 5170433870eSAlexander V. Chernikov } 5180433870eSAlexander V. Chernikov SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_scan, 51974935ce8SAlexander V. Chernikov CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 5200433870eSAlexander V. Chernikov 0, 0, run_test_inet_scan, "I", "Execute fib4_lookup scan tests"); 5210433870eSAlexander V. Chernikov 522b6f8436bSMarko Zec #define LPS_SEQ 0x1 523b6f8436bSMarko Zec #define LPS_ANN 0x2 524b6f8436bSMarko Zec #define LPS_REP 0x4 525b6f8436bSMarko Zec 526b6f8436bSMarko Zec struct lps_walk_state { 527b6f8436bSMarko Zec uint32_t *keys; 528b6f8436bSMarko Zec int pos; 529b6f8436bSMarko Zec int lim; 530b6f8436bSMarko Zec }; 531b6f8436bSMarko Zec 532b6f8436bSMarko Zec static int 533b6f8436bSMarko Zec reduce_keys(struct rtentry *rt, void *_data) 534b6f8436bSMarko Zec { 535b6f8436bSMarko Zec struct lps_walk_state *wa = (struct lps_walk_state *) _data; 536b6f8436bSMarko Zec struct in_addr addr; 537b6f8436bSMarko Zec uint32_t scopeid; 538b6f8436bSMarko Zec int plen; 539b6f8436bSMarko Zec 540b6f8436bSMarko Zec rt_get_inet_prefix_plen(rt, &addr, &plen, &scopeid); 541b6f8436bSMarko Zec wa->keys[wa->pos] = ntohl(addr.s_addr) | 542b6f8436bSMarko Zec (wa->keys[wa->pos] & ~(0xffffffffU << (32 - plen))); 543b6f8436bSMarko Zec 544b6f8436bSMarko Zec wa->pos++; 545b6f8436bSMarko Zec return (wa->pos == wa->lim); 546b6f8436bSMarko Zec } 547b6f8436bSMarko Zec 548b8598e2fSAlexander V. Chernikov static int 549b8598e2fSAlexander V. Chernikov rnd_lps(SYSCTL_HANDLER_ARGS) 550b8598e2fSAlexander V. Chernikov { 551b8598e2fSAlexander V. Chernikov struct epoch_tracker et; 552a43104ebSMarko Zec struct in_addr key; 553b6f8436bSMarko Zec struct lps_walk_state wa; 554b8598e2fSAlexander V. Chernikov struct timespec ts_pre, ts_post; 555b6f8436bSMarko Zec struct nhop_object *nh_fib; 556b8598e2fSAlexander V. Chernikov uint64_t total_diff, lps; 557*4a77a9b6SAlexander V. Chernikov uint32_t *keys, fibnum; 558b6f8436bSMarko Zec uint32_t t, p; 559a43104ebSMarko Zec uintptr_t acc = 0; 560b6f8436bSMarko Zec int i, pos, count = 0; 561b6f8436bSMarko Zec int seq = 0, rep = 0; 562a43104ebSMarko Zec int error; 563b8598e2fSAlexander V. Chernikov 564b8598e2fSAlexander V. Chernikov error = sysctl_handle_int(oidp, &count, 0, req); 565b8598e2fSAlexander V. Chernikov if (error != 0) 566b8598e2fSAlexander V. Chernikov return (error); 567b8598e2fSAlexander V. Chernikov if (count <= 0) 568b8598e2fSAlexander V. Chernikov return (0); 569*4a77a9b6SAlexander V. Chernikov fibnum = curthread->td_proc->p_fibnum; 570b8598e2fSAlexander V. Chernikov 571b8598e2fSAlexander V. Chernikov keys = malloc(sizeof(*keys) * count, M_TEMP, M_NOWAIT); 572a43104ebSMarko Zec if (keys == NULL) 573b8598e2fSAlexander V. Chernikov return (ENOMEM); 574b8598e2fSAlexander V. Chernikov printf("Preparing %d random keys...\n", count); 575b8598e2fSAlexander V. Chernikov arc4random_buf(keys, sizeof(*keys) * count); 576b6f8436bSMarko Zec if (arg2 & LPS_ANN) { 577b6f8436bSMarko Zec wa.keys = keys; 578b6f8436bSMarko Zec wa.pos = 0; 579b6f8436bSMarko Zec wa.lim = count; 580b6f8436bSMarko Zec printf("Reducing keys to announced address space...\n"); 581b6f8436bSMarko Zec do { 582*4a77a9b6SAlexander V. Chernikov rib_walk(fibnum, AF_INET, false, reduce_keys, 583b6f8436bSMarko Zec &wa); 584b6f8436bSMarko Zec } while (wa.pos < wa.lim); 585b6f8436bSMarko Zec printf("Reshuffling keys...\n"); 586b6f8436bSMarko Zec for (int i = 0; i < count; i++) { 587b6f8436bSMarko Zec p = random() % count; 588b6f8436bSMarko Zec t = keys[p]; 589b6f8436bSMarko Zec keys[p] = keys[i]; 590b6f8436bSMarko Zec keys[i] = t; 591b6f8436bSMarko Zec } 592b6f8436bSMarko Zec } 593b6f8436bSMarko Zec 594b6f8436bSMarko Zec if (arg2 & LPS_REP) { 595b6f8436bSMarko Zec rep = 1; 596b6f8436bSMarko Zec printf("REP "); 597b6f8436bSMarko Zec } 598b6f8436bSMarko Zec if (arg2 & LPS_SEQ) { 599b6f8436bSMarko Zec seq = 1; 600b6f8436bSMarko Zec printf("SEQ"); 601b6f8436bSMarko Zec } else if (arg2 & LPS_ANN) 602b6f8436bSMarko Zec printf("ANN"); 603b6f8436bSMarko Zec else 604b6f8436bSMarko Zec printf("RND"); 605b6f8436bSMarko Zec printf(" LPS test starting...\n"); 606b8598e2fSAlexander V. Chernikov 607b8598e2fSAlexander V. Chernikov NET_EPOCH_ENTER(et); 608b8598e2fSAlexander V. Chernikov nanouptime(&ts_pre); 609b6f8436bSMarko Zec for (i = 0, pos = 0; i < count; i++) { 610b6f8436bSMarko Zec key.s_addr = keys[pos++] ^ ((acc >> 10) & 0xff); 611*4a77a9b6SAlexander V. Chernikov nh_fib = fib4_lookup(fibnum, key, 0, NHR_NONE, 0); 612b6f8436bSMarko Zec if (seq) { 613b6f8436bSMarko Zec if (nh_fib != NULL) { 614b6f8436bSMarko Zec acc += (uintptr_t) nh_fib + 123; 615b6f8436bSMarko Zec if (acc & 0x1000) 616b6f8436bSMarko Zec acc += (uintptr_t) nh_fib->nh_ifp; 617b6f8436bSMarko Zec else 618b6f8436bSMarko Zec acc -= (uintptr_t) nh_fib->nh_ifp; 619b6f8436bSMarko Zec } else 620b6f8436bSMarko Zec acc ^= (acc >> 3) + (acc << 2) + i; 621b6f8436bSMarko Zec if (acc & 0x800) 622b6f8436bSMarko Zec pos++; 623b6f8436bSMarko Zec if (pos >= count) 624b6f8436bSMarko Zec pos = 0; 625a43104ebSMarko Zec } 626b6f8436bSMarko Zec if (rep && ((i & 0xf) == 0xf)) { 627b6f8436bSMarko Zec pos -= 0xf; 628b6f8436bSMarko Zec if (pos < 0) 629b6f8436bSMarko Zec pos += 0xf; 630a43104ebSMarko Zec } 631a43104ebSMarko Zec } 632b8598e2fSAlexander V. Chernikov nanouptime(&ts_post); 633b8598e2fSAlexander V. Chernikov NET_EPOCH_EXIT(et); 634b8598e2fSAlexander V. Chernikov 635b8598e2fSAlexander V. Chernikov free(keys, M_TEMP); 636b8598e2fSAlexander V. Chernikov 637b8598e2fSAlexander V. Chernikov total_diff = (ts_post.tv_sec - ts_pre.tv_sec) * 1000000000 + 638b6f8436bSMarko Zec (ts_post.tv_nsec - ts_pre.tv_nsec); 639b8598e2fSAlexander V. Chernikov lps = 1000000000ULL * count / total_diff; 640b6f8436bSMarko Zec printf("%d lookups in %zu.%06zu milliseconds, %lu.%06lu MLPS\n", 641b6f8436bSMarko Zec count, total_diff / 1000000, total_diff % 1000000, 642b6f8436bSMarko Zec lps / 1000000, lps % 1000000); 643b8598e2fSAlexander V. Chernikov 644b8598e2fSAlexander V. Chernikov return (0); 645b8598e2fSAlexander V. Chernikov } 646a43104ebSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd, 647a43104ebSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 648b6f8436bSMarko Zec 0, 0, rnd_lps, "I", 649a43104ebSMarko Zec "Measure lookups per second, uniformly random keys, independent lookups"); 650b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_ann, 651b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 652b6f8436bSMarko Zec 0, LPS_ANN, rnd_lps, "I", 653b6f8436bSMarko Zec "Measure lookups per second, random keys from announced address space, " 654b6f8436bSMarko Zec "independent lookups"); 655b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq, 656b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 657b6f8436bSMarko Zec 0, LPS_SEQ, rnd_lps, "I", 658b6f8436bSMarko Zec "Measure lookups per second, uniformly random keys, " 659b6f8436bSMarko Zec "artificial dependencies between lookups"); 660b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_ann, 661b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 662b6f8436bSMarko Zec 0, LPS_SEQ | LPS_ANN, rnd_lps, "I", 663b6f8436bSMarko Zec "Measure lookups per second, random keys from announced address space, " 664b6f8436bSMarko Zec "artificial dependencies between lookups"); 665b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_rep, 666b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 667b6f8436bSMarko Zec 0, LPS_REP, rnd_lps, "I", 668b6f8436bSMarko Zec "Measure lookups per second, uniformly random keys, independent lookups, " 669b6f8436bSMarko Zec "repeated keys"); 670b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_rnd_ann_rep, 671b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 672b6f8436bSMarko Zec 0, LPS_ANN | LPS_REP, rnd_lps, "I", 673b6f8436bSMarko Zec "Measure lookups per second, random keys from announced address space, " 674b6f8436bSMarko Zec "independent lookups, repeated keys"); 675b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_rep, 676b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 677b6f8436bSMarko Zec 0, LPS_SEQ | LPS_REP, rnd_lps, "I", 678b6f8436bSMarko Zec "Measure lookups per second, uniformly random keys, " 679b6f8436bSMarko Zec "artificial dependencies between lookups, repeated keys"); 680b6f8436bSMarko Zec SYSCTL_PROC(_net_route_test, OID_AUTO, run_lps_seq_ann_rep, 681b6f8436bSMarko Zec CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 682b6f8436bSMarko Zec 0, LPS_SEQ | LPS_ANN | LPS_REP, rnd_lps, "I", 683b6f8436bSMarko Zec "Measure lookups per second, random keys from announced address space, " 684b6f8436bSMarko Zec "artificial dependencies between lookups, repeated keys"); 6850433870eSAlexander V. Chernikov 6860433870eSAlexander V. Chernikov static int 6870433870eSAlexander V. Chernikov test_fib_lookup_modevent(module_t mod, int type, void *unused) 6880433870eSAlexander V. Chernikov { 6890433870eSAlexander V. Chernikov int error = 0; 6900433870eSAlexander V. Chernikov 6910433870eSAlexander V. Chernikov switch (type) { 6920433870eSAlexander V. Chernikov case MOD_LOAD: 6930433870eSAlexander V. Chernikov break; 6940433870eSAlexander V. Chernikov case MOD_UNLOAD: 6950433870eSAlexander V. Chernikov if (V_inet_addr_list != NULL) 6960433870eSAlexander V. Chernikov free(V_inet_addr_list, M_TEMP); 6970433870eSAlexander V. Chernikov if (V_inet6_addr_list != NULL) 6980433870eSAlexander V. Chernikov free(V_inet6_addr_list, M_TEMP); 6990433870eSAlexander V. Chernikov break; 7000433870eSAlexander V. Chernikov default: 7010433870eSAlexander V. Chernikov error = EOPNOTSUPP; 7020433870eSAlexander V. Chernikov break; 7030433870eSAlexander V. Chernikov } 7040433870eSAlexander V. Chernikov return (error); 7050433870eSAlexander V. Chernikov } 7060433870eSAlexander V. Chernikov 7070433870eSAlexander V. Chernikov static moduledata_t testfiblookupmod = { 7080433870eSAlexander V. Chernikov "test_fib_lookup", 7090433870eSAlexander V. Chernikov test_fib_lookup_modevent, 7100433870eSAlexander V. Chernikov 0 7110433870eSAlexander V. Chernikov }; 7120433870eSAlexander V. Chernikov 7130433870eSAlexander V. Chernikov DECLARE_MODULE(testfiblookupmod, testfiblookupmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 7140433870eSAlexander V. Chernikov MODULE_VERSION(testfiblookup, 1); 715