Rewritten kernel syncer. Now uses the rta trickery I've introduced yesterday
and does things "the right way". Few things are still missing (device routes etc.), I'll add them later in the evening.
This commit is contained in:
parent
04925e9040
commit
f39e4713c2
4 changed files with 136 additions and 90 deletions
|
@ -28,54 +28,39 @@ static int krt_scan_fd = -1;
|
||||||
|
|
||||||
/* FIXME: Filtering */
|
/* FIXME: Filtering */
|
||||||
|
|
||||||
static void
|
static int
|
||||||
krt_magic_route(struct krt_proto *p, net *net, ip_addr gw)
|
krt_uptodate(rte *k, rte *e)
|
||||||
{
|
{
|
||||||
neighbor *ng;
|
rta *ka = k->attrs, *ea = e->attrs;
|
||||||
rta a, *t;
|
|
||||||
rte *e;
|
|
||||||
|
|
||||||
ng = neigh_find(&p->p, &gw, 0);
|
if (ka->dest != ea->dest)
|
||||||
if (!ng)
|
return 0;
|
||||||
{
|
if (ka->dest == RTD_ROUTER && !ipa_equal(ka->gw, ea->gw))
|
||||||
log(L_ERR "Kernel told us to use non-neighbor %I for %I/%d\n", gw, net->n.prefix, net->n.pxlen);
|
return 0;
|
||||||
return;
|
/* FIXME: Device routes */
|
||||||
}
|
return 1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
krt_parse_entry(byte *e, struct krt_proto *p)
|
krt_parse_entry(byte *ent, struct krt_proto *p)
|
||||||
{
|
{
|
||||||
u32 dest0, gw0, mask0;
|
u32 dest0, gw0, mask0;
|
||||||
ip_addr dest, gw, mask;
|
ip_addr dest, gw, mask;
|
||||||
unsigned int flags;
|
unsigned int flags, verdict;
|
||||||
int masklen;
|
int masklen;
|
||||||
net *net;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
while (*e != '\t')
|
while (*ent != '\t')
|
||||||
e++;
|
ent++;
|
||||||
*e = 0;
|
*ent = 0;
|
||||||
|
|
||||||
dest = ipa_from_u32(dest0);
|
dest = ipa_from_u32(dest0);
|
||||||
ipa_ntoh(dest);
|
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);
|
log(L_WARN "krt: Ignoring redirect to %I/%d via %I", dest, masklen, gw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
net = net_get(&master_table, 0, dest, masklen);
|
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;
|
neighbor *ng = neigh_find(&p->p, &gw, 0);
|
||||||
rta *a = e->attrs;
|
if (ng)
|
||||||
int ok;
|
a.iface = ng->iface;
|
||||||
switch (a->dest)
|
else
|
||||||
{
|
/* FIXME: Remove this warning? */
|
||||||
case RTD_ROUTER:
|
log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d\n", gw, net->n.prefix, net->n.pxlen);
|
||||||
ok = (flags & RTF_GATEWAY) && ipa_equal(gw, a->gw);
|
a.dest = RTD_ROUTER;
|
||||||
break;
|
a.gw = gw;
|
||||||
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;
|
else if (flags & RTF_REJECT)
|
||||||
|
{
|
||||||
|
a.dest = RTD_UNREACHABLE;
|
||||||
|
a.gw = IPA_NONE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_AUTO_ROUTES
|
/* FIXME: Should support interface routes? */
|
||||||
if (!(flags & RTF_GATEWAY)) /* It's a device route */
|
/* FIXME: What about systems not generating their own if routes? (see CONFIG_AUTO_ROUTES) */
|
||||||
return;
|
return;
|
||||||
#endif
|
}
|
||||||
DBG("krt_parse_entry: kernel reporting unknown route %I/%d\n", dest, masklen);
|
|
||||||
if (p->scanopt.learn)
|
e = rte_get_temp(&a);
|
||||||
|
e->net = net;
|
||||||
|
old = net->routes;
|
||||||
|
if (old && !krt_capable(old))
|
||||||
|
old = NULL;
|
||||||
|
if (old)
|
||||||
{
|
{
|
||||||
if (flags & RTF_GATEWAY)
|
if (krt_uptodate(e, net->routes))
|
||||||
krt_magic_route(p, net, gw);
|
verdict = KRF_SEEN;
|
||||||
|
else
|
||||||
|
verdict = KRF_UPDATE;
|
||||||
}
|
}
|
||||||
net->n.flags |= 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
|
static int
|
||||||
|
@ -187,7 +194,7 @@ krt_scan_proc(struct krt_proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
krt_prune(void)
|
krt_prune(struct krt_proto *p)
|
||||||
{
|
{
|
||||||
struct rtable *t = &master_table;
|
struct rtable *t = &master_table;
|
||||||
struct fib_node *f;
|
struct fib_node *f;
|
||||||
|
@ -200,24 +207,57 @@ krt_prune(void)
|
||||||
FIB_WALK(&t->fib, f)
|
FIB_WALK(&t->fib, f)
|
||||||
{
|
{
|
||||||
net *n = (net *) 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:
|
old = n->routes;
|
||||||
DBG("krt_prune: removing %I/%d\n", n->n.prefix, n->n.pxlen);
|
n->routes = old->next;
|
||||||
krt_remove_route(n, NULL);
|
}
|
||||||
/* Fall-thru */
|
else
|
||||||
case 0:
|
old = NULL;
|
||||||
if (n->routes)
|
new = n->routes;
|
||||||
|
|
||||||
|
switch (verdict)
|
||||||
|
{
|
||||||
|
case KRF_CREATE:
|
||||||
|
if (new)
|
||||||
|
{
|
||||||
|
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);
|
DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
|
||||||
krt_add_route(n, n->routes);
|
krt_add_route(new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KRF_SEEN:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
die("krt_prune: invalid route status");
|
die("krt_prune: invalid route status");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old)
|
||||||
|
rte_free(old);
|
||||||
f->flags = 0;
|
f->flags = 0;
|
||||||
}
|
}
|
||||||
FIB_WALK_END;
|
FIB_WALK_END;
|
||||||
|
@ -229,7 +269,7 @@ krt_scan_fire(timer *t)
|
||||||
struct krt_proto *p = t->data;
|
struct krt_proto *p = t->data;
|
||||||
|
|
||||||
if (krt_scan_proc(p))
|
if (krt_scan_proc(p))
|
||||||
krt_prune();
|
krt_prune(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "lib/krt.h"
|
#include "lib/krt.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
krt_capable(net *net, rte *e)
|
krt_capable(rte *e)
|
||||||
{
|
{
|
||||||
rta *a = e->attrs;
|
rta *a = e->attrs;
|
||||||
|
|
||||||
|
@ -40,11 +40,12 @@ krt_capable(net *net, rte *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
krt_remove_route(net *net, rte *old)
|
krt_remove_route(rte *old)
|
||||||
{
|
{
|
||||||
|
net *net = old->net;
|
||||||
struct rtentry re;
|
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);
|
DBG("krt_remove_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
|
||||||
return;
|
return;
|
||||||
|
@ -58,12 +59,13 @@ krt_remove_route(net *net, rte *old)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
krt_add_route(net *net, rte *new)
|
krt_add_route(rte *new)
|
||||||
{
|
{
|
||||||
|
net *net = new->net;
|
||||||
struct rtentry re;
|
struct rtentry re;
|
||||||
rta *a = new->attrs;
|
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);
|
DBG("krt_add_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
|
||||||
return;
|
return;
|
||||||
|
@ -105,9 +107,9 @@ krt_set_notify(struct proto *x, net *net, rte *new, rte *old)
|
||||||
if (x->state != PRS_UP)
|
if (x->state != PRS_UP)
|
||||||
return;
|
return;
|
||||||
if (old)
|
if (old)
|
||||||
krt_remove_route(net, old);
|
krt_remove_route(old);
|
||||||
if (new)
|
if (new)
|
||||||
krt_add_route(net, new);
|
krt_add_route(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -117,3 +119,4 @@ krt_set_preconfig(struct krt_proto *x)
|
||||||
die("krt set: missing socket");
|
die("krt set: missing socket");
|
||||||
x->p.rt_notify = krt_set_notify;
|
x->p.rt_notify = krt_set_notify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
struct krt_set_params {
|
struct krt_set_params {
|
||||||
};
|
};
|
||||||
|
|
||||||
void krt_remove_route(net *net, rte *old);
|
void krt_remove_route(rte *old);
|
||||||
void krt_add_route(net *net, rte *new);
|
void krt_add_route(rte *new);
|
||||||
int krt_capable(net *net, rte *e);
|
int krt_capable(rte *e);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,8 +14,11 @@
|
||||||
|
|
||||||
/* Flags stored in net->n.flags */
|
/* 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_SEEN 1 /* Seen in kernel table during last scan */
|
||||||
#define KRF_UPDATE 2 /* Need to update this entry */
|
#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 */
|
/* sync-rt.c */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue