Implements static recursive routes.

This commit is contained in:
Ondrej Zajicek 2011-09-24 02:21:52 +02:00
parent 4271f2b77e
commit 4116db182d
4 changed files with 75 additions and 20 deletions

View file

@ -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 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). them out through the default route to prevent routing loops).
<p>There are three types of static routes: `classical' routes telling to <p>There are five types of static routes: `classical' routes telling
forward packets to a neighboring router, device routes specifying forwarding to forward packets to a neighboring router, multipath routes
to hosts on a directly connected network and special routes (sink, blackhole specifying several (possibly weighted) neighboring routers, device
etc.) which specify a special action to be done instead of forwarding the routes specifying forwarding to hosts on a directly connected network,
packet. 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.
<p>When the particular destination is not available (the interface is down or <p>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 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. with their weights.
<tag>route <m/prefix/ via <m/"interface"/</tag> Static device <tag>route <m/prefix/ via <m/"interface"/</tag> Static device
route through an interface to hosts on a directly connected network. route through an interface to hosts on a directly connected network.
<tag>route <m/prefix/ recursive <m/ip/</tag> Static recursive route,
its nexthop depends on a route table lookup for given IP address.
<tag>route <m/prefix/ drop|reject|prohibit</tag> Special routes <tag>route <m/prefix/ drop|reject|prohibit</tag> Special routes
specifying to drop the packet, return it as unreachable or return specifying to drop the packet, return it as unreachable or return
it as administratively prohibited. it as administratively prohibited.
<tag>check link <M>switch</M></tag> <tag>check link <m/switch/</tag>
The only option of the static protocol. If set, hardware link If set, hardware link states of network interfaces are taken
states of network interfaces are taken into consideration. into consideration. When link disappears (e.g. ethernet cable
When link disappears (e.g. ethernet cable is unplugged), is unplugged), static routes directing to that interface are
static routes directing to that interface are removed. It is removed. It is possible that some hardware drivers or
possible that some hardware drivers or platforms do not platforms do not implement this feature. Default: off.
implement this feature. Default: off.
<tag>igp table <m/name/</tag> Specifies a table that is used
for route table lookups of recursive routes. Default: the
same table as the protocol is connected to.
</descrip> </descrip>
<p>Static routes have no specific attributes. <p>Static routes have no specific attributes.

View file

@ -18,7 +18,7 @@ static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
CF_DECLS CF_DECLS
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
CF_KEYWORDS(MULTIPATH, WEIGHT) CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE)
CF_GRAMMAR CF_GRAMMAR
@ -35,6 +35,7 @@ static_proto:
static_proto_start proto_name '{' static_proto_start proto_name '{'
| static_proto proto_item ';' | static_proto proto_item ';'
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; } | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
| static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; }
| static_proto stat_route ';' | static_proto stat_route ';'
; ;
@ -79,6 +80,10 @@ stat_route:
| stat_route0 MULTIPATH stat_multipath { | stat_route0 MULTIPATH stat_multipath {
this_srt->dest = RTD_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 DROP { this_srt->dest = RTD_BLACKHOLE; }
| stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
| stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; }

View file

@ -47,6 +47,14 @@
#include "static.h" #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 void
static_install(struct proto *p, struct static_route *r, struct iface *ifa) 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; 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); aa = rta_lookup(&a);
n = net_get(p->table, r->net, r->masklen); n = net_get(p->table, r->net, r->masklen);
e = rte_get_temp(aa); 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 int
static_start(struct proto *p) static_start(struct proto *p)
{ {
struct static_config *c = (void *) p->cf; struct static_config *cf = (void *) p->cf;
struct static_route *r; struct static_route *r;
DBG("Static: take off!\n"); 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; return PS_UP;
} }
static int static int
static_shutdown(struct proto *p) static_shutdown(struct proto *p)
{ {
struct static_config *c = (void *) p->cf; struct static_config *cf = (void *) p->cf;
struct static_route *r; struct static_route *r;
/* Just reset the flag, the routes will be flushed by the nest */ /* 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; r->installed = 0;
WALK_LIST(r, c->other_routes) WALK_LIST(r, cf->other_routes)
r->installed = 0; r->installed = 0;
return PS_DOWN; 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 void
static_neigh_notify(struct neighbor *n) static_neigh_notify(struct neighbor *n)
{ {
@ -373,6 +398,9 @@ static_same_dest(struct static_route *x, struct static_route *y)
return 0; return 0;
return !x && !y; return !x && !y;
case RTDX_RECURSIVE:
return ipa_equal(x->via, y->via);
default: default:
return 1; return 1;
} }
@ -407,6 +435,12 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n)
static_remove(p, r); 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 int
static_reconfigure(struct proto *p, struct proto_config *new) 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_config *n = (void *) new;
struct static_route *r; struct static_route *r;
if (cf_igp_table(o) != cf_igp_table(n))
return 0;
/* Delete all obsolete routes and reset neighbor entries */ /* Delete all obsolete routes and reset neighbor entries */
WALK_LIST(r, o->iface_routes) WALK_LIST(r, o->iface_routes)
static_match(p, r, n); static_match(p, r, n);
@ -440,6 +477,7 @@ struct protocol proto_static = {
dump: static_dump, dump: static_dump,
start: static_start, start: static_start,
shutdown: static_shutdown, shutdown: static_shutdown,
cleanup: static_cleanup,
reconfigure: static_reconfigure, reconfigure: static_reconfigure,
}; };
@ -456,6 +494,7 @@ static_show_rt(struct static_route *r)
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break; case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break; case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
case RTD_MULTIPATH: bsprintf(via, "multipath"); break; case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
default: bsprintf(via, "???"); 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", r->net, r->masklen, via, r->installed ? "" : " (dormant)");

View file

@ -13,7 +13,8 @@ struct static_config {
struct proto_config c; struct proto_config c;
list iface_routes; /* Routes to search on interface events */ list iface_routes; /* Routes to search on interface events */
list other_routes; /* Routes hooked to neighbor cache and reject routes */ 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 /* Dummy nodes (parts of multipath route) abuses masklen field for weight
and if_name field for a ptr to the master (RTD_MULTIPATH) node. */ 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 *); void static_show(struct proto *);
#endif #endif