summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>1998-10-19 19:52:29 +0200
committerMartin Mares <mj@ucw.cz>1998-10-19 19:52:29 +0200
commit08045252553478457f923a9f941675df9992f507 (patch)
treecf34d40c0b6f3fa0697cf5164d64077eb1d849ce
parent567e6c62208d3bb05b58b8ed08c2be29d6542f2b (diff)
downloadbird-08045252553478457f923a9f941675df9992f507.tar
bird-08045252553478457f923a9f941675df9992f507.zip
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.
-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