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)
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");
#define _BIRD_ROUTE_H_
#include "lib/lists.h"
+#include "lib/redblack.h"
#include "lib/resource.h"
#include "lib/net.h"
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;
};
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 */
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 */
#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_)
* 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.
*/
{
uint addr_length = net_addr_length[addr_type];
+ f->tree_root = NULL;
+
if (!hash_order)
hash_order = HASH_DEF_ORDER;
f->fib_pool = p;
#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) \
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); \
})
}
}
-
-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
while (*ee)
{
- if (*ee == e)
+ if (*ee != e)
{
- *ee = e->next;
- if (it = e->readers)
+ ee = &((*ee)->next);
+ continue;
+ }
+
+ *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
{
- struct fib_node *l = e->next;
- while (!l)
- {
- h++;
- if (h >= f->hash_size)
- break;
- else
- l = f->hash_table[h];
+ if (hnext == UNDEF)
+ {
+ hnext = e->next;
+ while (!hnext)
+ {
+ h++;
+ if (h >= f->hash_size)
+ break;
+ else
+ hnext = f->hash_table[h];
+ }
}
- fib_merge_readers(it, l);
+ fit_put(it, hnext);
}
+ }
+#undef UNDEF
- if (f->fib_slab)
- sl_free(f->fib_slab, E);
- else
- mb_free(E);
+ 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);
+ 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");
}
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;
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;
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;
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");
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) &&