diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/static/config.Y | 30 | ||||
-rw-r--r-- | proto/static/static.c | 94 | ||||
-rw-r--r-- | proto/static/static.h | 10 |
3 files changed, 125 insertions, 9 deletions
diff --git a/proto/static/config.Y b/proto/static/config.Y index a9eaa872..ff506511 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -10,9 +10,11 @@ CF_HDR #include "proto/static/static.h" +static struct static_route *this_srt; + CF_DECLS -CF_KEYWORDS(STATIC) +CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE) CF_GRAMMAR @@ -27,6 +29,32 @@ static_proto_start: proto_start STATIC { static_proto: static_proto_start proto_name '{' | static_proto proto_item ';' + | static_proto stat_route ';' + ; + +stat_route0: ROUTE IPA pxlen { + this_srt = cfg_allocz(sizeof(struct static_route)); + add_tail(&((struct static_proto *) this_proto)->other_routes, &this_srt->n); + if (!ip_is_prefix($2, $3)) cf_error("Invalid network prefix: %I/%d", $2, $3); + this_srt->net = $2; + this_srt->masklen = $3; + } + ; + +stat_route: + stat_route0 VIA IPA { + this_srt->dest = RTD_ROUTER; + this_srt->via = $3; + } + | stat_route0 VIA TEXT { + this_srt->dest = RTD_DEVICE; + this_srt->if_name = $3; + rem_node(&this_srt->n); + add_tail(&((struct static_proto *) this_proto)->iface_routes, &this_srt->n); + } + | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } + | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } + | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } ; CF_CODE diff --git a/proto/static/static.c b/proto/static/static.c index 679ee6ee..bc060cda 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -8,6 +8,8 @@ #define LOCAL_DEBUG +#include <string.h> + #include "nest/bird.h" #include "nest/iface.h" #include "nest/protocol.h" @@ -19,21 +21,106 @@ #define GET_DATA struct static_proto *p = (struct static_proto *) P static void +static_install(struct static_proto *p, struct static_route *r, struct iface *ifa) +{ + net *n; + rta a, *aa; + rte *e; + + DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); + bzero(&a, sizeof(a)); + a.proto = &p->p; + a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC; + a.scope = SCOPE_UNIVERSE; + a.cast = RTC_UNICAST; + a.dest = r->dest; + a.tos = 0; + a.gw = r->via; + a.iface = ifa; + aa = rta_lookup(&a); + + n = net_get(&master_table, a.tos, r->net, r->masklen); + e = rte_get_temp(aa); + e->net = n; + e->pflags = 0; + rte_update(n, &p->p, e); +} + +static void +static_remove(struct static_proto *p, struct static_route *r) +{ + net *n; + + DBG("Removing static route %I/%d\n", r->net, r->masklen); + n = net_find(&master_table, 0, r->net, r->masklen); + if (n) + rte_update(n, &p->p, NULL); +} + +static void static_start(struct proto *P) { + GET_DATA; + struct static_route *r; + DBG("Static: take off!\n"); + WALK_LIST(r, p->other_routes) + if (r->dest == RTD_ROUTER) + { + struct neighbor *n = neigh_find(P, &r->via, NEF_STICKY); + if (n) + { + n->data = r; + r->neigh = n; + static_install(p, r, n->iface); + } + else + log(L_ERR "Static route destination %I is invalid. Ignoring.\n", r->via); + } + else + static_install(p, r, NULL); } static void static_neigh_notify(struct neighbor *n) { - DBG("Static: neighbor notify got, don't know why.\n"); + DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface); + if (n->iface) + static_install((struct static_proto *) n->proto, n->data, n->iface); + else + static_remove((struct static_proto *) n->proto, n->data); +} + +static void +static_dump_rt(struct static_route *r) +{ + debug("%16I/%2d: ", r->net, r->masklen); + switch (r->dest) + { + case RTD_ROUTER: + debug("via %I\n", r->via); + break; + case RTD_DEVICE: + debug("dev %s\n", r->if_name); + break; + default: + debug("rtd %d\n", r->dest); + break; + } } static void static_dump(struct proto *P) { - DBG("Static: no dumps available in demo version.\n"); + GET_DATA; + struct static_route *r; + + debug("Independent static routes:\n"); + WALK_LIST(r, p->other_routes) + static_dump_rt(r); + debug("Device static routes:\n"); + WALK_LIST(r, p->iface_routes) + static_dump_rt(r); } void @@ -45,7 +132,8 @@ static_init_instance(struct static_proto *P) p->start = static_start; p->neigh_notify = static_neigh_notify; p->dump = static_dump; - /* FIXME: Should shutdown remove all routes? */ + init_list(&P->iface_routes); + init_list(&P->other_routes); } static void diff --git a/proto/static/static.h b/proto/static/static.h index df18c133..b6d69457 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -11,20 +11,20 @@ struct static_proto { struct proto p; - list routes; + list iface_routes; /* Routes to search on interface events */ + list other_routes; /* Routes hooked to neighbor cache and reject routes */ }; void static_init_instance(struct static_proto *); struct static_route { node n; - u32 net; /* Network we route */ + ip_addr net; /* Network we route */ int masklen; /* Mask length */ int dest; /* Destination type (RTD_*) */ - u32 via; /* Destination router */ + ip_addr via; /* Destination router */ struct neighbor *neigh; - /* FIXME: Device routes, maybe via device patterns? */ - /* FIXME: More route attributes, probably via filter syntax */ + byte *if_name; /* Name for RTD_DEVICE routes */ }; #endif |