diff --git a/TODO b/TODO index 6298a53f..476506fd 100644 --- a/TODO +++ b/TODO @@ -16,9 +16,11 @@ Core - default preferences of protocols: prefer BGP over OSPF/RIP external routes? - secondary addresses -> subinterfaces - check if all protocols set proper packet priorities and TTL's. + - better default protocol names - config: comments at end of line -> explicit ';' needed? - remove post-config hooks? +- command-line arguments: name of config file - static: check validity of route destination? - static: device routes diff --git a/bird.conf b/bird.conf index 1d1c39af..6411a566 100644 --- a/bird.conf +++ b/bird.conf @@ -20,13 +20,18 @@ protocol device { protocol kernel { # disabled - learn; # Learn all routes from the kernel +# learn; # Learn all routes from the kernel scan time 10; # Scan kernel tables every 10 seconds +# route scan time 20; # But routes only every 20 seconds } protocol static { # disabled + route 0.0.0.0/0 via 62.168.0.13 + route 62.168.0.0/25 reject # route 10.0.0.0/8 reject -# route 10.1.0.0:255.255.255.0 via 62.168.0.3 +# route 10.1.1.0:255.255.255.0 via 62.168.0.3 +# route 10.1.2.0:255.255.255.0 via 62.168.0.3 +# route 10.1.3.0:255.255.255.0 via 62.168.0.4 # route 10.2.0.0/24 via "arc0" } diff --git a/sysdep/linux/krt-scan.Y b/sysdep/linux/krt-scan.Y index fcdcfe66..d02df113 100644 --- a/sysdep/linux/krt-scan.Y +++ b/sysdep/linux/krt-scan.Y @@ -12,7 +12,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(LEARN, SCAN, TIME) +CF_KEYWORDS(LEARN, ROUTE, SCAN, TIME) CF_GRAMMAR @@ -22,9 +22,9 @@ krt_scan_item: LEARN bool { ((struct krt_proto *) this_proto)->scanopt.learn = $2; } - | SCAN TIME expr { + | ROUTE SCAN TIME expr { /* Scan time of 0 means scan on startup only */ - ((struct krt_proto *) this_proto)->scanopt.recurrence = $3; + ((struct krt_proto *) this_proto)->scanopt.scan_time = $4; } ; diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c index 7dd64159..9801f8a3 100644 --- a/sysdep/linux/krt-scan.c +++ b/sysdep/linux/krt-scan.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,22 @@ static int krt_scan_fd = -1; /* FIXME: Filtering */ +struct iface * +krt_temp_iface(struct krt_proto *x, char *name) +{ + SCANOPT; + struct iface *i; + + WALK_LIST(i, p->temp_ifs) + if (!strcmp(i->name, name)) + return i; + i = mb_alloc(x->p.pool, sizeof(struct iface)); + bzero(i, sizeof(*i)); + strcpy(i->name, name); + add_tail(&p->temp_ifs, &i->n); + return i; +} + static int krt_uptodate(rte *k, rte *e) { @@ -35,10 +52,15 @@ krt_uptodate(rte *k, rte *e) if (ka->dest != ea->dest) return 0; - if (ka->dest == RTD_ROUTER && !ipa_equal(ka->gw, ea->gw)) - return 0; - /* FIXME: Device routes */ - return 1; + switch (ka->dest) + { + case RTD_ROUTER: + return ipa_equal(ka->gw, ea->gw); + case RTD_DEVICE: + return !strcmp(ka->iface->name, ea->iface->name); + default: + return 1; + } } static void @@ -76,7 +98,10 @@ krt_parse_entry(byte *ent, struct krt_proto *p) DBG("Got %I/%d via %I flags %x\n", dest, masklen, gw, flags); if (!(flags & RTF_UP)) - return; + { + DBG("Down.\n"); + return; + } if (flags & RTF_HOST) masklen = 32; if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) /* Redirect route */ @@ -86,6 +111,13 @@ krt_parse_entry(byte *ent, struct krt_proto *p) } net = net_get(&master_table, 0, dest, masklen); + if (net->n.flags) + { + /* Route to this destination was already seen. Strange, but it happens... */ + DBG("Already seen.\n"); + return; + } + a.proto = &p->p; a.source = RTS_INHERIT; a.scope = SCOPE_UNIVERSE; @@ -102,7 +134,7 @@ krt_parse_entry(byte *ent, struct krt_proto *p) a.iface = ng->iface; else /* FIXME: Remove this warning? */ - log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d\n", gw, net->n.prefix, net->n.pxlen); + log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", gw, net->n.prefix, net->n.pxlen); a.dest = RTD_ROUTER; a.gw = gw; } @@ -111,10 +143,15 @@ krt_parse_entry(byte *ent, struct krt_proto *p) a.dest = RTD_UNREACHABLE; a.gw = IPA_NONE; } + else if (isalpha(iface[0])) + { + a.dest = RTD_DEVICE; + a.gw = IPA_NONE; + a.iface = krt_temp_iface(p, iface); + } else { - /* FIXME: Should support interface routes? */ - /* FIXME: What about systems not generating their own if routes? (see CONFIG_AUTO_ROUTES) */ + log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen); return; } @@ -135,13 +172,14 @@ krt_parse_entry(byte *ent, struct krt_proto *p) else verdict = KRF_DELETE; - DBG("krt_parse_entry: verdict %d\n", verdict); + DBG("krt_parse_entry: verdict=%s\n", ((char *[]) { "CREATE", "SEEN", "UPDATE", "DELETE", "LEARN" }) [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); + a.source = RTS_DUMMY; + e->attrs = rta_lookup(&a); e->next = net->routes; net->routes = e; } @@ -155,7 +193,7 @@ krt_scan_proc(struct krt_proto *p) byte buf[32768]; int l, seen_hdr; - DBG("Scanning kernel table...\n"); + DBG("Scanning kernel routing table...\n"); if (krt_scan_fd < 0) { krt_scan_fd = open("/proc/net/route", O_RDONLY); @@ -263,13 +301,18 @@ krt_prune(struct krt_proto *p) FIB_WALK_END; } -static void -krt_scan_fire(timer *t) +void +krt_scan_ifaces_done(struct krt_proto *x) { - struct krt_proto *p = t->data; + SCANOPT; - if (krt_scan_proc(p)) - krt_prune(p); + p->accum_time += x->ifopt.scan_time; + if (p->scan_time && p->accum_time >= p->scan_time) + { + p->accum_time %= p->scan_time; + if (krt_scan_proc(x)) + krt_prune(x); + } } void @@ -277,30 +320,21 @@ krt_scan_preconfig(struct krt_proto *x) { SCANOPT; - p->recurrence = 60; + p->scan_time = 1; p->learn = 0; + init_list(&p->temp_ifs); } void krt_scan_start(struct krt_proto *x) { SCANOPT; - timer *t = tm_new(x->p.pool); - p->timer = t; - t->hook = krt_scan_fire; - t->data = x; - t->recurrent = p->recurrence; - krt_scan_fire(t); - if (t->recurrent) - tm_start(t, t->recurrent); + /* Force krt scan after first interface scan */ + p->accum_time = p->scan_time - x->ifopt.scan_time; } void krt_scan_shutdown(struct krt_proto *x) { - SCANOPT; - - tm_stop(p->timer); - /* FIXME: Remove all krt's? */ } diff --git a/sysdep/linux/krt-scan.h b/sysdep/linux/krt-scan.h index 18073e2b..fe41d46c 100644 --- a/sysdep/linux/krt-scan.h +++ b/sysdep/linux/krt-scan.h @@ -10,9 +10,10 @@ #define _BIRD_KRT_SCAN_H_ struct krt_scan_params { - int recurrence; /* How often should we scan krt, 0=only on startup */ int learn; /* Should we learn routes from the kernel? */ - struct timer *timer; + list temp_ifs; /* Temporary interfaces */ + int scan_time; /* How often should we scan krt, 0=only on startup */ + int accum_time; /* Accumulated scanning time */ }; #endif diff --git a/sysdep/unix/Modules b/sysdep/unix/Modules index 441c3f07..f6db6d35 100644 --- a/sysdep/unix/Modules +++ b/sysdep/unix/Modules @@ -9,3 +9,5 @@ krt.Y krt.h krt-set.c krt-set.h +krt-iface.h +krt-iface.Y diff --git a/sysdep/unix/krt-iface.Y b/sysdep/unix/krt-iface.Y new file mode 100644 index 00000000..becb70cf --- /dev/null +++ b/sysdep/unix/krt-iface.Y @@ -0,0 +1,30 @@ +/* + * BIRD -- UNIX Interface Syncer Configuration + * + * (c) 1998 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +CF_HDR + +#include "lib/krt-scan.h" + +CF_DECLS + +CF_KEYWORDS(LEARN, ROUTE, SCAN, TIME) + +CF_GRAMMAR + +CF_ADDTO(kern_proto, kern_proto krt_if_item ';') + +krt_if_item: + SCAN TIME expr { + /* Scan time of 0 means scan on startup only */ + ((struct krt_proto *) this_proto)->ifopt.scan_time = $3; + } + ; + +CF_CODE + +CF_END diff --git a/sysdep/unix/krt-iface.h b/sysdep/unix/krt-iface.h new file mode 100644 index 00000000..95cfff8c --- /dev/null +++ b/sysdep/unix/krt-iface.h @@ -0,0 +1,16 @@ +/* + * BIRD -- Unix Kernel Interface Syncer -- Setting Parameters + * + * (c) 1998 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_IFACE_H_ +#define _BIRD_KRT_IFACE_H_ + +struct krt_if_params { + int scan_time; +}; + +#endif diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c index 8bc2df11..33d5bca0 100644 --- a/sysdep/unix/krt-set.c +++ b/sysdep/unix/krt-set.c @@ -29,9 +29,7 @@ krt_capable(rte *e) 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 @@ -39,38 +37,25 @@ krt_capable(rte *e) !a->tos; } -void -krt_remove_route(rte *old) +static inline int +krt_capable_op(rte *e) { - net *net = old->net; - struct rtentry re; + rta *a = e->attrs; - if (!krt_capable(old) || old->attrs->source == RTS_INHERIT) - { - 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); +#ifdef CONFIG_AUTO_ROUTES + if (a->dest == RTD_ROUTER && a->source == RTS_DEVICE) + return 0; +#endif + return krt_capable(e); } -void -krt_add_route(rte *new) +static void +krt_ioctl(int ioc, rte *e, char *name) { - net *net = new->net; + net *net = e->net; struct rtentry re; - rta *a = new->attrs; + rta *a = e->attrs; - if (!krt_capable(new) || new->attrs->source == RTS_INHERIT) - { - 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); @@ -83,11 +68,9 @@ krt_add_route(rte *new) 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; @@ -97,8 +80,36 @@ krt_add_route(rte *new) 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); + if (ioctl(if_scan_sock, ioc, &re) < 0) + log(L_ERR "%s(%I/%d): %m", name, net->n.prefix, net->n.pxlen); +} + +void +krt_remove_route(rte *old) +{ + net *net = old->net; + + if (!krt_capable_op(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); + krt_ioctl(SIOCDELRT, old, "SIOCDELRT"); +} + +void +krt_add_route(rte *new) +{ + net *net = new->net; + + if (!krt_capable_op(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); + krt_ioctl(SIOCADDRT, new, "SIOCADDRT"); } void @@ -119,4 +130,3 @@ krt_set_preconfig(struct krt_proto *x) die("krt set: missing socket"); x->p.rt_notify = krt_set_notify; } - diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index aae5bd57..4ea88d50 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -11,6 +11,7 @@ #include "lib/krt-scan.h" #include "lib/krt-set.h" +#include "lib/krt-iface.h" /* Flags stored in net->n.flags */ @@ -28,6 +29,7 @@ struct krt_proto { struct proto p; struct krt_set_params setopt; struct krt_scan_params scanopt; + struct krt_if_params ifopt; }; extern struct proto *cf_krt_proto; @@ -37,9 +39,16 @@ extern struct proto *cf_krt_proto; void krt_scan_preconfig(struct krt_proto *); void krt_scan_start(struct krt_proto *); void krt_scan_shutdown(struct krt_proto *); +void krt_scan_ifaces_done(struct krt_proto *); /* krt-set.c */ void krt_set_preconfig(struct krt_proto *); +/* sync-if.c */ + +void krt_if_preconfig(struct krt_proto *); +void krt_if_start(struct krt_proto *); +void krt_if_shutdown(struct krt_proto *); + #endif diff --git a/sysdep/unix/sync-if.c b/sysdep/unix/sync-if.c index 76426e73..70a2c0ce 100644 --- a/sysdep/unix/sync-if.c +++ b/sysdep/unix/sync-if.c @@ -17,12 +17,14 @@ #include "nest/bird.h" #include "nest/iface.h" +#include "nest/route.h" +#include "nest/protocol.h" #include "lib/timer.h" +#include "lib/krt.h" #include "unix.h" int if_scan_sock; -int if_scan_period = 60; static timer *if_scan_timer; @@ -131,8 +133,9 @@ scan_if(timer *t) struct ifconf ic; static int last_ifbuf_size = 4*sizeof(struct ifreq); int res; + struct krt_proto *p = t->data; - DBG("Scanning interfaces...\n"); + DBG("It's interface scan time...\n"); for(;;) { if (last_ifbuf_size) @@ -165,6 +168,32 @@ scan_if(timer *t) DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size); #endif } + krt_scan_ifaces_done(p); +} + +void +krt_if_start(struct krt_proto *p) +{ + if_scan_timer = tm_new(&root_pool); + if_scan_timer->hook = scan_if; + if_scan_timer->data = p; + if_scan_timer->recurrent = p->ifopt.scan_time; + scan_if(if_scan_timer); + tm_start(if_scan_timer, p->ifopt.scan_time); +} + +void +krt_if_preconfig(struct krt_proto *p) +{ + p->ifopt.scan_time = 60; +} + +void +krt_if_shutdown(struct krt_proto *p) +{ + tm_stop(if_scan_timer); + rfree(if_scan_timer); + /* FIXME: What should we do with interfaces? */ } void @@ -174,9 +203,4 @@ scan_if_init(void) DBG("Using socket %d for interface and route scanning\n", if_scan_sock); if (if_scan_sock < 0) die("Cannot create scanning socket: %m"); - scan_if(NULL); - if_scan_timer = tm_new(&root_pool); - if_scan_timer->hook = scan_if; - if_scan_timer->recurrent = if_scan_period; - tm_start(if_scan_timer, if_scan_period); } diff --git a/sysdep/unix/sync-rt.c b/sysdep/unix/sync-rt.c index 169494e2..dc79118d 100644 --- a/sysdep/unix/sync-rt.c +++ b/sysdep/unix/sync-rt.c @@ -30,6 +30,7 @@ krt_start(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; krt_scan_start(p); + krt_if_start(p); } void @@ -37,6 +38,7 @@ krt_shutdown(struct proto *P, int time) { struct krt_proto *p = (struct krt_proto *) P; krt_scan_shutdown(p); + krt_if_shutdown(p); } void @@ -50,6 +52,7 @@ krt_preconfig(struct protocol *x) p->p.shutdown = krt_shutdown; krt_scan_preconfig(p); krt_set_preconfig(p); + krt_if_preconfig(p); } struct protocol proto_unix_kernel = {