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:
parent
a29de335c7
commit
4067ad1aa4
@ -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");
|
||||
|
22
nest/route.h
22
nest/route.h
@ -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_)
|
||||
|
||||
|
164
nest/rt-fib.c
164
nest/rt-fib.c
@ -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");
|
||||
|
@ -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) &&
|
||||
|
Loading…
x
Reference in New Issue
Block a user