mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-03-11 17:08:46 +00:00
The BIRD protocol SNMP makes it possible to retrieve management information through SNMP. This is accomplished by implementing AgentX protocol. The BIRD acts as an AgentX subagent, registers to master agent and provides management information. Master agent handles SNMP communication and forwards request to registered subagents. You will therefore need an additional component -- a SNMP daemon capable of acting as AgentX master agent. In theory, the information consumer don't have to support SNMP and could be very simple master agent for logging/monitoring the BIRD state. For more detail see provided documentation. This commit is squashed version of development history. Full development history could be found on branch `proto-snmp'.
1966 lines
48 KiB
C
1966 lines
48 KiB
C
/*
|
|
* BIRD -- Simple Network Management Protocol (SNMP) Unit tests
|
|
*
|
|
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
|
* (c) 2022 CZ.NIC z.s.p.o
|
|
*
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "test/birdtest.h"
|
|
#include "test/bt-utils.h"
|
|
|
|
#include "bgp4_mib.h"
|
|
#include "subagent.h"
|
|
#include "snmp.h"
|
|
#include "snmp_utils.h"
|
|
#include "mib_tree.h"
|
|
|
|
static int t_oid_empty(void);
|
|
static int t_oid_compare(void);
|
|
static int t_varbind_name_to_tx(void);
|
|
static int t_walk_oid_desc(void);
|
|
static int t_walk_oid_compare(void);
|
|
static int t_tree_find(void);
|
|
static int t_tree_traversal(void);
|
|
static int t_tree_leafs(void);
|
|
static int t_tree_add(void);
|
|
static int t_tree_delete(void);
|
|
|
|
#define SNMP_BUFFER_SIZE 1024
|
|
#define TESTS_NUM 32
|
|
#define SMALL_TESTS_NUM 10
|
|
static int tree_sizes[] = { 0, 1, 10, 100, 1000 };
|
|
|
|
/* smaller than theoretical maximum (2^32) to fit in memory */
|
|
#define OID_MAX_ID 16
|
|
|
|
#define SNMP_EXPECTED(actual, expected) \
|
|
bt_debug("%s expected: %3u actual: %3u\n", \
|
|
#expected, expected, actual);
|
|
|
|
static inline struct oid *
|
|
oid_allocate(uint size)
|
|
{
|
|
return tmp_alloc(sizeof(struct oid) + size * sizeof(u32));
|
|
}
|
|
|
|
static inline void
|
|
oid_init2(struct oid *oid, u8 n_subid, u8 prefix, u8 include, va_list ids)
|
|
{
|
|
oid->n_subid = n_subid;
|
|
oid->prefix = prefix;
|
|
oid->include = include;
|
|
oid->reserved = 0;
|
|
|
|
for (u8 i = 0; i < n_subid; i++)
|
|
{
|
|
u32 id = va_arg(ids, u32);
|
|
oid->ids[i] = id;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
oid_init(struct oid *oid, u8 n_subid, u8 prefix, u8 include, ...)
|
|
{
|
|
va_list ids;
|
|
va_start(ids, include);
|
|
oid_init2(oid, n_subid, prefix, include, ids);
|
|
va_end(ids);
|
|
}
|
|
|
|
static inline struct oid *
|
|
oid_create(u8 n_subid, u8 prefix, u8 include, ...)
|
|
{
|
|
struct oid *result = tmp_alloc(snmp_oid_size_from_len(n_subid));
|
|
va_list ids;
|
|
|
|
va_start(ids, include);
|
|
oid_init2(result, n_subid, prefix, include, ids);
|
|
va_end(ids);
|
|
|
|
return result;
|
|
}
|
|
|
|
static u32
|
|
oid_random_id(void)
|
|
{
|
|
return (bt_random() % (OID_MAX_ID));
|
|
}
|
|
|
|
static struct oid *
|
|
random_prefixed_oid(void)
|
|
{
|
|
u32 len = bt_random_n(OID_MAX_LEN + 1 - (ARRAY_SIZE(snmp_internet) + 1));
|
|
|
|
u8 prefix = (u8) bt_random_n(UINT8_MAX + 1);
|
|
|
|
if (!prefix)
|
|
return oid_create(0, 0, 0, 0);
|
|
|
|
struct oid *random = tmp_alloc(snmp_oid_size_from_len(len));
|
|
/* (bt_random_n(2) * bt_random()) has 0.5 probability to have value 0 and
|
|
* 0.5 to have random u32 (including zero) */
|
|
oid_init(random, 0, prefix, bt_random_n(2) * bt_random());
|
|
random->n_subid = len;
|
|
|
|
for (u32 id = 0; id < len; id++)
|
|
random->ids[id] = oid_random_id();
|
|
|
|
return random;
|
|
}
|
|
|
|
static struct oid *
|
|
random_no_prefix_oid(void)
|
|
{
|
|
/* probability that the random OID is prefixable is practically zero */
|
|
u32 len = bt_random_n(OID_MAX_LEN + 1);
|
|
|
|
struct oid *random = tmp_alloc(snmp_oid_size_from_len(len));
|
|
/* (bt_random_n(2) * bt_random()) has 0.5 probability to have value 0 and
|
|
* 0.5 to have random u32 (including zero) */
|
|
oid_init(random, 0, 0, bt_random_n(2) * bt_random());
|
|
random->n_subid = len;
|
|
|
|
for (u32 id = 0; id < len; id++)
|
|
random->ids[id] = oid_random_id();
|
|
|
|
return random;
|
|
}
|
|
|
|
static struct oid *
|
|
random_prefixable_oid(void)
|
|
{
|
|
/* generate the len without the snmp_internet prefix included and prefix ID */
|
|
u32 len = bt_random_n(OID_MAX_LEN + 1 - (ARRAY_SIZE(snmp_internet) + 1));
|
|
|
|
struct oid *random = tmp_alloc(
|
|
snmp_oid_size_from_len(len + ARRAY_SIZE(snmp_internet) + 1));
|
|
/* (bt_random_n(2) * bt_random()) has 0.5 probability to have value 0 and
|
|
* 0.5 to have random u32 (including zero) */
|
|
oid_init(random, 0, 0, bt_random_n(2) * bt_random());
|
|
random->n_subid = len + ARRAY_SIZE(snmp_internet) + 1;
|
|
|
|
for (u32 inet_id = 0; inet_id < ARRAY_SIZE(snmp_internet); inet_id++)
|
|
random->ids[inet_id] = snmp_internet[inet_id];
|
|
|
|
random->ids[ARRAY_SIZE(snmp_internet)] = bt_random_n(UINT8_MAX + 1);
|
|
|
|
for (u32 id = 0; id < len; id++)
|
|
random->ids[id + ARRAY_SIZE(snmp_internet) + 1] = oid_random_id();
|
|
|
|
return random;
|
|
}
|
|
|
|
static struct oid *
|
|
random_oid(void)
|
|
{
|
|
u32 option = bt_random_n(3);
|
|
|
|
if (option == 0)
|
|
return random_prefixed_oid();
|
|
else if (option == 1)
|
|
return random_no_prefix_oid();
|
|
else
|
|
return random_prefixable_oid();
|
|
}
|
|
|
|
static int
|
|
t_oid_empty(void)
|
|
{
|
|
struct lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
bt_assert(snmp_is_oid_empty(NULL) == 0);
|
|
|
|
{
|
|
struct oid *blank = oid_create(0, 0, 0 /* no ids */);
|
|
bt_assert(snmp_is_oid_empty(blank) == 1);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
|
|
{
|
|
struct oid *prefixed = oid_create(3, 100, 1,
|
|
/* ids */ ~((u32) 0), 0, 256);
|
|
bt_assert(snmp_is_oid_empty(prefixed) == 0);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
|
|
{
|
|
struct oid *to_prefix = oid_create(8, 0, 1,
|
|
/* ids */ 1, 3, 6, 1, 100, ~((u32) 0), 0, 256);
|
|
bt_assert(snmp_is_oid_empty(to_prefix) == 0);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
|
|
{
|
|
struct oid *unprefixable = oid_create(2, 0, 0,
|
|
/* ids */ 65535, 4);
|
|
bt_assert(snmp_is_oid_empty(unprefixable) == 0);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
{
|
|
struct oid *unprefixable2 = oid_create(8, 0, 1,
|
|
/* ids */ 1, 3, 6, 2, 1, 2, 15, 6);
|
|
bt_assert(snmp_is_oid_empty(unprefixable2) == 0);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
tmp_flush();
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_oid_compare(void)
|
|
{
|
|
struct lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
/* same length, no prefix */
|
|
struct oid *l1 = oid_create(5, 0, 1,
|
|
/* ids */ 1, 2, 3, 4, 5);
|
|
|
|
struct oid *r1 = oid_create(5, 0, 0,
|
|
/* ids */ 1, 2, 3, 4, 6);
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == -1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* same results for prefixed oids */
|
|
l1->prefix = 1;
|
|
r1->prefix = 1;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == -1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* different prefix -- has higher priority */
|
|
l1->prefix = 8;
|
|
r1->prefix = 4;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == 1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == -1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
|
|
/* different length, no prefix */
|
|
l1 = oid_create(4, 0, 0,
|
|
/* ids */ 1, 2, 3, 4);
|
|
|
|
r1 = oid_create(5, 0, 1,
|
|
/* ids */ 1, 2, 3, 4, 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == -1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* same results for prefixed oids */
|
|
l1->prefix = 3;
|
|
r1->prefix = 3;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == -1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* different prefix -- has higher priority */
|
|
l1->prefix = 17;
|
|
r1->prefix = 14;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == 1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == -1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
|
|
/* inverse order different length, no prefix */
|
|
l1 = oid_create(4, 0, 0,
|
|
/* ids */ 1, 2, 3, 5);
|
|
|
|
r1 = oid_create(5, 0, 0,
|
|
/* ids */ 1, 2, 3, 4, 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == 1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == -1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* same results for prefixed oids */
|
|
l1->prefix = 254;
|
|
r1->prefix = 254;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == 1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == -1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
/* different prefix -- has higher priority */
|
|
l1->prefix = 127;
|
|
r1->prefix = 35;
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == 1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == -1);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
|
|
/* ==== MIXED PREFIXED / NON PREFIXED OID compare ==== */
|
|
/* same length, mixed */
|
|
l1 = oid_create(6, 0, 1,
|
|
/* ids */ 1, 2, 17, 3, 21, 4);
|
|
|
|
r1 = oid_create(1, 5, 1,
|
|
/* ids */ 3);
|
|
|
|
bt_assert(snmp_oid_compare(l1, r1) == -1);
|
|
bt_assert(snmp_oid_compare(r1, l1) == 1);
|
|
|
|
bt_assert(snmp_oid_compare(l1, l1) == 0);
|
|
bt_assert(snmp_oid_compare(r1, r1) == 0);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
struct oid *super = oid_create(4, 0, 0, /* ids */ 1, 3, 6, 1);
|
|
struct oid *weird = oid_create(4, 70, 0, /* ids */ 9, 10, 10, 12);
|
|
|
|
bt_assert(snmp_oid_compare(super, weird) != 0);
|
|
|
|
struct oid *pref = oid_create(0, 7, 0); // no ids, only prefix
|
|
struct oid *no_pref = oid_create(5, 0, 0, /* ids */ 1, 3, 6, 1, 7);
|
|
|
|
bt_assert(snmp_oid_compare(pref, no_pref) == 0);
|
|
|
|
struct oid *inet = oid_create(4, 0, 0, /* ids */ 1, 3, 6, 1);
|
|
|
|
bt_assert(snmp_oid_compare(inet, pref) < 0);
|
|
bt_assert(snmp_oid_compare(pref, inet) > 0);
|
|
bt_assert(snmp_oid_compare(inet, no_pref) < 0);
|
|
bt_assert(snmp_oid_compare(no_pref, inet) > 0);
|
|
|
|
struct oid *pref2 = oid_create(0, 16, 0); // no ids, only prefix
|
|
struct oid *no_pref2 = oid_create(5, 0, 0, /* ids */ 1, 3, 6, 1, 16);
|
|
|
|
bt_assert(snmp_oid_compare(pref2, no_pref2) == 0);
|
|
bt_assert(snmp_oid_compare(no_pref2, pref2) == 0);
|
|
|
|
bt_assert(snmp_oid_compare(pref, pref2) < 0);
|
|
bt_assert(snmp_oid_compare(pref2, pref) > 0);
|
|
bt_assert(snmp_oid_compare(pref, no_pref2) < 0);
|
|
bt_assert(snmp_oid_compare(no_pref2, pref) > 0);
|
|
bt_assert(snmp_oid_compare(no_pref, pref2) < 0);
|
|
bt_assert(snmp_oid_compare(pref2, no_pref) > 0);
|
|
bt_assert(snmp_oid_compare(no_pref, no_pref2) < 0);
|
|
bt_assert(snmp_oid_compare(no_pref2, no_pref) > 0);
|
|
|
|
|
|
tmp_flush();
|
|
return 1;
|
|
}
|
|
|
|
static inline void
|
|
fix_byteorder(u32 *ids, u32 len)
|
|
{
|
|
for (u32 i = 0; i < len; i++)
|
|
STORE_U32(ids[i], ids[i]);
|
|
}
|
|
|
|
int
|
|
u32cmp_bo(const u32 *cpu_native, const u32 *net_bo, u32 len)
|
|
{
|
|
for (u32 i = 0; i < len; i++)
|
|
{
|
|
if (cpu_native[i] != LOAD_U32(net_bo[i]))
|
|
return LOAD_U32(net_bo[i]) - cpu_native[i];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define CREATE_RANDOM(gen) \
|
|
({ \
|
|
struct oid *_o = gen(); \
|
|
fix_byteorder(_o->ids, _o->n_subid); \
|
|
_o; \
|
|
})
|
|
|
|
static int
|
|
t_varbind_name_to_tx(void)
|
|
{
|
|
/* Test snmp_vb_name_to_tx() */
|
|
|
|
lp_state tmps = { };
|
|
struct snmp_proto *snmp_proto = tmp_alloc(sizeof(struct snmp_proto));
|
|
memset(snmp_proto, 0, sizeof(struct snmp_proto));
|
|
sock *s = sk_new(&root_pool);
|
|
snmp_proto->sock = s;
|
|
sk_set_tbsize(s, SNMP_BUFFER_SIZE);
|
|
void *buffer = s->tbuf;
|
|
|
|
struct snmp_pdu copy = {
|
|
.p = snmp_proto,
|
|
.sr_vb_start = (void *) buffer,
|
|
.buffer = buffer,
|
|
};
|
|
struct snmp_pdu c = copy;
|
|
struct oid *new;
|
|
struct agentx_varbind *vb;
|
|
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
/* testing prefixable OIDs */
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
const struct oid *oid = CREATE_RANDOM(random_prefixable_oid);
|
|
|
|
/* both LOAD_U8() and STORE_U8() are pointless as it byteorder does not
|
|
* influence single byte values.
|
|
*/
|
|
|
|
u8 subids = oid->n_subid;
|
|
u8 include = oid->include;
|
|
u32 pid = LOAD_U32(oid->ids[ARRAY_SIZE(snmp_internet)]);
|
|
|
|
/* reset to the default snmp_pdu */
|
|
c = copy; memset(buffer, 0, snmp_oid_size(oid) + 8);
|
|
|
|
vb = snmp_vb_name_to_tx(&c, oid);
|
|
new = &vb->name;
|
|
|
|
bt_assert(new->n_subid == subids - (ARRAY_SIZE(snmp_internet) + 1));
|
|
bt_assert(new->prefix == pid);
|
|
bt_assert(!!new->include == !!include);
|
|
bt_assert(new->reserved == 0);
|
|
|
|
for (u32 i = 0; i < new->n_subid; i++)
|
|
{
|
|
bt_assert(new->ids[i] == LOAD_U32(oid->ids[i + ARRAY_SIZE(snmp_internet) + 1]));
|
|
}
|
|
|
|
for (u32 j = 0; j < ARRAY_SIZE(snmp_internet); j++)
|
|
bt_assert(LOAD_U32(oid->ids[j]) == snmp_internet[j]);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
/* testing already prefixed OIDs */
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
const struct oid *prefixed = CREATE_RANDOM(random_prefixed_oid);
|
|
|
|
/* reset to the default snmp_pdu */
|
|
c = copy; memset(buffer, 0, snmp_oid_size(prefixed) + 8);
|
|
|
|
vb = snmp_vb_name_to_tx(&c, prefixed);
|
|
new = &vb->name;
|
|
|
|
bt_assert(new->n_subid == prefixed->n_subid);
|
|
bt_assert(new->prefix == prefixed->prefix);
|
|
bt_assert(!!new->include == !!prefixed->include);
|
|
bt_assert(new->reserved == 0);
|
|
bt_assert(!u32cmp_bo(&new->ids[0], &prefixed->ids[0], new->n_subid));
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
/* testing non-prefixable OIDs */
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
const struct oid *oid = CREATE_RANDOM(random_no_prefix_oid);
|
|
|
|
/* test that the OID is _really_ not prefixable */
|
|
if (oid->n_subid > ARRAY_SIZE(snmp_internet) &&
|
|
LOAD_U32(oid->ids[ARRAY_SIZE(snmp_internet) + 1]) <= UINT8_MAX)
|
|
{
|
|
for (u32 i = 0; i < ARRAY_SIZE(snmp_internet); i++)
|
|
if (LOAD_U32(oid->ids[i]) != snmp_internet[i]) goto continue_testing;
|
|
|
|
break; /* outer for loop */
|
|
}
|
|
|
|
continue_testing:
|
|
|
|
/* reset to the default snmp_pdu */
|
|
c = copy; memset(buffer, 0, snmp_oid_size(oid) + 8);
|
|
|
|
vb = snmp_vb_name_to_tx(&c, oid);
|
|
new = &vb->name;
|
|
|
|
bt_assert(new->n_subid == oid->n_subid);
|
|
bt_assert(new->prefix == oid->prefix);
|
|
bt_assert(!!new->include == !!oid->include);
|
|
bt_assert(new->reserved == 0);
|
|
bt_assert(!u32cmp_bo(&new->ids[0], &oid->ids[0], new->n_subid));
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
for (int test = 0; test < SMALL_TESTS_NUM; test++)
|
|
{
|
|
const struct oid *oid;
|
|
{
|
|
struct oid *work = random_prefixable_oid();
|
|
fix_byteorder(work->ids, work->n_subid);
|
|
|
|
/* include also the prefix ID (at index 4) */
|
|
u32 index = bt_random_n(ARRAY_SIZE(snmp_internet) + 1);
|
|
/* change randomly picked id at index from 0..5 (included) */
|
|
u32 random = bt_random();
|
|
if (index == ARRAY_SIZE(snmp_internet) && random > 255)
|
|
work->ids[index] = VALUE_U32(random);
|
|
else if (index != ARRAY_SIZE(snmp_internet) && work->ids[index] != random)
|
|
work->ids[index] = VALUE_U32(random);
|
|
else
|
|
continue;
|
|
oid = work;
|
|
}
|
|
|
|
/* reset to the default snmp_pdu */
|
|
c = copy; memset(buffer, 0, snmp_oid_size(oid) + 8);
|
|
|
|
vb = snmp_vb_name_to_tx(&c, oid);
|
|
new = &vb->name;
|
|
|
|
bt_assert(new->n_subid == oid->n_subid);
|
|
bt_assert(new->prefix == oid->prefix);
|
|
bt_assert(!!new->include == !!oid->include);
|
|
bt_assert(new->reserved == 0);
|
|
bt_assert(!u32cmp_bo(&new->ids[0], &oid->ids[0], new->n_subid));
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
rfree(snmp_proto->sock);
|
|
tmp_flush();
|
|
return 1;
|
|
}
|
|
|
|
static inline void
|
|
walk_to_oid_one(pool *pool, const struct oid *oid)
|
|
{
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree);
|
|
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
|
|
(void) mib_tree_add(pool, tree, oid, bt_random_n(2));
|
|
mib_tree_find(tree, &walk, oid);
|
|
|
|
char buf[1024];
|
|
struct oid *from_walk = (struct oid *) buf;
|
|
|
|
int r = mib_tree_walk_to_oid(&walk, from_walk,
|
|
(1024 - sizeof(struct oid)) / sizeof(u32));
|
|
|
|
/* the memory limit should not be breached */
|
|
bt_assert(r == 0);
|
|
|
|
bt_assert(snmp_oid_compare(from_walk, oid) == 0);
|
|
|
|
/* cleanup */
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
/* test MIB tree walk to OID */
|
|
static int
|
|
t_walk_to_oid(void)
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
|
|
walk_to_oid_one(pool, random_prefixed_oid());
|
|
walk_to_oid_one(pool, random_no_prefix_oid());
|
|
walk_to_oid_one(pool, random_prefixable_oid());
|
|
/* only a one of above */
|
|
//walk_to_oid_one(random_oid);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
tmp_flush();
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void
|
|
test_both(void *buffer, uint size, const struct oid *left, const struct oid
|
|
*right, const struct oid *expected)
|
|
{
|
|
memset(buffer, 0, size);
|
|
snmp_oid_common_ancestor(left, right, buffer);
|
|
bt_assert(snmp_oid_compare(buffer, expected) == 0);
|
|
|
|
memset(buffer, 0, size);
|
|
snmp_oid_common_ancestor(right, left, buffer);
|
|
bt_assert(snmp_oid_compare(buffer, expected) == 0);
|
|
}
|
|
|
|
#define TEST_BOTH(l, r, e) test_both(buffer, 1024, l, r, e)
|
|
static int
|
|
t_oid_ancestor(void)
|
|
{
|
|
const struct oid *null = oid_create(0, 0, 0);
|
|
const struct oid *shorter = oid_create(3, 15, 0, /* ids */ 192, 1, 7);
|
|
const struct oid *prefixed = oid_create(4, 15, 0, /* ids */ 192, 1, 7, 82);
|
|
const struct oid *no_prefix = oid_create(9, 0, 0, /* ids */ 1, 3, 6, 1, 15, 192, 1, 7, 82);
|
|
const struct oid *outside = oid_create(7, 0, 0, /* ids */ 4, 3, 2, 1, 8, 0, 2);
|
|
const struct oid *prefix_only = oid_create(0, 15, 0);
|
|
const struct oid *prefix_only2 = oid_create(0, 9, 0);
|
|
const struct oid *partial = oid_create(3, 0, 0, /* ids */ 1, 3, 6);
|
|
const struct oid *no_inet = oid_create(5, 0, 0, /* ids */ 1, 3, 6, 2, 5);
|
|
|
|
const struct oid *inet = oid_create(4, 0, 0, /* ids */ 1, 3, 6, 1);
|
|
|
|
|
|
const struct oid *oids[] = {
|
|
null, shorter, prefixed, no_prefix, outside, prefix_only, partial, no_inet, inet
|
|
};
|
|
|
|
char buffer[1024];
|
|
|
|
/* skip null oid */
|
|
for (size_t o = 1; o < ARRAY_SIZE(oids); o++)
|
|
TEST_BOTH(null, oids[o], null);
|
|
|
|
for (size_t o = 0; o < ARRAY_SIZE(oids); o++)
|
|
TEST_BOTH(oids[o], oids[o], oids[o]);
|
|
|
|
TEST_BOTH(partial, no_prefix, partial);
|
|
TEST_BOTH(partial, prefixed, partial);
|
|
TEST_BOTH(partial, prefix_only, partial);
|
|
TEST_BOTH(partial, prefix_only2, partial);
|
|
|
|
TEST_BOTH(prefix_only2, prefixed, inet);
|
|
TEST_BOTH(prefix_only2, no_prefix, inet);
|
|
|
|
TEST_BOTH(prefix_only2, inet, inet);
|
|
|
|
TEST_BOTH(prefix_only, prefix_only2, inet);
|
|
|
|
TEST_BOTH(prefix_only, prefixed, prefix_only);
|
|
TEST_BOTH(prefix_only, no_prefix, prefix_only);
|
|
|
|
TEST_BOTH(prefix_only, inet, inet);
|
|
|
|
/* skip null oid */
|
|
for (size_t o = 1; o < ARRAY_SIZE(oids); o++)
|
|
{
|
|
if (oids[o] == outside) continue;
|
|
|
|
TEST_BOTH(outside, oids[o], null);
|
|
}
|
|
|
|
TEST_BOTH(no_inet, partial, partial);
|
|
TEST_BOTH(no_inet, inet, partial);
|
|
TEST_BOTH(no_inet, prefix_only, partial);
|
|
TEST_BOTH(no_inet, prefix_only2, partial);
|
|
TEST_BOTH(no_inet, prefixed, partial);
|
|
TEST_BOTH(no_inet, no_prefix, partial);
|
|
|
|
TEST_BOTH(shorter, prefixed, shorter);
|
|
TEST_BOTH(shorter, no_prefix, shorter);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* really: static int test_snmp_oid_compare(const struct oid **left, const struct oid **right); */
|
|
static int
|
|
test_snmp_oid_compare(const void *left, const void *right)
|
|
{
|
|
return snmp_oid_compare(
|
|
*((const struct oid **) left),
|
|
*((const struct oid **) right)
|
|
);
|
|
}
|
|
|
|
static void
|
|
generate_raw_oids(struct oid *oids[], int size, struct oid *(*generator)(void))
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
/* binary version of ~5% */
|
|
if (i > 0 && bt_random_n(256) <= 13)
|
|
{
|
|
/* at this chance, we create a copy instead of generating new oid */
|
|
oids[i] = tmp_alloc(snmp_oid_size(oids[i-1]));
|
|
memcpy(oids[i], oids[i-1], snmp_oid_size(oids[i-1]));
|
|
}
|
|
else
|
|
oids[i] = generator();
|
|
}
|
|
}
|
|
|
|
static int
|
|
generate_oids(struct oid *oids[], struct oid *sorted[], int size, struct oid *(*generator)(void))
|
|
{
|
|
generate_raw_oids(oids, size, generator);
|
|
|
|
memcpy(sorted, oids, size * sizeof(struct oid *));
|
|
|
|
qsort(sorted, (size_t) size, sizeof(struct oid *),
|
|
test_snmp_oid_compare);
|
|
|
|
// test sizes 0, 1, 2, 10, ...
|
|
int last_used = 0;
|
|
for (int index = 0; index < size; index++)
|
|
{
|
|
if (snmp_oid_compare(sorted[last_used], sorted[index]) != 0)
|
|
sorted[++last_used] = sorted[index];
|
|
}
|
|
|
|
/* delete old pointers */
|
|
for (int i = last_used + 1; i < size; i++)
|
|
sorted[i] = NULL;
|
|
|
|
return (size > 1) ? last_used + 1 : size;
|
|
}
|
|
|
|
static int
|
|
t_walk_oid_desc(void)
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(tree_sizes) > 0);
|
|
int size = tree_sizes[ARRAY_SIZE(tree_sizes) - 1];
|
|
ASSERT(size > 0);
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
|
|
(void) generate_oids(oids, sorted, size, random_oid);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
(void) mib_tree_add(pool, tree, oids[i], 0);
|
|
|
|
for (int test = 0; test < size; test++)
|
|
{
|
|
int i = bt_random_n(size);
|
|
|
|
char buffer[1024];
|
|
struct oid *oid = (struct oid *) buffer;
|
|
|
|
memcpy(oid, oids[i], snmp_oid_size(oids[i]));
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
(void) mib_tree_find(tree, &walk, oid);
|
|
|
|
int type = bt_random_n(4);
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, oids[i]) == 0);
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
/* oid is longer than walk or has same length */
|
|
u8 ids = oid->n_subid;
|
|
u32 upto = MIN(OID_MAX_LEN - ids, 16);
|
|
|
|
if (!upto)
|
|
continue;
|
|
|
|
u32 new = bt_random_n(upto) + 1;
|
|
oid->n_subid = ids + new;
|
|
|
|
for (u32 i = 0; i < new; i++)
|
|
oid->ids[ids + i] = bt_random_n(OID_MAX_ID);
|
|
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, oid) > 0);
|
|
|
|
break;
|
|
}
|
|
case 2:
|
|
case 3:
|
|
{
|
|
/* oid is shorter than walk */
|
|
u8 ids = oid->n_subid;
|
|
|
|
if (ids == 0 || ids == OID_MAX_LEN)
|
|
continue;
|
|
|
|
u32 split = (ids > 1) ? bt_random_n(ids - 1) + 1 : 0;
|
|
u32 ext = (type == 3) ? bt_random_n(MIN(OID_MAX_LEN - ids, 16)) : 0;
|
|
|
|
oid->n_subid = split + ext;
|
|
for (u32 i = 0; i < ext; i++)
|
|
oid->ids[split + i] = bt_random_n(OID_MAX_ID);
|
|
|
|
int no_change = 1;
|
|
for (u32 j = 0; j < MIN(ids - split, ext); j++)
|
|
{
|
|
if (oid->ids[split + j] != oids[i]->ids[split + j])
|
|
no_change = 0;
|
|
}
|
|
|
|
if (no_change)
|
|
continue;
|
|
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, oid) < 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree);
|
|
|
|
u32 zero = 0;
|
|
const struct oid *null_oid = (struct oid *) &zero;
|
|
u32 index = bt_random_n(size);
|
|
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, null_oid) == 0);
|
|
if (!snmp_is_oid_empty(oids[index]))
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, oids[index]) > 0);
|
|
(void) mib_tree_find(tree, &walk, oids[index]);
|
|
if (!snmp_is_oid_empty(oids[index]))
|
|
bt_assert(mib_tree_walk_is_oid_descendant(&walk, null_oid) < 0);
|
|
}
|
|
|
|
u32 null_oid = 0;
|
|
mib_tree_remove(tree, (struct oid *) &null_oid);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_walk_oid_compare(void)
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
STATIC_ASSERT(ARRAY_SIZE(tree_sizes) > 0);
|
|
int size = tree_sizes[ARRAY_SIZE(tree_sizes) - 1];
|
|
ASSERT(size > 0);
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
|
|
(void) generate_oids(oids, sorted, size, random_oid);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
(void) mib_tree_add(pool, tree, oids[i], 0);
|
|
|
|
for (int test = 0; test < size; test++)
|
|
{
|
|
int i = bt_random_n(size);
|
|
|
|
char buffer[1024];
|
|
struct oid *oid = (struct oid *) buffer;
|
|
|
|
memcpy(oid, oids[i], snmp_oid_size(oids[i]));
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
(void) mib_tree_find(tree, &walk, oids[i]);
|
|
|
|
int type = bt_random_n(4);
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, oids[i]) == 0);
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
/* oid is longer than walk or has same length */
|
|
u8 ids = oid->n_subid;
|
|
u32 upto = MIN(OID_MAX_LEN - ids, 16);
|
|
|
|
if (!upto)
|
|
continue;
|
|
|
|
u32 new = bt_random_n(upto) + 1;
|
|
oid->n_subid = ids + new;
|
|
ASSERT(snmp_oid_size(oid) < 1024);
|
|
|
|
for (u32 i = 0; i < new; i++)
|
|
oid->ids[ids + i] = bt_random_n(OID_MAX_ID);
|
|
|
|
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, oid) < 0);
|
|
break;
|
|
}
|
|
case 2:
|
|
case 3:
|
|
{
|
|
/* oid is shorter than walk */
|
|
u8 ids = oid->n_subid;
|
|
|
|
if (ids == 0 || ids == OID_MAX_LEN)
|
|
continue;
|
|
|
|
u32 split = (ids > 1) ? bt_random_n(ids - 1) + 1 : 0;
|
|
u32 ext = (type == 3) ? bt_random_n(MIN(OID_MAX_LEN - ids, 16)) : 0;
|
|
|
|
oid->n_subid = split + ext;
|
|
for (u32 i = 0; i < ext; i++)
|
|
oid->ids[split + i] = bt_random_n(OID_MAX_ID);
|
|
|
|
int cmp_res = 0;
|
|
for (u32 j = 0; j < MIN(ids - split, ext) && !cmp_res; j++)
|
|
cmp_res = oids[i]->ids[split + j] - oid->ids[split + j];
|
|
|
|
if (!cmp_res && split + ext == ids)
|
|
continue;
|
|
|
|
if (!cmp_res && split + ext < ids)
|
|
cmp_res = +1;
|
|
|
|
if (!cmp_res && split + ext > ids)
|
|
cmp_res = -1;
|
|
|
|
if (cmp_res < 0)
|
|
cmp_res = -1;
|
|
else if (cmp_res > 0)
|
|
cmp_res = +1;
|
|
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, oid) == cmp_res);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree);
|
|
|
|
u32 zero = 0;
|
|
const struct oid *null_oid = (struct oid *) &zero;
|
|
u32 index = bt_random_n(size);
|
|
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, null_oid) == 0);
|
|
if (!snmp_is_oid_empty(oids[index]))
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, oids[index]) < 0);
|
|
else
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, oids[index]) == 0);
|
|
(void) mib_tree_find(tree, &walk, oids[index]);
|
|
if (!snmp_is_oid_empty(oids[index]))
|
|
bt_assert(mib_tree_walk_oid_compare(&walk, null_oid) > 0);
|
|
}
|
|
|
|
u32 null_oid = 0;
|
|
mib_tree_remove(tree, (struct oid *) &null_oid);
|
|
lp_restore(tmp_linpool, &tmps);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static void UNUSED
|
|
print_dups(const struct oid *oids[], uint size)
|
|
{
|
|
for (uint i = 0; i < size; i++)
|
|
for (uint j = i + 1; j < size; j++)
|
|
if (snmp_oid_compare(oids[i], oids[j]) == 0)
|
|
log(L_WARN "pair (%u, %u)", i, j);
|
|
}
|
|
|
|
static void UNUSED
|
|
print_all(const struct oid *oids[], uint size)
|
|
{
|
|
for (uint i = 0; i < size; i++)
|
|
snmp_oid_log(oids[i]);
|
|
}
|
|
|
|
static inline int
|
|
oid_is_leaf(const struct oid *oid, const struct oid *leafs[], uint leaf_idx)
|
|
{
|
|
for (uint l = 0; l < leaf_idx; l++)
|
|
if (snmp_oid_compare(oid, leafs[l]) == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
all_invalid(const struct oid *oids[], const byte *invalid, uint size, uint index)
|
|
{
|
|
if (!invalid[index])
|
|
return 0;
|
|
|
|
for (uint i = 0; i < size; i++)
|
|
{
|
|
if (i == index) continue;
|
|
|
|
if (snmp_oid_compare(oids[i], oids[index]) == 0 &&
|
|
!invalid[i])
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
count_error(const struct oid *oids[], const byte *invalid, uint size)
|
|
{
|
|
int error = 0;
|
|
for (uint i = 0; i < size; i++)
|
|
{
|
|
if (!invalid[i]) continue;
|
|
|
|
int skip = 0;
|
|
for (uint j = 0; j < i; j++)
|
|
{
|
|
if (snmp_oid_compare(oids[i], oids[j]) == 0)
|
|
{
|
|
skip = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (skip) continue;
|
|
|
|
if (all_invalid(oids, invalid, size, i))
|
|
error++;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
gen_test_add(struct oid *(*generator)(void))
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
size_t tsz = ARRAY_SIZE(tree_sizes);
|
|
|
|
int size = tree_sizes[test % tsz];
|
|
int with_leafs = (test % (2 * tsz)) < tsz;
|
|
int no_inet_prefix = (test % (4 * tsz)) < (2 * tsz);
|
|
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
byte *types = mb_alloc(pool, size * sizeof(byte));
|
|
byte *invalid_hist = mb_alloc(pool, size * sizeof(byte));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **leafs = (with_leafs) ? mb_alloc(pool, size * sizeof(struct oid *))
|
|
: NULL;
|
|
int leaf_idx = 0;
|
|
int empty_prefix_added = 0;
|
|
int distinct = generate_oids(oids, sorted, size, generator);
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
if (no_inet_prefix)
|
|
{
|
|
/* remove the node .1 and all children */
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
int invalid_counter = 0;
|
|
int counter = 0;
|
|
int cut = 0;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
int invalid = 0;
|
|
int is_leaf = (with_leafs) ? (int) bt_random_n(2) : 0;
|
|
types[i] = (byte) is_leaf;
|
|
|
|
int will_cut = 0;
|
|
int oid_nulled = snmp_is_oid_empty(oids[i]);
|
|
|
|
if (oid_nulled && is_leaf)
|
|
invalid = 1;
|
|
|
|
if (!no_inet_prefix)
|
|
{
|
|
char buffer[1024];
|
|
struct oid *o = (struct oid *) buffer;
|
|
|
|
struct oid *inet = oid_create(4, 0, 0, /* ids */ 1, 3, 6, 1);
|
|
snmp_oid_common_ancestor(oids[i], inet, o);
|
|
|
|
/* If the standard internet prefix is present,
|
|
* then the prefix leafs are invalid. */
|
|
if (snmp_oid_compare(oids[i], o) == 0)
|
|
invalid = is_leaf;
|
|
}
|
|
|
|
/* check existence of ancestor node of a new leaf */
|
|
for (int oi = 0; !invalid && !oid_nulled && oi < i; oi++)
|
|
{
|
|
char buffer[1024];
|
|
struct oid *o = (struct oid *) buffer;
|
|
|
|
if (invalid_hist[oi])
|
|
continue;
|
|
|
|
int other_is_leaf = (int) types[oi];
|
|
|
|
if (snmp_oid_compare(oids[oi], oids[i]) == 0 &&
|
|
!snmp_is_oid_empty(oids[i]))
|
|
{
|
|
if (other_is_leaf == is_leaf)
|
|
will_cut = 1;
|
|
else if (other_is_leaf != is_leaf)
|
|
invalid = 1;
|
|
|
|
break;
|
|
}
|
|
|
|
snmp_oid_common_ancestor(oids[oi], oids[i], o);
|
|
|
|
if ((snmp_oid_compare(oids[i], o) == 0 && is_leaf) ||
|
|
(snmp_oid_compare(oids[oi], o) == 0 && other_is_leaf))
|
|
{
|
|
invalid = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!invalid && will_cut)
|
|
cut++;
|
|
|
|
if (is_leaf && !invalid)
|
|
/* leafs could have duplicates */
|
|
leafs[leaf_idx++] = oids[i];
|
|
|
|
mib_node_u *node = mib_tree_add(pool, tree, oids[i], is_leaf);
|
|
|
|
bt_assert((node == NULL) == invalid);
|
|
|
|
invalid_hist[i] = 0;
|
|
if (invalid)
|
|
{
|
|
invalid_hist[i] = 1;
|
|
invalid_counter++;
|
|
}
|
|
|
|
if (node != NULL && (!snmp_is_oid_empty(oids[i]) || !empty_prefix_added))
|
|
counter++;
|
|
|
|
if (snmp_is_oid_empty(oids[i]) && !is_leaf)
|
|
empty_prefix_added = 1;
|
|
}
|
|
|
|
int error = count_error((const struct oid **) oids, invalid_hist, size);
|
|
bt_assert(counter - cut == distinct - error);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
mb_free(oids);
|
|
mb_free(sorted);
|
|
mb_free(leafs);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_tree_add(void)
|
|
{
|
|
|
|
gen_test_add(random_prefixed_oid);
|
|
gen_test_add(random_no_prefix_oid);
|
|
gen_test_add(random_prefixable_oid);
|
|
gen_test_add(random_oid);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
gen_test_find(struct oid *(*generator)(void))
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
size_t tsz = ARRAY_SIZE(tree_sizes);
|
|
|
|
int size = tree_sizes[test % tsz];
|
|
int with_leafs = (test % (2 * tsz)) < tsz;
|
|
int no_inet_prefix = (test % (4 * tsz)) < (2 * tsz);
|
|
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
mib_node_u **nodes = mb_alloc(pool, size * sizeof(mib_node_u *));
|
|
struct oid **searched = mb_alloc(pool, size * sizeof(struct oid *));
|
|
byte *types = mb_alloc(pool, size * sizeof(byte));
|
|
|
|
/* enough to hold snmp_internet copy */
|
|
uint longest_inet_pref_len = 0;
|
|
struct oid *longest_inet_pref = oid_create(4, 0, 0, /* ids */ 0, 0, 0, 0);
|
|
|
|
generate_raw_oids(oids, size, generator);
|
|
generate_raw_oids(searched, size, generator);
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
if (no_inet_prefix)
|
|
{
|
|
/* remove the node .1 and all children */
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
for (int i = 0; i < size; i++)
|
|
types[i] = (byte) ((with_leafs) ? bt_random_n(2) : 0);
|
|
|
|
/*
|
|
* by default initialized MIB tree will have internet prefix have inserted
|
|
*/
|
|
if (!no_inet_prefix)
|
|
{
|
|
memcpy(longest_inet_pref->ids, snmp_internet, sizeof(snmp_internet));
|
|
longest_inet_pref_len = 4;
|
|
}
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
nodes[i] = mib_tree_add(pool, tree, oids[i], types[i]);
|
|
|
|
if (nodes[i] == NULL) continue;
|
|
|
|
if (snmp_oid_is_prefixed(oids[i]))
|
|
{
|
|
memcpy(longest_inet_pref->ids, snmp_internet, sizeof(snmp_internet));
|
|
longest_inet_pref_len = 4;
|
|
}
|
|
else
|
|
{
|
|
for (uint j = 0; j < MIN(oids[i]->n_subid,
|
|
ARRAY_SIZE(snmp_internet)); j++)
|
|
{
|
|
if (oids[i]->ids[j] == snmp_internet[j] &&
|
|
j >= longest_inet_pref_len)
|
|
{
|
|
longest_inet_pref->ids[j] = snmp_internet[j];
|
|
longest_inet_pref_len = j + 1;
|
|
}
|
|
else if (oids[i]->ids[j] == snmp_internet[j])
|
|
;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
for (int j = 0; j < size; j++)
|
|
{
|
|
if (nodes[i] != NULL &&
|
|
nodes[j] != NULL &&
|
|
snmp_oid_compare(oids[i], oids[j]) == 0)
|
|
bt_assert(nodes[i] == nodes[j]);
|
|
}
|
|
}
|
|
|
|
mib_node_u *last = NULL;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
/*
|
|
* This solves cases where we tried to insert
|
|
* both leaf and inner node for same OID.
|
|
* Result of insertion should be NULL in cases
|
|
* when the insertion is inconsistent with the current tree state.
|
|
* (the first insertion wins)
|
|
*/
|
|
int expected_precise = 1;
|
|
mib_node_u *expected = nodes[i];
|
|
|
|
if (!no_inet_prefix)
|
|
{
|
|
char buf[1024];
|
|
struct oid *o = (struct oid *) buf;
|
|
snmp_oid_common_ancestor(oids[i], longest_inet_pref, o);
|
|
if (snmp_oid_compare(oids[i], o) == 0)
|
|
expected_precise = 0;
|
|
}
|
|
|
|
if (snmp_is_oid_empty(oids[i]))
|
|
{
|
|
expected_precise = 0;
|
|
}
|
|
|
|
for (int j = 0; expected_precise && j < size; j++)
|
|
{
|
|
if (i == j) continue;
|
|
|
|
if (snmp_oid_compare(oids[i], oids[j]) == 0 &&
|
|
types[i] != types[j] && nodes[i] == NULL)
|
|
{
|
|
if (nodes[j] != NULL)
|
|
{
|
|
expected = nodes[j];
|
|
break;
|
|
}
|
|
|
|
/* else expected = NULL; */
|
|
}
|
|
|
|
char buf[1024];
|
|
struct oid *o = (struct oid *) buf;
|
|
|
|
snmp_oid_common_ancestor(oids[i], oids[j], o);
|
|
|
|
/* oids[j] lies on path from root to oids[i] */
|
|
if (snmp_oid_compare(oids[i], o) == 0 &&
|
|
nodes[j] != NULL &&
|
|
expected == NULL)
|
|
{
|
|
expected_precise = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
struct mib_walk_state walk;
|
|
//mib_tree_walk_init(&walk, tree, 0);
|
|
mib_tree_walk_init(&walk, NULL);
|
|
mib_node_u *found = mib_tree_find(tree, &walk, oids[i]);
|
|
|
|
bt_assert(walk.stack_pos <= MIB_WALK_STACK_SIZE + 1);
|
|
bt_assert(walk.id_pos <= OID_MAX_LEN);
|
|
|
|
if (expected_precise)
|
|
bt_assert(found == expected);
|
|
else
|
|
/* found is an auto-inserted node on path to some dest OID */
|
|
bt_assert(found != NULL);
|
|
|
|
last = found;
|
|
|
|
/* test finding with walk state not pointing at the root of the tree */
|
|
u8 subids = oids[i]->n_subid;
|
|
if (subids > 0)
|
|
{
|
|
found = NULL;
|
|
u32 new_ids = bt_random_n(subids);
|
|
mib_tree_walk_init(&walk, (bt_random_n(2)) ? tree : NULL);
|
|
|
|
oids[i]->n_subid = new_ids;
|
|
|
|
mib_node_u *ignored UNUSED;
|
|
ignored = mib_tree_find(tree, &walk, oids[i]);
|
|
|
|
oids[i]->n_subid = subids;
|
|
|
|
found = mib_tree_find(tree, &walk, oids[i]);
|
|
|
|
/* see above */
|
|
if (expected_precise)
|
|
bt_assert(found == expected);
|
|
else
|
|
{
|
|
/* test that the result is same as direct searched from tree root */
|
|
bt_assert(found == last);
|
|
bt_assert(found != NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int search = 0; search < size; search++)
|
|
{
|
|
int has_node = snmp_is_oid_empty(searched[search]);
|
|
|
|
for (int stored = 0; stored < size; stored++)
|
|
{
|
|
char buf[1024];
|
|
struct oid *o = (struct oid *) buf;
|
|
snmp_oid_common_ancestor(oids[stored], searched[search], o);
|
|
|
|
/* test if OID oids[stored] is valid and if it forms a path from root
|
|
* with OID searched[search] */
|
|
if (nodes[stored] != NULL && snmp_oid_compare(searched[search], o) == 0)
|
|
{
|
|
has_node = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const struct oid *oid = searched[search];
|
|
if (!has_node && !snmp_oid_is_prefixed(oid))
|
|
{
|
|
for (uint i = 0; i < MIN(ARRAY_SIZE(snmp_internet),
|
|
oid->n_subid); i++)
|
|
{
|
|
if (longest_inet_pref->ids[i] != 0 &&
|
|
longest_inet_pref->ids[i] == oid->ids[i])
|
|
has_node = 1;
|
|
else
|
|
{
|
|
has_node = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (has_node && oid->n_subid > ARRAY_SIZE(snmp_internet))
|
|
has_node = 0;
|
|
}
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
mib_node_u *found = mib_tree_find(tree, &walk, searched[search]);
|
|
bt_assert(has_node == (found != NULL));
|
|
|
|
bt_assert(walk.stack_pos <= MIB_WALK_STACK_SIZE + 1);
|
|
bt_assert(walk.id_pos <= OID_MAX_LEN);
|
|
|
|
last = found;
|
|
|
|
u8 subids = searched[search]->n_subid;
|
|
if (subids > 0)
|
|
{
|
|
found = NULL;
|
|
u32 new_ids = bt_random_n(subids);
|
|
mib_tree_walk_init(&walk, (bt_random_n(2)) ? tree : NULL);
|
|
|
|
searched[search]->n_subid = new_ids;
|
|
|
|
mib_node_u *ignored UNUSED;
|
|
ignored = mib_tree_find(tree, &walk, searched[search]);
|
|
|
|
searched[search]->n_subid = subids;
|
|
|
|
found = mib_tree_find(tree, &walk, searched[search]);
|
|
|
|
bt_assert(has_node == (found != NULL));
|
|
|
|
bt_assert(walk.stack_pos <= MIB_WALK_STACK_SIZE + 1);
|
|
bt_assert(walk.id_pos <= OID_MAX_LEN);
|
|
|
|
/* test that the result is same as direct search from tree root */
|
|
bt_assert(last == found);
|
|
}
|
|
}
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
mb_free(oids);
|
|
mb_free(nodes);
|
|
mb_free(searched);
|
|
mb_free(types);
|
|
}
|
|
|
|
tmp_flush();
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_tree_find(void)
|
|
{
|
|
|
|
gen_test_find(random_prefixed_oid);
|
|
gen_test_find(random_no_prefix_oid);
|
|
gen_test_find(random_prefixable_oid);
|
|
gen_test_find(random_oid);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#if 0
|
|
static int
|
|
delete_cleanup(const struct oid *oid, struct oid *oids[], mib_node_u *valid[], int size)
|
|
{
|
|
uint counter = 0;
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
char buf[1024];
|
|
struct oid *o = (struct oid *) buf;
|
|
|
|
if (oid == oids[i])
|
|
{
|
|
counter++;
|
|
continue;
|
|
}
|
|
|
|
snmp_oid_common_ancestor(oid, oids[i], o);
|
|
|
|
if (snmp_oid_compare(oid, o) == 0)
|
|
{
|
|
valid[i] = NULL;
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
gen_test_delete_remove(struct oid *(*generator)(void), int remove)
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
size_t tsz = ARRAY_SIZE(tree_sizes);
|
|
|
|
int size = tree_sizes[test % tsz];
|
|
int with_leafs = (test % (2 * tsz)) < tsz;
|
|
int no_inet_prefix = (test % (4 * tsz)) < (2 * tsz);
|
|
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
mib_node_u **nodes = mb_alloc(pool, size * sizeof(mib_node_u *));
|
|
byte *types = mb_alloc(pool, size * sizeof(byte));
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
if (no_inet_prefix)
|
|
{
|
|
/* remove the node .1 and all children */
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
int distinct = generate_oids(oids, sorted, size, generator);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
int is_leaf;
|
|
is_leaf = types[i] = (byte) (with_leafs) ? bt_random_n(2) : 0;
|
|
(void) mib_tree_add(pool, tree, oids[i], is_leaf);
|
|
}
|
|
|
|
for (int d = 0; d < distinct; d++)
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
//mib_tree_walk_init(&walk, tree); TODO
|
|
nodes[d] = mib_tree_find(tree, &walk, sorted[d]);
|
|
}
|
|
|
|
/* we need to populate the nodes array after all insertions because
|
|
* some insertion may fail (== NULL) because we try to insert a leaf */
|
|
#if 0
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree, 0);
|
|
nodes[i] = mib_tree_find(tree, &walk, oids[i]);
|
|
}
|
|
#endif
|
|
|
|
int deleted, invalid_counter;
|
|
/* test deletion one of the inserted OIDs */
|
|
for (int round = 0; round < (size + 3) / 4 + remove; round++)
|
|
{
|
|
/* note: we do not run any rounds for size zero because bt_random_n(0)
|
|
* does not exist */
|
|
int i;
|
|
struct oid *oid;
|
|
if (!remove)
|
|
{
|
|
/* this way we are also testing remove non-existent tree nodes */
|
|
i = bt_random_n(size); /* not bt_random_n(distinct) */
|
|
oid = oids[i];
|
|
}
|
|
else
|
|
{
|
|
i = -1; /* break fast */
|
|
oid = generator();
|
|
}
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
// mib_tree_walk_init(&walk, tree); TODO
|
|
mib_node_u *node = mib_tree_find(tree, &walk, oid);
|
|
|
|
if (node == NULL)
|
|
continue;
|
|
|
|
if (!remove)
|
|
deleted = mib_tree_delete(tree, &walk);
|
|
else
|
|
deleted = mib_tree_remove(tree, oid);
|
|
|
|
bt_assert(deleted > 0 || snmp_is_oid_empty(oid));
|
|
|
|
invalid_counter = 0;
|
|
int counted_removed = 0;
|
|
for (int j = 0; j < distinct; j++)
|
|
{
|
|
//mib_tree_walk_init(&walk, tree, 0);
|
|
mib_tree_walk_init(&walk, NULL);
|
|
mib_node_u *node = mib_tree_find(tree, &walk, sorted[j]);
|
|
|
|
if (snmp_is_oid_empty(oid))
|
|
;
|
|
/* the oid could have multiple instances in the oids dataset */
|
|
else if (snmp_oid_compare(oid, sorted[j]) == 0 && !counted_removed)
|
|
{
|
|
invalid_counter++;
|
|
counted_removed = 1;
|
|
bt_assert(node == NULL);
|
|
nodes[j] = NULL;
|
|
}
|
|
else if (node != nodes[j])
|
|
{
|
|
invalid_counter++;
|
|
bt_assert(node == NULL);
|
|
nodes[j] = NULL;
|
|
}
|
|
}
|
|
|
|
/* we do not count the internal node that are included in the deleted */
|
|
bt_assert(deleted >= invalid_counter);
|
|
}
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
mb_free(oids);
|
|
mb_free(sorted);
|
|
mb_free(nodes);
|
|
}
|
|
|
|
tmp_flush();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_tree_delete(void)
|
|
{
|
|
|
|
gen_test_delete_remove(random_prefixed_oid, 0);
|
|
gen_test_delete_remove(random_no_prefix_oid, 0);
|
|
gen_test_delete_remove(random_prefixable_oid, 0);
|
|
gen_test_delete_remove(random_oid, 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
t_tree_remove(void)
|
|
{
|
|
|
|
gen_test_delete_remove(random_prefixed_oid, 1);
|
|
gen_test_delete_remove(random_no_prefix_oid, 1);
|
|
gen_test_delete_remove(random_prefixable_oid, 1);
|
|
gen_test_delete_remove(random_oid, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
gen_test_traverse(struct oid *(*generator)(void))
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
size_t tsz = ARRAY_SIZE(tree_sizes);
|
|
|
|
int size = tree_sizes[test % tsz];
|
|
int with_leafs = (test % (2 * tsz)) < tsz;
|
|
int no_inet_prefix = (test % (4 * tsz)) < (2 * tsz);
|
|
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
mib_node_u **nodes = mb_allocz(pool, size * sizeof(mib_node_u *));
|
|
|
|
const int distinct = generate_oids(oids, sorted, size, generator);
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
if (no_inet_prefix)
|
|
{
|
|
/* remove the node .1 and all children */
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
for (int o = 0; o < size; o++)
|
|
{
|
|
int is_leaf = (with_leafs) ? (int) bt_random_n(2) : 0;
|
|
(void) mib_tree_add(pool, tree, oids[o], is_leaf);
|
|
}
|
|
|
|
for (int d = 0; d < distinct; d++)
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
nodes[d] = mib_tree_find(tree, &walk, sorted[d]);
|
|
}
|
|
|
|
int bound = 0;
|
|
|
|
for (int d = 0; d < distinct; d++)
|
|
{
|
|
if (snmp_oid_is_prefixed(sorted[d]))
|
|
bound += 5;
|
|
bound += (int) sorted[d]->n_subid;
|
|
}
|
|
|
|
if (!no_inet_prefix)
|
|
bound += (ARRAY_SIZE(snmp_internet) + 1);
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree);
|
|
|
|
char buf[1024], buf2[1024];
|
|
struct oid *oid = (struct oid *) buf;
|
|
struct oid *last = (struct oid *) buf2;
|
|
memset(oid, 0, sizeof(struct oid)); /* create a null OID */
|
|
memset(last, 0, sizeof(struct oid));
|
|
|
|
int oid_index = 0;
|
|
if (size > 0 && snmp_is_oid_empty(sorted[oid_index]))
|
|
oid_index++;
|
|
|
|
mib_node_u *current;
|
|
int i = 0;
|
|
while ((current = mib_tree_walk_next(tree, &walk)) != NULL && i++ < bound)
|
|
{
|
|
memcpy(last, oid, snmp_oid_size(oid));
|
|
mib_tree_walk_to_oid(&walk, oid,
|
|
(1024 - sizeof(struct oid) / sizeof(u32)));
|
|
|
|
bt_assert(snmp_oid_compare(last, oid) < 0);
|
|
|
|
while (oid_index < distinct && nodes[oid_index] == NULL)
|
|
oid_index++;
|
|
|
|
if (oid_index < distinct && snmp_oid_compare(sorted[oid_index], oid) == 0)
|
|
oid_index++;
|
|
}
|
|
|
|
bt_assert(current == NULL);
|
|
while (oid_index < distinct && nodes[oid_index] == NULL)
|
|
oid_index++;
|
|
|
|
/* the bound check is only for that the loop is finite */
|
|
bt_assert(i <= bound + 2);
|
|
|
|
current = mib_tree_walk_next(tree, &walk);
|
|
bt_assert(current == NULL);
|
|
bt_assert(oid_index == distinct);
|
|
|
|
mb_free(oids);
|
|
mb_free(sorted);
|
|
mb_free(nodes);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
tmp_flush();
|
|
}
|
|
|
|
static int
|
|
t_tree_traversal(void)
|
|
{
|
|
gen_test_traverse(random_prefixed_oid);
|
|
gen_test_traverse(random_no_prefix_oid);
|
|
gen_test_traverse(random_prefixable_oid);
|
|
gen_test_traverse(random_oid);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
gen_test_leafs(struct oid *(*generator)(void))
|
|
{
|
|
lp_state tmps;
|
|
lp_save(tmp_linpool, &tmps);
|
|
|
|
pool *pool = &root_pool;
|
|
|
|
for (int test = 0; test < TESTS_NUM; test++)
|
|
{
|
|
size_t tsz = ARRAY_SIZE(tree_sizes);
|
|
|
|
int size = tree_sizes[test % tsz];
|
|
int with_leafs = (test % (2 * tsz)) < tsz;
|
|
int no_inet_prefix = (test % (4 * tsz)) < (2 * tsz);
|
|
|
|
struct oid **oids = mb_alloc(pool, size * sizeof(struct oid *));
|
|
struct oid **sorted = mb_alloc(pool, size * sizeof(struct oid *));
|
|
mib_node_u **nodes = mb_allocz(pool, size * sizeof(mib_node_u *));
|
|
|
|
const int distinct = generate_oids(oids, sorted, size, generator);
|
|
|
|
struct mib_tree storage, *tree = &storage;
|
|
mib_tree_init(pool, tree);
|
|
|
|
if (no_inet_prefix)
|
|
{
|
|
/* remove the node .1 and all children */
|
|
const struct oid *inet_pref = oid_create(1, 0, 0, /* ids */ 1);
|
|
mib_tree_remove(tree, inet_pref);
|
|
}
|
|
|
|
for (int o = 0; o < size; o++)
|
|
{
|
|
int is_leaf = (with_leafs) ? (int) bt_random_n(2) : 0;
|
|
(void) mib_tree_add(pool, tree, oids[o], is_leaf);
|
|
}
|
|
|
|
int leafs = 0;
|
|
for (int d = 0; d < distinct; d++)
|
|
{
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, NULL);
|
|
nodes[d] = mib_tree_find(tree, &walk, sorted[d]);
|
|
|
|
/* count only leafs that was successfully inserted without duplicits */
|
|
if (nodes[d] != NULL && mib_node_is_leaf(nodes[d]))
|
|
leafs++;
|
|
}
|
|
|
|
struct mib_walk_state walk;
|
|
mib_tree_walk_init(&walk, tree);
|
|
if (!with_leafs)
|
|
{
|
|
struct mib_leaf *leaf = mib_tree_walk_next_leaf(tree, &walk, 0);
|
|
bt_assert(leaf == NULL);
|
|
|
|
continue;
|
|
}
|
|
|
|
char buf[1024], buf2[1024];
|
|
struct oid *oid = (struct oid *) buf;
|
|
struct oid *last = (struct oid *) buf2;
|
|
memset(oid, 0, sizeof(struct oid)); /* create a null OID */
|
|
memset(last, 0, sizeof(struct oid));
|
|
|
|
int oid_index = 0;
|
|
|
|
struct mib_leaf *current;
|
|
int i = 0; /* iteration counter ~ leafs found */
|
|
while ((current = mib_tree_walk_next_leaf(tree, &walk, 0)) != NULL && i++ < leafs)
|
|
{
|
|
memcpy(last, oid, snmp_oid_size(oid));
|
|
mib_tree_walk_to_oid(&walk, oid,
|
|
(1024 - sizeof(struct oid) / sizeof(u32)));
|
|
|
|
bt_assert(snmp_oid_compare(last, oid) < 0);
|
|
bt_assert(mib_node_is_leaf(((mib_node_u *)current)));
|
|
|
|
while (oid_index < distinct &&
|
|
(nodes[oid_index] == NULL || !mib_node_is_leaf(nodes[oid_index])))
|
|
oid_index++;
|
|
|
|
if (oid_index < distinct && snmp_oid_compare(sorted[oid_index], oid) == 0)
|
|
oid_index++;
|
|
}
|
|
|
|
bt_assert(current == NULL);
|
|
while (oid_index < distinct &&
|
|
(nodes[oid_index] == NULL || !mib_node_is_leaf(nodes[oid_index])))
|
|
oid_index++;
|
|
|
|
current = mib_tree_walk_next_leaf(tree, &walk, 0);
|
|
bt_assert(current == NULL);
|
|
bt_assert(oid_index == distinct);
|
|
bt_assert(i == leafs);
|
|
|
|
mb_free(oids);
|
|
mb_free(sorted);
|
|
mb_free(nodes);
|
|
|
|
lp_restore(tmp_linpool, &tmps);
|
|
}
|
|
|
|
tmp_flush();
|
|
}
|
|
|
|
static int
|
|
t_tree_leafs(void)
|
|
{
|
|
|
|
gen_test_leafs(random_prefixed_oid);
|
|
gen_test_leafs(random_no_prefix_oid);
|
|
gen_test_leafs(random_prefixable_oid);
|
|
gen_test_leafs(random_oid);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#if 0
|
|
static int
|
|
t_tree_all(void)
|
|
{
|
|
/* random sequences of insertion/deletion/searches and walks */
|
|
return 0; /* failed */
|
|
}
|
|
#endif
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
bt_init(argc, argv);
|
|
bt_bird_init();
|
|
|
|
bt_test_suite(t_oid_empty, "Function that determines if the OID is empty");
|
|
bt_test_suite(t_oid_compare, "Function defining lexicographical order on OIDs");
|
|
bt_test_suite(t_varbind_name_to_tx, "Function loading OID from RX buffer with prefixation");
|
|
bt_test_suite(t_oid_ancestor, "Function finding common ancestor of two OIDs");
|
|
bt_test_suite(t_walk_to_oid, "Function transforming MIB tree walk state to OID");
|
|
bt_test_suite(t_walk_oid_desc, "Function testing relation being subtree between MIB tree walk and OID");
|
|
bt_test_suite(t_walk_oid_compare, "Function comparing MIB tree walk and OID");
|
|
|
|
bt_test_suite(t_tree_find, "MIB tree search");
|
|
bt_test_suite(t_tree_traversal, "MIB tree traversal");
|
|
bt_test_suite(t_tree_leafs, "MIB tree leafs traversal");
|
|
bt_test_suite(t_tree_add, "MIB tree insertion");
|
|
bt_test_suite(t_tree_delete, "MIB tree deletion");
|
|
bt_test_suite(t_tree_remove, "MIB tree removal");
|
|
//bt_test_suite(t_tree_all, "MIB tree random find, add, delete mix");
|
|
|
|
return bt_exit_value();
|
|
}
|