Changeset View
Changeset View
Standalone View
Standalone View
sys/tests/fib_lookup/fib_lookup.c
Show All 37 Lines | |||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/radix.h> | |||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_fib.h> | #include <netinet/in_fib.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet6/in6_fib.h> | #include <netinet6/in6_fib.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/nhop.h> | #include <net/route/nhop.h> | ||||
#include <net/route/route_ctl.h> | #include <net/route/route_ctl.h> | ||||
#include <net/route/route_var.h> | #include <net/route/route_var.h> | ||||
#include <net/route/route_debug.h> | |||||
#include <net/route/fib_algo.h> | #include <net/route/fib_algo.h> | ||||
#define CHUNK_SIZE 10000 | #define CHUNK_SIZE 10000 | ||||
VNET_DEFINE_STATIC(struct in_addr *, inet_addr_list); | VNET_DEFINE_STATIC(struct in_addr *, inet_addr_list); | ||||
#define V_inet_addr_list VNET(inet_addr_list) | #define V_inet_addr_list VNET(inet_addr_list) | ||||
VNET_DEFINE_STATIC(int, inet_list_size); | VNET_DEFINE_STATIC(int, inet_list_size); | ||||
#define V_inet_list_size VNET(inet_list_size) | #define V_inet_list_size VNET(inet_list_size) | ||||
▲ Show 20 Lines • Show All 358 Lines • ▼ Show 20 Lines | run_test_inet_random(SYSCTL_HANDLER_ARGS) | ||||
if (pass_packets == 0) | if (pass_packets == 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
printf("%zu packets in %zu nanoseconds, %zu pps\n", | printf("%zu packets in %zu nanoseconds, %zu pps\n", | ||||
total_packets, total_diff, total_packets * 1000000000 / total_diff); | total_packets, total_diff, total_packets * 1000000000 / total_diff); | ||||
return (0); | return (0); | ||||
} | } | ||||
SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_random, | SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_random1, | ||||
CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | ||||
0, 0, run_test_inet_random, "I", "Execute fib4_lookup random check tests"); | 0, 0, run_test_inet_random, "I", "Execute fib4_lookup random check tests"); | ||||
struct inet_array { | struct inet_array { | ||||
uint32_t alloc_items; | uint32_t alloc_items; | ||||
uint32_t num_items; | uint32_t num_items; | ||||
uint32_t rnh_prefixes; | uint32_t rnh_prefixes; | ||||
▲ Show 20 Lines • Show All 303 Lines • ▼ Show 20 Lines | run_test_inet6_scan(SYSCTL_HANDLER_ARGS) | ||||
printf("%zu packets in %zu nanoseconds, %zu pps\n", | printf("%zu packets in %zu nanoseconds, %zu pps\n", | ||||
total_packets, total_diff, total_packets * 1000000000 / total_diff); | total_packets, total_diff, total_packets * 1000000000 / total_diff); | ||||
return (0); | return (0); | ||||
} | } | ||||
SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet6_scan, | SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet6_scan, | ||||
CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | ||||
0, 0, run_test_inet6_scan, "I", "Execute fib6_lookup scan tests"); | 0, 0, run_test_inet6_scan, "I", "Execute fib6_lookup scan tests"); | ||||
#define RADIX_MAX_KEY_LEN 32 | |||||
static char rn_ones[RADIX_MAX_KEY_LEN] = { | |||||
-1, -1, -1, -1, -1, -1, -1, -1, | |||||
-1, -1, -1, -1, -1, -1, -1, -1, | |||||
-1, -1, -1, -1, -1, -1, -1, -1, | |||||
-1, -1, -1, -1, -1, -1, -1, -1, | |||||
}; | |||||
#define LEN(x) ( (int) (*(const u_char *)(x)) ) | |||||
static int | |||||
rn_satisfies_leaf(const char *trial, struct radix_node *leaf, int skip) | |||||
{ | |||||
const char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; | |||||
const char *cplim; | |||||
int length = min(LEN(cp), LEN(cp2)); | |||||
if (cp3 == NULL) | |||||
cp3 = rn_ones; | |||||
else | |||||
length = min(length, LEN(cp3)); | |||||
cplim = cp + length; cp3 += skip; cp2 += skip; | |||||
for (cp += skip; cp < cplim; cp++, cp2++, cp3++) | |||||
if ((*cp ^ *cp2) & *cp3) | |||||
return (0); | |||||
return (1); | |||||
} | |||||
#define RN_IS_ROOT(_rn) (((_rn)->rn_flags & RNF_ROOT) != 0) | |||||
#define IS_LEAF(_rn) (((_rn)->rn_bit < 0)) | |||||
#define RN_IS_LEAF(_rn) ((_rn)->rn_bit < 0) | |||||
static int | |||||
get_pxlen(struct radix_node *rn) | |||||
{ | |||||
const int offset = 32, host_plen = 32; | |||||
if (rn->rn_mask == NULL) { | |||||
return ((LEN(rn->rn_key) * 8) - offset); | |||||
} | |||||
if (RN_IS_ROOT(rn)) | |||||
return (0); | |||||
return ((rn->rn_mask != NULL) ? -(1 + rn->rn_bit) - offset : host_plen); | |||||
} | |||||
static int | |||||
get_masklen(const struct radix_node *rn) | |||||
{ | |||||
if (rn->rn_mask == NULL) { | |||||
return ((LEN(rn->rn_key) * 8)); | |||||
} | |||||
return (-(1 + rn->rn_bit)); | |||||
} | |||||
static struct radix_node * | |||||
_rn_get_parent(struct radix_node *rn) | |||||
{ | |||||
struct radix_node *rn_parent; | |||||
const void *v = rn->rn_key; | |||||
int mlen = get_masklen(rn); | |||||
rn_parent = rn_nextprefix(rn); | |||||
if (rn_parent != NULL) | |||||
return (rn_parent); | |||||
while (!RN_IS_ROOT(rn)) { | |||||
rn = rn->rn_parent; | |||||
/* Now dive left to find the leaf node */ | |||||
struct radix_node *rn_l = rn->rn_left; | |||||
while (rn_l != NULL && !RN_IS_LEAF(rn_l)) | |||||
rn_l = rn_l->rn_left; | |||||
/* now rn_left is a leaft */ | |||||
for (; rn_l != NULL; rn_l = rn_nextprefix(rn_l)) { | |||||
if (RN_IS_ROOT(rn_l)) | |||||
continue; | |||||
if (rn_satisfies_leaf(v, rn_l, 32) && (get_masklen(rn_l) < mlen)) | |||||
return (rn_l); | |||||
} | |||||
} | |||||
return (NULL); | |||||
} | |||||
static int | |||||
parent_route_chedk(struct rtentry *rt, void *vw) | |||||
{ | |||||
struct rib_head *rh = (struct rib_head *)vw; | |||||
char buf[32]; | |||||
rt_print_buf(rt, buf, sizeof(buf)); | |||||
struct rtentry *rt_parent = rt_get_parent(rh, rt); | |||||
if (rt_parent != NULL) { | |||||
char pbuf[32]; | |||||
rt_print_buf(rt_parent, pbuf, sizeof(pbuf)); | |||||
printf("X: %s -> %s\n", buf, pbuf); | |||||
} else | |||||
printf("X: %s -> NULL\n", buf); | |||||
return (0); | |||||
} | |||||
static void | |||||
print_rt(struct rtentry *rt, const char *name, char *prepend, int off) | |||||
{ | |||||
struct radix_node *rn = (struct radix_node *)rt; | |||||
if (IS_LEAF(rn)) { | |||||
struct in_addr addr4 = {}; | |||||
uint32_t scopeid; | |||||
int plen = 0; | |||||
char abuf[16]; | |||||
int xplen = get_pxlen(rn); | |||||
if (!(rn->rn_flags & RNF_ROOT)) { | |||||
struct radix_node *parent = _rn_get_parent(rn); | |||||
rt_get_inet_prefix_plen(rt, &addr4, &plen, &scopeid); | |||||
inet_ntop(AF_INET, &addr4, abuf, sizeof(abuf)); | |||||
prepend[off] = '\0'; | |||||
printf("%s%s a=%p p=%p f=%d [L] %s/%d{%d}", prepend, name, | |||||
rn, rn->rn_parent, rn->rn_flags, abuf, plen, xplen); | |||||
if (parent != NULL) { | |||||
rt_get_inet_prefix_plen(RNTORT(parent), &addr4, &plen, &scopeid); | |||||
inet_ntop(AF_INET, &addr4, abuf, sizeof(abuf)); | |||||
printf(" P=%s/%d (%p)", abuf, plen, parent); | |||||
} | |||||
printf("\n"); | |||||
prepend[off] = ' '; | |||||
} else { | |||||
prepend[off] = '\0'; | |||||
printf("%s%s a=%p p=%p f=%d [RL]\n", prepend, name, | |||||
rn, rn->rn_parent, rn->rn_flags); | |||||
prepend[off] = ' '; | |||||
} | |||||
} else { | |||||
prepend[off] = '\0'; | |||||
printf("%s%s a=%p p=%p f=%d [N]\n", prepend, name, rn, rn->rn_parent, rn->rn_flags); | |||||
prepend[off] = ' '; | |||||
} | |||||
if (!IS_LEAF(rn)) { | |||||
if (rn->rn_left != NULL) | |||||
print_rt(RNTORT(rn->rn_left), "L", prepend, off + 1); | |||||
if (rn->rn_right != NULL) | |||||
print_rt(RNTORT(rn->rn_right), "R", prepend, off + 1); | |||||
} else if (rn_nextprefix(rn) != NULL) { | |||||
struct radix_node *rn_next = rn_nextprefix(rn); | |||||
for (; rn_next != NULL; rn_next = rn_nextprefix(rn_next)) { | |||||
print_rt(RNTORT(rn_next), "D", prepend, off + 1); | |||||
} | |||||
} | |||||
} | |||||
static int | |||||
run_test_inet_parent(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct epoch_tracker et; | |||||
uint32_t fibnum = curthread->td_proc->p_fibnum; | |||||
int count = 0; | |||||
int error = sysctl_handle_int(oidp, &count, 0, req); | |||||
if (error != 0) | |||||
return (error); | |||||
if (count == 0) | |||||
return (0); | |||||
printf("-------------------------------------------\n"); | |||||
NET_EPOCH_ENTER(et); | |||||
struct rib_head *rh; | |||||
rh = rt_tables_get_rnh(fibnum, AF_INET); | |||||
char pbuf[64]; | |||||
memset(pbuf, ' ', sizeof(pbuf)); | |||||
pbuf[sizeof(pbuf) - 1] = '\0'; | |||||
print_rt(RNTORT(rh->head.rnh_treetop), "V", pbuf, 0); | |||||
rib_walk(fibnum, AF_INET, false, parent_route_chedk, rh); | |||||
NET_EPOCH_EXIT(et); | |||||
return (0); | |||||
} | |||||
SYSCTL_PROC(_net_route_test, OID_AUTO, run_inet_parent, | |||||
CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, | |||||
0, 0, run_test_inet_parent, "I", "Execute fib6_lookup scan tests"); | |||||
#define LPS_SEQ 0x1 | #define LPS_SEQ 0x1 | ||||
#define LPS_ANN 0x2 | #define LPS_ANN 0x2 | ||||
#define LPS_REP 0x4 | #define LPS_REP 0x4 | ||||
struct lps_walk_state { | struct lps_walk_state { | ||||
uint32_t *keys; | uint32_t *keys; | ||||
int pos; | int pos; | ||||
▲ Show 20 Lines • Show All 186 Lines • Show Last 20 Lines |