summaryrefslogtreecommitdiffstats
path: root/sysdep
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/linux/krt-scan.c49
-rw-r--r--sysdep/unix/krt-set.c90
-rw-r--r--sysdep/unix/krt-set.h4
3 files changed, 135 insertions, 8 deletions
diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c
index efc8e93..1b00636 100644
--- a/sysdep/linux/krt-scan.c
+++ b/sysdep/linux/krt-scan.c
@@ -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? */
}
diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c
index 9da836d..2c355ee 100644
--- a/sysdep/unix/krt-set.c
+++ b/sysdep/unix/krt-set.c
@@ -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;
}
diff --git a/sysdep/unix/krt-set.h b/sysdep/unix/krt-set.h
index 3b906ba..a2107e1 100644
--- a/sysdep/unix/krt-set.h
+++ b/sysdep/unix/krt-set.h
@@ -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