Routing table core changes to support full route filtering:
o Introduced rte_cow() which should be used for copying on write the rte's in filters. Each rte now carries a flag saying whether it's a real route (possessing table linkage and other insignia) or a local copy. This function can be expected to be fast since its fast-path is inlined. o Introduced rte_update_pool which is a linear memory pool used for all temporary data during rte_update. You should not reference it directly -- instead use a pool pointer passed to all related functions. o Split rte_update to three functions: rte_update The front end: handles all checking, inbound filtering and calls rte_recalculate() for the final version of the route. rte_recalculate Update the table according to already filtered route. rte_announce Announce routing table changes to all protocols, passing them through export filters and so on. The interface has _not_ changed -- still call rte_update() and it will do the rest for you automagically. o Use new filtering semantics to be explained in a separate mail.
This commit is contained in:
parent
9e0e485e50
commit
e2dc2f30ef
2 changed files with 108 additions and 26 deletions
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BIRD Internet Routing Daemon -- Routing Table
|
* BIRD Internet Routing Daemon -- Routing Table
|
||||||
*
|
*
|
||||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -150,6 +150,8 @@ typedef struct rte {
|
||||||
} u;
|
} u;
|
||||||
} rte;
|
} rte;
|
||||||
|
|
||||||
|
#define REF_COW 1 /* Copy this rte on write */
|
||||||
|
|
||||||
extern rtable master_table;
|
extern rtable master_table;
|
||||||
|
|
||||||
void rt_init(void);
|
void rt_init(void);
|
||||||
|
@ -162,6 +164,8 @@ void rte_update(net *net, struct proto *p, rte *new);
|
||||||
void rte_discard(rte *old);
|
void rte_discard(rte *old);
|
||||||
void rte_dump(rte *);
|
void rte_dump(rte *);
|
||||||
void rte_free(rte *);
|
void rte_free(rte *);
|
||||||
|
rte *rte_do_cow(rte *);
|
||||||
|
static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
|
||||||
void rt_dump(rtable *);
|
void rt_dump(rtable *);
|
||||||
void rt_dump_all(void);
|
void rt_dump_all(void);
|
||||||
void rt_feed_baby(struct proto *p);
|
void rt_feed_baby(struct proto *p);
|
||||||
|
|
128
nest/rt-table.c
128
nest/rt-table.c
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
rtable master_table;
|
rtable master_table;
|
||||||
static slab *rte_slab;
|
static slab *rte_slab;
|
||||||
|
static linpool *rte_update_pool;
|
||||||
|
|
||||||
#define RT_GC_MIN_TIME 5 /* FIXME: Make configurable */
|
#define RT_GC_MIN_TIME 5 /* FIXME: Make configurable */
|
||||||
#define RT_GC_MIN_COUNT 100
|
#define RT_GC_MIN_COUNT 100
|
||||||
|
@ -95,6 +96,17 @@ rte_get_temp(rta *a)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rte *
|
||||||
|
rte_do_cow(rte *r)
|
||||||
|
{
|
||||||
|
rte *e = sl_alloc(rte_slab);
|
||||||
|
|
||||||
|
memcpy(e, r, sizeof(rte));
|
||||||
|
e->attrs = rta_clone(r->attrs);
|
||||||
|
e->flags = 0;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
static int /* Actually better or at least as good as */
|
static int /* Actually better or at least as good as */
|
||||||
rte_better(rte *new, rte *old)
|
rte_better(rte *new, rte *old)
|
||||||
{
|
{
|
||||||
|
@ -114,21 +126,42 @@ rte_better(rte *new, rte *old)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
do_rte_announce(struct proto *p, net *net, rte *new, rte *old)
|
do_rte_announce(struct proto *p, net *net, rte *new, rte *old, ea_list *tmpa)
|
||||||
{
|
{
|
||||||
if (p->out_filter)
|
rte *new0 = new;
|
||||||
|
rte *old0 = old;
|
||||||
|
if (new)
|
||||||
{
|
{
|
||||||
if (old && f_run(p->out_filter, old, NULL) != F_ACCEPT)
|
int ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0;
|
||||||
old = NULL;
|
if (ok < 0 ||
|
||||||
if (new && f_run(p->out_filter, new, NULL) != F_ACCEPT)
|
(!ok && (p->out_filter == FILTER_REJECT ||
|
||||||
|
p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool) > F_MODIFY)
|
||||||
|
)
|
||||||
|
)
|
||||||
new = NULL;
|
new = NULL;
|
||||||
}
|
}
|
||||||
|
if (old && p->out_filter)
|
||||||
|
{
|
||||||
|
/* FIXME: Do we really need to filter old routes? */
|
||||||
|
if (p->out_filter == FILTER_REJECT)
|
||||||
|
old = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL;
|
||||||
|
if (f_run(p->out_filter, &old, &tmpb, rte_update_pool) > F_MODIFY)
|
||||||
|
old = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (new || old)
|
if (new || old)
|
||||||
p->rt_notify(p, net, new, old);
|
p->rt_notify(p, net, new, old);
|
||||||
|
if (new && new != new0) /* Discard temporary rte's */
|
||||||
|
rte_free(new);
|
||||||
|
if (old && old != old0)
|
||||||
|
rte_free(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rte_announce(net *net, rte *new, rte *old)
|
rte_announce(net *net, rte *new, rte *old, ea_list *tmpa)
|
||||||
{
|
{
|
||||||
struct proto *p;
|
struct proto *p;
|
||||||
|
|
||||||
|
@ -136,7 +169,7 @@ rte_announce(net *net, rte *new, rte *old)
|
||||||
{
|
{
|
||||||
ASSERT(p->core_state == FS_HAPPY);
|
ASSERT(p->core_state == FS_HAPPY);
|
||||||
if (p->rt_notify)
|
if (p->rt_notify)
|
||||||
do_rte_announce(p, net, new, old);
|
do_rte_announce(p, net, new, old, tmpa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +188,12 @@ rt_feed_baby(struct proto *p)
|
||||||
net *n = (net *) fn;
|
net *n = (net *) fn;
|
||||||
rte *e;
|
rte *e;
|
||||||
for(e=n->routes; e; e=e->next)
|
for(e=n->routes; e; e=e->next)
|
||||||
do_rte_announce(p, n, e, NULL);
|
{
|
||||||
|
struct proto *q = e->attrs->proto;
|
||||||
|
ea_list *tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
|
||||||
|
do_rte_announce(p, n, e, NULL, tmpa);
|
||||||
|
lp_flush(rte_update_pool);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
t = t->sibling;
|
t = t->sibling;
|
||||||
|
@ -209,24 +247,13 @@ rte_free_quick(rte *e)
|
||||||
sl_free(rte_slab, e);
|
sl_free(rte_slab, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rte_update(net *net, struct proto *p, rte *new)
|
rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa)
|
||||||
{
|
{
|
||||||
rte *old_best = net->routes;
|
rte *old_best = net->routes;
|
||||||
rte *old = NULL;
|
rte *old = NULL;
|
||||||
rte **k, *r, *s;
|
rte **k, *r, *s;
|
||||||
|
|
||||||
if (new)
|
|
||||||
{
|
|
||||||
if (!rte_validate(new) || p->in_filter && f_run(p->in_filter, new, NULL) != F_ACCEPT)
|
|
||||||
{
|
|
||||||
rte_free(new);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
|
|
||||||
new->attrs = rta_lookup(new->attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
k = &net->routes; /* Find and remove original route from the same protocol */
|
k = &net->routes; /* Find and remove original route from the same protocol */
|
||||||
while (old = *k)
|
while (old = *k)
|
||||||
{
|
{
|
||||||
|
@ -240,7 +267,7 @@ rte_update(net *net, struct proto *p, rte *new)
|
||||||
|
|
||||||
if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */
|
if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */
|
||||||
{
|
{
|
||||||
rte_announce(net, new, old_best);
|
rte_announce(net, new, old_best, tmpa);
|
||||||
new->next = net->routes;
|
new->next = net->routes;
|
||||||
net->routes = new;
|
net->routes = new;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +279,7 @@ rte_update(net *net, struct proto *p, rte *new)
|
||||||
for(s=net->routes; s; s=s->next)
|
for(s=net->routes; s; s=s->next)
|
||||||
if (rte_better(s, r))
|
if (rte_better(s, r))
|
||||||
r = s;
|
r = s;
|
||||||
rte_announce(net, r, old_best);
|
rte_announce(net, r, old_best, tmpa);
|
||||||
if (r) /* Re-link the new optimal route */
|
if (r) /* Re-link the new optimal route */
|
||||||
{
|
{
|
||||||
k = &net->routes;
|
k = &net->routes;
|
||||||
|
@ -291,10 +318,60 @@ rte_update(net *net, struct proto *p, rte *new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rte_update_nest_cnt; /* Nesting counter to allow recursive updates */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
rte_update_lock(void)
|
||||||
|
{
|
||||||
|
rte_update_nest_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
rte_update_unlock(void)
|
||||||
|
{
|
||||||
|
if (!--rte_update_nest_cnt)
|
||||||
|
lp_flush(rte_update_pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rte_update(net *net, struct proto *p, rte *new)
|
||||||
|
{
|
||||||
|
ea_list *tmpa = NULL;
|
||||||
|
|
||||||
|
rte_update_lock();
|
||||||
|
if (new)
|
||||||
|
{
|
||||||
|
if (!rte_validate(new) || p->in_filter == FILTER_REJECT)
|
||||||
|
goto drop;
|
||||||
|
if (p->make_tmp_attrs)
|
||||||
|
tmpa = p->make_tmp_attrs(new, rte_update_pool);
|
||||||
|
if (p->in_filter)
|
||||||
|
{
|
||||||
|
int fr = f_run(p->in_filter, &new, &tmpa, rte_update_pool);
|
||||||
|
if (fr > F_MODIFY)
|
||||||
|
goto drop;
|
||||||
|
if (fr == F_MODIFY && p->store_tmp_attrs)
|
||||||
|
p->store_tmp_attrs(new, tmpa);
|
||||||
|
}
|
||||||
|
if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
|
||||||
|
new->attrs = rta_lookup(new->attrs);
|
||||||
|
new->flags |= REF_COW;
|
||||||
|
}
|
||||||
|
rte_recalculate(net, p, new, tmpa);
|
||||||
|
rte_update_unlock();
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
rte_free(new);
|
||||||
|
rte_update_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
|
rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
|
||||||
{
|
{
|
||||||
rte_update(old->net, old->attrs->proto, NULL);
|
rte_update_lock();
|
||||||
|
rte_recalculate(old->net, old->attrs->proto, NULL, NULL);
|
||||||
|
rte_update_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -357,6 +434,7 @@ rt_init(void)
|
||||||
{
|
{
|
||||||
rta_init();
|
rta_init();
|
||||||
rt_table_pool = rp_new(&root_pool, "Routing tables");
|
rt_table_pool = rp_new(&root_pool, "Routing tables");
|
||||||
|
rte_update_pool = lp_new(rt_table_pool, 4080);
|
||||||
rt_setup(rt_table_pool, &master_table, "master");
|
rt_setup(rt_table_pool, &master_table, "master");
|
||||||
rte_slab = sl_new(rt_table_pool, sizeof(rte));
|
rte_slab = sl_new(rt_table_pool, sizeof(rte));
|
||||||
rt_last_gc = now;
|
rt_last_gc = now;
|
||||||
|
|
Loading…
Reference in a new issue