1
0
mirror of https://github.com/bgp/bgpq4.git synced 2024-05-11 05:55:05 +00:00
bgp-bgpq4/sx_prefix.c
2021-08-17 12:11:05 +00:00

1359 lines
33 KiB
C

/*
* Copyright (c) 2019-2020 Job Snijders <job@sobornost.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "sx_prefix.h"
#include "sx_report.h"
int debug_aggregation = 0;
extern int debug_expander;
struct sx_prefix*
sx_prefix_alloc(struct sx_prefix* p)
{
struct sx_prefix* sp = malloc(sizeof(struct sx_prefix));
if (!sp)
return NULL;
if (p)
memcpy(sp, p, sizeof(struct sx_prefix));
else
memset(sp, 0, sizeof(struct sx_prefix));
return sp;
}
void
sx_prefix_destroy(struct sx_prefix* p)
{
if (p)
free(p);
}
void
sx_radix_node_destroy(struct sx_radix_node *n)
{
if (n) {
if (n->payload)
free(n->payload);
if (n->prefix)
free(n->prefix);
free(n);
}
}
void
sx_prefix_adjust_masklen(struct sx_prefix* p)
{
int nbytes = (p->family == AF_INET ? 4 : 16);
int i;
if (p->masklen == nbytes * 8)
return; /* mask is all ones */
for (i = nbytes -1; i > p->masklen / 8; i--) {
p->addr.addrs[i] = 0;
}
for (i = 1; i <= 8 - p->masklen % 8; i++) {
p->addr.addrs[p->masklen / 8] &= (0xff << i);
}
}
void
sx_prefix_mask(struct sx_prefix* p, struct sx_prefix* q)
{
int i;
memset(q->addr.addrs, 0, sizeof(q->addr.addrs));
q->family = p->family;
q->masklen = p->masklen;
for (i = 0; i < p->masklen / 8; i++)
q->addr.addrs[i] = 0xff;
for (i = 1; i <= p->masklen % 8; i++)
q->addr.addrs[p->masklen / 8] |= (1 << (8 - i));
}
void
sx_prefix_imask(struct sx_prefix* p, struct sx_prefix* q)
{
int i;
memset(q->addr.addrs, 0xff, sizeof(q->addr.addrs));
q->family = p->family;
q->masklen = p->masklen;
for (i = 0; i < p->masklen / 8; i++)
q->addr.addrs[i] = 0;
for (i = 1;i <= p->masklen % 8; i++)
q->addr.addrs[p->masklen / 8] &= ~(1 <<(8 - i));
}
int
sx_prefix_parse(struct sx_prefix* p, int af, char* text)
{
char* c = NULL;
int masklen, ret;
char mtext[INET6_ADDRSTRLEN+5];
strlcpy(mtext, text, sizeof(mtext));
c = strchr(mtext,'/');
if (c) {
char* eod;
*c = 0;
masklen = strtol(c+1, &eod, 10);
if (eod && eod[0] && !isspace(eod[0])) {
*c = '/';
sx_report(SX_ERROR, "Invalid masklen in prefix %s\n",
text);
goto fixups;
}
} else {
masklen = -1;
}
if (!af) {
if (strchr(mtext, ':'))
af = AF_INET6;
else
af = AF_INET;
}
ret = inet_pton(af, mtext, &p->addr);
if (ret != 1) {
int aparts[4];
/*
* contrary to documentation (man inet_ntop on FreeBSD),
* addresses with leading zeros are not parsed correctly. Try
* to workaround this issue manually.
*/
if (af == AF_INET && sscanf(mtext, "%i.%i.%i.%i", aparts,
aparts + 1, aparts + 2, aparts + 3) == 4
&& aparts[0] >= 0 && aparts[0] < 256
&& aparts[1] >= 0 && aparts[1] < 256
&& aparts[2] >= 0 && aparts[2] < 256
&& aparts[3] >= 0 && aparts[3] < 256) {
p->addr.addr.s_addr = htonl((aparts[0] << 24) +
(aparts[1] << 16) + (aparts[2] << 8) + aparts[3]);
} else {
if (c)
*c = '/';
sx_report(SX_ERROR,"Unable to parse prefix '%s', af=%i"
" (%s), ret=%i\n", mtext, af,
af == AF_INET ? "inet" : "inet6", ret);
goto fixups;
}
}
if (af == AF_INET) {
if (masklen == -1)
p->masklen = 32;
else {
if (masklen < 0 || masklen > 32) {
p->masklen = 32;
} else {
p->masklen = masklen;
}
}
} else if (af == AF_INET6) {
if (masklen == -1)
p->masklen = 128;
else {
if (masklen < 0 || masklen > 128) {
p->masklen = 128;
} else {
p->masklen = masklen;
}
}
} else {
sx_report(SX_ERROR, "Invalid address family %i\n", af);
goto fixups;
}
p->family = af;
sx_prefix_adjust_masklen(p);
if (c)
*c = '/';
return 1;
fixups:
return 0;
}
int
sx_prefix_isbitset(struct sx_prefix* p, int n)
{
unsigned char s;
/* bits outside the prefix considered unset */
if (p->family == AF_INET && (n < 0 || n > 32))
return 0;
else if (p->family == AF_INET6 && (n < 0 || n > 128))
return 0;
s = p->addr.addrs[(n - 1) / 8];
return (s & (0x80 >> ((n - 1) % 8))) ? 1 : 0;
}
void
sx_prefix_setbit(struct sx_prefix* p, int n)
{
unsigned char* s;
if (p->family == AF_INET && (n < 0 || n > 32))
return;
else if (p->family == AF_INET6 && (n < 0 || n > 128))
return;
s = p->addr.addrs + (n - 1) / 8;
(*s) |= 0x80 >> ((n - 1) % 8);
}
int
sx_radix_tree_insert_specifics(struct sx_radix_tree* t, struct sx_prefix *p,
unsigned min, unsigned max)
{
struct sx_prefix *np;
np = sx_prefix_alloc(p);
if (np->masklen >= min) {
struct sx_radix_node *nn = sx_radix_tree_insert(t, np);
sx_prefix_destroy(np);
np = nn->prefix;
}
if (np->masklen + 1 > max)
return 1;
np->masklen += 1;
sx_radix_tree_insert_specifics(t, np, min, max);
sx_prefix_setbit(np, np->masklen);
sx_radix_tree_insert_specifics(t, np, min, max);
return 1;
}
int
sx_prefix_range_parse(struct sx_radix_tree* tree, int af, int maxlen,
char* text)
{
char* d = strchr(text, '^');
struct sx_prefix *p;
unsigned long min, max;
p = sx_prefix_alloc(NULL);
if (!d || !d[1])
return 0;
*d = 0;
if (!sx_prefix_parse(p, 0, text)) {
sx_report(SX_ERROR, "Unable to parse prefix %s^%s\n", text,
d+1);
return 0;
}
*d = '^';
if (af && p->family != af) {
sx_report(SX_ERROR, "Ignoring prefix %s, wrong af %i\n", text,
p->family);
return 0;
}
if (maxlen && p->masklen > maxlen) {
SX_DEBUG(debug_expander, "Ignoring prefix %s, masklen %i > max"
" masklen %u\n", text, p->masklen, maxlen);
return 0;
}
if (d[1] == '-') {
min = p->masklen + 1;
max = maxlen;
} else if (d[1] == '+') {
min = p->masklen;
max = maxlen;
} else if (isdigit(d[1])) {
char* dm = NULL;
min = strtoul(d+1, &dm, 10);
if (dm && *dm == '-' && isdigit(dm[1])) {
max = strtoul(dm + 1, NULL, 10);
} else if (dm && *dm) {
sx_report(SX_ERROR, "Unable to parse prefix-range "
"%s\n", text);
return 0;
}
} else {
sx_report(SX_ERROR, "Invalid prefix-range %s\n", text);
return 0;
}
if (min < p->masklen) {
sx_report(SX_ERROR, "Invalid prefix-range %s: min %lu < "
"masklen %u\n", text, min, p->masklen);
return 0;
}
if (af == AF_INET && max > 32) {
sx_report(SX_ERROR, "Invalid prefix-range %s: max %lu > "
"32\n", text, max);
return 0;
} else if (af == AF_INET6 && max > 128) {
sx_report(SX_ERROR, "Invalid ipv6 prefix-range %s: max %lu > "
"128\n", text, max);
return 0;
}
if (max > maxlen)
max = maxlen;
SX_DEBUG(debug_expander, "parsed prefix-range %s as %lu-%lu (maxlen: "
"%u)\n", text, min, max, maxlen);
sx_radix_tree_insert_specifics(tree, p, min, max);
return 1;
}
struct sx_prefix*
sx_prefix_new(int af, char* text)
{
struct sx_prefix* p = NULL;
if (!text)
return NULL;
p = sx_prefix_alloc(NULL);
if (!p)
return NULL;
if (!sx_prefix_parse(p, af, text)) {
sx_prefix_destroy(p);
return NULL;
}
return p;
}
int
sx_prefix_fprint(FILE* f, struct sx_prefix* p)
{
char buffer[128];
if (!p) {
fprintf(f?f:stdout,"(null)");
return 0;
}
inet_ntop(p->family, &p->addr, buffer, sizeof(buffer));
return fprintf( f ? f : stdout, "%s/%i", buffer, p->masklen);
}
int
sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char* sep)
{
char buffer[128];
if (!sep)
sep="/";
if (!p) {
snprintf(rbuffer, srb, "(null)");
return 0;
}
inet_ntop(p->family, &p->addr, buffer, sizeof(buffer));
return snprintf(rbuffer, srb, "%s%s%i", buffer, sep, p->masklen);
}
int
sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb)
{
return sx_prefix_snprintf_sep(p, rbuffer, srb, "/");
}
void
sx_prefix_snprintf_fmt(struct sx_prefix* p, FILE* f,
const char* name, const char* format,
unsigned int aggregateLow, unsigned int aggregateHi)
{
unsigned off = 0;
const char* c = format;
struct sx_prefix *q = sx_prefix_alloc(NULL);
char prefix[128];
while (*c) {
if (*c == '%') {
switch (*(c + 1)) {
case 'r':
case 'n':
if (NULL != inet_ntop(p->family, &p->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
case 'l':
fprintf(f, "%i", p->masklen);
break;
case 'a':
fprintf(f, "%u", aggregateLow);
break;
case 'A':
fprintf(f, "%u", aggregateHi);
break;
case '%':
fprintf(f, "%%");
break;
case 'N':
fprintf(f, "%s", name);
break;
case 'm':
sx_prefix_mask(p, q);
if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
case 'i':
sx_prefix_imask(p, q);
if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
default :
sx_report(SX_ERROR, "Unknown format char "
"'%c'\n", *(c + 1));
return;
}
c += 2;
} else if (*c == '\\') {
switch(*(c+1)) {
case 'n':
fprintf(f, "\n");
break;
case 't':
fprintf(f, "\t");
break;
case '\\':
fprintf(f, "\\");
break;
default:
fprintf(f, "%c", *(c + 1));
break;
}
c += 2;
} else {
fprintf(f, "%c", *c);
c++;
}
}
}
int
sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb)
{
char buffer[128];
if (!p) {
snprintf(rbuffer, srb, "(null)");
return 0;
}
inet_ntop(p->family, &p->addr, buffer, sizeof(buffer));
return snprintf(rbuffer, srb, "%s\\/%i", buffer, p->masklen);
}
struct sx_radix_tree*
sx_radix_tree_new(int af)
{
struct sx_radix_tree* rt = malloc(sizeof(struct sx_radix_tree));
if (!rt)
return NULL;
memset(rt, 0, sizeof(struct sx_radix_tree));
rt->family = af;
return rt;
}
int
sx_radix_tree_empty(struct sx_radix_tree* t)
{
return t->head == NULL;
}
struct sx_radix_node*
sx_radix_node_new(struct sx_prefix* prefix)
{
struct sx_radix_node* rn = malloc(sizeof(struct sx_radix_node));
if (!rn)
return NULL;
memset(rn, 0, sizeof(struct sx_radix_node));
if (prefix)
rn->prefix = sx_prefix_alloc(prefix);
return rn;
}
int
sx_prefix_eqbits(struct sx_prefix* a, struct sx_prefix* b)
{
int i;
int nbytes = (a->family == AF_INET ? 4 : 16);
for (i = 0; i < nbytes; i++) {
if (a->addr.addrs[i] == b->addr.addrs[i])
continue;
else {
int j;
for (j = 0; j < 8 && i * 8 + j <= a->masklen
&& i * 8 + j<= b->masklen; j++) {
if ((a->addr.addrs[i] & (0x80 >> j))
!= (b->addr.addrs[i] & (0x80 >> j)))
return i * 8 + j;
}
}
}
if (a->masklen < b->masklen)
return a->masklen;
return b->masklen;
}
struct sx_prefix*
sx_prefix_overlay(struct sx_prefix* p, int n)
{
struct sx_prefix* sp = sx_prefix_alloc(p);
sp->masklen = n;
sx_prefix_adjust_masklen(sp);
return sp;
}
void
sx_radix_tree_unlink(struct sx_radix_tree* tree, struct sx_radix_node* node)
{
next:
if (node->r && node->l)
node->isGlue = 1;
else if (node->r) {
if (node->parent) {
if (node->parent->r == node) {
node->parent->r = node->r;
node->r->parent = node->parent;
} else if (node->parent->l == node) {
node->parent->l = node->r;
node->r->parent = node->parent;
} else {
sx_report(SX_ERROR,"Unlinking node which is "
"not descendant of its parent\n");
}
} else if (tree->head == node) {
/* only one case, really */
tree->head = node->r;
node->r->parent = NULL;
} else {
sx_report(SX_ERROR,"Unlinking node with no parent and"
" not root\n");
}
sx_radix_node_destroy(node);
return;
} else if (node->l) {
if (node->parent) {
if (node->parent->r == node) {
node->parent->r = node->l;
node->l->parent = node->parent;
} else if (node->parent->l==node) {
node->parent->l=node->l;
node->l->parent=node->parent;
} else {
sx_report(SX_ERROR,"Unlinking node which is not descendant "
"of its parent\n");
}
} else if (tree->head==node) {
tree->head=node->l;
node->l->parent=NULL;
} else {
sx_report(SX_ERROR,"Unlinking node with no parent and not root\n");
}
sx_radix_node_destroy(node);
return;
} else {
/* the only case - node does not have descendants */
if (node->parent) {
if (node->parent->l == node)
node->parent->l = NULL;
else if (node->parent->r == node)
node->parent->r=NULL;
else {
sx_report(SX_ERROR,"Unlinking node which is "
"not descendant of its parent\n");
}
if (node->parent->isGlue) {
node = node->parent;
goto next;
}
} else if (tree->head==node) {
tree->head = NULL;
} else {
sx_report(SX_ERROR, "Unlinking node with no parent and"
" not root\n");
}
sx_radix_node_destroy(node);
return;
}
}
struct sx_radix_node*
sx_radix_tree_lookup(struct sx_radix_tree* tree, struct sx_prefix* prefix)
{
int eb;
struct sx_radix_node* candidate = NULL, *chead;
if (!tree || !prefix)
return NULL;
if (tree->family!=prefix->family)
return NULL;
if (!tree->head)
return NULL;
chead = tree->head;
next:
eb = sx_prefix_eqbits(chead->prefix, prefix);
if (eb == chead->prefix->masklen && eb == prefix->masklen) {
/* they are equal */
if (chead->isGlue)
return candidate;
return chead;
} else if (eb < chead->prefix->masklen) {
return candidate;
} else if (eb < prefix->masklen) {
/* it equals chead->masklen */
if (sx_prefix_isbitset(prefix, eb + 1)) {
if (chead->r) {
if (!chead->isGlue) {
candidate = chead;
}
chead = chead->r;
goto next;
} else {
if (chead->isGlue)
return candidate;
return chead;
}
} else {
if (chead->l) {
if (!chead->isGlue) {
candidate = chead;
}
chead = chead->l;
goto next;
} else {
if (chead->isGlue)
return candidate;
return chead;
}
}
} else {
char pbuffer[128], cbuffer[128];
sx_prefix_snprintf(prefix, pbuffer, sizeof(pbuffer));
sx_prefix_snprintf(chead->prefix, cbuffer, sizeof(cbuffer));
printf("Unreachible point... eb=%i, prefix=%s, chead=%s\n",
eb, pbuffer, cbuffer);
abort();
}
}
struct sx_radix_node*
sx_radix_tree_insert(struct sx_radix_tree* tree, struct sx_prefix* prefix)
{
int eb;
struct sx_radix_node** candidate=NULL, *chead;
if (!tree || !prefix)
return NULL;
if (tree->family!=prefix->family)
return NULL;
if (!tree->head) {
tree->head=sx_radix_node_new(prefix);
return tree->head;
}
candidate = &tree->head;
chead = tree->head;
next:
eb = sx_prefix_eqbits(prefix, chead->prefix);
if (eb < prefix->masklen && eb < chead->prefix->masklen) {
struct sx_prefix *neoRoot = sx_prefix_alloc(prefix);
struct sx_radix_node* rn, *ret=sx_radix_node_new(prefix);
neoRoot->masklen = eb;
sx_prefix_adjust_masklen(neoRoot);
rn=sx_radix_node_new(neoRoot);
sx_prefix_destroy(neoRoot);
neoRoot = rn->prefix;
if (!rn) {
sx_report(SX_ERROR,"Unable to create node: %s\n",
strerror(errno));
return NULL;
}
if (sx_prefix_isbitset(prefix, eb + 1)) {
rn->l = chead;
rn->r = ret;
} else {
rn->l = ret;
rn->r = chead;
}
rn->parent = chead->parent;
chead->parent = rn;
ret->parent = rn;
rn->isGlue = 1;
*candidate = rn;
return ret;
} else if (eb == prefix->masklen && eb < chead->prefix->masklen) {
struct sx_radix_node* ret = sx_radix_node_new(prefix);
if (sx_prefix_isbitset(chead->prefix, eb + 1)) {
ret->r = chead;
} else {
ret->l = chead;
}
ret->parent = chead->parent;
chead->parent = ret;
*candidate = ret;
return ret;
} else if (eb == chead->prefix->masklen && eb < prefix->masklen) {
if (sx_prefix_isbitset(prefix, eb + 1)) {
if (chead->r) {
candidate = &chead->r;
chead = chead->r;
goto next;
} else {
chead->r = sx_radix_node_new(prefix);
chead->r->parent = chead;
return chead->r;
}
} else {
if (chead->l) {
candidate = &chead->l;
chead = chead->l;
goto next;
} else {
chead->l = sx_radix_node_new(prefix);
chead->l->parent = chead;
return chead->l;
}
}
} else if (eb == chead->prefix->masklen && eb == prefix->masklen) {
/* equal routes... */
if (chead->isGlue) {
chead->isGlue = 0;
}
return chead;
} else {
char pbuffer[128], cbuffer[128];
sx_prefix_snprintf(prefix, pbuffer, sizeof(pbuffer));
sx_prefix_snprintf(chead->prefix, cbuffer, sizeof(cbuffer));
printf("Unreachible point... eb=%i, prefix=%s, chead=%s\n", eb,
pbuffer, cbuffer);
abort();
}
}
void
sx_radix_node_fprintf(struct sx_radix_node* node, void* udata)
{
FILE* out = (udata?udata:stdout);
char buffer[128];
if (!node) {
fprintf(out, "(null)\n");
} else {
sx_prefix_snprintf(node->prefix, buffer, sizeof(buffer));
fprintf(out, "%s %s\n", buffer, node->isGlue ? "(glue)" : "");
}
}
int
sx_radix_node_foreach(struct sx_radix_node* node,
void (*func)(struct sx_radix_node*, void*), void* udata)
{
func(node, udata);
if (node->l)
sx_radix_node_foreach(node->l, func, udata);
if (node->r)
sx_radix_node_foreach(node->r, func, udata);
return 0;
}
int
sx_radix_tree_foreach(struct sx_radix_tree* tree,
void (*func)(struct sx_radix_node*, void*), void* udata)
{
if (!func || !tree || !tree->head)
return 0;
sx_radix_node_foreach(tree->head, func, udata);
return 0;
}
int
sx_radix_node_aggregate(struct sx_radix_node* node)
{
if (node->l)
sx_radix_node_aggregate(node->l);
if (node->r)
sx_radix_node_aggregate(node->r);
if (debug_aggregation) {
printf("Aggregating on node: ");
sx_prefix_fprint(stdout, node->prefix);
printf(" %s%s%u,%u\n", node->isGlue?"Glue ":"",
node->isAggregate?"Aggregate ":"",node->aggregateLow,
node->aggregateHi);
if (node->r) {
printf("R-Tree: ");
sx_prefix_fprint(stdout, node->r->prefix);
printf(" %s%s%u,%u\n",
(node->r->isGlue) ? "Glue " : "",
(node->r->isAggregate) ? " Aggregate ": "",
node->r->aggregateLow, node->r->aggregateHi);
if (node->r->son) {
printf("R-Son: ");
sx_prefix_fprint(stdout, node->r->son->prefix);
printf(" %s%s%u,%u\n",
node->r->son->isGlue ? "Glue " : "",
node->r->son->isAggregate ? "Aggregate " : "",
node->r->son->aggregateLow,
node->r->son->aggregateHi);
}
}
if (node->l) {
printf("L-Tree: ");
sx_prefix_fprint(stdout, node->l->prefix);
printf(" %s%s%u,%u\n", node->l->isGlue ? "Glue ": "",
node->l->isAggregate ? "Aggregate ": "",
node->l->aggregateLow, node->l->aggregateHi);
if (node->l->son) {
printf("L-Son: ");
sx_prefix_fprint(stdout, node->l->son->prefix);
printf(" %s%s%u,%u\n",
node->l->son->isGlue ? "Glue " : "",
node->l->son->isAggregate ? "Aggregate " : "",
node->l->son->aggregateLow,
node->l->son->aggregateHi);
}
}
}
if (node->r && node->l) {
if (!node->r->isAggregate && !node->l->isAggregate
&& !node->r->isGlue && !node->l->isGlue
&& node->r->prefix->masklen == node->l->prefix->masklen) {
if (node->r->prefix->masklen == node->prefix->masklen+1) {
node->isAggregate = 1;
node->r->isGlue = 1;
node->l->isGlue = 1;
node->aggregateHi = node->r->prefix->masklen;
if (node->isGlue) {
node->isGlue = 0;
node->aggregateLow = node->r->prefix->masklen;
} else {
node->aggregateLow = node->prefix->masklen;
}
}
if (node->r->son && node->l->son
&& node->r->son->isAggregate
&& node->l->son->isAggregate
&& node->r->son->aggregateHi == node->l->son->aggregateHi
&& node->r->son->aggregateLow == node->l->son->aggregateLow
&& node->r->prefix->masklen == node->prefix->masklen + 1
&& node->l->prefix->masklen == node->prefix->masklen + 1) {
node->son = sx_radix_node_new(node->prefix);
node->son->isGlue = 0;
node->son->isAggregate = 1;
node->son->aggregateHi = node->r->son->aggregateHi;
node->son->aggregateLow = node->r->son->aggregateLow;
node->r->son->isGlue = 1;
node->l->son->isGlue = 1;
}
} else if (node->r->isAggregate && node->l->isAggregate
&& node->r->aggregateHi == node->l->aggregateHi
&& node->r->aggregateLow==node->l->aggregateLow) {
if (node->r->prefix->masklen == node->prefix->masklen + 1
&& node->l->prefix->masklen == node->prefix->masklen + 1) {
if (node->isGlue) {
node->r->isGlue = 1;
node->l->isGlue = 1;
node->isAggregate = 1;
node->isGlue = 0;
node->aggregateHi = node->r->aggregateHi;
node->aggregateLow = node->r->aggregateLow;
} else if (node->r->prefix->masklen == node->r->aggregateLow) {
node->r->isGlue = 1;
node->l->isGlue = 1;
node->isAggregate = 1;
node->aggregateHi = node->r->aggregateHi;
node->aggregateLow = node->prefix->masklen;
} else {
node->son = sx_radix_node_new(node->prefix);
node->son->isGlue = 0;
node->son->isAggregate = 1;
node->son->aggregateHi = node->r->aggregateHi;
node->son->aggregateLow = node->r->aggregateLow;
node->r->isGlue = 1;
node->l->isGlue = 1;
if (node->r->son && node->l->son
&& node->r->son->aggregateHi == node->l->son->aggregateHi
&& node->r->son->aggregateLow == node->l->son->aggregateLow) {
node->son->son = sx_radix_node_new(node->prefix);
node->son->son->isGlue = 0;
node->son->son->isAggregate = 1;
node->son->son->aggregateHi = node->r->son->aggregateHi;
node->son->son->aggregateLow = node->r->son->aggregateLow;
node->r->son->isGlue = 1;
node->l->son->isGlue = 1;
}
}
}
} else if (node->l->son && node->r->isAggregate
&& node->l->son->isAggregate
&& node->r->aggregateHi == node->l->son->aggregateHi
&& node->r->aggregateLow == node->l->son->aggregateLow) {
if (node->r->prefix->masklen == node->prefix->masklen + 1
&& node->l->prefix->masklen == node->prefix->masklen + 1) {
if (node->isGlue) {
node->r->isGlue = 1;
node->l->son->isGlue = 1;
node->isAggregate = 1;
node->isGlue = 0;
node->aggregateHi = node->r->aggregateHi;
node->aggregateLow = node->r->aggregateLow;
} else {
node->son = sx_radix_node_new(node->prefix);
node->son->isGlue = 0;
node->son->isAggregate = 1;
node->son->aggregateHi = node->r->aggregateHi;
node->son->aggregateLow = node->r->aggregateLow;
node->r->isGlue = 1;
node->l->son->isGlue = 1;
}
}
} else if (node->r->son && node->l->isAggregate
&& node->r->son->isAggregate
&& node->l->aggregateHi == node->r->son->aggregateHi
&& node->l->aggregateLow == node->r->son->aggregateLow) {
if (node->l->prefix->masklen == node->prefix->masklen + 1
&& node->r->prefix->masklen == node->prefix->masklen+1) {
if (node->isGlue) {
node->l->isGlue = 1;
node->r->son->isGlue = 1;
node->isAggregate = 1;
node->isGlue = 0;
node->aggregateHi = node->l->aggregateHi;
node->aggregateLow = node->l->aggregateLow;
} else {
node->son = sx_radix_node_new(node->prefix);
node->son->isGlue = 0;
node->son->isAggregate = 1;
node->son->aggregateHi = node->l->aggregateHi;
node->son->aggregateLow = node->l->aggregateLow;
node->l->isGlue = 1;
node->r->son->isGlue = 1;
}
}
}
}
return 0;
}
int
sx_radix_tree_aggregate(struct sx_radix_tree* tree)
{
if (tree && tree->head)
return sx_radix_node_aggregate(tree->head);
return 0;
}
static void
setGlueUpTo(struct sx_radix_node* node, void* udata)
{
unsigned refine = *(unsigned*)udata;
if (node && node->prefix->masklen <= refine)
node->isGlue = 1;
}
int
sx_radix_node_refine(struct sx_radix_node* node, unsigned refine)
{
if (!node->isGlue && node->prefix->masklen<refine) {
node->isAggregate = 1;
node->aggregateLow = node->prefix->masklen;
node->aggregateHi = refine;
if (node->l) {
sx_radix_node_foreach(node->l, setGlueUpTo, &refine);
sx_radix_node_refine(node->l, refine);
}
if (node->r) {
sx_radix_node_foreach(node->r, setGlueUpTo, &refine);
sx_radix_node_refine(node->r, refine);
}
} else if (!node->isGlue && node->prefix->masklen == refine) {
/* not setting aggregate in this case */
if (node->l)
sx_radix_node_refine(node->l, refine);
if (node->r)
sx_radix_node_refine(node->r, refine);
} else if (node->isGlue) {
if (node->r)
sx_radix_node_refine(node->r, refine);
if (node->l)
sx_radix_node_refine(node->l, refine);
} else {
/* node->prefix.masklen > refine */
/*
* do nothing, should pass specifics 'as is'. Also, do not
* process any embedded routes, their masklen is bigger, too...
node->isGlue = 1;
if (node->l)
sx_radix_node_foreach(node->l, setGlue, NULL);
if (node->r)
sx_radix_node_foreach(node->r, setGlue, NULL);
*/
}
return 0;
}
int
sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine)
{
if (tree && tree->head)
return sx_radix_node_refine(tree->head, refine);
return 0;
}
static void
setGlueFrom(struct sx_radix_node* node, void* udata)
{
unsigned refine = *(unsigned*)udata;
if (node && node->prefix->masklen <= refine)
node->isGlue = 1;
}
static int
sx_radix_node_refineLow(struct sx_radix_node* node, unsigned refineLow)
{
if (!node->isGlue && node->prefix->masklen<=refineLow) {
if (!node->isAggregate) {
node->isAggregate = 1;
node->aggregateLow = refineLow;
if (node->prefix->family == AF_INET)
node->aggregateHi = 32;
else
node->aggregateHi = 128;
} else
node->aggregateLow=refineLow;
if (node->l) {
sx_radix_node_foreach(node->l, setGlueFrom, &refineLow);
sx_radix_node_refineLow(node->l, refineLow);
}
if (node->r) {
sx_radix_node_foreach(node->r, setGlueFrom, &refineLow);
sx_radix_node_refineLow(node->r, refineLow);
}
} else if (!node->isGlue && node->prefix->masklen == refineLow) {
/* not setting aggregate in this case */
if (node->l)
sx_radix_node_refineLow(node->l, refineLow);
if (node->r)
sx_radix_node_refineLow(node->r, refineLow);
} else if (node->isGlue) {
if (node->r)
sx_radix_node_refineLow(node->r, refineLow);
if (node->l)
sx_radix_node_refineLow(node->l, refineLow);
} else {
/* node->prefix.masklen > refine */
/* do nothing, should pass specifics 'as is'. Also, do not
process any embedded routes, their masklen is bigger, too...
node->isGlue = 1;
if (node->l)
sx_radix_node_foreach(node->l, setGlue, NULL);
if (node->r)
sx_radix_node_foreach(node->r, setGlue, NULL);
*/
}
return 0;
}
int
sx_radix_tree_refineLow(struct sx_radix_tree* tree, unsigned refineLow)
{
if (tree && tree->head)
return sx_radix_node_refineLow(tree->head, refineLow);
return 0;
}
#if SX_PTREE_TEST
int
main() {
struct sx_prefix* p;
int n;
struct sx_radix_tree* tree;
struct sx_radix_node* node;
p = sx_prefix_new(0, "10.11.12.13/24");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.13/33");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.13/-133");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET, "10.11.12.14/24");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET, "10.11.12.14/33");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET, "10.11.12.14/-133");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "10.11.12.15/24");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "10.11.12.15/33");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "10.11.12.15/-133");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "2001:1b00::/24");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "2001:1b00::/33");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "2001:1b00::/-133");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "2001:1b01::/24");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "2001:1b01::/33");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(AF_INET6, "2001:1b01::/-133");
sx_prefix_fprint(stdout, p);
printf("\n");
#define SX_TEST_EBITS(a,b,susp) n = sx_prefix_eqbits(sx_prefix_new(0,a)),\
sx_prefix_new(0,b))); \
if (n != susp) \
printf("FAILED: %s eqbits %s=%i, not %i\n", a, b, n,
susp);\
else
printf("OK, %s eqbits %s = %i, as suspected\n", a, b,
n);
SX_TEST_EBITS("192.168.0.0/24", "192.168.1.0/24", 23);
SX_TEST_EBITS("192.168.0.0/32", "192.168.0.1/32", 31);
#if SX_LIBPTREE_IPV6
SX_TEST_EBITS("2001:1b00::/32", "2001:1b01::/32", 31);
#endif
p = sx_prefix_new(0, "10.11.12.255/32");
sx_prefix_fprint(stdout, p);
printf("\n31'th bit is %i\n",sx_prefix_isbitset(p, 31));
printf("32'th bit is %i\n",sx_prefix_isbitset(p, 32));
printf("33'th bit is %i\n",sx_prefix_isbitset(p, 33));
p = sx_prefix_new(0, "10.11.12.255/31");
sx_prefix_fprint(stdout, p);
printf("\n31'th bit is %i\n", sx_prefix_isbitset(p, 31));
printf("32'th bit is %i\n", sx_prefix_isbitset(p, 32));
printf("33'th bit is %i\n", sx_prefix_isbitset(p, 33));
p = sx_prefix_new(0, "10.11.12.255/30");
sx_prefix_fprint(stdout, p);
printf("\n31'th bit is %i\n", sx_prefix_isbitset(p, 31));
p = sx_prefix_new(0, "10.11.12.255/29");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.255/28");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.255/27");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.255/26");
sx_prefix_fprint(stdout, p);
printf("\n");
p = sx_prefix_new(0, "10.11.12.255/25");
sx_prefix_fprint(stdout, p);
printf("\n25'th bit is %i\n", sx_prefix_isbitset(p, 25));
p = sx_prefix_new(0, "10.11.12.255/24");
sx_prefix_fprint(stdout, p);
printf("\n25'th bit is %i\n", sx_prefix_isbitset(p, 25));
tree = sx_radix_tree_new(AF_INET);
sx_radix_tree_insert(tree, sx_prefix_new(0, "81.9.100.10/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.83/32"));
sx_radix_tree_foreach(tree, sx_radix_node_fprintf, NULL);
tree = sx_radix_tree_new(AF_INET);
sx_radix_tree_insert(tree, sx_prefix_new(0, "81.9.100.10/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.83/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.84/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.85/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.86/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.87/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.90/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.90/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "127.0.0.1/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "127.0.0.1/24"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "127.0.0.0/24"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "128.0.0.0/1"));
sx_radix_tree_foreach(tree, sx_radix_node_fprintf, NULL);
printf("lookup 1.1.1.1: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "1.1.1.1"));
sx_radix_node_fprintf(node, NULL);
printf("lookup 217.170.80.90: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "217.170.80.90"));
sx_radix_node_fprintf(node, NULL);
sx_radix_tree_unlink(tree, node);
printf("lookup 217.170.80.90 after delete: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "217.170.80.90"));
sx_radix_node_fprintf(node, NULL);
sx_radix_tree_insert(tree, sx_prefix_new(0, "217.170.80.90/32"));
printf("lookup 217.170.80.90 after reinsert: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "217.170.80.90"));
sx_radix_node_fprintf(node, NULL);
printf("lookup 217.170.80.81: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "217.170.80.81"));
sx_radix_node_fprintf(node, NULL);
printf("lookup 127.0.0.1/24: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "127.0.0.1/24"));
sx_radix_node_fprintf(node, NULL);
printf("lookup 127.0.0.1/26: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "127.0.0.1/26"));
sx_radix_node_fprintf(node, NULL);
printf("lookup 127.0.0.1/23: ");
node = sx_radix_tree_lookup(tree, sx_prefix_new(0, "127.0.0.1/23"));
sx_radix_node_fprintf(node, NULL);
tree = sx_radix_tree_new(AF_INET6);
sx_radix_tree_insert(tree, sx_prefix_new(0, "2100:1b00::/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "2100:1b01::/32"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "2100:1b00::/33"));
sx_radix_tree_insert(tree, sx_prefix_new(0, "2100:1b00::1/128"));
sx_radix_tree_foreach(tree, sx_radix_node_fprintf, NULL);
return 0;
}
#endif