0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00
bird/lib/rt-normalize_test.c
Katerina Kubecova 4af3ee1f2f EAttr normalization rewritten to use bucket sort
The EAttr ID space is dense so we can just walk once, sweep the whole
input and go home.

There is a little bit of memory inefficiency in allocating always the
largest possible block, yet it isn't too bad.

There are also unit tests for this.
2024-12-12 21:02:34 +01:00

207 lines
5.9 KiB
C

#include "test/birdtest.h"
#include "nest/route.h"
static _Bool
eattr_same_value2(const eattr *a, const eattr *b)
{
// this function comes from rt-attr.c
if (
a->id != b->id ||
a->flags != b->flags ||
a->type != b->type ||
a->undef != b->undef
)
return 0;
if (a->undef)
return 1;
if (a->type & EAF_EMBEDDED)
return a->u.data == b->u.data;
else
return adata_same(a->u.ptr, b->u.ptr);
}
void
init_ea_list(struct ea_list *eal, int count)
{
eal->flags = 0;
eal->count = count;
eal->next = NULL;
}
void
init_ea_with_3eattr(struct ea_list *eal)
{
init_ea_list(eal, 3);
eal->attrs[0] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 1234);
eal->attrs[1] = EA_LITERAL_EMBEDDED(&ea_gen_source, 0, 5678);
ip_addr dummy;
dummy.addr[0] = 123;
eal->attrs[2] = EA_LITERAL_STORE_ADATA(&ea_gen_from, 0, &dummy, sizeof(ip_addr));
eal->attrs[0].originated = 0;
eal->attrs[1].originated = 1;
}
static int
t_normalize_one_layer(void)
{
struct ea_list *eal = xmalloc(sizeof(struct ea_list) + 3 * sizeof(eattr));
init_ea_with_3eattr(eal);
struct ea_list *new_eal = ea_normalize(eal, 0);
eattr *result[] = {&eal->attrs[0], &eal->attrs[2], &eal->attrs[1]};
if (new_eal->count != 3)
return 0;
for(uint i = 0; i < new_eal->count; i++)
if (!(eattr_same_value2(&new_eal->attrs[i], result[i]) &&
new_eal->attrs[i].originated == result[i]->originated &&
new_eal->attrs[i].fresh == 0))
return 0;
if (new_eal->flags != EALF_SORTED)
return 0;
return 1;
}
static int
t_normalize_two_layers(void)
{
struct ea_list *eal1 = xmalloc(sizeof(struct ea_list) + 4 * sizeof(eattr));
struct ea_list *eal2 = xmalloc(sizeof(struct ea_list) + 5 * sizeof(eattr));
init_ea_with_3eattr(eal1);
struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(1357);
eal1->attrs[3] = EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhad.ad);
eal1->attrs[3].originated = 1;
eal1->count++;
// ids are 4, 7, 6, 1 in this order
nhad = NEXTHOP_DEST_LITERAL(13);
eal2->attrs[0] = EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhad.ad);
eal2->attrs[0].originated = 0;
eal2->attrs[1] = EA_LITERAL_EMBEDDED(&ea_gen_source, 0, 8765);
eal2->attrs[2] = EA_LITERAL_EMBEDDED(&ea_gen_igp_metric, 0, 45);
eal2->attrs[3] = EA_LITERAL_EMBEDDED(&ea_gen_mpls_policy, 0, 57);
eal2->attrs[3].originated = 0;
eal2->attrs[4] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 0);
eal2->attrs[4].undef = 1;
// ids are 1, 7, 5, 9, 4 in this order
eal2->count = 5;
eal2->next = eal1;
struct ea_list *new_eal = ea_normalize(eal2, 0);
if (new_eal->count != 5)
return 0;
eattr result[5];
result[0] = eal2->attrs[0]; // id 1
result[0].originated = 1;
result[1] = eal2->attrs[2]; // id 5, eattr with id 4 was undefed
result[2] = eal1->attrs[2]; // id 6
result[3] = eal2->attrs[1]; // id 7
result[3].originated = 1;
result[4] = eal2->attrs[3]; // id 9
for(uint i = 0; i < new_eal->count; i++)
if (!(eattr_same_value2(&new_eal->attrs[i], &result[i]) &&
new_eal->attrs[i].originated == result[i].originated &&
new_eal->attrs[i].fresh == 0))
return 0;
if (new_eal->flags != EALF_SORTED)
return 0;
return 1;
}
static int
normalize_two_leave_last(void)
{
struct ea_list *eal1 = xmalloc(sizeof(struct ea_list) + 4 * sizeof(eattr));
struct ea_list *eal2 = xmalloc(sizeof(struct ea_list) + 5 * sizeof(eattr));
struct ea_list *base = xmalloc(sizeof(struct ea_list) + 4 * sizeof(eattr));
struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(13);
base->attrs[0] = EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhad.ad); // changes
base->attrs[0].originated = 0;
base->attrs[1] = EA_LITERAL_EMBEDDED(&ea_gen_source, 0, 8765); // remains
base->attrs[2] = EA_LITERAL_EMBEDDED(&ea_gen_mpls_policy, 0, 57); // will be set
base->attrs[2].originated = 0;
base->attrs[3].undef = 1;
base->attrs[3] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 0); // remains unset (set ad unset)
base->attrs[3].undef = 1;
struct nexthop_adata nnnhad = NEXTHOP_DEST_LITERAL(31);
eal1->attrs[0] = EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nnnhad.ad);
eal1->attrs[1] = EA_LITERAL_EMBEDDED(&ea_gen_source, 0, 8765);
eal1->attrs[2] = EA_LITERAL_EMBEDDED(&ea_gen_igp_metric, 0, 66);
eal1->attrs[3] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 36);
struct nexthop_adata nnhad = NEXTHOP_DEST_LITERAL(333);
eal2->attrs[0] = EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nnhad.ad);
eal2->attrs[1] = EA_LITERAL_EMBEDDED(&ea_gen_igp_metric, 0, 45);
eal2->attrs[1].undef = 1;
eal2->attrs[2] = EA_LITERAL_EMBEDDED(&ea_gen_mpls_policy, 0, 58);
eal2->attrs[3] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 0);
eal2->attrs[3].undef = 1;
ip_addr dummy;
dummy.addr[0] = 123;
eal2->attrs[4] = EA_LITERAL_STORE_ADATA(&ea_gen_from, 0, &dummy, sizeof(ip_addr));
eattr result[3];
result[0] = eal2->attrs[0]; // 1
result[1] = eal2->attrs[4]; // 6
result[2] = eal2->attrs[2]; // 9
base->count = 4;
base->next = NULL;
base->stored = EALS_CUSTOM;
eal1->count = 4;
eal1->next = base;
eal1->stored = 0;
eal2->count = 5;
eal2->next = eal1;
eal2->stored = 0;
struct ea_list *new_eal = ea_normalize(eal2, BIT32_ALL(EALS_CUSTOM));
for(uint i = 0; i < new_eal->count; i++)
log("two l %i ", new_eal->attrs[i].id);
if (new_eal->count != 3)
return 0;
return 1;
for(uint i = 0; i < new_eal->count; i++)
if (!(eattr_same_value2(&new_eal->attrs[i], &result[i]) &&
new_eal->attrs[i].originated == result[i].originated &&
new_eal->attrs[i].fresh == 0))
return 0;
if (new_eal->flags != EALF_SORTED)
return 0;
return 1;
}
int
main(int argc, char *argv[])
{
bt_init(argc, argv);
rta_init();
bt_test_suite(t_normalize_one_layer, "One layer normalization");
bt_test_suite(t_normalize_two_layers, "Two layers normalization");
bt_test_suite(normalize_two_leave_last, "Two layers normalization with base layer");
return bt_exit_value();
}