From 0e02abfd5770062768eeb4c75061b7d2f656489d Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Mon, 17 May 1999 20:14:52 +0000 Subject: [PATCH] From now we support multiple tables. The master_table variable is definitely gone. Both rte_update() and rte_discard() have an additional argument telling which table should they modify. Also, rte_update() no longer walks the whole protocol list -- each table has a list of all protocols connected to this table and having the rt_notify hook set. Each protocol can also freely decide (by calling proto_add_announce_hook) to connect to any other table, but it will be probably used only by the table-to-table protocol. The default debugging dumps now include all routing tables and also all their connections. --- conf/conf.c | 3 ++ conf/confbase.Y | 4 +- doc/bird.conf.example | 3 ++ nest/config.Y | 29 +++++++++-- nest/proto.c | 33 ++++++++++++- nest/protocol.h | 17 ++++++- nest/route.h | 18 +++++-- nest/rt-table.c | 110 ++++++++++++++++++++++++++++++------------ 8 files changed, 175 insertions(+), 42 deletions(-) diff --git a/conf/conf.c b/conf/conf.c index 61fe9f88..0ce593c7 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -10,6 +10,7 @@ #include #include "nest/bird.h" +#include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" #include "lib/resource.h" @@ -49,6 +50,7 @@ config_parse(struct config *c) cf_lex_init(1); cf_lex_init_tables(); protos_preconfig(c); + rt_preconfig(c); cf_parse(); filters_postconfig(); /* FIXME: Do we really need this? */ protos_postconfig(c); @@ -65,6 +67,7 @@ void config_commit(struct config *c) { config = c; + rt_commit(c); protos_commit(c); } diff --git a/conf/confbase.Y b/conf/confbase.Y index 522a1803..2343536a 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -25,6 +25,7 @@ CF_DECLS ip_addr a; struct symbol *s; char *t; + struct rtable_config *r; struct f_inst *x; struct filter *f; struct f_tree *e; @@ -78,8 +79,7 @@ expr: CF_ADDTO(conf, definition) definition: DEFINE SYM '=' expr ';' { - if ($2->class != SYM_VOID) cf_error("Symbol already defined"); - $2->class = SYM_NUMBER; + cf_define_symbol($2, SYM_NUMBER, NULL); $2->aux = $4; } ; diff --git a/doc/bird.conf.example b/doc/bird.conf.example index 6580ee7a..c3becbb5 100644 --- a/doc/bird.conf.example +++ b/doc/bird.conf.example @@ -11,6 +11,8 @@ #filter sink { reject; } #filter okay { accept; } +#table testable; + #protocol rip MyRIP_test { # preference xyzzy; # debug all; @@ -38,6 +40,7 @@ protocol device { protocol static { # disabled; +# table testable; # route 0.0.0.0/0 via 62.168.0.13; # route 62.168.0.0/25 reject; # route 10.0.0.0/8 reject; diff --git a/nest/config.Y b/nest/config.Y index c535e9ec..667f435c 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -17,16 +17,18 @@ void rt_dev_add_iface(char *); CF_DECLS CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) -CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE) +CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE) %type idval %type imexport +%type rtable CF_GRAMMAR /* Setting of router ID */ CF_ADDTO(conf, rtrid) + rtrid: ROUTER ID idval ';' { new_config->router_id = $3; } @@ -37,6 +39,19 @@ idval: | IPA { $$ = ipa_to_u32($1); } ; +/* Creation of routing tables */ + +CF_ADDTO(conf, newtab) + +newtab: TABLE SYM { + struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config)); + struct symbol *s = $2; + cf_define_symbol(s, SYM_TABLE, c); + c->name = s->name; + add_tail(&new_config->tables, &c->n); + } + ; + /* Definition of protocols */ CF_ADDTO(conf, proto) @@ -51,9 +66,7 @@ proto_name: this_proto->name = s->name; } | SYM { - if ($1->class) cf_error("Symbol already defined"); - $1->class = SYM_PROTO; - $1->def = this_proto; + cf_define_symbol($1, SYM_PROTO, this_proto); this_proto->name = $1->name; } ; @@ -70,6 +83,7 @@ proto_item: | DEBUG OFF { this_proto->debug = 0; } | IMPORT imexport { this_proto->in_filter = $2; } | EXPORT imexport { this_proto->out_filter = $2; } + | TABLE rtable { this_proto->table = $2; } ; imexport: @@ -78,6 +92,13 @@ imexport: | NONE { $$ = FILTER_REJECT; } ; +rtable: + SYM { + if ($1->class != SYM_TABLE) cf_error("Table name expected"); + $$ = $1->def; + } + ; + /* Direct device route protocol */ CF_ADDTO(proto, dev_proto '}') diff --git a/nest/proto.c b/nest/proto.c index ad4aa11d..3199fee2 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -86,7 +86,7 @@ proto_new(struct proto_config *c, unsigned size) p->preference = c->preference; p->disabled = c->disabled; p->proto = pr; - p->table = &master_table; + p->table = (c->table ? : c->global->master_rtc)->table; p->in_filter = c->in_filter; p->out_filter = c->out_filter; return p; @@ -101,6 +101,33 @@ proto_init_instance(struct proto *p) p->attn->data = p; } +struct announce_hook * +proto_add_announce_hook(struct proto *p, struct rtable *t) +{ + struct announce_hook *h; + + if (!p->rt_notify) + return NULL; + DBG("Connecting protocol %s to table %s\n", p->name, t->name); + h = mb_alloc(p->pool, sizeof(struct announce_hook)); + h->table = t; + h->proto = p; + h->next = p->ahooks; + p->ahooks = h; + add_tail(&t->hooks, &h->n); + return h; +} + +static void +proto_flush_hooks(struct proto *p) +{ + struct announce_hook *h; + + for(h=p->ahooks; h; h=h->next) + rem_node(&h->n); + p->ahooks = NULL; +} + void * proto_config_new(struct protocol *pr, unsigned size) { @@ -296,6 +323,7 @@ proto_feed(void *P) struct proto *p = P; DBG("Feeding protocol %s\n", p->name); + proto_add_announce_hook(p, p->table); if_feed_baby(p); rt_feed_baby(p); p->core_state = FS_HAPPY; @@ -365,11 +393,12 @@ proto_flush_all(void *unused) { struct proto *p; - rt_prune(&master_table); + rt_prune_all(); neigh_prune(); while ((p = HEAD(flush_proto_list))->n.next) { DBG("Flushing protocol %s\n", p->name); + proto_flush_hooks(p); rfree(p->pool); p->pool = NULL; p->core_state = FS_HUNGRY; diff --git a/nest/protocol.h b/nest/protocol.h index 5e1e2ce9..3aed2f21 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -73,6 +73,7 @@ struct proto_config { struct protocol *proto; /* Protocol */ char *name; unsigned debug, preference, disabled; /* Generic parameters */ + struct rtable_config *table; /* Table we're attached to */ struct filter *in_filter, *out_filter; /* Attached filters */ /* Protocol-specific data follow... */ @@ -128,9 +129,10 @@ struct proto { void (*rte_insert)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *); - struct rtable *table; /* Routing table we're connected to */ + struct rtable *table; /* Our primary routing table */ struct filter *in_filter; /* Input filter */ struct filter *out_filter; /* Output filter */ + struct announce_hook *ahooks; /* Announcement hooks for this protocol */ /* Hic sunt protocol-specific data */ }; @@ -222,6 +224,19 @@ void proto_notify_state(struct proto *p, unsigned state); extern struct proto_config *cf_dev_proto; +/* + * Route Announcement Hook + */ + +struct announce_hook { + node n; + struct rtable *table; + struct proto *proto; + struct announce_hook *next; /* Next hook for the same protocol */ +}; + +struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); + /* * Callback to sysdep code when shutdown is finished */ diff --git a/nest/route.h b/nest/route.h index 10628cdb..5e6b8739 100644 --- a/nest/route.h +++ b/nest/route.h @@ -9,6 +9,7 @@ #ifndef _BIRD_ROUTE_H_ #define _BIRD_ROUTE_H_ +#include "lib/lists.h" #include "lib/resource.h" #include "lib/timer.h" @@ -104,9 +105,17 @@ void fit_put(struct fib_iterator *, struct fib_node *); * It's guaranteed that there is at most one RTE for every (prefix,proto) pair. */ +struct rtable_config { + node n; + char *name; + struct rtable *table; +}; + typedef struct rtable { + node n; /* Node in list of all tables */ struct fib fib; char *name; /* Name of this table */ + list hooks; /* List of announcement hooks */ } rtable; typedef struct network { @@ -152,16 +161,18 @@ typedef struct rte { #define REF_COW 1 /* Copy this rte on write */ -extern rtable master_table; +struct config; void rt_init(void); +void rt_preconfig(struct config *); +void rt_commit(struct config *); void rt_setup(pool *, rtable *, char *); static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); } static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); } rte *rte_find(net *net, struct proto *p); rte *rte_get_temp(struct rta *); -void rte_update(net *net, struct proto *p, rte *new); -void rte_discard(rte *old); +void rte_update(rtable *tab, net *net, struct proto *p, rte *new); +void rte_discard(rtable *tab, rte *old); void rte_dump(rte *); void rte_free(rte *); rte *rte_do_cow(rte *); @@ -170,6 +181,7 @@ void rt_dump(rtable *); void rt_dump_all(void); void rt_feed_baby(struct proto *p); void rt_prune(rtable *tab); +void rt_prune_all(void); /* * Route Attributes diff --git a/nest/rt-table.c b/nest/rt-table.c index 2b60bb83..a603c7f1 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -15,9 +15,9 @@ #include "nest/protocol.h" #include "lib/resource.h" #include "lib/event.h" +#include "conf/conf.h" #include "filter/filter.h" -rtable master_table; static slab *rte_slab; static linpool *rte_update_pool; @@ -25,6 +25,7 @@ static linpool *rte_update_pool; #define RT_GC_MIN_COUNT 100 static pool *rt_table_pool; +static list routing_tables; static event *rt_gc_event; static bird_clock_t rt_last_gc; static int rt_gc_counter; @@ -44,6 +45,7 @@ rt_setup(pool *p, rtable *t, char *name) bzero(t, sizeof(*t)); fib_init(&t->fib, p, sizeof(rte), 0, rte_init); t->name = name; + init_list(&t->hooks); } rte * @@ -97,8 +99,9 @@ rte_better(rte *new, rte *old) } static inline void -do_rte_announce(struct proto *p, net *net, rte *new, rte *old, ea_list *tmpa) +do_rte_announce(struct announce_hook *a, net *net, rte *new, rte *old, ea_list *tmpa) { + struct proto *p = a->proto; rte *new0 = new; rte *old0 = old; if (new) @@ -132,39 +135,42 @@ do_rte_announce(struct proto *p, net *net, rte *new, rte *old, ea_list *tmpa) } static void -rte_announce(net *net, rte *new, rte *old, ea_list *tmpa) +rte_announce(rtable *tab, net *net, rte *new, rte *old, ea_list *tmpa) { - struct proto *p; + struct announce_hook *a; - WALK_LIST(p, proto_list) + WALK_LIST(a, tab->hooks) { - ASSERT(p->core_state == FS_HAPPY); - if (p->rt_notify) - do_rte_announce(p, net, new, old, tmpa); + ASSERT(a->proto->core_state == FS_HAPPY); + do_rte_announce(a, net, new, old, tmpa); } } void rt_feed_baby(struct proto *p) { - rtable *t = &master_table; + struct announce_hook *h; - if (!p->rt_notify) + if (!p->ahooks) return; debug("Announcing routes to new protocol %s\n", p->name); - FIB_WALK(&t->fib, fn) + for(h=p->ahooks; h; h=h->next) { - net *n = (net *) fn; - rte *e; - for(e=n->routes; e; e=e->next) + rtable *t = h->table; + FIB_WALK(&t->fib, fn) { - 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); + net *n = (net *) fn; + rte *e; + for(e=n->routes; e; e=e->next) + { + 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(h, n, e, NULL, tmpa); + lp_flush(rte_update_pool); + } } + FIB_WALK_END; } - FIB_WALK_END; } static inline int @@ -215,7 +221,7 @@ rte_free_quick(rte *e) } static void -rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa) +rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmpa) { rte *old_best = net->routes; rte *old = NULL; @@ -234,7 +240,7 @@ rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa) if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */ { - rte_announce(net, new, old_best, tmpa); + rte_announce(table, net, new, old_best, tmpa); new->next = net->routes; net->routes = new; } @@ -246,7 +252,7 @@ rte_recalculate(net *net, struct proto *p, rte *new, ea_list *tmpa) for(s=net->routes; s; s=s->next) if (rte_better(s, r)) r = s; - rte_announce(net, r, old_best, tmpa); + rte_announce(table, net, r, old_best, tmpa); if (r) /* Re-link the new optimal route */ { k = &net->routes; @@ -301,7 +307,7 @@ rte_update_unlock(void) } void -rte_update(net *net, struct proto *p, rte *new) +rte_update(rtable *table, net *net, struct proto *p, rte *new) { ea_list *tmpa = NULL; @@ -324,7 +330,7 @@ rte_update(net *net, struct proto *p, rte *new) new->attrs = rta_lookup(new->attrs); new->flags |= REF_COW; } - rte_recalculate(net, p, new, tmpa); + rte_recalculate(table, net, p, new, tmpa); rte_update_unlock(); return; @@ -334,10 +340,10 @@ drop: } void -rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */ +rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during garbage collection */ { rte_update_lock(); - rte_recalculate(old->net, old->attrs->proto, NULL, NULL); + rte_recalculate(t, old->net, old->attrs->proto, NULL, NULL); rte_update_unlock(); } @@ -361,6 +367,7 @@ rt_dump(rtable *t) { rte *e; net *n; + struct announce_hook *a; debug("Dump of routing table <%s>\n", t->name); #ifdef DEBUGGING @@ -373,20 +380,27 @@ rt_dump(rtable *t) rte_dump(e); } FIB_WALK_END; + WALK_LIST(a, t->hooks) + debug("\tAnnounces routes to protocol %s\n", a->proto->name); debug("\n"); } void rt_dump_all(void) { - rt_dump(&master_table); + rtable *t; + + WALK_LIST(t, routing_tables) + rt_dump(t); } static void rt_gc(void *unused) { + rtable *t; + DBG("Entered routing table garbage collector after %d seconds and %d deletes\n", (int)(now - rt_last_gc), rt_gc_counter); - rt_prune(&master_table); + rt_prune_all(); rt_last_gc = now; rt_gc_counter = 0; } @@ -397,11 +411,11 @@ 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; rt_gc_event = ev_new(rt_table_pool); rt_gc_event->hook = rt_gc; + init_list(&routing_tables); } void @@ -422,7 +436,7 @@ again: for (e=n->routes; e; e=e->next, rcnt++) if (e->attrs->proto->core_state != FS_HAPPY) { - rte_discard(e); + rte_discard(tab, e); rdel++; goto rescan; } @@ -437,3 +451,39 @@ again: FIB_ITERATE_END(f); DBG("Pruned %d of %d routes and %d of %d networks\n", rcnt, rdel, ncnt, ndel); } + +void +rt_prune_all(void) +{ + rtable *t; + + WALK_LIST(t, routing_tables) + rt_prune(t); +} + +void +rt_preconfig(struct config *c) +{ + struct symbol *s = cf_find_symbol("master"); + struct rtable_config *r = cfg_allocz(sizeof(struct rtable_config)); + + cf_define_symbol(s, SYM_TABLE, r); + r->name = s->name; + init_list(&c->tables); + add_tail(&c->tables, &r->n); + c->master_rtc = r; +} + +void +rt_commit(struct config *c) +{ + struct rtable_config *r; + + WALK_LIST(r, c->tables) + { + rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable)); + rt_setup(rt_table_pool, t, r->name); + add_tail(&routing_tables, &t->n); + r->table = t; + } +}