mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Extend the trie_walk_init api + test
The trie_walk_init() function now supports also searching whole trie subnet and all successor nets (in lexicographic order). This behavior can be accomplished by setting @net, and @include_successors to subnet, and non-zero respectivelly.
This commit is contained in:
parent
3242529750
commit
722eab2fe7
@ -201,7 +201,7 @@ void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
|
|||||||
int trie_match_net(const struct f_trie *t, const net_addr *n);
|
int trie_match_net(const struct f_trie *t, const net_addr *n);
|
||||||
int trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0);
|
int trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0);
|
||||||
int trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0);
|
int trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0);
|
||||||
void trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *from);
|
int trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *from, u8 include_successors);
|
||||||
int trie_walk_next(struct f_trie_walk_state *s, net_addr *net);
|
int trie_walk_next(struct f_trie_walk_state *s, net_addr *net);
|
||||||
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
|
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
|
||||||
void trie_format(const struct f_trie *t, buffer *buf);
|
void trie_format(const struct f_trie *t, buffer *buf);
|
||||||
@ -253,14 +253,17 @@ trie_match_next_longest_ip6(net_addr_ip6 *n, ip6_addr *found)
|
|||||||
|
|
||||||
#define TRIE_WALK_TO_ROOT_END })
|
#define TRIE_WALK_TO_ROOT_END })
|
||||||
|
|
||||||
|
#define TRIE_WALK2(trie, net, from, include) ({ \
|
||||||
#define TRIE_WALK(trie, net, from) ({ \
|
|
||||||
net_addr net; \
|
net_addr net; \
|
||||||
struct f_trie_walk_state tws_; \
|
struct f_trie_walk_state tws_; \
|
||||||
trie_walk_init(&tws_, trie, from); \
|
trie_walk_init(&tws_, trie, from, include); \
|
||||||
while (trie_walk_next(&tws_, &net))
|
while (trie_walk_next(&tws_, &net))
|
||||||
|
|
||||||
#define TRIE_WALK_END })
|
#define TRIE_WALK2_END })
|
||||||
|
|
||||||
|
#define TRIE_WALK(trie, net, from) TRIE_WALK2(trie, net, from, 0) \
|
||||||
|
|
||||||
|
#define TRIE_WALK_END TRIE_WALK2_END
|
||||||
|
|
||||||
|
|
||||||
#define F_CMP_ERROR 999
|
#define F_CMP_ERROR 999
|
||||||
|
74
filter/trie-data-edge
Normal file
74
filter/trie-data-edge
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
17.192.0.0/12
|
||||||
|
17.192.64.0/18
|
||||||
|
17.192.64.16/28
|
||||||
|
17.192.64.96/28
|
||||||
|
17.192.64.240/28
|
||||||
|
17.192.64.144/28
|
||||||
|
17.192.192.0/18
|
||||||
|
17.201.0.0/18
|
||||||
|
17.216.0.0/18
|
||||||
|
17.201.0.16/28
|
||||||
|
101.80.0.0/12
|
||||||
|
101.192.192.0/18
|
||||||
|
101.201.0.0/18
|
||||||
|
101.201.0.80/28
|
||||||
|
101.216.0.0/18
|
||||||
|
180.201.0.0/18
|
||||||
|
180.216.0.0/18
|
||||||
|
180.48.0.0/12
|
||||||
|
251.16.0.0/12
|
||||||
|
|
||||||
|
1.0.0.0/12
|
||||||
|
1.1.0.0/18
|
||||||
|
1.1.1.0/28
|
||||||
|
1.1.3.0/28
|
||||||
|
1.1.5.0/28
|
||||||
|
1.1.7.0/28
|
||||||
|
1.3.0.0/18
|
||||||
|
1.5.0.0/18
|
||||||
|
1.5.1.0/28
|
||||||
|
1.5.3.0/28
|
||||||
|
1.7.0.0/18
|
||||||
|
3.0.0.0/12
|
||||||
|
3.1.0.0/18
|
||||||
|
3.3.0.0/18
|
||||||
|
3.5.0.0/18
|
||||||
|
5.0.0.0/12
|
||||||
|
5.1.0.0/28
|
||||||
|
7.0.0.0/12
|
||||||
|
|
||||||
|
1.0.0.0/12
|
||||||
|
3.0.0.0/12
|
||||||
|
3.1.0.0/18
|
||||||
|
5.0.0.0/12
|
||||||
|
5.1.0.0/18
|
||||||
|
5.3.0.0/18
|
||||||
|
5.3.1.0/28
|
||||||
|
5.3.3.0/28
|
||||||
|
5.5.0.0/18
|
||||||
|
7.0.0.0/12
|
||||||
|
7.1.0.0/18
|
||||||
|
7.3.0.0/18
|
||||||
|
7.5.0.0/18
|
||||||
|
7.7.0.0/18
|
||||||
|
7.7.1.0/28
|
||||||
|
7.7.3.0/28
|
||||||
|
7.7.5.0/28
|
||||||
|
7.7.7.0/28
|
||||||
|
|
||||||
|
1.0.0.0/8
|
||||||
|
1.1.0.0/16
|
||||||
|
1.1.255.0/24
|
||||||
|
1.32.0.0/12
|
||||||
|
1.34.0.0/16
|
||||||
|
1.64.0.0/12
|
||||||
|
|
||||||
|
0.0.0.0/0
|
||||||
|
1.1.1.1/32
|
||||||
|
255.255.255.255/32
|
||||||
|
|
||||||
|
0.0.0.0/0
|
||||||
|
123.45.0.0/16
|
||||||
|
|
||||||
|
0.0.0.0/0
|
||||||
|
|
175
filter/trie.c
175
filter/trie.c
@ -115,7 +115,6 @@
|
|||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
#include "filter/data.h"
|
#include "filter/data.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the trie_add_prefix(), we use ip_addr (assuming that it is the same as
|
* In the trie_add_prefix(), we use ip_addr (assuming that it is the same as
|
||||||
* ip6_addr) to handle both IPv4 and IPv6 prefixes. In contrast to rest of the
|
* ip6_addr) to handle both IPv4 and IPv6 prefixes. In contrast to rest of the
|
||||||
@ -784,20 +783,46 @@ done:
|
|||||||
|
|
||||||
#define SAME_PREFIX(A,B,X,L) ((X) ? ip4_prefix_equal((A)->v4.addr, net4_prefix(B), (L)) : ip6_prefix_equal((A)->v6.addr, net6_prefix(B), (L)))
|
#define SAME_PREFIX(A,B,X,L) ((X) ? ip4_prefix_equal((A)->v4.addr, net4_prefix(B), (L)) : ip6_prefix_equal((A)->v6.addr, net6_prefix(B), (L)))
|
||||||
#define GET_NET_BITS(N,X,A,B) ((X) ? ip4_getbits(net4_prefix(N), (A), (B)) : ip6_getbits(net6_prefix(N), (A), (B)))
|
#define GET_NET_BITS(N,X,A,B) ((X) ? ip4_getbits(net4_prefix(N), (A), (B)) : ip6_getbits(net6_prefix(N), (A), (B)))
|
||||||
|
#define GET_NODE_BITS(N,X,A,B) ((X) ? ip4_getbits((N)->v4.addr, (A), (B)) : ip6_getbits((N)->v6.addr, (A), (B)))
|
||||||
|
#define NEXT_PREFIX(A,B,X) ((X) ? ip4_compare((A)->v4.addr, net4_prefix(B)) < 0 : ip6_compare((A)->v6.addr, net6_prefix(B)) < 0)
|
||||||
|
#define CHECK_LOCAL_MASK(A,B,L,X) \
|
||||||
|
((X) ? (A)->v4.local >= trie_local_mask4(net4_prefix(B), (B)->pxlen, (L)) : (A)->v6.local >= trie_local_mask6(net6_prefix(B), (B)->pxlen, (L)))
|
||||||
|
#define MATCH_LOCAL_MASK(A,B,L,X) \
|
||||||
|
(!!((X) ? (A)->v4.local & trie_local_mask4(net4_prefix(B), (B)->pxlen, (L)) : (A)->v6.local & trie_local_mask6(net6_prefix(B), (B)->pxlen, (L))))
|
||||||
|
#define SELECT_CHILD(pos,step) ((1u << (step)) + (pos))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We want to select a specific subtrie base on it's index in child array c.
|
||||||
|
*
|
||||||
|
* 1
|
||||||
|
* 2 3
|
||||||
|
* 4 5 6 7
|
||||||
|
* 8 9 A B C D E F
|
||||||
|
* -----------------------------------------------------
|
||||||
|
* 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
|
||||||
|
* idx 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trie_walk_init
|
* trie_walk_init
|
||||||
* @s: walk state
|
* @s: walk state
|
||||||
* @t: trie
|
* @t: trie
|
||||||
* @net: optional subnet for walk
|
* @net: optional subnet for walk
|
||||||
|
* @include_successors: optional flag for continue walking beyond subnet @net
|
||||||
*
|
*
|
||||||
* Initialize walk state for subsequent walk through nodes of the trie @t by
|
* Initialize walk state for subsequent walk through nodes of the trie @t by
|
||||||
* trie_walk_next(). The argument @net allows to restrict walk to given subnet,
|
* trie_walk_next(). The argument @net allows to restrict walk to given subnet,
|
||||||
* otherwise full walk over all nodes is used. This is done by finding node at
|
* otherwise full walk over all nodes is used. This is done by finding node at
|
||||||
* or below @net and starting position in it.
|
* or below @net and starting position in it. The argument @include_successors,
|
||||||
|
* which requeries specifing the @net argument, removes the restriction for all
|
||||||
|
* nets lexicographically succeeding the @net. This is done by storing the walken
|
||||||
|
* nodes on the state's stack.
|
||||||
|
*
|
||||||
|
* For set @include_successors the return value is 1 if the @net is present in
|
||||||
|
* the trie @t, in all other cases 0.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *net)
|
trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *net, u8 include_successors)
|
||||||
{
|
{
|
||||||
*s = (struct f_trie_walk_state) {
|
*s = (struct f_trie_walk_state) {
|
||||||
.ipv4 = t->ipv4,
|
.ipv4 = t->ipv4,
|
||||||
@ -809,7 +834,7 @@ trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_ad
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!net)
|
if (!net)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/* We want to find node of level at least plen */
|
/* We want to find node of level at least plen */
|
||||||
int plen = ROUND_DOWN_POW2(net->pxlen, TRIE_STEP);
|
int plen = ROUND_DOWN_POW2(net->pxlen, TRIE_STEP);
|
||||||
@ -827,29 +852,157 @@ trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_ad
|
|||||||
/* We found final node */
|
/* We found final node */
|
||||||
if (nlen >= plen)
|
if (nlen >= plen)
|
||||||
{
|
{
|
||||||
|
if (!include_successors)
|
||||||
|
s->stack[0] = n;
|
||||||
|
else
|
||||||
|
s->stack[s->stack_pos] = n;
|
||||||
|
|
||||||
if (nlen == plen)
|
if (nlen == plen)
|
||||||
{
|
{
|
||||||
/* Find proper local_pos, while accept_length is not used */
|
/* Find proper local_pos, while accept_length is not used */
|
||||||
int step = net->pxlen - plen;
|
int step = net->pxlen - plen;
|
||||||
s->start_pos = s->local_pos = (1u << step) + GET_NET_BITS(net, v4, plen, step);
|
s->local_pos = (1u << step) + GET_NET_BITS(net, v4, plen, step);
|
||||||
s->accept_length = plen;
|
s->accept_length = plen;
|
||||||
|
|
||||||
|
if (!include_successors)
|
||||||
|
{
|
||||||
|
s->start_pos = s->local_pos;
|
||||||
|
return MATCH_LOCAL_MASK(n, net, nlen, v4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_LOCAL(n, v4) != 0 && !CHECK_LOCAL_MASK(n, net, nlen, v4))
|
||||||
|
{
|
||||||
|
s->local_pos = (1u << TRIE_STEP) + GET_NET_BITS(net, v4, nlen, TRIE_STEP);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 1;
|
||||||
|
int bits = GET_NET_BITS(net, v4, nlen, TRIE_STEP);
|
||||||
|
for (int i = 0; i < net->pxlen - plen; i++)
|
||||||
|
{
|
||||||
|
if (bits & (1u << (TRIE_STEP - i - 1)))
|
||||||
|
pos = 2 * pos + 1;
|
||||||
|
else
|
||||||
|
pos = 2 * pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->local_pos = pos;
|
||||||
|
return MATCH_LOCAL_MASK(n, net, nlen, v4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Start from pos 1 in local node, but first try accept mask */
|
/* Start from pos 1 in current node, but first try accept mask */
|
||||||
s->accept_length = net->pxlen;
|
s->accept_length = net->pxlen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->stack[0] = n;
|
/* We store node in stack before moving on */
|
||||||
return;
|
if (include_successors)
|
||||||
}
|
s->stack[s->stack_pos++] = n;
|
||||||
|
|
||||||
/* Choose child */
|
/* Choose child */
|
||||||
n = GET_CHILD(n, v4, GET_NET_BITS(net, v4, nlen, TRIE_STEP));
|
n = GET_CHILD(n, v4, GET_NET_BITS(net, v4, nlen, TRIE_STEP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We do not override the trie root in case of inclusive search */
|
||||||
|
if (!include_successors)
|
||||||
|
{
|
||||||
s->stack[0] = NULL;
|
s->stack[0] = NULL;
|
||||||
return;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are out of path, find nearest successor */
|
||||||
|
if (s->stack_pos == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we end up on node that has compressed path, we need to step up node
|
||||||
|
* for better decision making
|
||||||
|
*/
|
||||||
|
s->stack_pos--;
|
||||||
|
n = s->stack[s->stack_pos];
|
||||||
|
ASSERT(n != NULL);
|
||||||
|
int nlen = v4 ? n->v4.plen : n->v6.plen;
|
||||||
|
|
||||||
|
struct net_addr_ip4 *net4 = NULL;
|
||||||
|
struct net_addr_ip6 *net6 = NULL;
|
||||||
|
|
||||||
|
if (v4) net4 = (net_addr_ip4 *) net;
|
||||||
|
else net6 = (net_addr_ip6 *) net;
|
||||||
|
|
||||||
|
/* We known for sure that the searched prefix is not in the trie */
|
||||||
|
int cmp;
|
||||||
|
int bits = GET_NET_BITS(net, v4, nlen, TRIE_STEP);
|
||||||
|
const struct f_trie_node *child = GET_CHILD(n, v4, bits);
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
cmp = v4 ? ip4_compare(child->v4.addr, net4->prefix)
|
||||||
|
: ip6_compare(child->v6.addr, net6->prefix);
|
||||||
|
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
if (v4 ? child->v4.plen <= net4->pxlen : child->v6.plen <= net6->pxlen)
|
||||||
|
bits = 0;
|
||||||
|
else
|
||||||
|
bits = 15;
|
||||||
|
}
|
||||||
|
else if (cmp < 0)
|
||||||
|
{
|
||||||
|
for (int i = bits; i < (1 << TRIE_STEP); i++)
|
||||||
|
{
|
||||||
|
const struct f_trie_node *tmp = GET_CHILD(n, v4, i);
|
||||||
|
if (!tmp) continue;
|
||||||
|
if (v4 ? ip4_compare(tmp->v4.addr, net4->prefix) > 0
|
||||||
|
: ip6_compare(tmp->v6.addr, net6->prefix) > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
child = tmp;
|
||||||
|
}
|
||||||
|
bits = 15;
|
||||||
|
}
|
||||||
|
else /* cmp > 0 */
|
||||||
|
bits = 0;
|
||||||
|
|
||||||
|
s->stack_pos++;
|
||||||
|
s->stack[s->stack_pos] = n = child;
|
||||||
|
child = GET_CHILD(child, v4, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlen = (v4) ? n->v4.plen : n->v6.plen;
|
||||||
|
cmp = v4 ? ip4_compare(n->v4.addr, net4->prefix)
|
||||||
|
: ip6_compare(n->v6.addr, net6->prefix);
|
||||||
|
|
||||||
|
s->accept_length = nlen;
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
bits = GET_NET_BITS(net, v4, nlen, TRIE_STEP);
|
||||||
|
if (plen - nlen >= TRIE_STEP)
|
||||||
|
{
|
||||||
|
s->local_pos = SELECT_CHILD(bits, TRIE_STEP);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 1;
|
||||||
|
for (int i = 0; i < net->pxlen - plen; i++)
|
||||||
|
{
|
||||||
|
if (bits & (1u << (TRIE_STEP - i - 1)))
|
||||||
|
pos = 2 * pos + 1;
|
||||||
|
else
|
||||||
|
pos = 2 * pos;
|
||||||
|
}
|
||||||
|
s->local_pos = pos;
|
||||||
|
}
|
||||||
|
else if (cmp < 0)
|
||||||
|
{
|
||||||
|
s->local_pos = SELECT_CHILD(bits, TRIE_STEP);
|
||||||
|
}
|
||||||
|
else /* cmp > 0 */
|
||||||
|
{
|
||||||
|
/* Everything already set */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_ACCEPT_BIT(N,X,B) ((X) ? ip4_getbit((N)->v4.accept, (B)) : ip6_getbit((N)->v6.accept, (B)))
|
#define GET_ACCEPT_BIT(N,X,B) ((X) ? ip4_getbit((N)->v4.accept, (B)) : ip6_getbit((N)->v6.accept, (B)))
|
||||||
|
@ -259,10 +259,6 @@ make_random_prefix_list(int num, int v6, int tight)
|
|||||||
struct f_prefix_node *px = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
|
struct f_prefix_node *px = lp_allocz(tmp_linpool, sizeof(struct f_prefix_node));
|
||||||
get_random_prefix(&px->prefix, v6, tight);
|
get_random_prefix(&px->prefix, v6, tight);
|
||||||
add_tail(prefixes, &px->n);
|
add_tail(prefixes, &px->n);
|
||||||
|
|
||||||
char buf[64];
|
|
||||||
bt_format_net(buf, 64, &px->prefix.net);
|
|
||||||
bt_debug("ADD %s{%d,%d}\n", buf, px->prefix.lo, px->prefix.hi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefixes;
|
return prefixes;
|
||||||
@ -313,10 +309,6 @@ read_prefix_list(FILE *f, int v6, int plus)
|
|||||||
px->prefix.lo = pl;
|
px->prefix.lo = pl;
|
||||||
px->prefix.hi = plus ? IP4_MAX_PREFIX_LENGTH : pl;
|
px->prefix.hi = plus ? IP4_MAX_PREFIX_LENGTH : pl;
|
||||||
add_tail(pxlist, &px->n);
|
add_tail(pxlist, &px->n);
|
||||||
|
|
||||||
char buf[64];
|
|
||||||
bt_format_net(buf, 64, &px->prefix.net);
|
|
||||||
bt_debug("ADD %s{%d,%d}\n", buf, px->prefix.lo, px->prefix.hi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_syscall(errno, "fgets()");
|
bt_syscall(errno, "fgets()");
|
||||||
@ -649,17 +641,89 @@ log_networks(const net_addr *a, const net_addr *b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_walk_return_val(struct f_trie *trie, struct f_prefix pxset[], uint count, int include)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
net_addr net;
|
||||||
|
get_random_net(&net, !trie->ipv4);
|
||||||
|
struct f_trie_walk_state tws;
|
||||||
|
bt_assert(!trie_walk_init(&tws, trie, &net, include));
|
||||||
|
|
||||||
|
net_addr res;
|
||||||
|
bt_assert(!trie_walk_next(&tws, &res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 index = xrandom(count);
|
||||||
|
net_addr *tested = &pxset[index].net;
|
||||||
|
|
||||||
|
net_addr res;
|
||||||
|
struct f_trie_walk_state tws;
|
||||||
|
bt_assert(trie_walk_init(&tws, trie, tested, include)); /* return true */
|
||||||
|
bt_assert(trie_walk_next(&tws, &res));
|
||||||
|
bt_assert(net_equal(tested, &res));
|
||||||
|
|
||||||
|
net_addr rand_net;
|
||||||
|
get_random_net(&rand_net, !trie->ipv4);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (net_equal(&pxset[i].net, &rand_net))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
memset(&tws, 0, sizeof(tws));
|
||||||
|
bt_assert(!trie_walk_init(&tws, trie, &rand_net, include)); /* return false */
|
||||||
|
|
||||||
|
if (include)
|
||||||
|
{
|
||||||
|
if (net_compare(&pxset[count - 1].net, &rand_net) < 0)
|
||||||
|
bt_assert(!trie_walk_next(&tws, &res));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bt_assert(trie_walk_next(&tws, &res));
|
||||||
|
bt_assert(net_compare(&rand_net, &res) < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 pos;
|
||||||
|
for (pos = 0; pos < count; pos++)
|
||||||
|
if (net_compare(&pxset[pos].net, &rand_net) > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos < count && net_in_netX(&pxset[pos].net, &rand_net))
|
||||||
|
{
|
||||||
|
bt_assert(trie_walk_next(&tws, &res));
|
||||||
|
bt_assert(net_equal(&pxset[pos].net, &res));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bt_assert(!trie_walk_next(&tws, &res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
t_trie_walk(void)
|
t_trie_walk(void)
|
||||||
{
|
{
|
||||||
bt_bird_init();
|
bt_bird_init();
|
||||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||||
|
|
||||||
|
unsigned long r = rand();
|
||||||
|
log("random seed for t_trie_walk is %lu", r);
|
||||||
|
srandom(r);
|
||||||
|
//srandom(732437807);
|
||||||
|
//srandom(1182332329);
|
||||||
|
|
||||||
for (int round = 0; round < TESTS_NUM*8; round++)
|
for (int round = 0; round < TESTS_NUM*8; round++)
|
||||||
{
|
{
|
||||||
int level = round / TESTS_NUM;
|
int level = round / TESTS_NUM;
|
||||||
int v6 = level % 2;
|
int v6 = level % 2;
|
||||||
int num = PREFIXES_NUM * (int[]){1, 10, 100, 1000}[level / 2];
|
int num = PREFIXES_NUM * (int[]){0, 1, 10, 100, 1000}[level / 2];
|
||||||
int pos = 0, end = 0;
|
int pos = 0, end = 0;
|
||||||
list *prefixes = make_random_prefix_list(num, v6, 1);
|
list *prefixes = make_random_prefix_list(num, v6, 1);
|
||||||
struct f_trie *trie = make_trie_from_prefix_list(prefixes);
|
struct f_trie *trie = make_trie_from_prefix_list(prefixes);
|
||||||
@ -672,6 +736,8 @@ t_trie_walk(void)
|
|||||||
|
|
||||||
qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes);
|
qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes);
|
||||||
|
|
||||||
|
/* Test trie_walk_init() return value */
|
||||||
|
test_walk_return_val(trie, pxset, num, 0);
|
||||||
|
|
||||||
/* Full walk */
|
/* Full walk */
|
||||||
bt_debug("Full walk (round %d, %d nets)\n", round, num);
|
bt_debug("Full walk (round %d, %d nets)\n", round, num);
|
||||||
@ -696,13 +762,19 @@ t_trie_walk(void)
|
|||||||
bt_assert(pxc == trie->prefix_count);
|
bt_assert(pxc == trie->prefix_count);
|
||||||
bt_debug("Full walk done\n");
|
bt_debug("Full walk done\n");
|
||||||
|
|
||||||
|
|
||||||
/* Prepare net for subnet walk - start with random prefix */
|
/* Prepare net for subnet walk - start with random prefix */
|
||||||
pos = bt_random() % num;
|
if (num)
|
||||||
|
pos = xrandom(num);
|
||||||
|
else
|
||||||
|
pos = 0;
|
||||||
end = pos + (int[]){2, 2, 3, 4}[level / 2];
|
end = pos + (int[]){2, 2, 3, 4}[level / 2];
|
||||||
end = MIN(end, num);
|
end = MIN(end, num);
|
||||||
|
|
||||||
struct f_prefix from = pxset[pos];
|
struct f_prefix from;
|
||||||
|
if (num)
|
||||||
|
from = pxset[pos];
|
||||||
|
else
|
||||||
|
get_random_prefix(&from, v6, 1);
|
||||||
|
|
||||||
/* Find a common superprefix to several subsequent prefixes */
|
/* Find a common superprefix to several subsequent prefixes */
|
||||||
for (; pos < end; pos++)
|
for (; pos < end; pos++)
|
||||||
@ -880,6 +952,425 @@ t_trie_walk_to_root(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
test_walk_init(struct f_trie *trie, u32 in_px, u32 in_plen, u32 res_px, u32 res_plen, int has_next)
|
||||||
|
{
|
||||||
|
net_addr_ip4 net = NET_ADDR_IP4(ip4_from_u32(in_px), in_plen);
|
||||||
|
struct f_trie_walk_state tws;
|
||||||
|
/* return value of trie_walk_init() is tested elsewhere */
|
||||||
|
trie_walk_init(&tws, trie, (struct net_addr *) &net, 1);
|
||||||
|
net_addr res;
|
||||||
|
int b = trie_walk_next(&tws, &res);
|
||||||
|
bt_assert(b == has_next);
|
||||||
|
if (has_next)
|
||||||
|
{
|
||||||
|
net_addr_ip4 expected = NET_ADDR_IP4(ip4_from_u32(res_px), res_plen);
|
||||||
|
bt_assert(net_equal_ip4((struct net_addr_ip4 *) &res, &expected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a very simplistic and deterministic test suite to test all reasoable code paths in
|
||||||
|
* trie_walk_init()
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
t_trie_walk_determ(void)
|
||||||
|
{
|
||||||
|
bt_bird_init();
|
||||||
|
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||||
|
|
||||||
|
#define EDGE_CASE_COUNT 7
|
||||||
|
list *prefixes[EDGE_CASE_COUNT] = { 0 };
|
||||||
|
struct f_trie *tries[EDGE_CASE_COUNT] = { 0 };
|
||||||
|
|
||||||
|
bt_debug("Reading data from 'filter/trie-data-edge'\n");
|
||||||
|
int n = read_prefix_file("filter/trie-data-edge", 0, prefixes, tries);
|
||||||
|
bt_debug("Read data from 'trie-data-edge' %d lists\n", n);
|
||||||
|
|
||||||
|
if (n < EDGE_CASE_COUNT)
|
||||||
|
{
|
||||||
|
bt_debug("Loaded less lists than expected!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_walk_init(tries[0], 100663296, 7 /* 6.0.0.0/7 */, 297795584, 12 /* 17.192.0.0/12 */, 1);
|
||||||
|
test_walk_init(tries[0], 201326592, 12 /* 12.0.0.0/12 */, 297795584, 12 /* 17.192.0.0/12 */, 1);
|
||||||
|
test_walk_init(tries[0], 297795584, 14 /* 17.192.0.0/14 */, 297811968, 18 /* 17.192.64.00/18 */, 1);
|
||||||
|
test_walk_init(tries[0], 297795584, 18 /* 17.192.0.0/24 */, 297811968, 18 /* 17.192.64.00/18 */, 1);
|
||||||
|
test_walk_init(tries[0], 297798400, 24 /* 17.192.11.0/24 */, 297811968, 18 /* 17.192.64.0/18 */, 1);
|
||||||
|
test_walk_init(tries[0], 297811968, 28 /* 17.192.64.0/28 */, 297811984, 28 /* 17.192.64.16/28 */, 1);
|
||||||
|
test_walk_init(tries[0], 297811980, 31 /* 17.192.64.12/31 */, 297811984, 28 /* 17.192.64.16/28 */, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
* Tests on left leaning trie
|
||||||
|
*/
|
||||||
|
struct f_trie *left = tries[1];
|
||||||
|
test_walk_init(left, 0, 4 /* 0.0.0.0/4 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 0, 12 /* 0.0.0.0/12 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 0, 24 /* 0.0.0.0/24 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 0, 32 /* 0.0.0.0/32 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 16777216, 12 /* 1.0.0.0/12 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 16777216, 14 /* 1.0.0.0/14 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16777216, 16 /* 1.0.0.0/16 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16777216, 18 /* 1.0.0.0/18 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 18 /* 1.1.0.0/18 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 20 /* 1.1.0.0/20 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 24 /* 1.1.0.0/24 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 28 /* 1.1.0.0/28 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 30 /* 1.1.0.0/30 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16842753, 32 /* 1.1.0.0/32 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
|
||||||
|
/* longest path or it's extension */
|
||||||
|
test_walk_init(left, 16843009, 28 /* 1.1.1.0/28 */, 16843008, 28 /* 1.1.1.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843009, 30 /* 1.1.1.0/30 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843009, 32 /* 1.1.1.0/32 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
|
||||||
|
/* prefixes `after' longest path */
|
||||||
|
test_walk_init(left, 16843264, 23 /* 1.1.2.0/23 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843264, 24 /* 1.1.2.0/24 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843264, 26 /* 1.1.2.0/26 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843264, 28 /* 1.1.2.0/28 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843264, 32 /* 1.1.2.0/32 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843521, 28 /* 1.1.3.0/28 */, 16843520, 28 /* 1.1.3.0/28 */, 1);
|
||||||
|
|
||||||
|
/* extension of longest path */
|
||||||
|
test_walk_init(left, 16843521, 30 /* 1.1.3.0/30 */, 16844032, 28 /* 1.1.5.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16843521, 32 /* 1.1.3.0/32 */, 16844032, 28 /* 1.1.5.0/28 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 16844544, 28 /* 1.1.7.0/28 */, 16844544, 28 /* 1.1.7.0/28 */, 1);
|
||||||
|
test_walk_init(left, 16844544, 30 /* 1.1.7.0/30 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16844544, 32 /* 1.1.7.0/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 16844801, 24 /* 1.1.8.0/24 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16844801, 28 /* 1.1.8.0/28 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16844801, 32 /* 1.1.8.0/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 16908290, 16 /* 1.2.0.0/16 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 18 /* 1.2.0.0/18 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 22 /* 1.2.0.0/22 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 24 /* 1.2.0.0/24 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 28 /* 1.2.0.0/28 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 30 /* 1.2.0.0/30 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16908290, 32 /* 1.2.0.0/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 16973827, 18 /* 1.3.0.0/18 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 20 /* 1.3.0.0/20 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 22 /* 1.3.0.0/22 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 24 /* 1.3.0.0/24 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 28 /* 1.3.0.0/28 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 30 /* 1.3.0.0/30 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16973827, 32 /* 1.3.0.0/32 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 33554432, 9 /* 2.0.0.0/9 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 12 /* 2.0.0.0/12 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 14 /* 2.0.0.0/14 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 18 /* 2.0.0.0/18 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 22 /* 2.0.0.0/22 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 28 /* 2.0.0.0/28 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 30 /* 2.0.0.0/30 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 33554432, 32 /* 2.0.0.0/32 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 50659333, 18 /* 3.5.0.0/18 */, 50659328, 18 /* 3.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 50659333, 19 /* 3.5.0.0/19 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 50659333, 32 /* 3.5.0.0/32 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 50659589, 30 /* 3.5.1.0/30 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 50659845, 32 /* 3.5.2.0/32 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 50724870, 16 /* 3.6.0.0/16 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 50724870, 18 /* 3.6.0.0/18 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 67108864, 6 /* 4.0.0.0/6 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 12 /* 4.0.0.0/12 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 14 /* 4.0.0.0/14 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 18 /* 4.0.0.0/18 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 20 /* 4.0.0.0/20 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 28 /* 4.0.0.0/28 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 30 /* 4.0.0.0/30 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 67108864, 32 /* 4.0.0.0/32 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 83886080, 10 /* 5.0.0.0/10 */, 83886080, 12 /* 5.0.0.0/12 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 83886080, 14 /* 5.0.0.0/14 */, 83951616, 28 /* 5.1.0.0/28 */, 1);
|
||||||
|
test_walk_init(left, 83886080, 28 /* 5.0.0.0/28 */, 83951616, 28 /* 5.1.0.0/28 */, 1);
|
||||||
|
test_walk_init(left, 83886080, 30 /* 5.0.0.0/30 */, 83951616, 28 /* 5.1.0.0/28 */, 1);
|
||||||
|
test_walk_init(left, 83886080, 32 /* 5.0.0.0/32 */, 83951616, 28 /* 5.1.0.0/28 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 83951617, 30 /* 5.1.0.0/30 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 83951617, 32 /* 5.1.0.0/32 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 84017154, 32 /* 5.2.0.0/32 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 8 /* 6.0.0.0/8 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 12 /* 6.0.0.0/12 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 16 /* 6.0.0.0/16 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 18 /* 6.0.0.0/18 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 22 /* 6.0.0.0/22 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 100663296, 32 /* 6.0.0.0/32 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 117440512, 9 /* 7.0.0.0/9 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 117440512, 12 /* 7.0.0.0/12 */, 117440512, 12 /* 7.0.0.0/12 */, 1);
|
||||||
|
|
||||||
|
test_walk_init(left, 117440512, 13 /* 7.0.0.0/13 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 117440512, 23 /* 7.0.0.0/23 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 117440512, 32 /* 7.0.0.0/32 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 117506049, 20 /* 7.1.0.0/20 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 117506049, 32 /* 7.1.0.0/32 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 134217728, 9 /* 8.0.0.0/9 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 134217728, 14 /* 8.0.0.0/14 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 134283265, 32 /* 8.1.0.0/32 */, 0, 0 /* N/A */, 0);
|
||||||
|
|
||||||
|
test_walk_init(left, 4194368, 24 /* 0.64.0.0/24 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 4196160, 24 /* 0.64.7.0/24 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 4229952, 25 /* 0.64.139.0/25 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 4259648, 26 /* 0.64.255.0/26 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 8388736, 24 /* 0.128.0.0/24 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 8390528, 25 /* 0.128.7.0/25 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 8450176, 22 /* 0.128.240.0/22 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 8453760, 23 /* 0.128.254.0/23 */, 16777216, 12 /* 1.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left,2147483648, 3 /* 128.0.0.0/3 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left,2147483648, 9 /* 128.0.0.0/9 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left,2148597777, 25 /* 128.17.0.0/25 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 20971584, 23 /* 1.64.0.0/23 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 20973376, 24 /* 1.64.7.0/24 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 21007168, 24 /* 1.64.139.0/24 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 25230976, 23 /* 1.128.254.0/23 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 16859137, 30 /* 1.1.64.0/30 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16859137, 32 /* 1.1.64.7/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16859137, 32 /* 1.1.64.138/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16859137, 31 /* 1.1.64.240/31 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16875521, 29 /* 1.1.128.0/29 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16875521, 32 /* 1.1.128.7/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16875521, 29 /* 1.1.128.240/29 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16875521, 31 /* 1.1.128.254/31 */, 16973824, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16990211, 25 /* 1.3.64.0/25 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16990211, 32 /* 1.3.64.7/32 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16990211, 29 /* 1.3.64.240/29 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16990211, 31 /* 1.3.64.254/31 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 17006595, 26 /* 1.3.128.0/26 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 17006595, 32 /* 1.3.128.7/32 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 17006595, 29 /* 1.3.128.240/29 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 17006595, 31 /* 1.3.128.254/31 */, 17104896, 18 /* 1.5.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 17252359, 26 /* 1.7.64.0/26 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17252359, 32 /* 1.7.64.7/32 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17252359, 28 /* 1.7.64.240/28 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17252359, 31 /* 1.7.64.254/31 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17268743, 25 /* 1.7.128.0/25 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17268743, 32 /* 1.7.128.7/32 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17268743, 29 /* 1.7.128.240/29 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17268743, 31 /* 1.7.128.254/31 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 125829120, 9 /* 7.128.0.0/9 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(left, 125829120, 12 /* 7.128.0.0/12 */, 0, 0 /* N/A */, 0);
|
||||||
|
|
||||||
|
/* corner cases */
|
||||||
|
test_walk_init(left, 17825792, 16 /* 1.16.0.0/16 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 17825792, 24 /* 1.16.0.0/24 */, 50331648, 12 /* 3.0.0.0/12 */, 1);
|
||||||
|
test_walk_init(left, 16846848, 24 /* 1.1.16.0/24 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16846848, 32 /* 1.1.16.0/32 */, 16973824, 18 /* 1.3.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16777472, 24 /* 1.0.1.0/24 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
test_walk_init(left, 16781312, 19 /* 1.0.16.0/19 */, 16842752, 18 /* 1.1.0.0/18 */, 1);
|
||||||
|
|
||||||
|
struct f_trie *corner = tries[3];
|
||||||
|
test_walk_init(corner,16777216, 12 /* 1.0.0.0/12 */, 16842752, 16 /* 1.1.0.0/16 */, 1);
|
||||||
|
test_walk_init(corner,16908288, 32 /* 1.2.0.0/32 */, 18874368, 12 /* 1.32.0.0/12 */, 1);
|
||||||
|
|
||||||
|
struct f_trie *with_zero = tries[4];
|
||||||
|
test_walk_init(with_zero, 50529027, 32 /* 3.3.3.3/32 */, 4294967295, 32 /* 255.255.255.255/32 */, 1);
|
||||||
|
|
||||||
|
struct f_trie *two_px = tries[5];
|
||||||
|
test_walk_init(two_px, 0, 0 /* 0.0.0.0/0 */, 0, 0 /* 0.0.0.0/0 */, 1);
|
||||||
|
test_walk_init(two_px, 1, 32 /* 0.0.0.1/32 */, 2066546688, 16 /* 123.45.0.0/16 */, 1);
|
||||||
|
test_walk_init(two_px, 3355443200, 8 /* 200.0.0.0/8 */, 0, 0 /* N/A */, 0);
|
||||||
|
test_walk_init(two_px, 50529027, 32 /* 3.3.3.3/32 */, 2066546688, 16 /* 123.45.0.0/16 */, 1);
|
||||||
|
|
||||||
|
struct f_trie *root_only = tries[6];
|
||||||
|
test_walk_init(root_only, 50529027, 32 /* 3.3.3.3/32 */, 0, 0 /* N/A */, 0);
|
||||||
|
|
||||||
|
bt_bird_cleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
t_trie_walk_inclusive(void)
|
||||||
|
{
|
||||||
|
bt_bird_init();
|
||||||
|
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||||
|
|
||||||
|
unsigned long r = rand();
|
||||||
|
log("random seed for t_trie_walk_inclusive is %lu", r);
|
||||||
|
srandom(r);
|
||||||
|
//srandom(1325299055);
|
||||||
|
//srandom(25273275);
|
||||||
|
//srandom(1959294931);
|
||||||
|
//srandom(1182332329);
|
||||||
|
|
||||||
|
for (int round = 0; round < TESTS_NUM*8; round++)
|
||||||
|
{
|
||||||
|
int level = round / TESTS_NUM;
|
||||||
|
int v6 = level % 2;
|
||||||
|
int num = PREFIXES_NUM * (int[]){0, 1, 10, 100, 1000}[level / 2];
|
||||||
|
int pos = 0, end = 0;
|
||||||
|
list *prefixes = make_random_prefix_list(num, v6, 1);
|
||||||
|
struct f_trie *trie = make_trie_from_prefix_list(prefixes);
|
||||||
|
struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix));
|
||||||
|
|
||||||
|
struct f_prefix_node *n;
|
||||||
|
WALK_LIST(n, *prefixes)
|
||||||
|
pxset[pos++] = n->prefix;
|
||||||
|
memset(&pxset[pos], 0, sizeof (struct f_prefix));
|
||||||
|
|
||||||
|
qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes);
|
||||||
|
|
||||||
|
/* Test trie_walk_init() return value */
|
||||||
|
test_walk_return_val(trie, pxset, num, 1);
|
||||||
|
|
||||||
|
/* Full walk */
|
||||||
|
bt_debug("Full walk inclusive (round %d, %d nets)\n", round, num);
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
uint pxc = 0;
|
||||||
|
/* Last argument should have no effect on the walk */
|
||||||
|
TRIE_WALK2(trie, net, NULL, 1)
|
||||||
|
{
|
||||||
|
log_networks(&net, &pxset[pos].net);
|
||||||
|
bt_assert(net_equal(&net, &pxset[pos].net));
|
||||||
|
|
||||||
|
/* Skip possible duplicates */
|
||||||
|
while (net_equal(&pxset[pos].net, &pxset[pos + 1].net))
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
pxc++;
|
||||||
|
}
|
||||||
|
TRIE_WALK2_END;
|
||||||
|
|
||||||
|
bt_assert(pos == num);
|
||||||
|
bt_assert(pxc == trie->prefix_count);
|
||||||
|
bt_debug("Full walk inclusive done\n");
|
||||||
|
|
||||||
|
/* Prepare net for subnet walk - start with random prefix from trie */
|
||||||
|
if (num)
|
||||||
|
pos = xrandom(num);
|
||||||
|
else
|
||||||
|
pos = 0;
|
||||||
|
end = pos + (int[]){2, 2, 3, 4}[level / 2];
|
||||||
|
end = MIN(end, num);
|
||||||
|
|
||||||
|
struct f_prefix from;
|
||||||
|
if (num)
|
||||||
|
from = pxset[pos];
|
||||||
|
else
|
||||||
|
get_random_prefix(&from, v6, 1);
|
||||||
|
|
||||||
|
/* Find a common superprefix to several subsequent prefixes */
|
||||||
|
for (; pos < end; pos++)
|
||||||
|
{
|
||||||
|
if (net_equal(&from.net, &pxset[pos].net))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int common = !v6 ?
|
||||||
|
ip4_pxlen(net4_prefix(&from.net), net4_prefix(&pxset[pos].net)) :
|
||||||
|
ip6_pxlen(net6_prefix(&from.net), net6_prefix(&pxset[pos].net));
|
||||||
|
from.net.pxlen = MIN(from.net.pxlen, common);
|
||||||
|
|
||||||
|
if (!v6)
|
||||||
|
((net_addr_ip4 *) &from.net)->prefix =
|
||||||
|
ip4_and(net4_prefix(&from.net), net4_prefix(&pxset[pos].net));
|
||||||
|
else
|
||||||
|
((net_addr_ip6 *) &from.net)->prefix =
|
||||||
|
ip6_and(net6_prefix(&from.net), net6_prefix(&pxset[pos].net));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix irrelevant bits */
|
||||||
|
if (!v6)
|
||||||
|
((net_addr_ip4 *) &from.net)->prefix =
|
||||||
|
ip4_and(net4_prefix(&from.net), ip4_mkmask(net4_pxlen(&from.net)));
|
||||||
|
else
|
||||||
|
((net_addr_ip6 *) &from.net)->prefix =
|
||||||
|
ip6_and(net6_prefix(&from.net), ip6_mkmask(net6_pxlen(&from.net)));
|
||||||
|
|
||||||
|
|
||||||
|
/* Find initial position for final prefix */
|
||||||
|
for (pos = 0; pos < num; pos++)
|
||||||
|
if (compare_prefixes(&pxset[pos], &from) >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int p0 = pos;
|
||||||
|
char buf0[64];
|
||||||
|
bt_format_net(buf0, 64, &from.net);
|
||||||
|
bt_debug("Subnet walk inclusive for %s (round %d, %d nets)\n", buf0, round, num);
|
||||||
|
|
||||||
|
/* Subnet walk */
|
||||||
|
TRIE_WALK2(trie, net, &from.net, 1)
|
||||||
|
{
|
||||||
|
bt_assert(net_compare(&net, &pxset[pos].net) >= 0);
|
||||||
|
bt_assert(net_compare(&net, &from.net) >= 0);
|
||||||
|
|
||||||
|
if (!net_equal(&net, &pxset[pos + 1].net) || !(net_compare(&net, &from.net) >= 0))
|
||||||
|
{
|
||||||
|
/* Make sure that net is from inserted prefixes */
|
||||||
|
bt_format_net(buf0, 64, &net);
|
||||||
|
bt_debug("got: %s", buf0);
|
||||||
|
bt_format_net(buf0, 64, &pxset[pos].net);
|
||||||
|
bt_debug(" expected %s", buf0);
|
||||||
|
if (pos + 1 < num)
|
||||||
|
{
|
||||||
|
bt_format_net(buf0, 64, &pxset[pos + 1].net);
|
||||||
|
bt_debug(" (next: %s)\n", buf0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bt_debug("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_assert(net_equal(&net, &pxset[pos].net));
|
||||||
|
bt_assert(net_compare(&net, &from.net) >= 0);
|
||||||
|
|
||||||
|
|
||||||
|
/* Skip possible duplicates */
|
||||||
|
while (net_equal(&pxset[pos].net, &pxset[pos + 1].net))
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
}
|
||||||
|
TRIE_WALK2_END;
|
||||||
|
|
||||||
|
|
||||||
|
bt_debug("pos == num %u %u; p0 %u \n", pos, num, p0);
|
||||||
|
bt_debug("Subnet walk done inclusive for %s (found %d nets)\n", buf0, pos - p0);
|
||||||
|
bt_assert(pos == num);
|
||||||
|
|
||||||
|
/* Prepare net for subnet walk - start with random prefix (likely not from trie) */
|
||||||
|
get_random_prefix(&from, v6, 1);
|
||||||
|
|
||||||
|
for (pos = 0; pos < num; pos++)
|
||||||
|
if (compare_prefixes(&pxset[pos], &from) >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p0 = pos;
|
||||||
|
bt_format_net(buf0, 64, &from.net);
|
||||||
|
bt_debug("Subnet walk inclusive for random %s (round %d, %d nets)\n", buf0, round, num);
|
||||||
|
|
||||||
|
/* Subnet walk */
|
||||||
|
TRIE_WALK2(trie, net, &from.net, 1)
|
||||||
|
{
|
||||||
|
bt_assert(net_equal(&net, &pxset[pos].net));
|
||||||
|
bt_assert(net_compare(&net, &from.net) >= 0);
|
||||||
|
|
||||||
|
while (net_equal(&pxset[pos].net, &pxset[pos + 1].net))
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
TRIE_WALK2_END;
|
||||||
|
|
||||||
|
bt_debug("Subnet walk inclusive for random %s (found %d nets from %d)\n", buf0, pos - p0, num - p0);
|
||||||
|
bt_assert(pos == num);
|
||||||
|
|
||||||
|
tmp_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_bird_cleanup();
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -891,6 +1382,8 @@ main(int argc, char *argv[])
|
|||||||
bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward.");
|
bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward.");
|
||||||
bt_test_suite(t_trie_walk, "Testing TRIE_WALK() on random tries");
|
bt_test_suite(t_trie_walk, "Testing TRIE_WALK() on random tries");
|
||||||
bt_test_suite(t_trie_walk_to_root, "Testing TRIE_WALK_TO_ROOT() on random tries");
|
bt_test_suite(t_trie_walk_to_root, "Testing TRIE_WALK_TO_ROOT() on random tries");
|
||||||
|
bt_test_suite(t_trie_walk_inclusive, "Testing TRIE_WALK2() on random tries");
|
||||||
|
bt_test_suite(t_trie_walk_determ, "Testing trie_walk_init() on edge case tries deterministically");
|
||||||
|
|
||||||
// bt_test_suite(t_bench_trie_datasets_subset, "Benchmark tries from datasets by random subset of nets");
|
// bt_test_suite(t_bench_trie_datasets_subset, "Benchmark tries from datasets by random subset of nets");
|
||||||
// bt_test_suite(t_bench_trie_datasets_random, "Benchmark tries from datasets by generated addresses");
|
// bt_test_suite(t_bench_trie_datasets_random, "Benchmark tries from datasets by generated addresses");
|
||||||
|
@ -261,7 +261,7 @@ rt_show_cont(struct cli *c)
|
|||||||
if (d->trie_walk)
|
if (d->trie_walk)
|
||||||
{
|
{
|
||||||
d->walk_lock = rt_lock_trie(tab);
|
d->walk_lock = rt_lock_trie(tab);
|
||||||
trie_walk_init(d->walk_state, tab->trie, d->addr);
|
trie_walk_init(d->walk_state, tab->trie, d->addr, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
FIB_ITERATE_INIT(&d->fit, &tab->fib);
|
FIB_ITERATE_INIT(&d->fit, &tab->fib);
|
||||||
|
Loading…
Reference in New Issue
Block a user