From 08045252553478457f923a9f941675df9992f507 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Mon, 19 Oct 1998 17:52:29 +0000 Subject: [PATCH] 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. --- sysdep/linux/krt-scan.c | 51 ++++++++++++++++++++--- sysdep/unix/krt-set.c | 90 +++++++++++++++++++++++++++++++++++++++-- sysdep/unix/krt-set.h | 4 ++ 3 files changed, 136 insertions(+), 9 deletions(-) diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c index efc8e930..1b006360 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); @@ -145,15 +150,48 @@ krt_scan_proc(void) return 1; } +static void +krt_prune(void) +{ + struct rtable *t = &master_table; + struct fib_node *f; + + 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) { - struct krt_proto *x = t->data; - SCANOPT; - - DBG("Scanning kernel table...\n"); - if (!krt_scan_proc()) - return; + 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 9da836d8..2c355eee 100644 --- a/sysdep/unix/krt-set.c +++ b/sysdep/unix/krt-set.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #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 3b906baf..a2107e12 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