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
them out through the default route to prevent routing loops).
<p>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.
<p>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.
<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
@ -2442,17 +2444,22 @@ definition of the protocol contains mainly a list of static routes:
with their weights.
<tag>route <m/prefix/ via <m/"interface"/</tag> Static device
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
specifying to drop the packet, return it as unreachable or return
it as administratively prohibited.
<tag>check link <M>switch</M></tag>
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.
<tag>check link <m/switch/</tag>
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.
<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>
<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_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; }

View file

@ -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)");

View file

@ -14,6 +14,7 @@ struct static_config {
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 */
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