Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/utils/bgpstream_utils_patricia.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,13 @@ bgpstream_patricia_tree_insert(bgpstream_patricia_tree_t *pt,
bgpstream_addr_version_t v = pfx->address.version;
bgpstream_patricia_node_t *node_it = bgpstream_patricia_get_head(pt, v);

/* Be kind and mask off any trailing bits in the provided prefix */
uint8_t bitlen = pfx->mask_len;
bgpstream_pfx_t pfxclean;
bgpstream_pfx_copy(&pfxclean, pfx);
bgpstream_addr_mask(&pfxclean.address, bitlen);
pfx = &pfxclean;

/* if Patricia Tree is empty, then insert new node */
if (node_it == NULL) {
if ((new_node = bgpstream_patricia_node_create(pt, pfx)) == NULL) {
Expand All @@ -663,7 +670,6 @@ bgpstream_patricia_tree_insert(bgpstream_patricia_tree_t *pt,

node_it = bpt_find_insert_point(node_it, pfx, &relation, &differ_bit);

uint8_t bitlen = pfx->mask_len;
if (relation == BGPSTREAM_PATRICIA_SELF) {
/* check the node contains an actual prefix,
* i.e. it is not a glue node */
Expand Down
111 changes: 110 additions & 1 deletion test/bgpstream-test-utils-patricia.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "bgpstream_test.h"

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
Expand All @@ -48,6 +49,54 @@
#define IPV6_TEST_PFX_B_CHILD "2001:48d0:101:501:beef::/96"
#define IPV6_TEST_64_CNT 65537

// does NOT mask off trailing bits in the resulting prefix
// copied from bgpstream_str2pfx
static bgpstream_pfx_t *str2pfx_raw(const char *pfx_str, bgpstream_pfx_t *pfx)
{
if (pfx_str == NULL || pfx == NULL) {
return NULL;
}

char pfx_copy[INET6_ADDRSTRLEN + 3];
char *endptr = NULL;

/* strncpy() functions copy at most len characters from src into
* dst. If src is less than len characters long, the remainder of
* dst is filled with `\0' characters. Otherwise, dst is not
* terminated. */
strncpy(pfx_copy, pfx_str, INET6_ADDRSTRLEN + 3);
if (pfx_copy[INET6_ADDRSTRLEN + 3 - 1] != '\0') {
return NULL;
}

/* get pointer to ip/mask divisor */
char *found = strchr(pfx_copy, '/');
if (found == NULL) {
return NULL;
}

*found = '\0';
/* get the ip address */
if (bgpstream_str2addr(pfx_copy, &pfx->address) == NULL) {
return NULL;
}

/* get the mask len */
errno = 0;
unsigned long int r = strtoul(found + 1, &endptr, 10);
int ret = errno;
if (!(endptr != NULL && *endptr == '\0') || ret != 0 ||
(pfx->address.version == BGPSTREAM_ADDR_VERSION_IPV4 && r > 32) ||
(pfx->address.version == BGPSTREAM_ADDR_VERSION_IPV6 && r > 128)) {
return NULL;
}
pfx->mask_len = (uint8_t)r;
pfx->allowed_matches = BGPSTREAM_PREFIX_MATCH_ANY;

return pfx;
}


static int test_patricia()
{
bgpstream_patricia_tree_t *pt;
Expand All @@ -59,7 +108,7 @@ static int test_patricia()
int count6 = 0;

// Convenience macros
#define s2p(str) bgpstream_str2pfx((str), &pfx)
#define s2p(str) str2pfx_raw((str), &pfx)
#define BPT_insert bgpstream_patricia_tree_insert
#define BPT_search_exact bgpstream_patricia_tree_search_exact
#define BPT_get_pfx_overlap_info bgpstream_patricia_tree_get_pfx_overlap_info
Expand Down Expand Up @@ -168,6 +217,66 @@ static int test_patricia()
}
bgpstream_patricia_tree_destroy(pt);

/* Default route */
pt = bgpstream_patricia_tree_create(NULL);
res = bgpstream_patricia_tree_result_set_create();
count4 = 0;
INSERT(4, "10.0.0.0/8", ++count4);
INSERT(4, "10.1.2.3/32", ++count4);
INSERT(4, "0.0.0.0/0", ++count4);
INSERT(4, "192.172.226.78/32", ++count4);

CHECK("Patricia Tree v4 default route - non-default case",
(node = BPT_search_exact(pt, s2p("10.1.2.3/32"))) != NULL &&
BPT_get_mincovering_pfx(pt, node, res) == 0 &&
bgpstream_patricia_tree_result_set_count(res) == 1 &&
(node = bgpstream_patricia_tree_result_set_next(res)) != NULL &&
(pfxp = BPT_get_pfx(node)) != NULL &&
bgpstream_pfx_equal(pfxp, s2p("10.0.0.0/8")) != 0);

CHECK("Patricia Tree v4 default route - default case",
(node = BPT_search_exact(pt, s2p("192.172.226.78/32"))) != NULL &&
BPT_get_mincovering_pfx(pt, node, res) == 0 &&
bgpstream_patricia_tree_result_set_count(res) == 1 &&
(node = bgpstream_patricia_tree_result_set_next(res)) != NULL &&
(pfxp = BPT_get_pfx(node)) != NULL &&
bgpstream_pfx_equal(pfxp, s2p("0.0.0.0/0")) != 0);
bgpstream_patricia_tree_destroy(pt);
bgpstream_patricia_tree_result_set_destroy(&res);

/* Incorrectly masked prefixes */
pt = bgpstream_patricia_tree_create(NULL);
res = bgpstream_patricia_tree_result_set_create();
count4 = 0;

// simple case: we expect the parent of 10.1.2.3/32 to be 10.1.0.0/16
INSERT(4, "10.1.2.3/16", ++count4); // should be masked off during insertion
INSERT(4, "10.1.2.3/32", ++count4);
// insert a node so that a glue node is created at the root
INSERT(4, "192.172.226.77/32", ++count4);
// insert our incorrectly masked "default" route, it should replace the root glue node
INSERT(4, "192.172.226.78/0", ++count4);
INSERT(4, "192.172.226.78/32", ++count4);

CHECK("Patricia Tree v4 - unmasked prefixes",
(node = BPT_search_exact(pt, s2p("10.1.2.3/32"))) != NULL &&
BPT_get_mincovering_pfx(pt, node, res) == 0 &&
bgpstream_patricia_tree_result_set_count(res) == 1 &&
(node = bgpstream_patricia_tree_result_set_next(res)) != NULL &&
(pfxp = BPT_get_pfx(node)) != NULL &&
bgpstream_pfx_equal(pfxp, s2p("10.1.0.0/16")) != 0);

CHECK("Patricia Tree v4 - unmasked prefixes; replace glue",
(node = BPT_search_exact(pt, s2p("192.172.226.78/32"))) != NULL &&
BPT_get_mincovering_pfx(pt, node, res) == 0 &&
bgpstream_patricia_tree_result_set_count(res) == 1 &&
(node = bgpstream_patricia_tree_result_set_next(res)) != NULL &&
(pfxp = BPT_get_pfx(node)) != NULL &&
bgpstream_pfx_equal(pfxp, s2p("0.0.0.0/0")) != 0);

bgpstream_patricia_tree_destroy(pt);
bgpstream_patricia_tree_result_set_destroy(&res);

return 0;
}

Expand Down