diff --git a/TODO b/TODO index 1544345f..7fc453dd 100644 --- a/TODO +++ b/TODO @@ -6,6 +6,8 @@ Core - config: define ipaddr constants? - config: better default protocol names +- do we really need preconfig? + - counters (according to SNMP MIB?) - better memory allocators - default preferences of protocols: prefer BGP over OSPF/RIP external routes? diff --git a/doc/bird.conf.example b/doc/bird.conf.example index 1d8203dc..d91a792a 100644 --- a/doc/bird.conf.example +++ b/doc/bird.conf.example @@ -16,7 +16,7 @@ # debug all #} -protocol device { +protocol direct { # disabled # interface "-eth*", "*" } @@ -25,13 +25,16 @@ protocol kernel { # disabled # learn # Learn all routes from the 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 + scan time 20 # Scan kernel routing table every 20 seconds # async off # Netlink: Disable asynchronous events # input filter sink # output filter okay } +protocol device { + scan time 10 # Scan interfaces every 10 seconds +} + protocol static { # disabled # route 0.0.0.0/0 via 62.168.0.13 diff --git a/nest/config.Y b/nest/config.Y index 83001328..61a12cab 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -16,7 +16,7 @@ void rt_dev_add_iface(char *); CF_DECLS -CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DEVICE) +CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(INTERFACE, INPUT, OUTPUT, FILTER) %type idval @@ -44,7 +44,7 @@ proto_start: PROTOCOL proto_name: /* EMPTY */ { - struct symbol *s = cf_default_name(this_proto->proto->name); + struct symbol *s = cf_default_name(this_proto->proto->name, &this_proto->proto->name_counter); s->class = SYM_PROTO; s->def = this_proto; this_proto->name = s->name; @@ -71,24 +71,30 @@ proto_item: | OUTPUT FILTER filter { this_proto->out_filter = $3; } ; -/* Device protocol */ +/* Direct device route protocol */ CF_ADDTO(proto, dev_proto '}') -dev_proto_start: proto_start DEVICE { - if (!(this_proto = cf_dev_proto)) cf_error("Device protocol already defined"); - cf_dev_proto = NULL; +dev_proto_start: proto_start DIRECT { + struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config)); + struct iface_patt *k = cfg_alloc(sizeof(struct iface_patt)); + this_proto = &p->c; + p->c.preference = DEF_PREF_DIRECT; + init_list(&p->iface_list); + k->pattern = "*"; + add_tail(&p->iface_list, &k->n); } ; dev_proto: - dev_proto_start '{' + dev_proto_start proto_name '{' | dev_proto proto_item ';' | dev_proto dev_iface_list ';' ; dev_iface_list: INTERFACE TEXT { + /* FIXME: Beware of obscure semantics. */ init_list(&((struct rt_dev_config *) this_proto)->iface_list); rt_dev_add_iface($2); } diff --git a/nest/rt-dev.c b/nest/rt-dev.c index fcaabd8b..c122b967 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -18,8 +18,6 @@ #include "conf/conf.h" #include "lib/resource.h" -struct proto_config *cf_dev_proto; - static void dev_if_notify(struct proto *p, unsigned c, struct iface *new, struct iface *old) { @@ -77,22 +75,8 @@ dev_init(struct proto_config *c) return p; } -static void -dev_preconfig(struct protocol *x, struct config *c) -{ - struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config)); - struct iface_patt *k = cfg_alloc(sizeof(struct iface_patt)); - - cf_dev_proto = &p->c; - p->c.preference = DEF_PREF_DIRECT; - init_list(&p->iface_list); - k->pattern = "*"; - add_tail(&p->iface_list, &k->n); -} - struct protocol proto_device = { - name: "Device", - priority: 100, - preconfig: dev_preconfig, + name: "Direct", + priority: 90, init: dev_init, }; diff --git a/sysdep/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h index 5dfb934f..53167c86 100644 --- a/sysdep/linux/netlink/krt-iface.h +++ b/sysdep/linux/netlink/krt-iface.h @@ -19,8 +19,9 @@ 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) { }; +static inline void krt_if_preconfig(struct kif_config *c) { }; +static inline void krt_if_start(struct kif_proto *p) { }; +static inline void krt_if_shutdown(struct kif_proto *p) { }; +static inline void krt_if_io_init(void) { }; #endif diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index 93eb4ad7..57e18991 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -392,7 +392,7 @@ nl_parse_addr(struct nlmsghdr *h) } void -krt_if_scan(struct krt_proto *p) +krt_if_scan(struct kif_proto *p) { struct nlmsghdr *h; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 8427ba47..6e1952e7 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -693,6 +693,7 @@ io_init(void) init_list(&far_timers); init_list(&sock_list); init_list(&global_event_list); + krt_io_init(); now = time(NULL); } diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c index 3b665a44..63035588 100644 --- a/sysdep/unix/krt-iface.c +++ b/sysdep/unix/krt-iface.c @@ -131,7 +131,7 @@ scan_ifs(struct ifreq *r, int cnt) } void -krt_if_scan(struct krt_proto *p) +krt_if_scan(struct kif_proto *p) { struct ifconf ic; static int last_ifbuf_size = 4*sizeof(struct ifreq); @@ -172,23 +172,25 @@ krt_if_scan(struct krt_proto *p) } void -krt_if_preconfig(struct krt_config *c) +krt_if_preconfig(struct kif_config *c) { } void -krt_if_start(struct krt_proto *p) +krt_if_start(struct kif_proto *p) { +} + +void +krt_if_shutdown(struct kif_proto *p) +{ +} + +void +krt_if_io_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) - { - 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) -{ + die("Cannot create scanning socket: %m"); } diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 661e5052..083df7d6 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -1,7 +1,7 @@ /* * BIRD -- UNIX Kernel Syncer Configuration * - * (c) 1998 Martin Mares + * (c) 1998--1999 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -11,24 +11,31 @@ CF_HDR #include "lib/krt.h" #define THIS_KRT ((struct krt_config *) this_proto) +#define THIS_KIF ((struct kif_config *) this_proto) CF_DECLS -CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, ROUTE, LEARN) +CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE) CF_GRAMMAR -/* Kernel protocol */ +/* Kernel syncer 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; + if (cf_krt) + cf_error("Kernel protocol already defined"); + cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config)); + this_proto->preference = 0; + THIS_KRT->scan_time = 60; + THIS_KRT->learn = THIS_KRT->persist = 0; + krt_scan_preconfig(THIS_KRT); + krt_set_preconfig(THIS_KRT); } ; -CF_ADDTO(kern_proto, kern_proto_start '{') +CF_ADDTO(kern_proto, kern_proto_start proto_name '{') CF_ADDTO(kern_proto, kern_proto proto_item ';') CF_ADDTO(kern_proto, kern_proto kern_item ';') @@ -38,10 +45,34 @@ kern_item: /* 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; } ; +/* Kernel interface protocol */ + +CF_ADDTO(proto, kif_proto '}') + +kif_proto_start: proto_start DEVICE { + if (cf_kif) + cf_error("Kernel device protocol already defined"); + cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config)); + this_proto->preference = DEF_PREF_DIRECT; + THIS_KIF->scan_time = 60; + krt_if_preconfig(THIS_KIF); + } + ; + +CF_ADDTO(kif_proto, kif_proto_start '{') +CF_ADDTO(kif_proto, kif_proto proto_item ';') +CF_ADDTO(kif_proto, kif_proto kif_item ';') + +kif_item: + SCAN TIME expr { + /* Scan time of 0 means scan on startup only */ + THIS_KIF->scan_time = $3; + } + ; + CF_CODE CF_END diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 9ad42379..8a3db3f1 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -17,7 +17,94 @@ #include "unix.h" #include "krt.h" -struct proto_config *cf_krt; +/* + * Global resources + */ + +void +krt_io_init(void) +{ + krt_if_io_init(); +} + +/* + * Interfaces + */ + +struct proto_config *cf_kif; + +static struct kif_proto *kif_proto; +static timer *kif_scan_timer; +static bird_clock_t kif_last_shot; + +static void +kif_scan(timer *t) +{ + struct kif_proto *p = t->data; + + DBG("KIF: It's interface scan time...\n"); + kif_last_shot = now; + krt_if_scan(p); +} + +static void +kif_force_scan(void) +{ + if (kif_proto && kif_last_shot + 2 < now) + { + kif_scan(kif_scan_timer); + tm_start(kif_scan_timer, ((struct kif_config *) kif_proto->p.cf)->scan_time); + } +} + +static struct proto * +kif_init(struct proto_config *c) +{ + struct kif_proto *p = proto_new(c, sizeof(struct kif_proto)); + return &p->p; +} + +static int +kif_start(struct proto *P) +{ + struct kif_proto *p = (struct kif_proto *) P; + + kif_proto = p; + krt_if_start(p); + + /* Start periodic interface scanning */ + kif_scan_timer = tm_new(P->pool); + kif_scan_timer->hook = kif_scan; + kif_scan_timer->data = p; + kif_scan_timer->recurrent = KIF_CF->scan_time; + kif_scan(kif_scan_timer); + tm_start(kif_scan_timer, KIF_CF->scan_time); + + return PS_UP; +} + +static int +kif_shutdown(struct proto *P) +{ + struct kif_proto *p = (struct kif_proto *) P; + + tm_stop(kif_scan_timer); + krt_if_shutdown(p); + kif_proto = NULL; + + if_start_update(); /* Remove all interfaces */ + if_end_update(); + + return PS_DOWN; +} + +struct protocol proto_unix_iface = { + name: "Device", + priority: 100, + init: kif_init, + start: kif_start, + shutdown: kif_shutdown, +}; /* * Routes @@ -210,7 +297,7 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new) * FIXME: This is limited to one inherited route per destination as we * use single protocol for all inherited routes. Probably leave it * as-is (and document it :)), because the correct solution is to - * multiple kernel tables anyway. + * use multiple kernel tables anyway. */ DBG("Learning\n"); rte_update(net, &p->p, e); @@ -234,35 +321,27 @@ 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); - } + kif_force_scan(); + DBG("KRT: It's route scan time...\n"); + krt_scan_fire(p); + krt_prune(p); } /* * Protocol glue */ +struct proto_config *cf_krt; + static int krt_start(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; - p->accum_time = KRT_CF->route_scan_time - KRT_CF->scan_time; - - krt_if_start(p); krt_scan_start(p); krt_set_start(p); - /* Start periodic interface scanning */ + /* Start periodic routing table scanning */ krt_scan_timer = tm_new(P->pool); krt_scan_timer->hook = krt_scan; krt_scan_timer->data = p; @@ -278,35 +357,17 @@ krt_shutdown(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; + tm_stop(krt_scan_timer); + 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) { @@ -318,8 +379,7 @@ krt_init(struct proto_config *c) struct protocol proto_unix_kernel = { name: "Kernel", - priority: 90, - preconfig: krt_preconfig, + priority: 80, init: krt_init, start: krt_start, shutdown: krt_shutdown, diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 02814c68..bde509c1 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -11,6 +11,8 @@ struct krt_config; struct krt_proto; +struct kif_config; +struct kif_proto; #include "lib/krt-scan.h" #include "lib/krt-set.h" @@ -34,8 +36,7 @@ struct krt_config { 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 scan_time; /* How often we re-scan routes */ int learn; /* Learn routes from other sources */ }; @@ -44,7 +45,6 @@ struct krt_proto { 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; @@ -60,6 +60,23 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); #define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */ #define KRT_SRC_ALIEN 2 /* Route installed by someone else */ +extern struct protocol proto_unix_iface; + +struct kif_config { + struct proto_config c; + struct krt_if_params iface; + int scan_time; /* How often we re-scan interfaces */ +}; + +struct kif_proto { + struct proto p; + struct krt_if_status iface; +}; + +extern struct proto_config *cf_kif; + +#define KIF_CF ((struct kif_config *)p->p.cf) + /* krt-scan.c */ void krt_scan_preconfig(struct krt_config *); @@ -79,10 +96,11 @@ void krt_set_notify(struct proto *x, net *net, rte *new, rte *old); /* 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_preconfig(struct kif_config *); +void krt_if_start(struct kif_proto *); +void krt_if_shutdown(struct kif_proto *); -void krt_if_scan(struct krt_proto *); +void krt_if_scan(struct kif_proto *); +void krt_if_io_init(void); #endif diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 45940fb9..5f260caa 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -205,6 +205,7 @@ main(int argc, char **argv) protos_build(); add_tail(&protocol_list, &proto_unix_kernel.n); + add_tail(&protocol_list, &proto_unix_iface.n); read_config(); diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 7b338714..2d260744 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -26,4 +26,8 @@ void io_loop(void); void fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port); void get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port); +/* krt.c bits */ + +void krt_io_init(void); + #endif