summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sysdep/linux/krt-scan.c200
-rw-r--r--sysdep/unix/krt-set.c17
-rw-r--r--sysdep/unix/krt-set.h6
-rw-r--r--sysdep/unix/krt.h3
4 files changed, 136 insertions, 90 deletions
diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c
index baa39d85..7dd64159 100644
--- a/sysdep/linux/krt-scan.c
+++ b/sysdep/linux/krt-scan.c
@@ -28,54 +28,39 @@ static int krt_scan_fd = -1;
/* FIXME: Filtering */
-static void
-krt_magic_route(struct krt_proto *p, net *net, ip_addr gw)
+static int
+krt_uptodate(rte *k, rte *e)
{
- neighbor *ng;
- rta a, *t;
- rte *e;
+ rta *ka = k->attrs, *ea = e->attrs;
- ng = neigh_find(&p->p, &gw, 0);
- if (!ng)
- {
- log(L_ERR "Kernel told us to use non-neighbor %I for %I/%d\n", gw, net->n.prefix, net->n.pxlen);
- return;
- }
- a.proto = &p->p;
- a.source = RTS_INHERIT;
- a.scope = SCOPE_UNIVERSE;
- a.cast = RTC_UNICAST;
- a.dest = RTD_ROUTER;
- a.tos = 0;
- a.flags = 0;
- a.gw = gw;
- a.from = IPA_NONE;
- a.iface = ng->iface;
- a.attrs = NULL;
- t = rta_lookup(&a);
- e = rte_get_temp(t);
- e->net = net;
- rte_update(net, &p->p, e);
+ if (ka->dest != ea->dest)
+ return 0;
+ if (ka->dest == RTD_ROUTER && !ipa_equal(ka->gw, ea->gw))
+ return 0;
+ /* FIXME: Device routes */
+ return 1;
}
static void
-krt_parse_entry(byte *e, struct krt_proto *p)
+krt_parse_entry(byte *ent, struct krt_proto *p)
{
u32 dest0, gw0, mask0;
ip_addr dest, gw, mask;
- unsigned int flags;
+ unsigned int flags, verdict;
int masklen;
net *net;
- byte *iface = e;
+ byte *iface = ent;
+ rta a;
+ rte *e, *old;
- if (sscanf(e, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4)
+ if (sscanf(ent, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4)
{
- log(L_ERR "krt read: unable to parse `%s'", e);
+ log(L_ERR "krt read: unable to parse `%s'", ent);
return;
}
- while (*e != '\t')
- e++;
- *e = 0;
+ while (*ent != '\t')
+ ent++;
+ *ent = 0;
dest = ipa_from_u32(dest0);
ipa_ntoh(dest);
@@ -99,47 +84,69 @@ krt_parse_entry(byte *e, struct krt_proto *p)
log(L_WARN "krt: Ignoring redirect to %I/%d via %I", dest, masklen, gw);
return;
}
+
net = net_get(&master_table, 0, dest, masklen);
- if (net->routes)
+ a.proto = &p->p;
+ a.source = RTS_INHERIT;
+ a.scope = SCOPE_UNIVERSE;
+ a.cast = RTC_UNICAST;
+ a.tos = a.flags = a.aflags = 0;
+ a.from = IPA_NONE;
+ a.iface = NULL;
+ a.attrs = NULL;
+
+ if (flags & RTF_GATEWAY)
{
- rte *e = net->routes;
- rta *a = e->attrs;
- int ok;
- switch (a->dest)
- {
- case RTD_ROUTER:
- ok = (flags & RTF_GATEWAY) && ipa_equal(gw, a->gw);
- break;
- case RTD_DEVICE:
-#ifdef CONFIG_AUTO_ROUTES
- ok = 1;
- /* FIXME: What about static interface routes? */
-#else
- ok = !(flags & RTF_GATEWAY) && !strcmp(iface, a->iface->name);
-#endif
- break;
- case RTD_UNREACHABLE:
- ok = flags & RTF_REJECT;
- break;
- default:
- ok = 0;
- }
- net->n.flags |= ok ? KRF_SEEN : KRF_UPDATE;
+ neighbor *ng = neigh_find(&p->p, &gw, 0);
+ if (ng)
+ a.iface = ng->iface;
+ else
+ /* FIXME: Remove this warning? */
+ log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d\n", gw, net->n.prefix, net->n.pxlen);
+ a.dest = RTD_ROUTER;
+ a.gw = gw;
+ }
+ else if (flags & RTF_REJECT)
+ {
+ a.dest = RTD_UNREACHABLE;
+ a.gw = IPA_NONE;
}
else
{
-#ifdef CONFIG_AUTO_ROUTES
- if (!(flags & RTF_GATEWAY)) /* It's a device route */
- return;
-#endif
- DBG("krt_parse_entry: kernel reporting unknown route %I/%d\n", dest, masklen);
- if (p->scanopt.learn)
- {
- if (flags & RTF_GATEWAY)
- krt_magic_route(p, net, gw);
- }
- net->n.flags |= KRF_UPDATE;
+ /* FIXME: Should support interface routes? */
+ /* FIXME: What about systems not generating their own if routes? (see CONFIG_AUTO_ROUTES) */
+ return;
+ }
+
+ e = rte_get_temp(&a);
+ e->net = net;
+ old = net->routes;
+ if (old && !krt_capable(old))
+ old = NULL;
+ if (old)
+ {
+ if (krt_uptodate(e, net->routes))
+ verdict = KRF_SEEN;
+ else
+ verdict = KRF_UPDATE;
+ }
+ else if (p->scanopt.learn && !net->routes)
+ verdict = KRF_LEARN;
+ else
+ verdict = KRF_DELETE;
+
+ DBG("krt_parse_entry: verdict %d\n", verdict);
+
+ net->n.flags = verdict;
+ if (verdict != KRF_SEEN)
+ {
+ /* Get a cached copy of attributes and link the route */
+ e->attrs = rta_lookup(e->attrs);
+ e->next = net->routes;
+ net->routes = e;
}
+ else
+ rte_free(e);
}
static int
@@ -187,7 +194,7 @@ krt_scan_proc(struct krt_proto *p)
}
static void
-krt_prune(void)
+krt_prune(struct krt_proto *p)
{
struct rtable *t = &master_table;
struct fib_node *f;
@@ -200,24 +207,57 @@ krt_prune(void)
FIB_WALK(&t->fib, f)
{
net *n = (net *) f;
- switch (f->flags)
+ int verdict = f->flags;
+ rte *new, *old;
+
+ if (verdict != KRF_CREATE && verdict != KRF_SEEN)
{
- case KRF_UPDATE:
- DBG("krt_prune: removing %I/%d\n", n->n.prefix, n->n.pxlen);
- krt_remove_route(n, NULL);
- /* Fall-thru */
- case 0:
- if (n->routes)
+ old = n->routes;
+ n->routes = old->next;
+ }
+ else
+ old = NULL;
+ new = n->routes;
+
+ switch (verdict)
+ {
+ case KRF_CREATE:
+ if (new)
{
- DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
- krt_add_route(n, n->routes);
+ if (new->attrs->source == RTS_INHERIT)
+ {
+ DBG("krt_prune: removing inherited %I/%d\n", n->n.prefix, n->n.pxlen);
+ rte_update(n, &p->p, NULL);
+ }
+ else
+ {
+ DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
+ krt_add_route(new);
+ }
}
break;
case KRF_SEEN:
+ /* Nothing happens */
+ break;
+ case KRF_UPDATE:
+ DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen);
+ krt_remove_route(old);
+ krt_add_route(new);
+ break;
+ case KRF_DELETE:
+ DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen);
+ krt_remove_route(old);
+ break;
+ case KRF_LEARN:
+ DBG("krt_prune: learning %I/%d\n", n->n.prefix, n->n.pxlen);
+ rte_update(n, &p->p, new);
break;
default:
die("krt_prune: invalid route status");
}
+
+ if (old)
+ rte_free(old);
f->flags = 0;
}
FIB_WALK_END;
@@ -229,7 +269,7 @@ krt_scan_fire(timer *t)
struct krt_proto *p = t->data;
if (krt_scan_proc(p))
- krt_prune();
+ krt_prune(p);
}
void
diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c
index 2c355eee..8bc2df11 100644
--- a/sysdep/unix/krt-set.c
+++ b/sysdep/unix/krt-set.c
@@ -22,7 +22,7 @@
#include "lib/krt.h"
int
-krt_capable(net *net, rte *e)
+krt_capable(rte *e)
{
rta *a = e->attrs;
@@ -40,11 +40,12 @@ krt_capable(net *net, rte *e)
}
void
-krt_remove_route(net *net, rte *old)
+krt_remove_route(rte *old)
{
+ net *net = old->net;
struct rtentry re;
- if (old && !krt_capable(net, old))
+ if (!krt_capable(old) || old->attrs->source == RTS_INHERIT)
{
DBG("krt_remove_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
@@ -58,12 +59,13 @@ krt_remove_route(net *net, rte *old)
}
void
-krt_add_route(net *net, rte *new)
+krt_add_route(rte *new)
{
+ net *net = new->net;
struct rtentry re;
rta *a = new->attrs;
- if (!krt_capable(net, new))
+ if (!krt_capable(new) || new->attrs->source == RTS_INHERIT)
{
DBG("krt_add_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
@@ -105,9 +107,9 @@ krt_set_notify(struct proto *x, net *net, rte *new, rte *old)
if (x->state != PRS_UP)
return;
if (old)
- krt_remove_route(net, old);
+ krt_remove_route(old);
if (new)
- krt_add_route(net, new);
+ krt_add_route(new);
}
void
@@ -117,3 +119,4 @@ krt_set_preconfig(struct krt_proto *x)
die("krt set: missing socket");
x->p.rt_notify = krt_set_notify;
}
+
diff --git a/sysdep/unix/krt-set.h b/sysdep/unix/krt-set.h
index a2107e12..214d91ac 100644
--- a/sysdep/unix/krt-set.h
+++ b/sysdep/unix/krt-set.h
@@ -12,8 +12,8 @@
struct krt_set_params {
};
-void krt_remove_route(net *net, rte *old);
-void krt_add_route(net *net, rte *new);
-int krt_capable(net *net, rte *e);
+void krt_remove_route(rte *old);
+void krt_add_route(rte *new);
+int krt_capable(rte *e);
#endif
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 24122e94..aae5bd57 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -14,8 +14,11 @@
/* Flags stored in net->n.flags */
+#define KRF_CREATE 0 /* Not seen in kernel table */
#define KRF_SEEN 1 /* Seen in kernel table during last scan */
#define KRF_UPDATE 2 /* Need to update this entry */
+#define KRF_DELETE 3 /* Should be deleted */
+#define KRF_LEARN 4 /* We should learn this route */
/* sync-rt.c */