summaryrefslogtreecommitdiff
path: root/proto/static
diff options
context:
space:
mode:
Diffstat (limited to 'proto/static')
-rw-r--r--proto/static/config.Y30
-rw-r--r--proto/static/static.c94
-rw-r--r--proto/static/static.h10
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