diff --git a/TODO b/TODO index 8045604d..1544345f 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,7 @@ Core - static: check validity of route destination? - device: configuration of interface patterns +- device: what to do if we need to shut down this protocol? - adding of route: check whether all bits not covered by masklen are zero diff --git a/doc/bird.conf.example b/doc/bird.conf.example index 15fd8449..9f5907d4 100644 --- a/doc/bird.conf.example +++ b/doc/bird.conf.example @@ -24,6 +24,7 @@ protocol kernel { persist # Don't remove routes on bird shutdown scan time 10 # Scan kernel tables every 10 seconds route scan time 20 # But routes only every 20 seconds +# async off # Netlink: Disable asynchronous events } protocol static { diff --git a/sysdep/cf/linux-20.h b/sysdep/cf/linux-20.h index 807ddcd6..e514218f 100644 --- a/sysdep/cf/linux-20.h +++ b/sysdep/cf/linux-20.h @@ -12,6 +12,10 @@ #undef CONFIG_AUTO_ROUTES #define CONFIG_ALL_MULTICAST +#define CONFIG_UNIX_IFACE +#define CONFIG_UNIX_SET +#define CONFIG_LINUX_SCAN + /* Link: sysdep/linux Link: sysdep/unix diff --git a/sysdep/linux/Modules b/sysdep/linux/Modules index 03d032d9..4a99916a 100644 --- a/sysdep/linux/Modules +++ b/sysdep/linux/Modules @@ -1,5 +1,4 @@ -#ifndef CONFIG_NETLINK +#ifdef CONFIG_LINUX_SCAN krt-scan.c krt-scan.h -krt-scan.Y #endif diff --git a/sysdep/linux/krt-scan.Y b/sysdep/linux/krt-scan.Y deleted file mode 100644 index 58339895..00000000 --- a/sysdep/linux/krt-scan.Y +++ /dev/null @@ -1,33 +0,0 @@ -/* - * BIRD -- Linux Kernel 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_scan_item ';') - -krt_scan_item: - LEARN bool { - ((struct krt_config *) this_proto)->scanopt.learn = $2; - } - | ROUTE SCAN TIME expr { - /* Scan time of 0 means scan on startup only */ - ((struct krt_config *) this_proto)->scanopt.scan_time = $4; - } - ; - -CF_CODE - -CF_END diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c index 1428a7ac..3e5a2401 100644 --- a/sysdep/linux/krt-scan.c +++ b/sysdep/linux/krt-scan.c @@ -23,60 +23,34 @@ #include "lib/unix.h" #include "lib/krt.h" -#define SCANOPT struct krt_scan_params *p = &(((struct krt_config *)(x->p.cf))->scanopt) -#define SCANSTAT struct krt_scan_status *s = &x->scanstat - static int krt_scan_fd = -1; -/* FIXME: Filtering */ - struct iface * -krt_temp_iface(struct krt_proto *x, char *name) +krt_temp_iface(struct krt_proto *p, char *name) { - SCANOPT; - SCANSTAT; struct iface *i; - WALK_LIST(i, s->temp_ifs) + WALK_LIST(i, p->scan.temp_ifs) if (!strcmp(i->name, name)) return i; - i = mb_alloc(x->p.pool, sizeof(struct iface)); + i = mb_alloc(p->p.pool, sizeof(struct iface)); bzero(i, sizeof(*i)); strcpy(i->name, name); - add_tail(&s->temp_ifs, &i->n); + add_tail(&p->scan.temp_ifs, &i->n); return i; } -static int -krt_uptodate(rte *k, rte *e) -{ - rta *ka = k->attrs, *ea = e->attrs; - - if (ka->dest != ea->dest) - return 0; - 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 -krt_parse_entry(byte *ent, struct krt_proto *x) +krt_parse_entry(byte *ent, struct krt_proto *p) { - SCANOPT; u32 dest0, gw0, mask0; ip_addr dest, gw, mask; - unsigned int flags, verdict; + unsigned int flags; int masklen; net *net; byte *iface = ent; rta a; - rte *e, *old; + rte *e; if (sscanf(ent, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4) { @@ -114,14 +88,8 @@ krt_parse_entry(byte *ent, struct krt_proto *x) } 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 = &x->p; + a.proto = &p->p; a.source = RTS_INHERIT; a.scope = SCOPE_UNIVERSE; a.cast = RTC_UNICAST; @@ -132,7 +100,7 @@ krt_parse_entry(byte *ent, struct krt_proto *x) if (flags & RTF_GATEWAY) { - neighbor *ng = neigh_find(&x->p, &gw, 0); + neighbor *ng = neigh_find(&p->p, &gw, 0); if (ng) a.iface = ng->iface; else @@ -150,7 +118,7 @@ krt_parse_entry(byte *ent, struct krt_proto *x) { a.dest = RTD_DEVICE; a.gw = IPA_NONE; - a.iface = krt_temp_iface(x, iface); + a.iface = krt_temp_iface(p, iface); } else { @@ -160,43 +128,15 @@ krt_parse_entry(byte *ent, struct krt_proto *x) e = rte_get_temp(&a); e->net = net; - old = net->routes; - if (old && !krt_capable(old)) - old = NULL; - if (old) - { - if (krt_uptodate(e, net->routes)) - verdict = KRF_SEEN; - else - verdict = KRF_UPDATE; - } - else if (p->learn && !net->routes) - verdict = KRF_LEARN; - else - verdict = KRF_DELETE; - - 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 */ - a.source = RTS_DUMMY; - e->attrs = rta_lookup(&a); - e->next = net->routes; - net->routes = e; - } - else - rte_free(e); + krt_got_route(p, e); } -static int -krt_scan_proc(struct krt_proto *p) +void +krt_scan_fire(struct krt_proto *p) { byte buf[32768]; int l, seen_hdr; - DBG("Scanning kernel routing table...\n"); if (krt_scan_fd < 0) { krt_scan_fd = open("/proc/net/route", O_RDONLY); @@ -206,7 +146,7 @@ krt_scan_proc(struct krt_proto *p) else if (lseek(krt_scan_fd, 0, SEEK_SET) < 0) { log(L_ERR "krt seek: %m"); - return 0; + return; } seen_hdr = 0; while ((l = read(krt_scan_fd, buf, sizeof(buf))) > 0) @@ -215,7 +155,7 @@ krt_scan_proc(struct krt_proto *p) if (l & 127) { log(L_ERR "krt read: misaligned entry: l=%d", l); - return 0; + return; } while (l >= 128) { @@ -228,114 +168,20 @@ krt_scan_proc(struct krt_proto *p) if (l < 0) { log(L_ERR "krt read: %m"); - return 0; + return; } DBG("KRT scan done, seen %d lines\n", seen_hdr); - return 1; -} - -static void -krt_prune(struct krt_proto *p) -{ - 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; - int verdict = f->flags; - rte *new, *old; - - if (verdict != KRF_CREATE && verdict != KRF_SEEN) - { - old = n->routes; - n->routes = old->next; - } - else - old = NULL; - new = n->routes; - - switch (verdict) - { - case KRF_CREATE: - if (new) - { - if (new->attrs->source == RTS_INHERIT) - { - DBG("krt_prune: removing inherited %I/%d\n", n->n.prefix, n->n.pxlen); - rte_update(n, &p->p, NULL); - } - else - { - DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen); - krt_add_route(new); - } - } - break; - case KRF_SEEN: - /* Nothing happens */ - break; - case KRF_UPDATE: - DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen); - krt_remove_route(old); - krt_add_route(new); - break; - case KRF_DELETE: - DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen); - krt_remove_route(old); - break; - case KRF_LEARN: - DBG("krt_prune: learning %I/%d\n", n->n.prefix, n->n.pxlen); - rte_update(n, &p->p, new); - break; - default: - bug("krt_prune: invalid route status"); - } - - if (old) - rte_free(old); - f->flags = 0; - } - FIB_WALK_END; -} - -void -krt_scan_ifaces_done(struct krt_proto *x) -{ - SCANOPT; - SCANSTAT; - - s->accum_time += ((struct krt_config *) x->p.cf)->ifopt.scan_time; - if (p->scan_time && s->accum_time >= p->scan_time) - { - s->accum_time %= p->scan_time; - if (krt_scan_proc(x)) - krt_prune(x); - } } void krt_scan_preconfig(struct krt_config *c) { - c->scanopt.scan_time = 60; - c->scanopt.learn = 0; } void krt_scan_start(struct krt_proto *x) { - SCANOPT; - SCANSTAT; - - /* Force krt scan after first interface scan */ - s->accum_time = p->scan_time - ((struct krt_config *) x->p.cf)->ifopt.scan_time; - - init_list(&s->temp_ifs); + init_list(&x->scan.temp_ifs); } void diff --git a/sysdep/linux/krt-scan.h b/sysdep/linux/krt-scan.h index ef1f7290..c5bf5884 100644 --- a/sysdep/linux/krt-scan.h +++ b/sysdep/linux/krt-scan.h @@ -1,5 +1,5 @@ /* - * BIRD -- Linux Kernel Route Syncer -- Scanning Parameters + * BIRD -- Linux Kernel Route Syncer -- Scanning * * (c) 1998--1999 Martin Mares * @@ -10,13 +10,10 @@ #define _BIRD_KRT_SCAN_H_ struct krt_scan_params { - int learn; /* Should we learn routes from the kernel? */ - int scan_time; /* How often should we scan krt, 0=only on startup */ }; struct krt_scan_status { list temp_ifs; /* Temporary interfaces */ - int accum_time; /* Accumulated scanning time */ }; #endif diff --git a/sysdep/linux/netlink/Modules b/sysdep/linux/netlink/Modules index 80338101..c26f7f72 100644 --- a/sysdep/linux/netlink/Modules +++ b/sysdep/linux/netlink/Modules @@ -1,3 +1,5 @@ -krt.c -krt.h -krt.Y +krt-iface.h +krt-set.h +krt-scan.h +netlink.c +netlink.Y diff --git a/sysdep/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h new file mode 100644 index 00000000..5dfb934f --- /dev/null +++ b/sysdep/linux/netlink/krt-iface.h @@ -0,0 +1,26 @@ +/* + * BIRD -- Unix Kernel Netlink Interface Syncer -- Dummy Include File + * + * (c) 1998--1999 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_ + +/* + * We don't have split iface/scan/set parts. See krt-scan.h. + */ + +struct krt_if_params { +}; + +struct krt_if_status { +}; + +static inline void krt_if_preconfig(struct krt_config *c) { }; +static inline void krt_if_start(struct krt_proto *p) { }; +static inline void krt_if_shutdown(struct krt_proto *p) { }; + +#endif diff --git a/sysdep/linux/netlink/krt-scan.h b/sysdep/linux/netlink/krt-scan.h new file mode 100644 index 00000000..cd118de4 --- /dev/null +++ b/sysdep/linux/netlink/krt-scan.h @@ -0,0 +1,26 @@ +/* + * BIRD -- Linux Kernel Netlink Route Syncer -- Scanning + * + * (c) 1998--1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_SCAN_H_ +#define _BIRD_KRT_SCAN_H_ + +/* + * We don't have split iface/scan/set for Netlink. All options + * and run-time parameters are declared here instead of splitting + * to krt-set.h, krt-iface.h and this file. + */ + +struct krt_scan_params { + int async; /* Allow asynchronous events */ +}; + +struct krt_scan_status { + list temp_ifs; /* Temporary interfaces */ +}; + +#endif diff --git a/sysdep/linux/netlink/krt-set.h b/sysdep/linux/netlink/krt-set.h new file mode 100644 index 00000000..32fdad0a --- /dev/null +++ b/sysdep/linux/netlink/krt-set.h @@ -0,0 +1,26 @@ +/* + * BIRD -- Unix Kernel Netlink Route Syncer -- Dummy Include File + * + * (c) 1998--1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_SET_H_ +#define _BIRD_KRT_SET_H_ + +/* + * We don't have split iface/scan/set parts. See krt-scan.h. + */ + +struct krt_set_params { +}; + +struct krt_set_status { +}; + +static inline void krt_set_preconfig(struct krt_config *c) { }; +static inline void krt_set_start(struct krt_proto *p) { }; +static inline void krt_set_shutdown(struct krt_proto *p) { }; + +#endif diff --git a/sysdep/linux/netlink/krt.Y b/sysdep/linux/netlink/krt.Y deleted file mode 100644 index c5726408..00000000 --- a/sysdep/linux/netlink/krt.Y +++ /dev/null @@ -1,46 +0,0 @@ -/* - * BIRD -- Netlink Interface Configuration - * - * (c) 1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -CF_HDR - -#include "lib/krt.h" - -#define KRT_PROTO ((struct krt_config *) this_proto) - -CF_DECLS - -CF_KEYWORDS(KERNEL, PERSIST, ROUTE, SCAN, TIME, LEARN) - -CF_GRAMMAR - -/* Kernel protocol */ - -CF_ADDTO(proto, kern_proto '}') - -kern_proto_start: proto_start KERNEL { - if (!(this_proto = cf_krt)) cf_error("Kernel protocol already defined"); - cf_krt = NULL; - } - ; - -kern_proto: - kern_proto_start '{' - | kern_proto proto_item ';' - | kern_proto kern_item ';' - ; - -kern_item: - PERSIST bool { KRT_PROTO->persist = $2; } - | SCAN TIME expr { KRT_PROTO->scan_time = $3; } - | LEARN bool { KRT_PROTO->learn = $2; } - | ROUTE SCAN TIME expr { KRT_PROTO->route_scan_time = $4; } - ; - -CF_CODE - -CF_END diff --git a/sysdep/linux/netlink/krt.h b/sysdep/linux/netlink/krt.h deleted file mode 100644 index 8dd55cc5..00000000 --- a/sysdep/linux/netlink/krt.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * BIRD -- Linux Netlink Interface - * - * (c) 1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#ifndef _BIRD_NETLINK_KRT_H_ -#define _BIRD_NETLINK_KRT_H_ - -extern struct protocol proto_unix_kernel; - -struct krt_config { - struct proto_config c; - int persist; /* Keep routes when we exit */ - int scan_time; /* How often we re-scan interfaces */ - int route_scan_time; /* How often we re-scan routes */ - int learn; /* Learn routes from other sources */ -}; - -extern struct proto_config *cf_krt; - -struct krt_proto { - struct proto p; -}; - -void scan_if_init(void); - -#endif diff --git a/sysdep/linux/netlink/netlink.Y b/sysdep/linux/netlink/netlink.Y new file mode 100644 index 00000000..b5c45f29 --- /dev/null +++ b/sysdep/linux/netlink/netlink.Y @@ -0,0 +1,25 @@ +/* + * BIRD -- Linux Netlink Configuration + * + * (c) 1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +CF_HDR + +CF_DECLS + +CF_KEYWORDS(ASYNC) + +CF_GRAMMAR + +CF_ADDTO(kern_proto, kern_proto nl_item ';') + +nl_item: + ASYNC bool { THIS_KRT->scan.async = $2; } + ; + +CF_CODE + +CF_END diff --git a/sysdep/linux/netlink/krt.c b/sysdep/linux/netlink/netlink.c similarity index 87% rename from sysdep/linux/netlink/krt.c rename to sysdep/linux/netlink/netlink.c index c399e201..6e6fafd3 100644 --- a/sysdep/linux/netlink/krt.c +++ b/sysdep/linux/netlink/netlink.c @@ -15,8 +15,6 @@ #define LOCAL_DEBUG -#undef ASYNC_NETLINK /* Define if async notifications should be used (debug) */ - #include "nest/bird.h" #include "nest/route.h" #include "nest/protocol.h" @@ -46,13 +44,11 @@ #define MSG_TRUNC 0x20 #endif -struct proto_config *cf_krt; - /* * Synchronous Netlink interface */ -static int nl_sync_fd; /* Unix socket for synchronous netlink actions */ +static int nl_sync_fd = -1; /* Unix socket for synchronous netlink actions */ static u32 nl_sync_seq; /* Sequence number of last request sent */ static byte *nl_rx_buffer; /* Receive buffer */ @@ -61,6 +57,19 @@ static int nl_rx_size = 8192; static struct nlmsghdr *nl_last_hdr; /* Recently received packet */ static unsigned int nl_last_size; +static void +nl_open(void) +{ + if (nl_sync_fd < 0) + { + nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nl_sync_fd < 0) + die("Unable to open rtnetlink socket: %m"); + nl_sync_seq = now; + nl_rx_buffer = xmalloc(nl_rx_size); + } +} + static void nl_send(void *rq, int size) { @@ -327,8 +336,8 @@ nl_parse_addr(struct nlmsghdr *h) if_update(&f); } -static void -nl_scan_ifaces(void) +void +krt_if_scan(struct krt_proto *p) { struct nlmsghdr *h; @@ -351,6 +360,27 @@ nl_scan_ifaces(void) if_end_update(); } +/* + * Routes + */ + +int +krt_capable(rte *e) +{ + return 1; /* FIXME */ +} + +void +krt_set_notify(struct proto *p, net *n, rte *new, rte *old) +{ + /* FIXME */ +} + +void +krt_scan_fire(struct krt_proto *p) +{ +} + /* * Asynchronous Netlink interface */ @@ -364,34 +394,15 @@ nl_async_hook(sock *sk, int size) return 0; } -/* - * Protocol core - */ - static void -krt_preconfig(struct protocol *x, struct config *c) -{ - struct krt_config *z = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config)); - - cf_krt = &z->c; - z->c.preference = DEF_PREF_UKR; -} - -static struct proto * -krt_init(struct proto_config *c) -{ - struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); - - return &p->p; -} - -static void -nl_open_async(struct proto *p) +nl_open_async(struct krt_proto *p) { sock *sk; struct sockaddr_nl sa; - sk = nl_async_sk = sk_new(p->pool); + DBG("KRT: Opening async netlink socket\n"); + + sk = nl_async_sk = sk_new(p->p.pool); sk->type = SK_MAGIC; sk->rx_hook = nl_async_hook; sk->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -405,43 +416,25 @@ nl_open_async(struct proto *p) die("Unable to bind secondary rtnetlink socket: %m"); } -static int -krt_start(struct proto *p) +/* + * Interface to the UNIX krt module + */ + +void +krt_scan_preconfig(struct krt_config *x) { -#ifdef ASYNC_NETLINK - nl_open_async(p); -#endif - - /* FIXME: Filter kernel routing table etc. */ - - return PS_UP; -} - -static int -krt_shutdown(struct proto *p) -{ - /* FIXME: Remove all our routes from the kernel */ - - return PS_DOWN; + x->scan.async = 1; } void -scan_if_init(void) +krt_scan_start(struct krt_proto *p) { - nl_sync_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (nl_sync_fd < 0) - die("Unable to open rtnetlink socket: %m"); - nl_sync_seq = now; - nl_rx_buffer = xmalloc(nl_rx_size); - /* FIXME: Should we fetch our local address and compare it with addresses of all incoming messages? */ - - nl_scan_ifaces(); + nl_open(); + if (KRT_CF->scan.async) + nl_open_async(p); } -struct protocol proto_unix_kernel = { - name: "Kernel", - preconfig: krt_preconfig, - init: krt_init, - start: krt_start, - shutdown: krt_shutdown -}; +void +krt_scan_shutdown(struct krt_proto *p) +{ +} diff --git a/sysdep/unix/Modules b/sysdep/unix/Modules index e2ff0f85..bb0385d5 100644 --- a/sysdep/unix/Modules +++ b/sysdep/unix/Modules @@ -4,14 +4,16 @@ timer.h io.c unix.h -#ifndef CONFIG_NETLINK -sync-if.c -sync-rt.c -krt.Y +krt.c krt.h +krt.Y + +#ifdef CONFIG_UNIX_IFACE +krt-iface.c +krt-iface.h +#endif + +#ifdef CONFIG_UNIX_SET krt-set.c krt-set.h -krt-set.Y -krt-iface.h -krt-iface.Y #endif diff --git a/sysdep/unix/krt-iface.Y b/sysdep/unix/krt-iface.Y deleted file mode 100644 index c74eb02b..00000000 --- a/sysdep/unix/krt-iface.Y +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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_config *) this_proto)->ifopt.scan_time = $3; - } - ; - -CF_CODE - -CF_END diff --git a/sysdep/unix/sync-if.c b/sysdep/unix/krt-iface.c similarity index 84% rename from sysdep/unix/sync-if.c rename to sysdep/unix/krt-iface.c index 3dfa4f01..3b665a44 100644 --- a/sysdep/unix/sync-if.c +++ b/sysdep/unix/krt-iface.c @@ -24,9 +24,7 @@ #include "unix.h" -int if_scan_sock; - -static timer *if_scan_timer; +int if_scan_sock = -1; static void scan_ifs(struct ifreq *r, int cnt) @@ -132,15 +130,13 @@ scan_ifs(struct ifreq *r, int cnt) if_end_update(); } -static void -scan_if(timer *t) +void +krt_if_scan(struct krt_proto *p) { struct ifconf ic; static int last_ifbuf_size = 4*sizeof(struct ifreq); int res; - struct krt_proto *p = t->data; - DBG("It's interface scan time...\n"); for(;;) { if (last_ifbuf_size) @@ -173,40 +169,26 @@ 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) -{ - struct krt_config *c = (struct krt_config *) p->p.cf; - - if_scan_timer = tm_new(p->p.pool); - if_scan_timer->hook = scan_if; - if_scan_timer->data = p; - if_scan_timer->recurrent = c->ifopt.scan_time; - scan_if(if_scan_timer); - tm_start(if_scan_timer, c->ifopt.scan_time); } void krt_if_preconfig(struct krt_config *c) { - c->ifopt.scan_time = 60; +} + +void +krt_if_start(struct krt_proto *p) +{ + if (if_scan_sock < 0) + { + if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + DBG("Using socket %d for interface and route scanning\n", if_scan_sock); + if (if_scan_sock < 0) + die("Cannot create scanning socket: %m"); + } } void krt_if_shutdown(struct krt_proto *p) { - tm_stop(if_scan_timer); - /* FIXME: What should we do with interfaces? */ -} - -void -scan_if_init(void) -{ - if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - DBG("Using socket %d for interface and route scanning\n", if_scan_sock); - if (if_scan_sock < 0) - die("Cannot create scanning socket: %m"); } diff --git a/sysdep/unix/krt-iface.h b/sysdep/unix/krt-iface.h index 87c88515..b27e86dc 100644 --- a/sysdep/unix/krt-iface.h +++ b/sysdep/unix/krt-iface.h @@ -1,5 +1,5 @@ /* - * BIRD -- Unix Kernel Interface Syncer -- Setting Parameters + * BIRD -- Unix Kernel Interface Syncer * * (c) 1998--1999 Martin Mares * @@ -10,10 +10,11 @@ #define _BIRD_KRT_IFACE_H_ struct krt_if_params { - int scan_time; }; struct krt_if_status { }; +extern int if_scan_sock; + #endif diff --git a/sysdep/unix/krt-set.Y b/sysdep/unix/krt-set.Y deleted file mode 100644 index 551ee16d..00000000 --- a/sysdep/unix/krt-set.Y +++ /dev/null @@ -1,29 +0,0 @@ -/* - * BIRD -- UNIX Kernel Syncer Configuration - * - * (c) 1998--1999 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(PERSIST) - -CF_GRAMMAR - -CF_ADDTO(kern_proto, kern_proto krt_set_item ';') - -krt_set_item: - PERSIST bool { - ((struct krt_config *) this_proto)->setopt.persist = $2; - } - ; - -CF_CODE - -CF_END diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c index e77015b3..dae01f46 100644 --- a/sysdep/unix/krt-set.c +++ b/sysdep/unix/krt-set.c @@ -84,7 +84,7 @@ krt_ioctl(int ioc, rte *e, char *name) log(L_ERR "%s(%I/%d): %m", name, net->n.prefix, net->n.pxlen); } -void +static void krt_remove_route(rte *old) { net *net = old->net; @@ -98,7 +98,7 @@ krt_remove_route(rte *old) krt_ioctl(SIOCDELRT, old, "SIOCDELRT"); } -void +static void krt_add_route(rte *new) { net *net = new->net; @@ -126,7 +126,6 @@ krt_set_start(struct krt_proto *x) { if (if_scan_sock < 0) bug("krt set: missing socket"); - x->p.rt_notify = krt_set_notify; } void @@ -137,25 +136,4 @@ krt_set_preconfig(struct krt_config *c) void krt_set_shutdown(struct krt_proto *x) { - struct rtable *t = &master_table; - - if (((struct krt_config *) x->p.cf)->setopt.persist) - return; - DBG("Flushing kernel routes...\n"); - while (t && t->tos) - t = t->sibling; - if (!t) - return; - FIB_WALK(&t->fib, f) - { - net *n = (net *) f; - rte *e = n->routes; - if (e) - { - rta *a = e->attrs; - if (a->source != RTS_DEVICE && a->source != RTS_INHERIT) - krt_remove_route(e); - } - } - FIB_WALK_END; } diff --git a/sysdep/unix/krt-set.h b/sysdep/unix/krt-set.h index ec96e652..cfa5fb76 100644 --- a/sysdep/unix/krt-set.h +++ b/sysdep/unix/krt-set.h @@ -1,5 +1,5 @@ /* - * BIRD -- Unix Kernel Route Syncer -- Setting Parameters + * BIRD -- Unix Kernel Route Syncer -- Setting * * (c) 1998--1999 Martin Mares * @@ -10,15 +10,9 @@ #define _BIRD_KRT_SET_H_ struct krt_set_params { - int persist; }; struct krt_set_status { }; -void krt_remove_route(rte *old); -void krt_add_route(rte *new); -int krt_capable(rte *e); -void krt_set_notify(struct proto *x, net *net, rte *new, rte *old); - #endif diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 7711f3ba..661e5052 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -10,9 +10,11 @@ CF_HDR #include "lib/krt.h" +#define THIS_KRT ((struct krt_config *) this_proto) + CF_DECLS -CF_KEYWORDS(KERNEL) +CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, ROUTE, LEARN) CF_GRAMMAR @@ -28,6 +30,17 @@ kern_proto_start: proto_start KERNEL { CF_ADDTO(kern_proto, kern_proto_start '{') CF_ADDTO(kern_proto, kern_proto proto_item ';') +CF_ADDTO(kern_proto, kern_proto kern_item ';') + +kern_item: + PERSIST bool { THIS_KRT->persist = $2; } + | SCAN TIME expr { + /* Scan time of 0 means scan on startup only */ + THIS_KRT->scan_time = $3; + } + | ROUTE SCAN TIME expr { THIS_KRT->route_scan_time = $4; } + | LEARN bool { THIS_KRT->learn = $2; } + ; CF_CODE diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c new file mode 100644 index 00000000..d44a57d8 --- /dev/null +++ b/sysdep/unix/krt.c @@ -0,0 +1,291 @@ +/* + * BIRD -- UNIX Kernel Synchronization + * + * (c) 1998--1999 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#define LOCAL_DEBUG + +#include "nest/bird.h" +#include "nest/iface.h" +#include "nest/route.h" +#include "nest/protocol.h" +#include "lib/timer.h" + +#include "unix.h" +#include "krt.h" + +struct proto_config *cf_krt; + +/* + * Routes + */ + +static void +krt_flush_routes(struct krt_proto *p) +{ + struct rtable *t = &master_table; + + DBG("Flushing kernel routes...\n"); + while (t && t->tos) + t = t->sibling; + if (!t) + return; + FIB_WALK(&t->fib, f) + { + net *n = (net *) f; + rte *e = n->routes; + if (e) + { + rta *a = e->attrs; + if (a->source != RTS_DEVICE && a->source != RTS_INHERIT) + krt_set_notify(&p->p, e->net, e, NULL); + } + } + FIB_WALK_END; +} + +/* FIXME: Inbound/outbound route filtering? */ +/* FIXME: Synchronization of multiple routing tables? */ + +static int +krt_uptodate(rte *k, rte *e) +{ + rta *ka = k->attrs, *ea = e->attrs; + + if (ka->dest != ea->dest) + return 0; + 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; + } +} + +/* + * This gets called back when the low-level scanning code discovers a route. + * We expect that the route is a temporary rte and its attributes are uncached. + */ + +void +krt_got_route(struct krt_proto *p, rte *e) +{ + rte *old; + net *net = e->net; + int verdict; + + if (net->n.flags) + { + /* Route to this destination was already seen. Strange, but it happens... */ + DBG("Already seen.\n"); + return; + } + + old = net->routes; + if (old && !krt_capable(old)) + old = NULL; + if (old) + { + if (krt_uptodate(e, net->routes)) + verdict = KRF_SEEN; + else + verdict = KRF_UPDATE; + } + else if (KRT_CF->learn && !net->routes) + verdict = KRF_LEARN; + else + verdict = KRF_DELETE; + + 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 */ + rta *a = e->attrs; + a->source = RTS_DUMMY; + e->attrs = rta_lookup(a); + e->next = net->routes; + net->routes = e; + } + else + rte_free(e); +} + +static void +krt_prune(struct krt_proto *p) +{ + struct proto *pp = &p->p; + 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; + int verdict = f->flags; + rte *new, *old; + + if (verdict != KRF_CREATE && verdict != KRF_SEEN) + { + old = n->routes; + n->routes = old->next; + } + else + old = NULL; + new = n->routes; + + switch (verdict) + { + case KRF_CREATE: + if (new) + { + if (new->attrs->source == RTS_INHERIT) + { + DBG("krt_prune: removing inherited %I/%d\n", n->n.prefix, n->n.pxlen); + rte_update(n, pp, NULL); + } + else + { + DBG("krt_prune: reinstalling %I/%d\n", n->n.prefix, n->n.pxlen); + krt_set_notify(pp, n, new, NULL); + } + } + break; + case KRF_SEEN: + /* Nothing happens */ + break; + case KRF_UPDATE: + DBG("krt_prune: updating %I/%d\n", n->n.prefix, n->n.pxlen); + krt_set_notify(pp, n, new, old); + break; + case KRF_DELETE: + DBG("krt_prune: deleting %I/%d\n", n->n.prefix, n->n.pxlen); + krt_set_notify(pp, n, NULL, old); + break; + case KRF_LEARN: + DBG("krt_prune: learning %I/%d\n", n->n.prefix, n->n.pxlen); + rte_update(n, pp, new); + break; + default: + bug("krt_prune: invalid route status"); + } + + if (old) + rte_free(old); + f->flags = 0; + } + FIB_WALK_END; +} + +/* + * Periodic scanning + */ + +static timer *krt_scan_timer; + +static void +krt_scan(timer *t) +{ + struct krt_proto *p = t->data; + + DBG("KRT: It's scan time...\n"); + krt_if_scan(p); + + p->accum_time += KRT_CF->scan_time; + if (KRT_CF->route_scan_time && p->accum_time >= KRT_CF->route_scan_time) + { + p->accum_time %= KRT_CF->route_scan_time; + DBG("Scanning kernel routing table...\n"); + krt_scan_fire(p); + krt_prune(p); + } +} + +/* + * Protocol glue + */ + +static int +krt_start(struct proto *P) +{ + struct krt_proto *p = (struct krt_proto *) P; + + p->accum_time = 0; + + krt_if_start(p); + krt_scan_start(p); + krt_set_start(p); + + /* Start periodic interface scanning */ + krt_scan_timer = tm_new(P->pool); + krt_scan_timer->hook = krt_scan; + krt_scan_timer->data = p; + krt_scan_timer->recurrent = KRT_CF->scan_time; + krt_scan(krt_scan_timer); + tm_start(krt_scan_timer, KRT_CF->scan_time); + + return PS_UP; +} + +int +krt_shutdown(struct proto *P) +{ + struct krt_proto *p = (struct krt_proto *) P; + + if (!KRT_CF->persist) + krt_flush_routes(p); + + krt_set_shutdown(p); + krt_scan_shutdown(p); + + /* Stop periodic interface scans */ + tm_stop(krt_scan_timer); + krt_if_shutdown(p); + /* FIXME: What should we do with interfaces? */ + + return PS_DOWN; +} + +static void +krt_preconfig(struct protocol *x, struct config *c) +{ + struct krt_config *z = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config)); + + cf_krt = &z->c; + z->c.preference = DEF_PREF_UKR; + z->scan_time = z->route_scan_time = 60; + z->learn = z->persist = 0; + + krt_scan_preconfig(z); + krt_set_preconfig(z); + krt_if_preconfig(z); +} + +static struct proto * +krt_init(struct proto_config *c) +{ + struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); + + p->p.rt_notify = krt_set_notify; + return &p->p; +} + +struct protocol proto_unix_kernel = { + name: "Kernel", + priority: 90, + preconfig: krt_preconfig, + init: krt_init, + start: krt_start, + shutdown: krt_shutdown, +}; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index cebf3354..1c59799f 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -1,7 +1,7 @@ /* - * BIRD -- Unix Kernel Route Syncer + * BIRD -- UNIX Kernel Route Syncer * - * (c) 1998 Martin Mares + * (c) 1998--1999 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -9,6 +9,9 @@ #ifndef _BIRD_KRT_H_ #define _BIRD_KRT_H_ +struct krt_config; +struct krt_proto; + #include "lib/krt-scan.h" #include "lib/krt-set.h" #include "lib/krt-iface.h" @@ -21,32 +24,42 @@ #define KRF_DELETE 3 /* Should be deleted */ #define KRF_LEARN 4 /* We should learn this route */ -/* sync-rt.c */ +/* krt.c */ extern struct protocol proto_unix_kernel; struct krt_config { struct proto_config c; - struct krt_set_params setopt; - struct krt_scan_params scanopt; - struct krt_if_params ifopt; + struct krt_set_params set; + struct krt_scan_params scan; + struct krt_if_params iface; + int persist; /* Keep routes when we exit */ + int scan_time; /* How often we re-scan interfaces */ + int route_scan_time; /* How often we re-scan routes */ + int learn; /* Learn routes from other sources */ }; struct krt_proto { struct proto p; - struct krt_set_status setstat; - struct krt_scan_status scanstat; - struct krt_if_status ifstat; + struct krt_set_status set; + struct krt_scan_status scan; + struct krt_if_status iface; + int accum_time; /* Accumulated route scanning time */ }; extern struct proto_config *cf_krt; +#define KRT_CF ((struct krt_config *)p->p.cf) + +void krt_got_route(struct krt_proto *p, struct rte *e); + /* krt-scan.c */ void krt_scan_preconfig(struct krt_config *); void krt_scan_start(struct krt_proto *); void krt_scan_shutdown(struct krt_proto *); -void krt_scan_ifaces_done(struct krt_proto *); + +void krt_scan_fire(struct krt_proto *); /* krt-set.c */ @@ -54,15 +67,15 @@ void krt_set_preconfig(struct krt_config *); void krt_set_start(struct krt_proto *); void krt_set_shutdown(struct krt_proto *); -/* sync-if.c */ +int krt_capable(rte *e); +void krt_set_notify(struct proto *x, net *net, rte *new, rte *old); -extern int if_scan_sock; -extern int if_scan_period; - -void scan_if_init(void); +/* krt-iface.c */ void krt_if_preconfig(struct krt_config *); void krt_if_start(struct krt_proto *); void krt_if_shutdown(struct krt_proto *); +void krt_if_scan(struct krt_proto *); + #endif diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 71bb712a..e5e9934c 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -204,8 +204,6 @@ main(int argc, char **argv) signal_init(); - scan_if_init(); - protos_start(); ev_run_list(&global_event_list); diff --git a/sysdep/unix/sync-rt.c b/sysdep/unix/sync-rt.c deleted file mode 100644 index 99ef92a0..00000000 --- a/sysdep/unix/sync-rt.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * BIRD -- Unix Routing Table Scanning and Syncing - * - * (c) 1998--1999 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include -#include -#include -#include -#include - -#define LOCAL_DEBUG - -#include "nest/bird.h" -#include "nest/iface.h" -#include "nest/route.h" -#include "nest/protocol.h" -#include "lib/timer.h" - -#include "unix.h" -#include "krt.h" - -struct proto_config *cf_krt; - -static int -krt_start(struct proto *p) -{ - struct krt_proto *k = (struct krt_proto *) p; - - krt_scan_start(k); - krt_set_start(k); - krt_if_start(k); - return PS_UP; -} - -int -krt_shutdown(struct proto *p) -{ - struct krt_proto *k = (struct krt_proto *) p; - - krt_scan_shutdown(k); - krt_if_shutdown(k); - krt_set_shutdown(k); - return PS_DOWN; -} - -static void -krt_preconfig(struct protocol *x, struct config *c) -{ - struct krt_config *z = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config)); - - cf_krt = &z->c; - z->c.preference = DEF_PREF_UKR; - krt_scan_preconfig(z); - krt_set_preconfig(z); - krt_if_preconfig(z); -} - -static struct proto * -krt_init(struct proto_config *c) -{ - struct krt_proto *p = proto_new(c, sizeof(struct krt_proto)); - - return &p->p; -} - -struct protocol proto_unix_kernel = { - name: "Kernel", - preconfig: krt_preconfig, - init: krt_init, - start: krt_start, - shutdown: krt_shutdown, -};