0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-11 17:08:46 +00:00

Nest: Using the brand-new redblack tree to provide an ordered route listing

This commit is contained in:
Jan Maria Matejka 2018-12-03 10:31:59 +01:00
parent a29de335c7
commit 4067ad1aa4
4 changed files with 102 additions and 91 deletions

View File

@ -71,7 +71,7 @@ CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERE
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED, ORDERED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, STATISTICS)
@ -558,6 +558,10 @@ r_args:
rt_show_add_table($$, t->table);
$$->tables_defined_by = RSD_TDB_ALL;
}
| r_args ORDERED {
$$ = $1;
$$->fit.flags |= FIF_ORDERED;
}
| r_args FILTER filter {
$$ = $1;
if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");

View File

@ -10,6 +10,7 @@
#define _BIRD_ROUTE_H_
#include "lib/lists.h"
#include "lib/redblack.h"
#include "lib/resource.h"
#include "lib/net.h"
@ -37,13 +38,17 @@ struct fib_node {
struct fib_node *next; /* Next in hash chain */
struct fib_iterator *readers; /* List of readers of this node */
byte flags; /* User-defined, will be removed */
REDBLACK_NODE(struct fib_node, rb); /* Node in search tree */
net_addr addr[0];
};
#define FIF_ORDERED 1
struct fib_iterator { /* See lib/slists.h for an explanation */
struct fib_iterator *prev, *next; /* Must be synced with struct fib_node! */
byte efef; /* 0xff to distinguish between iterator and node */
byte pad[3];
byte flags; /* FIF_* */
byte pad[2];
struct fib_node *node; /* Or NULL if freshly merged */
uint hash;
};
@ -53,6 +58,7 @@ typedef void (*fib_init_fn)(void *);
struct fib {
pool *fib_pool; /* Pool holding all our data */
slab *fib_slab; /* Slab holding all fib nodes */
struct fib_node *tree_root; /* Tree to hold lexicographically sorted entries */
struct fib_node **hash_table; /* Node hash table */
uint hash_size; /* Number of hash table entries (a power of two) */
uint hash_order; /* Binary logarithm of hash_size */
@ -73,7 +79,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e)
void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init);
void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */
void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */
void *fib_get_chain(struct fib *f, const net_addr *a) DEPRECATED; /* Find first node in linked list from hash table */
void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */
void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */
void fib_delete(struct fib *, void *); /* Remove fib entry */
@ -98,21 +104,27 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin
#define FIB_ITERATE_INIT(it, fib) fit_init(it, fib)
#define FIB_ITERATE_START(fib, it, type, z) do { \
struct fib_iterator *it_ = it; \
struct fib_node *fn_ = fit_get(fib, it); \
uint count_ = (fib)->hash_size; \
uint hpos_ = (it)->hash; \
uint hpos_ = (it_)->hash; \
type *z; \
for(;;) { \
if (!fn_) \
{ \
if (++hpos_ >= count_) \
if ((it_->flags & FIF_ORDERED) || \
(++hpos_ >= count_)) \
break; \
fn_ = (fib)->hash_table[hpos_]; \
continue; \
} \
z = fib_node_to_user(fib, fn_);
#define FIB_ITERATE_END fn_ = fn_->next; } } while(0)
#define FIB_ITERATE_END \
fn_ = (it_->flags & FIF_ORDERED) ? \
REDBLACK_NEXT(struct fib_node, rb, fn_) : \
fn_->next; \
} } while(0)
#define FIB_ITERATE_PUT(it) fit_put(it, fn_)

View File

