summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2010-11-14 05:49:56 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2010-11-14 05:49:56 +0100
commit2ef9177a47e7137dd09b06a353a6e5f6e671c951 (patch)
tree3fb8f3e25eec4dd513cb87399caf7c0e6ff5f955
parent9d35f8c51f1062ddd8e2f41cf535d8a8d69ec6be (diff)
downloadbird-2ef9177a47e7137dd09b06a353a6e5f6e671c951.tar
bird-2ef9177a47e7137dd09b06a353a6e5f6e671c951.zip
Add multicast support to static protocol and generic route handling.
-rw-r--r--nest/protocol.h1
-rw-r--r--nest/route.h19
-rw-r--r--nest/rt-table.c143
-rw-r--r--proto/static/config.Y4
-rw-r--r--proto/static/static.c18
-rw-r--r--proto/static/static.h1
-rw-r--r--sysdep/unix/krt.c9
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, [<name>], [[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))