summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
Diffstat (limited to 'proto')
-rw-r--r--proto/static/config.Y7
-rw-r--r--proto/static/static.c51
-rw-r--r--proto/static/static.h6
3 files changed, 56 insertions, 8 deletions
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,31 +218,45 @@ 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)
{
struct proto *p = n->proto;
@@ -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