@ -2,6 +2,7 @@
* BIRD -- Forwarding Information Base -- Data Structures
*
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
* (c) 2018 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@ -111,6 +112,8 @@ fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offse
{
uint addr_length = net_addr_length[addr_type];
f->tree_root = NULL;
if (!hash_order)
hash_order = HASH_DEF_ORDER;
f->fib_pool = p;
@ -172,6 +175,7 @@ fib_rehash(struct fib *f, int step)
#define CAST(t) (const net_addr_##t *)
#define CAST2(t) (net_addr_##t *)
#define FIB_KEY(e) ((e)->addr)
#define FIB_HASH(f,a,t) (net_hash_##t(CAST(t) a) >> f->hash_shift)
#define FIB_FIND(f,a,t) \
@ -194,6 +198,8 @@ fib_rehash(struct fib *f, int step)
net_copy_##t(CAST2(t) e->addr, CAST(t) a); \
e->next = *ee; \
*ee = e; \
REDBLACK_INSERT(struct fib_node, rb, CAST(t) FIB_KEY, \
net_compare_##t, f->tree_root, e); \
})
@ -363,41 +369,6 @@ fib_route(struct fib *f, const net_addr *n)
}
}
static inline void
fib_merge_readers(struct fib_iterator *i, struct fib_node *to)
{
if (to)
{
struct fib_iterator *j = to->readers;
if (!j)
{
/* Fast path */
to->readers = i;
i->prev = (struct fib_iterator *) to;
}
else
{
/* Really merging */
while (j->next)
j = j->next;
j->next = i;
i->prev = j;
}
while (i && i->node)
{
i->node = NULL;
i = i->next;
}
}
else /* No more nodes */
while (i)
{
i->prev = NULL;
i = i->next;
}
}
/**
* fib_delete - delete a FIB node
* @f: FIB to delete from
@ -417,33 +388,54 @@ fib_delete(struct fib *f, void *E)
while (*ee)
{
if (*ee == e)
if (*ee != e)
{
*ee = e->next;
if (it = e->readers)
{
struct fib_node *l = e->next;
while (!l)
{
h++;
if (h >= f->hash_size)
break;
else
l = f->hash_table[h];
}
fib_merge_readers(it, l);
}
if (f->fib_slab)
sl_free(f->fib_slab, E);
else
mb_free(E);
if (f->entries-- < f->entries_min)
fib_rehash(f, -HASH_LO_STEP);
return;
ee = &((*ee)->next);
continue;
}
ee = &((*ee)->next);
*ee = e->next;
#define UNDEF ((void *) 1)
struct fib_node *onext = UNDEF, *hnext = UNDEF;
while (it = e->readers)
{
e->readers = it->next;
if (it->flags & FIF_ORDERED)
{
if (onext == UNDEF)
onext = REDBLACK_NEXT(struct fib_node, rb, e);
fit_put(it, onext);
}
else
{
if (hnext == UNDEF)
{
hnext = e->next;
while (!hnext)
{
h++;
if (h >= f->hash_size)
break;
else
hnext = f->hash_table[h];
}
}
fit_put(it, hnext);
}
}
#undef UNDEF
if (f->fib_slab)
sl_free(f->fib_slab, E);
else
mb_free(E);
REDBLACK_DELETE(struct fib_node, rb, f->tree_root, e);
if (f->entries-- < f->entries_min)
fib_rehash(f, -HASH_LO_STEP);
return;
}
bug("fib_delete() called for invalid node");
}
@ -469,16 +461,18 @@ fit_init(struct fib_iterator *i, struct fib *f)
struct fib_node *n;
i->efef = 0xff;
for(h=0; h<f->hash_size; h++)
if (n = f->hash_table[h])
{
i->prev = (struct fib_iterator *) n;
if (i->next = n->readers)
i->next->prev = i;
n->readers = i;
i->node = n;
return;
}
if (i->flags & FIF_ORDERED)
{
if (n = REDBLACK_FIRST(struct fib_node, rb, f->tree_root))
return fit_put(i, n);
}
else
{
for(h=0; h<f->hash_size; h++)
if (n = f->hash_table[h])
return fit_put(i, n);
}
/* The fib is empty, nothing to do */
i->prev = i->next = NULL;
i->node = NULL;
@ -496,14 +490,8 @@ fit_get(struct fib *f, struct fib_iterator *i)
i->hash = ~0 - 1;
return NULL;
}
if (!(n = i->node))
{
/* No node info available, we are a victim of merging. Try harder. */
j = i;
while (j->efef == 0xff)
j = j->prev;
n = (struct fib_node *) j;
}
ASSERT(i->node);
n = i->node;
j = i->prev;
if (k = i->next)
k->prev = j;
@ -528,12 +516,20 @@ fit_put(struct fib_iterator *i, struct fib_node *n)
void
fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uint hpos)
{
if (n = n->next)
goto found;
if (i->flags & FIF_ORDERED)
{
if (n = REDBLACK_NEXT(struct fib_node, rb, n))
goto found;
}
else
{
if (n = n->next)
goto found;
while (++hpos < f->hash_size)
if (n = f->hash_table[hpos])
goto found;
while (++hpos < f->hash_size)
if (n = f->hash_table[hpos])
goto found;
}
/* We are at the end */
i->prev = i->next = NULL;
@ -576,8 +572,6 @@ fib_check(struct fib *f)
bug("fib_check: iterator->prev mismatch");
j0 = j;
if (!j->node)
nulls++;
else if (nulls)
bug("fib_check: iterator nullified");
else if (j->node != n)
bug("fib_check: iterator->node mismatch");

View File

@ -101,6 +101,7 @@ net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
match with the smallest matching src prefix. */
for (fn = fib_get_chain(&t->fib, (net_addr *) n); fn; fn = fn->next)
{
/* TODO: This may be more effectively done by searching in the redblack tree. */
net_addr_ip6_sadr *a = (void *) fn->addr;
if (net_equal_dst_ip6_sadr(n, a) &&