Commit 08045252 authored by Martin Mareš's avatar Martin Mareš

Basic kernel routing table syncing implemented. Learning of routes installed

by other programs or the kernel itself is not supported yet, but it's not
needed for development of other protocols.
parent 567e6c62
......@@ -26,6 +26,8 @@
static int krt_scan_fd = -1;
/* FIXME: Filtering */
static void
krt_parse_entry(byte *e)
{
......@@ -98,6 +100,8 @@ krt_parse_entry(byte *e)
if (!(flags & RTF_GATEWAY)) /* It's a device route */
return;
#endif
DBG("krt_parse_entry: kernel reporting unknown route %I/%d\n", dest, masklen);
/* FIXME: should be able to learn kernel routes */
net->n.flags |= KRF_UPDATE;
}
}
......@@ -108,6 +112,7 @@ krt_scan_proc(void)
byte buf[32768];
int l, seen_hdr;
DBG("Scanning kernel table...\n");
if (krt_scan_fd < 0)
{
krt_scan_fd = open("/proc/net/route", O_RDONLY);
......@@ -146,14 +151,47 @@ krt_scan_proc(void)
}
static void
krt_scan_fire(timer *t)
krt_prune(void)
{
struct krt_proto *x = t->data;
SCANOPT;
struct rtable *t = &master_table;
struct fib_node *f;
DBG("Scanning kernel table...\n");
if (!krt_scan_proc())
DBG("Pruning routes...\n");
while (t && t->tos)
t = t->sibling;
if (!t)
return;
FIB_WALK(&t->fib, f)
{
net *n = (net *) f;
switch (f->flags)
{
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)
{
DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen);
krt_add_route(n, n->routes);
}
break;
case KRF_SEEN:
break;
default:
die("krt_prune: invalid route status");
}
f->flags = 0;
}
FIB_WALK_END;
}
static void
krt_scan_fire(timer *t)
{
if (krt_scan_proc())
krt_prune();
}
void
......@@ -185,4 +223,5 @@ krt_scan_shutdown(struct krt_proto *x)
SCANOPT;
tm_stop(p->timer);
/* FIXME: Remove all krt's? */
}
......@@ -10,7 +10,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/route.h>
#define LOCAL_DEBUG
......@@ -18,18 +18,102 @@
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "lib/timer.h"
#include "lib/unix.h"
#include "lib/krt.h"
int
krt_capable(net *net, rte *e)
{
rta *a = e->attrs;
return
a->cast == RTC_UNICAST &&
(a->dest == RTD_ROUTER
#ifndef CONFIG_AUTO_ROUTES
|| a->dest == RTD_DEVICE
#endif
#ifdef RTF_REJECT
|| a->dest == RTD_UNREACHABLE
#endif
) &&
!a->tos;
}
void
krt_remove_route(net *net, rte *old)
{
struct rtentry re;
if (old && !krt_capable(net, old))
{
DBG("krt_remove_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
}
DBG("krt_remove_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
bzero(&re, sizeof(re));
fill_in_sockaddr((struct sockaddr_in *) &re.rt_dst, net->n.prefix, 0);
fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0);
if (ioctl(if_scan_sock, SIOCDELRT, &re) < 0)
log(L_ERR "SIOCDELRT(%I/%d): %m", net->n.prefix, net->n.pxlen);
}
void
krt_add_route(net *net, rte *new)
{
struct rtentry re;
rta *a = new->attrs;
if (!krt_capable(net, new))
{
DBG("krt_add_route(ignored %I/%d)\n", net->n.prefix, net->n.pxlen);
return;
}
DBG("krt_add_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
bzero(&re, sizeof(re));
fill_in_sockaddr((struct sockaddr_in *) &re.rt_dst, net->n.prefix, 0);
fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0);
re.rt_flags = RTF_UP;
if (net->n.pxlen == 32)
re.rt_flags |= RTF_HOST;
switch (a->dest)
{
case RTD_ROUTER:
fill_in_sockaddr((struct sockaddr_in *) &re.rt_gateway, a->gw, 0);
re.rt_flags |= RTF_GATEWAY;
break;
#ifndef CONFIG_AUTO_ROUTES
case RTD_DEVICE:
re.rt_dev = a->iface->name;
break;
#endif
#ifdef RTF_REJECT
case RTD_UNREACHABLE:
re.rt_flags |= RTF_REJECT;
break;
#endif
default:
die("krt set: unknown flags, but not filtered");
}
if (ioctl(if_scan_sock, SIOCADDRT, &re) < 0)
log(L_ERR "SIOCADDRT(%I/%d): %m", net->n.prefix, net->n.pxlen);
}
void
krt_set_notify(struct proto *x, net *net, rte *new, rte *old)
{
DBG("krt_set_notify(%I/%d)\n", net->n.prefix, net->n.pxlen);
if (x->state != PRS_UP)
return;
if (old)
krt_remove_route(net, old);
if (new)
krt_add_route(net, new);
}
void
krt_set_preconfig(struct krt_proto *x)
{
if (if_scan_sock < 0)
die("krt set: missing socket");
x->p.rt_notify = krt_set_notify;
}
......@@ -12,4 +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);
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment