mirror of
https://github.com/bgp/bgpq4.git
synced 2024-05-11 05:55:05 +00:00
1359 lines
33 KiB
C
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
|