diff --git a/doc/bird.sgml b/doc/bird.sgml index d96d19de..c929dbeb 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2420,11 +2420,13 @@ telling to return packets as undeliverable if they are in your IP block, you don't have any specific destination for them and you don't want to send them out through the default route to prevent routing loops). -
There are three types of static routes: `classical' routes telling to -forward packets to a neighboring router, device routes specifying forwarding -to hosts on a directly connected network and special routes (sink, blackhole -etc.) which specify a special action to be done instead of forwarding the -packet. +
There are five types of static routes: `classical' routes telling +to forward packets to a neighboring router, multipath routes +specifying several (possibly weighted) neighboring routers, device +routes specifying forwarding to hosts on a directly connected network, +recursive routes computing their nexthops by doing route table lookups +for a given IP and special routes (sink, blackhole etc.) which specify +a special action to be done instead of forwarding the packet.
When the particular destination is not available (the interface is down or
the next hop of the route is not a neighbor at the moment), Static just
@@ -2442,17 +2444,22 @@ definition of the protocol contains mainly a list of static routes:
with their weights.
Static routes have no specific attributes.
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 46debbc3..77d2419f 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -18,7 +18,7 @@ static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
CF_DECLS
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
-CF_KEYWORDS(MULTIPATH, WEIGHT)
+CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE)
CF_GRAMMAR
@@ -35,6 +35,7 @@ static_proto:
static_proto_start proto_name '{'
| static_proto proto_item ';'
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
+ | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; }
| static_proto stat_route ';'
;
@@ -79,6 +80,10 @@ stat_route:
| stat_route0 MULTIPATH stat_multipath {
this_srt->dest = RTD_MULTIPATH;
}
+ | stat_route0 RECURSIVE ipa {
+ this_srt->dest = RTDX_RECURSIVE;
+ this_srt->via = $3;
+ }
| stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; }
diff --git a/proto/static/static.c b/proto/static/static.c
index b9534882..2f33d817 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -47,6 +47,14 @@
#include "static.h"
+static inline rtable *
+p_igp_table(struct proto *p)
+{
+ struct static_config *cf = (void *) p->cf;
+ return cf->igp_table ? cf->igp_table->table : p->table;
+}
+
+
static void
static_install(struct proto *p, struct static_route *r, struct iface *ifa)
{
@@ -97,6 +105,9 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
a.nexthops = nhs;
}
+ if (r->dest == RTDX_RECURSIVE)
+ rta_set_recursive_next_hop(p->table, &a, p_igp_table(p), &r->via, &r->via);
+
aa = rta_lookup(&a);
n = net_get(p->table, r->net, r->masklen);
e = rte_get_temp(aa);
@@ -207,30 +218,44 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
static int
static_start(struct proto *p)
{
- struct static_config *c = (void *) p->cf;
+ struct static_config *cf = (void *) p->cf;
struct static_route *r;
DBG("Static: take off!\n");
- WALK_LIST(r, c->other_routes)
- static_add(p, c, r);
+
+ if (cf->igp_table)
+ rt_lock_table(cf->igp_table->table);
+
+ WALK_LIST(r, cf->other_routes)
+ static_add(p, cf, r);
return PS_UP;
}
static int
static_shutdown(struct proto *p)
{
- struct static_config *c = (void *) p->cf;
+ struct static_config *cf = (void *) p->cf;
struct static_route *r;
/* Just reset the flag, the routes will be flushed by the nest */
- WALK_LIST(r, c->iface_routes)
+ WALK_LIST(r, cf->iface_routes)
r->installed = 0;
- WALK_LIST(r, c->other_routes)
+ WALK_LIST(r, cf->other_routes)
r->installed = 0;
return PS_DOWN;
}
+static void
+static_cleanup(struct proto *p)
+{
+ struct static_config *cf = (void *) p->cf;
+
+ if (cf->igp_table)
+ rt_unlock_table(cf->igp_table->table);
+}
+
+
static void
static_neigh_notify(struct neighbor *n)
{
@@ -373,6 +398,9 @@ static_same_dest(struct static_route *x, struct static_route *y)
return 0;
return !x && !y;
+ case RTDX_RECURSIVE:
+ return ipa_equal(x->via, y->via);
+
default:
return 1;
}
@@ -407,6 +435,12 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n)
static_remove(p, r);
}
+static inline rtable *
+cf_igp_table(struct static_config *cf)
+{
+ return cf->igp_table ? cf->igp_table->table : NULL;
+}
+
static int
static_reconfigure(struct proto *p, struct proto_config *new)
{
@@ -414,6 +448,9 @@ static_reconfigure(struct proto *p, struct proto_config *new)
struct static_config *n = (void *) new;
struct static_route *r;
+ if (cf_igp_table(o) != cf_igp_table(n))
+ return 0;
+
/* Delete all obsolete routes and reset neighbor entries */
WALK_LIST(r, o->iface_routes)
static_match(p, r, n);
@@ -440,6 +477,7 @@ struct protocol proto_static = {
dump: static_dump,
start: static_start,
shutdown: static_shutdown,
+ cleanup: static_cleanup,
reconfigure: static_reconfigure,
};
@@ -456,6 +494,7 @@ static_show_rt(struct static_route *r)
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
+ case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
default: bsprintf(via, "???");
}
cli_msg(-1009, "%I/%d %s%s", r->net, r->masklen, via, r->installed ? "" : " (dormant)");
diff --git a/proto/static/static.h b/proto/static/static.h
index c91b9cef..775743cf 100644
--- a/proto/static/static.h
+++ b/proto/static/static.h
@@ -13,7 +13,8 @@ struct static_config {
struct proto_config c;
list iface_routes; /* Routes to search on interface events */
list other_routes; /* Routes hooked to neighbor cache and reject routes */
- int check_link; /* Whether iface link state is used */
+ int check_link; /* Whether iface link state is used */
+ struct rtable_config *igp_table; /* Table used for recursive next hop lookups */
};
@@ -35,6 +36,9 @@ struct static_route {
/* Dummy nodes (parts of multipath route) abuses masklen field for weight
and if_name field for a ptr to the master (RTD_MULTIPATH) node. */
+
+#define RTDX_RECURSIVE 0x7f /* Phony dest value for recursive routes */
+
void static_show(struct proto *);
#endif