From 2ef9177a47e7137dd09b06a353a6e5f6e671c951 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 14 Nov 2010 05:49:56 +0100 Subject: Add multicast support to static protocol and generic route handling. --- nest/protocol.h | 1 + nest/route.h | 19 +++++-- nest/rt-table.c | 143 ++++++++++++++++++++++++++++++++++---------------- proto/static/config.Y | 4 +- proto/static/static.c | 18 +++---- proto/static/static.h | 1 + sysdep/unix/krt.c | 9 ++-- 7 files changed, 132 insertions(+), 63 deletions(-) diff --git a/nest/protocol.h b/nest/protocol.h index 70999f0..e36219a 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -192,6 +192,7 @@ struct proto { struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */ struct announce_hook *feed_ahook; /* Announce hook we currently feed */ + int feed_cast; /* Are we feeding unicast or multicast routes? */ /* Hic sunt protocol-specific data */ }; diff --git a/nest/route.h b/nest/route.h index a849bf0..0634ab7 100644 --- a/nest/route.h +++ b/nest/route.h @@ -124,7 +124,8 @@ struct rtable_config { typedef struct rtable { node n; /* Node in list of all tables */ - struct fib fib; + struct fib fib_unicast; + struct fib fib_multicast; char *name; /* Name of this table */ list hooks; /* List of announcement hooks */ int pipe_busy; /* Pipe loop detection */ @@ -140,8 +141,10 @@ typedef struct rtable { bird_clock_t gc_time; /* Time of last GC */ byte gc_scheduled; /* GC is scheduled */ byte hcu_scheduled; /* Hostcache update is scheduled */ - byte nhu_state; /* Next Hop Update state */ - struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */ + byte nhu_state_unicast; /* Next Hop Update state */ + byte nhu_state_multicast; /* Next Hop Update state (multicast) */ + struct fib_iterator nhu_fit_unicast; /* Next Hop Update FIB iterator */ + struct fib_iterator nhu_fit_multicast; /* Next Hop Update FIB iterator (multicast) */ } rtable; typedef struct network { @@ -225,8 +228,6 @@ void rt_commit(struct config *new, struct config *old); void rt_lock_table(rtable *); void rt_unlock_table(rtable *); void rt_setup(pool *, rtable *, char *, struct rtable_config *); -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(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new); @@ -245,6 +246,7 @@ struct rtable_config *rt_new_table(struct symbol *s); struct rt_show_data { ip_addr prefix; unsigned pxlen; + int cast; rtable *table; struct filter *filter; int verbose; @@ -316,6 +318,13 @@ typedef struct rta { #define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other protocol-specific metric is availabe */ +static inline struct fib *rt_fib(rtable *tab, int cast) { return (cast == RTC_MULTICAST) ? &tab->fib_multicast : &tab->fib_unicast; } +static inline net *net_find2(rtable *tab, ip_addr addr, unsigned len, int cast) { return (net *) fib_find(rt_fib(tab, cast), &addr, len); } +static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return net_find2(tab, addr, len, RTC_UNICAST); } +static inline net *net_get2(rtable *tab, ip_addr addr, unsigned len, int cast) { return (net *) fib_get(rt_fib(tab, cast), &addr, len); } +static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return net_get2(tab, addr, len, RTC_UNICAST); } + + /* * Extended Route Attributes */ diff --git a/nest/rt-table.c b/nest/rt-table.c index a4976f0..5d17ca0 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -54,14 +54,14 @@ static void rt_format_via(rte *e, byte *via); static void rt_free_hostcache(rtable *tab); static void rt_notify_hostcache(rtable *tab, net *net); static void rt_update_hostcache(rtable *tab); -static void rt_next_hop_update(rtable *tab); -static void rt_prune(rtable *tab); +static void rt_next_hop_update(rtable *tab, int cast); +static void rt_prune(rtable *tab, int cast); static inline void rt_schedule_gc(rtable *tab); /* Like fib_route(), but skips empty net entries */ static net * -net_route(rtable *tab, ip_addr a, int len) +net_route(rtable *tab, ip_addr a, int len, int cast) { ip_addr a0; net *n; @@ -69,7 +69,7 @@ net_route(rtable *tab, ip_addr a, int len) while (len >= 0) { a0 = ipa_and(a, ipa_mkmask(len)); - n = fib_find(&tab->fib, &a0, len); + n = fib_find(rt_fib(tab, cast), &a0, len); if (n && n->routes) return n; len--; @@ -775,9 +775,17 @@ rt_dump(rtable *t) debug("Dump of routing table <%s>\n", t->name); #ifdef DEBUGGING - fib_check(&t->fib); + fib_check(rt_fib(t, RTC_UNICAST)); + fib_check(rt_fib(t, RTC_MULTICAST)); #endif - FIB_WALK(&t->fib, fn) + FIB_WALK(rt_fib(t, RTC_UNICAST), fn) + { + n = (net *) fn; + for(e=n->routes; e; e=e->next) + rte_dump(e); + } + FIB_WALK_END; + FIB_WALK(rt_fib(t, RTC_MULTICAST), fn) { n = (net *) fn; for(e=n->routes; e; e=e->next) @@ -826,11 +834,12 @@ rt_schedule_hcu(rtable *tab) static inline void rt_schedule_nhu(rtable *tab) { - if (tab->nhu_state == 0) + if (tab->nhu_state_unicast == 0 || tab->nhu_state_multicast == 0) ev_schedule(tab->rt_event); /* state change 0->1, 2->3 */ - tab->nhu_state |= 1; + tab->nhu_state_unicast |= 1; + tab->nhu_state_multicast |= 1; } static void @@ -841,18 +850,25 @@ rt_event(void *ptr) if (tab->hcu_scheduled) rt_update_hostcache(tab); - if (tab->nhu_state) - rt_next_hop_update(tab); + if (tab->nhu_state_unicast) + rt_next_hop_update(tab, RTC_UNICAST); + + if (tab->nhu_state_multicast) + rt_next_hop_update(tab, RTC_MULTICAST); if (tab->gc_scheduled) - rt_prune(tab); + { + rt_prune(tab, RTC_UNICAST); + rt_prune(tab, RTC_MULTICAST); + } } void rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf) { bzero(t, sizeof(*t)); - fib_init(&t->fib, p, sizeof(net), 0, rte_init); + fib_init(&t->fib_unicast, p, sizeof(net), 0, rte_init); + fib_init(&t->fib_multicast, p, sizeof(net), 0, rte_init); t->name = name; t->config = cf; init_list(&t->hooks); @@ -890,18 +906,18 @@ rt_init(void) * protocols and also stale network entries. */ static void -rt_prune(rtable *tab) +rt_prune(rtable *tab, int cast) { struct fib_iterator fit; int rcnt = 0, rdel = 0, ncnt = 0, ndel = 0; - DBG("Pruning route table %s\n", tab->name); + DBG("Pruning route table %s%s\n", tab->name, (cast == RTC_MULTICAST) ? ", multicast" : ""); #ifdef DEBUGGING - fib_check(&tab->fib); + fib_check(rt_fib(tab, cast)); #endif - FIB_ITERATE_INIT(&fit, &tab->fib); + FIB_ITERATE_INIT(&fit, rt_fib(tab, cast)); again: - FIB_ITERATE_START(&tab->fib, &fit, f) + FIB_ITERATE_START(rt_fib(tab, cast), &fit, f) { net *n = (net *) f; rte *e; @@ -918,7 +934,7 @@ again: if (!n->routes) /* Orphaned FIB entry? */ { FIB_ITERATE_PUT(&fit, f); - fib_delete(&tab->fib, f); + fib_delete(rt_fib(tab, cast), f); ndel++; goto again; } @@ -926,7 +942,7 @@ again: FIB_ITERATE_END(f); DBG("Pruned %d of %d routes and %d of %d networks\n", rdel, rcnt, ndel, ncnt); #ifdef DEBUGGING - fib_check(&tab->fib); + fib_check(rt_fib(tab, cast)); #endif tab->gc_counter = 0; tab->gc_time = now; @@ -944,7 +960,10 @@ rt_prune_all(void) rtable *t; WALK_LIST(t, routing_tables) - rt_prune(t); + { + rt_prune(t, RTC_UNICAST); + rt_prune(t, RTC_MULTICAST); + } } void @@ -1061,21 +1080,23 @@ rt_next_hop_update_net(rtable *tab, net *n) } static void -rt_next_hop_update(rtable *tab) +rt_next_hop_update(rtable *tab, int cast) { - struct fib_iterator *fit = &tab->nhu_fit; + struct fib *fib = rt_fib(tab, cast); + struct fib_iterator *fit = (cast == RTC_MULTICAST) ? &tab->nhu_fit_multicast : &tab->nhu_fit_unicast; + byte *state = (cast == RTC_MULTICAST) ? &tab->nhu_state_multicast : &tab->nhu_state_unicast; int max_feed = 32; - if (tab->nhu_state == 0) + if (*state == 0) return; - if (tab->nhu_state == 1) + if (*state == 1) { - FIB_ITERATE_INIT(fit, &tab->fib); - tab->nhu_state = 2; + FIB_ITERATE_INIT(fit, fib); + *state = 2; } - FIB_ITERATE_START(&tab->fib, fit, fn) + FIB_ITERATE_START(fib, fit, fn) { if (max_feed <= 0) { @@ -1088,9 +1109,9 @@ rt_next_hop_update(rtable *tab) FIB_ITERATE_END(fn); /* state change 2->0, 3->1 */ - tab->nhu_state &= 1; + *state &= 1; - if (tab->nhu_state > 0) + if (*state > 0) ev_schedule(tab->rt_event); } @@ -1140,7 +1161,8 @@ rt_unlock_table(rtable *r) if (r->hostcache) rt_free_hostcache(r); rem_node(&r->n); - fib_free(&r->fib); + fib_free(&r->fib_multicast); + fib_free(&r->fib_unicast); rfree(r->rt_event); mb_free(r); config_del_obstacle(conf); @@ -1240,13 +1262,14 @@ rt_feed_baby(struct proto *p) DBG("Announcing routes to new protocol %s\n", p->name); p->feed_ahook = p->ahooks; fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator)); + p->feed_cast = RTC_UNICAST; goto next_hook; } fit = p->feed_iterator; again: h = p->feed_ahook; - FIB_ITERATE_START(&h->table->fib, fit, fn) + FIB_ITERATE_START(rt_fib(h->table, p->feed_cast), fit, fn) { net *n = (net *) fn; rte *e = n->routes; @@ -1275,7 +1298,18 @@ again: } } FIB_ITERATE_END(fn); - p->feed_ahook = h->next; + + + if (p->feed_cast == RTC_UNICAST) /* If we were feeding unicast routes, proceed with multicast */ + { + p->feed_cast = RTC_MULTICAST; + } + else /* Otherwise, continue with next hook */ + { + p->feed_cast = RTC_UNICAST; + p->feed_ahook = h->next; + } + if (!p->feed_ahook) { mb_free(p->feed_iterator); @@ -1285,7 +1319,7 @@ again: next_hook: h = p->feed_ahook; - FIB_ITERATE_INIT(fit, &h->table->fib); + FIB_ITERATE_INIT(fit, rt_fib(h->table, p->feed_cast)); goto again; } @@ -1303,7 +1337,7 @@ rt_feed_baby_abort(struct proto *p) if (p->feed_ahook) { /* Unlink the iterator and exit */ - fit_get(&p->feed_ahook->table->fib, p->feed_iterator); + fit_get(rt_fib(p->feed_ahook->table, p->feed_cast), p->feed_iterator); p->feed_ahook = NULL; } } @@ -1503,7 +1537,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) u32 old_metric = he->igp_metric; int pxlen = 0; - net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH); + net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH, RTC_UNICAST); if (n) { rta *a = n->routes->attrs; @@ -1641,6 +1675,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm byte tm[TM_DATETIME_BUFFER_SIZE], info[256]; rta *a = e->attrs; int primary = (e->net->routes == e); + int multicast = (a->cast == RTC_MULTICAST); rt_format_via(e, via); tm_format_datetime(tm, &config->tf_route, e->lastmod); @@ -1661,8 +1696,8 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm a->proto->proto->get_route_info(e, info, tmpa); else bsprintf(info, " (%d)", e->pref); - cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->proto->name, - tm, from, primary ? " *" : "", info); + cli_printf(c, -1007, "%-18s %s%s [%s %s%s]%s%s", ia, via, multicast ? " MC" : "", + a->proto->name, tm, from, primary ? " *" : "", info); if (d->verbose) rta_show(c, a, tmpa); } @@ -1730,7 +1765,7 @@ rt_show_cont(struct cli *c) #else unsigned max = 64; #endif - struct fib *fib = &d->table->fib; + struct fib *fib = rt_fib(d->table, d->cast); struct fib_iterator *it = &d->fit; FIB_ITERATE_START(fib, it, f) @@ -1756,6 +1791,14 @@ rt_show_cont(struct cli *c) rt_show_net(c, n, d); } FIB_ITERATE_END(f); + + if (d->cast == RTC_UNICAST) + { + FIB_ITERATE_INIT(&d->fit, rt_fib(d->table, RTC_MULTICAST)); + d->cast = RTC_MULTICAST; + return; + } + if (d->stats) cli_printf(c, 14, "%d of %d routes for %d networks", d->show_counter, d->rt_counter, d->net_counter); else @@ -1770,30 +1813,40 @@ rt_show_cleanup(struct cli *c) struct rt_show_data *d = c->rover; /* Unlink the iterator */ - fit_get(&d->table->fib, &d->fit); + fit_get(rt_fib(d->table, d->cast), &d->fit); } void rt_show(struct rt_show_data *d) { - net *n; + net *n, *n2; if (d->pxlen == 256) { - FIB_ITERATE_INIT(&d->fit, &d->table->fib); + FIB_ITERATE_INIT(&d->fit, rt_fib(d->table, RTC_UNICAST)); this_cli->cont = rt_show_cont; this_cli->cleanup = rt_show_cleanup; this_cli->rover = d; + d->cast = RTC_UNICAST; } else { if (d->show_for) - n = net_route(d->table, d->prefix, d->pxlen); + { + n = net_route(d->table, d->prefix, d->pxlen, RTC_UNICAST); + n2 = net_route(d->table, d->prefix, d->pxlen, RTC_MULTICAST); + } else - n = net_find(d->table, d->prefix, d->pxlen); - if (n) + { + n = net_find2(d->table, d->prefix, d->pxlen, RTC_UNICAST); + n2 = net_find2(d->table, d->prefix, d->pxlen, RTC_MULTICAST); + } + if (n || n2) { - rt_show_net(this_cli, n, d); + if (n) + rt_show_net(this_cli, n, d); + if (n2) + rt_show_net(this_cli, n2, d); cli_msg(0, ""); } else diff --git a/proto/static/config.Y b/proto/static/config.Y index a7e5016..b089864 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -16,7 +16,7 @@ static struct static_route *this_srt; CF_DECLS -CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE) +CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, MULTICAST) CF_GRAMMAR @@ -39,6 +39,7 @@ stat_route0: ROUTE prefix { add_tail(&((struct static_config *) this_proto)->other_routes, &this_srt->n); this_srt->net = $2.addr; this_srt->masklen = $2.len; + this_srt->cast = RTC_UNICAST; } ; @@ -56,6 +57,7 @@ stat_route: | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } + | stat_route MULTICAST { this_srt->cast = RTC_MULTICAST; } ; CF_CLI(SHOW STATIC, optsym, [], [[Show details of static protocol]]) diff --git a/proto/static/static.c b/proto/static/static.c index 6b42a37..e15a43b 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -23,7 +23,7 @@ * newly added routes and removes the obsolete ones. */ -#undef LOCAL_DEBUG +#define LOCAL_DEBUG #include "nest/bird.h" #include "nest/iface.h" @@ -45,18 +45,18 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) if (r->installed) return; - DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); + DBG("Installing static route %I/%d, rtd=%d%s\n", r->net, r->masklen, r->dest, (r->cast == RTC_MULTICAST) ? ", multicast" : ""); bzero(&a, sizeof(a)); a.proto = p; a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC; a.scope = SCOPE_UNIVERSE; - a.cast = RTC_UNICAST; + a.cast = r->cast; a.dest = r->dest; a.gw = r->via; a.iface = ifa; aa = rta_lookup(&a); - n = net_get(p->table, r->net, r->masklen); + n = net_get2(p->table, r->net, r->masklen, r->cast); e = rte_get_temp(aa); e->net = n; e->pflags = 0; @@ -72,8 +72,8 @@ static_remove(struct proto *p, struct static_route *r) if (!r->installed) return; - DBG("Removing static route %I/%d\n", r->net, r->masklen); - n = net_find(p->table, r->net, r->masklen); + DBG("Removing static route %I/%d%s\n", r->net, r->masklen, (r->cast == RTC_MULTICAST) ? ", multicast" : ""); + n = net_find2(p->table, r->net, r->masklen, r->cast); if (n) rte_update(p->table, n, p, p, NULL); r->installed = 0; @@ -247,13 +247,13 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) if (r->neigh) r->neigh->data = NULL; WALK_LIST(t, n->iface_routes) - if (static_same_net(r, t)) + if (static_same_net(r, t) && r->cast == t->cast) { t->installed = static_same_dest(r, t); return; } WALK_LIST(t, n->other_routes) - if (static_same_net(r, t)) + if (static_same_net(r, t) && r->cast == t->cast) { t->installed = static_same_dest(r, t); return; @@ -311,7 +311,7 @@ static_show_rt(struct static_route *r) case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; default: bsprintf(via, "???"); } - cli_msg(-1009, "%I/%d %s%s", r->net, r->masklen, via, r->installed ? "" : " (dormant)"); + cli_msg(-1009, "%I/%d %s%s%s", r->net, r->masklen, via, r->cast == RTC_MULTICAST ? "" : " multicast", r->installed ? "" : " (dormant)"); } void diff --git a/proto/static/static.h b/proto/static/static.h index 5d2bd21..e100068 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -26,6 +26,7 @@ struct static_route { ip_addr via; /* Destination router */ struct neighbor *neigh; byte *if_name; /* Name for RTD_DEVICE routes */ + int cast; int installed; /* Installed in master table */ }; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 562dc71..6785161 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -324,7 +324,7 @@ krt_learn_scan(struct krt_proto *p, rte *e) static void krt_learn_prune(struct krt_proto *p) { - struct fib *fib = &p->krt_table.fib; + struct fib *fib = rt_fib(&p->krt_table, RTC_UNICAST); struct fib_iterator fit; KRT_TRACE(p, D_EVENTS, "Pruning inherited routes"); @@ -502,7 +502,7 @@ krt_flush_routes(struct krt_proto *p) struct rtable *t = p->p.table; KRT_TRACE(p, D_EVENTS, "Flushing kernel routes"); - FIB_WALK(&t->fib, f) + FIB_WALK(rt_fib(t, RTC_UNICAST), f) { net *n = (net *) f; rte *e = n->routes; @@ -616,7 +616,7 @@ krt_prune(struct krt_proto *p) struct rtable *t = p->p.table; KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); - FIB_WALK(&t->fib, f) + FIB_WALK(rt_fib(t, RTC_UNICAST), f) { net *n = (net *) f; int verdict = f->flags & KRF_VERDICT_MASK; @@ -743,6 +743,9 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool * if (e->attrs->proto == P) return -1; + if (e->attrs->cast != RTC_UNICAST) + return -1; + if (!KRT_CF->devroutes && (e->attrs->dest == RTD_DEVICE) && (e->attrs->source != RTS_STATIC_DEVICE)) -- cgit v1.2.3