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. route Static device route through an interface to hosts on a directly connected network. + route Static recursive route, + its nexthop depends on a route table lookup for given IP address. route Special routes specifying to drop the packet, return it as unreachable or return it as administratively prohibited. - check link switch - The only option of the static protocol. If set, hardware link - states of network interfaces are taken into consideration. - When link disappears (e.g. ethernet cable is unplugged), - static routes directing to that interface are removed. It is - possible that some hardware drivers or platforms do not - implement this feature. Default: off. + check link + If set, hardware link states of network interfaces are taken + into consideration. When link disappears (e.g. ethernet cable + is unplugged), static routes directing to that interface are + removed. It is possible that some hardware drivers or + platforms do not implement this feature. Default: off. + + igp table Specifies a table that is used + for route table lookups of recursive routes. Default: the + same table as the protocol is connected to.

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