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
|
||||
*
|
||||
* (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.
|
||||
*/
|
||||
|
@ -150,6 +150,8 @@ typedef struct rte {
|
|||
} u;
|
||||
} rte;
|
||||
|
||||
#define REF_COW 1 /* Copy this rte on write */
|
||||
|
||||
extern rtable master_table;
|
||||
|
||||
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_dump(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_all(void);
|
||||
void rt_feed_baby(struct proto *p);
|
||||
|
|
128
nest/rt-table.c
128
nest/rt-table.c
|
@ -19,6 +19,7 @@
|
|||
|
||||
rtable master_table;
|
||||
static slab *rte_slab;
|
||||
static linpool *rte_update_pool;
|
||||
|
||||
#define RT_GC_MIN_TIME 5 /* FIXME: Make configurable */
|
||||
#define RT_GC_MIN_COUNT 100
|
||||
|
@ -95,6 +96,17 @@ rte_get_temp(rta *a)
|
|||
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 */
|
||||
rte_better(rte *new, rte *old)
|
||||
{
|
||||
|
@ -114,21 +126,42 @@ rte_better(rte *new, rte *old)
|
|||
}
|
||||
|
||||
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)
|
||||
old = NULL;
|
||||
if (new && f_run(p->out_filter, new, NULL) != F_ACCEPT)
|
||||
int ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0;
|
||||
if (ok < 0 ||
|
||||
(!ok && (p->out_filter == FILTER_REJECT ||
|
||||
p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool) > F_MODIFY)
|
||||
)
|
||||
)
|
||||
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)
|
||||
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
|
||||
rte_announce(net *net, rte *new, rte *old)
|
||||
static void
|
||||
rte_announce(net *net, rte *new, rte *old, ea_list *tmpa)
|
||||
{
|
||||
struct proto *p;
|
||||
|
||||
|
@ -136,7 +169,7 @@ rte_announce(net *net, rte *new, rte *old)
|
|||
{
|
||||
ASSERT(p->core_state == FS_HAPPY);
|
||||
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;
|
||||
rte *e;
|
||||
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;
|
||||
t = t->sibling;
|
||||
|
@ -209,24 +247,13 @@ rte_free_quick(rte *e)
|
|||
sl_free(rte_slab, e);
|
||||
}
|
||||
|
||||
void
|
||||
rte_update(net *net, struct proto *p, rte *new)
|
||||
static void
|
||||
rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa)
|
||||
{
|
||||
rte *old_best = net->routes;
|
||||
rte *old = NULL;
|
||||
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 */
|
||||
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 */
|
||||
{
|
||||
rte_announce(net, new, old_best);
|
||||
rte_announce(net, new, old_best, tmpa);
|
||||
new->next = net->routes;
|
||||
net->routes = new;
|
||||
}
|
||||
|
@ -252,7 +279,7 @@ rte_update(net *net, struct proto *p, rte *new)
|
|||
for(s=net->routes; s; s=s->next)
|
||||
if (rte_better(s, r))
|
||||
r = s;
|
||||
rte_announce(net, r, old_best);
|
||||
rte_announce(net, r, old_best, tmpa);
|
||||
if (r) /* Re-link the new optimal route */
|
||||
{
|
||||
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
|
||||
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
|
||||
|
@ -357,6 +434,7 @@ rt_init(void)
|
|||
{
|
||||
rta_init();
|
||||
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");
|
||||
rte_slab = sl_new(rt_table_pool, sizeof(rte));
|
||||
rt_last_gc = now;
|
||||
|
|
Loading…
Reference in a new issue