diff --git a/sysdep/bsd/Modules b/sysdep/bsd/Modules index 3729587..96455db 100644 --- a/sysdep/bsd/Modules +++ b/sysdep/bsd/Modules @@ -1,3 +1,4 @@ krt-sock.c +krt-sock.Y krt-sys.h sysio.h diff --git a/sysdep/bsd/krt-sock.Y b/sysdep/bsd/krt-sock.Y new file mode 100644 index 0000000..0218f18 --- /dev/null +++ b/sysdep/bsd/krt-sock.Y @@ -0,0 +1,32 @@ +/* + * BIRD -- BSD Kernel Syncer Configuration + * + * (c) 1999--2000 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +CF_HDR + +CF_DECLS + +CF_KEYWORDS(KERNEL, TABLE) + +CF_GRAMMAR + +CF_ADDTO(kern_proto, kern_proto kern_sys_item ';') + +kern_sys_item: + KERNEL TABLE expr { + if ($3 && (krt_max_tables == 1)) + cf_error("Multiple kernel routing tables not supported"); + if ($3 < 0 || $3 >= krt_max_tables) + cf_error("Kernel table id must be in range 0-%d", krt_max_tables - 1); + + THIS_KRT->sys.table_id = $3; + } + ; + +CF_CODE + +CF_END diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index e970d6b..08dfccc 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -1,5 +1,5 @@ /* - * BIRD -- Unix Routing Table Syncing + * BIRD -- BSD Routing Table Syncing * * (c) 2004 Ondrej Filip * @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -34,18 +35,112 @@ #include "lib/socket.h" -#ifndef RTAX_MAX -#define RTAX_MAX 8 +/* + * There are significant differences in multiple tables support between BSD variants. + * + * OpenBSD has table_id field for routes in route socket protocol, therefore all + * tables could be managed by one kernel socket. FreeBSD lacks such field, + * therefore multiple sockets (locked to specific table using SO_SETFIB socket + * option) must be used. + * + * Both FreeBSD and OpenBSD uses separate scans for each table. In OpenBSD, + * table_id is specified explicitly as sysctl scan argument, while in FreeBSD it + * is handled implicitly by changing default table using setfib() syscall. + * + * KRT_SHARED_SOCKET - use shared kernel socked instead of one for each krt_proto + * KRT_USE_SETFIB_SCAN - use setfib() for sysctl() route scan + * KRT_USE_SETFIB_SOCK - use SO_SETFIB socket option for kernel sockets + * KRT_USE_SYSCTL_7 - use 7-th arg of sysctl() as table id for route scans + * KRT_USE_SYSCTL_NET_FIBS - use net.fibs sysctl() for dynamic max number of fibs + */ + +#ifdef __FreeBSD__ +#define KRT_MAX_TABLES 256 +#define KRT_USE_SETFIB_SCAN +#define KRT_USE_SETFIB_SOCK +#define KRT_USE_SYSCTL_NET_FIBS #endif -struct ks_msg +#ifdef __OpenBSD__ +#define KRT_MAX_TABLES (RT_TABLEID_MAX+1) +#define KRT_SHARED_SOCKET +#define KRT_USE_SYSCTL_7 +#endif + +#ifndef KRT_MAX_TABLES +#define KRT_MAX_TABLES 1 +#endif + + + +/* Dynamic max number of tables */ + +int krt_max_tables; + +#ifdef KRT_USE_SYSCTL_NET_FIBS + +static int +krt_get_max_tables(void) { - struct rt_msghdr rtm; - struct sockaddr_storage buf[RTAX_MAX]; -}; + int fibs; + size_t fibs_len = sizeof(fibs); + + if (sysctlbyname("net.fibs", &fibs, &fibs_len, NULL, 0) < 0) + { + log(L_WARN "KRT: unable to get max number of fib tables: %m"); + return 1; + } + + return MIN(fibs, KRT_MAX_TABLES); +} + +#else + +static int +krt_get_max_tables(void) +{ + return KRT_MAX_TABLES; +} + +#endif /* KRT_USE_SYSCTL_NET_FIBS */ + + +/* setfib() syscall for FreeBSD scans */ + +#ifdef KRT_USE_SETFIB_SCAN + +/* +static int krt_default_fib; + +static int +krt_get_active_fib(void) +{ + int fib; + size_t fib_len = sizeof(fib); + + if (sysctlbyname("net.my_fibnum", &fib, &fib_len, NULL, 0) < 0) + { + log(L_WARN "KRT: unable to get active fib number: %m"); + return 0; + } + + return fib; +} +*/ + +extern int setfib(int fib); +#endif /* KRT_USE_SETFIB_SCAN */ -static int rt_sock = 0; + +/* table_id -> krt_proto map */ + +#ifdef KRT_SHARED_SOCKET +static struct krt_proto *krt_table_map[KRT_MAX_TABLES]; +#endif + + +/* Route socket message processing */ int krt_capable(rte *e) @@ -65,6 +160,16 @@ krt_capable(rte *e) ); } +#ifndef RTAX_MAX +#define RTAX_MAX 8 +#endif + +struct ks_msg +{ + struct rt_msghdr rtm; + struct sockaddr_storage buf[RTAX_MAX]; +}; + #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) @@ -81,7 +186,7 @@ krt_capable(rte *e) body += l;} static int -krt_sock_send(int cmd, rte *e) +krt_send_route(struct krt_proto *p, int cmd, rte *e) { net *net = e->net; rta *a = e->attrs; @@ -103,13 +208,13 @@ krt_sock_send(int cmd, rte *e) msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1; if (net->n.pxlen == MAX_PREFIX_LENGTH) - { msg.rtm.rtm_flags |= RTF_HOST; - } else - { msg.rtm.rtm_addrs |= RTA_NETMASK; - } + +#ifdef KRT_SHARED_SOCKET + msg.rtm.rtm_tableid = KRT_CF->sys.table_id; +#endif #ifdef RTF_REJECT if(a->dest == RTD_UNREACHABLE) @@ -192,7 +297,7 @@ krt_sock_send(int cmd, rte *e) l = body - (char *)&msg; msg.rtm.rtm_msglen = l; - if ((l = write(rt_sock, (char *)&msg, l)) < 0) { + if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) { log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen); return -1; } @@ -201,16 +306,16 @@ krt_sock_send(int cmd, rte *e) } void -krt_replace_rte(struct krt_proto *p UNUSED, net *n, rte *new, rte *old, +krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs UNUSED) { int err = 0; if (old) - krt_sock_send(RTM_DELETE, old); + krt_send_route(p, RTM_DELETE, old); if (new) - err = krt_sock_send(RTM_ADD, new); + err = krt_send_route(p, RTM_ADD, new); if (err < 0) n->n.flags |= KRF_SYNC_ERROR; @@ -221,8 +326,10 @@ krt_replace_rte(struct krt_proto *p UNUSED, net *n, rte *new, rte *old, #define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0) static void -krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) +krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) { + /* p is NULL iff KRT_SHARED_SOCKET and !scan */ + rte *e; net *net; sockaddr dst, gate, mask; @@ -244,6 +351,17 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) if (flags & RTF_LLINFO) SKIP("link-local\n"); +#ifdef KRT_SHARED_SOCKET + if (!scan) + { + int table_id = msg->rtm.rtm_tableid; + p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id] : NULL; + + if (!p) + SKIP("unknown table id %d\n", table_id); + } +#endif + GETADDR(&dst, RTA_DST); GETADDR(&gate, RTA_GATEWAY); GETADDR(&mask, RTA_NETMASK); @@ -594,17 +712,18 @@ krt_read_addr(struct ks_msg *msg) ifa_delete(&ifa); } - -void +static void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan) { + /* p is NULL iff KRT_SHARED_SOCKET and !scan */ + switch (msg->rtm.rtm_type) { case RTM_GET: if(!scan) return; case RTM_ADD: case RTM_DELETE: - krt_read_rt(msg, (struct krt_proto *)p, scan); + krt_read_route(msg, (struct krt_proto *)p, scan); break; case RTM_IFANNOUNCE: krt_read_ifannounce(msg); @@ -621,14 +740,57 @@ krt_read_msg(struct proto *p, struct ks_msg *msg, int scan) } } + +/* Sysctl based scans */ + +static byte *krt_buffer; +static size_t krt_buflen, krt_bufmin; +static struct proto *krt_buffer_owner; + +static byte * +krt_buffer_update(struct proto *p, size_t *needed) +{ + size_t req = *needed; + + if ((req > krt_buflen) || + ((p == krt_buffer_owner) && (req < krt_bufmin))) + { + /* min buflen is 32 kB, step is 8 kB, or 128 kB if > 1 MB */ + size_t step = (req < 0x100000) ? 0x2000 : 0x20000; + krt_buflen = (req < 0x6000) ? 0x8000 : (req + step); + krt_bufmin = (req < 0x8000) ? 0 : (req - 2*step); + + if (krt_buffer) + mb_free(krt_buffer); + krt_buffer = mb_alloc(krt_pool, krt_buflen); + krt_buffer_owner = p; + } + + *needed = krt_buflen; + return krt_buffer; +} + +static void +krt_buffer_release(struct proto *p) +{ + if (p == krt_buffer_owner) + { + mb_free(krt_buffer); + krt_buffer = NULL; + krt_buflen = 0; + krt_buffer_owner = 0; + } +} + static void -krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) +krt_sysctl_scan(struct proto *p, int cmd, int table_id) { - byte *next; - int mib[6]; - size_t obl, needed; + byte *buf, *next; + int mib[7], mcnt; + size_t needed; struct ks_msg *m; int retries = 3; + int rv; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -636,125 +798,258 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd) mib[3] = BIRD_PF; mib[4] = cmd; mib[5] = 0; + mcnt = 6; - try: - if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0) - die("krt_sysctl_scan 1: %m"); - - obl = *bl; +#ifdef KRT_USE_SYSCTL_7 + if (table_id >= 0) + { + mib[6] = table_id; + mcnt = 7; + } +#endif - while (needed > *bl) *bl *= 2; - while (needed < (*bl/2)) *bl /= 2; +#ifdef KRT_USE_SETFIB_SCAN + if (table_id > 0) + if (setfib(table_id) < 0) + { + log(L_ERR "KRT: setfib(%d) failed: %m", table_id); + return; + } +#endif - if ((obl!=*bl) || !*buf) + try: + rv = sysctl(mib, mcnt, NULL, &needed, NULL, 0); + if (rv < 0) { - if (*buf) mb_free(*buf); - if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc"); + /* OpenBSD returns EINVAL for not yet used tables */ + if ((errno == EINVAL) && (table_id > 0)) + goto exit; + + log(L_ERR "KRT: Route scan estimate failed: %m"); + goto exit; } - if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0) + /* The table is empty */ + if (needed == 0) + goto exit; + + buf = krt_buffer_update(p, &needed); + + rv = sysctl(mib, mcnt, buf, &needed, NULL, 0); + if (rv < 0) { - if (errno == ENOMEM) - { - /* The buffer size changed since last sysctl ('needed' is not changed) */ - if (retries--) - goto try; + /* The buffer size changed since last sysctl ('needed' is not changed) */ + if ((errno == ENOMEM) && retries--) + goto try; - log(L_ERR "KRT: Route scan failed"); - return; - } - die("krt_sysctl_scan 2: %m"); + log(L_ERR "KRT: Route scan failed: %m"); + goto exit; } - for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen) +#ifdef KRT_USE_SETFIB_SCAN + if (table_id > 0) + if (setfib(0) < 0) + die("KRT: setfib(%d) failed: %m", 0); +#endif + + /* Process received messages */ + for (next = buf; next < (buf + needed); next += m->rtm.rtm_msglen) { m = (struct ks_msg *)next; krt_read_msg(p, m, 1); } -} -static byte *krt_buffer = NULL; -static byte *kif_buffer = NULL; -static size_t krt_buflen = 32768; -static size_t kif_buflen = 4096; + return; + + exit: + krt_buffer_release(p); + +#ifdef KRT_USE_SETFIB_SCAN + if (table_id > 0) + if (setfib(0) < 0) + die("KRT: setfib(%d) failed: %m", 0); +#endif +} void krt_do_scan(struct krt_proto *p) { - krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP); + krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id); } void kif_do_scan(struct kif_proto *p) { - struct proto *P = (struct proto *)p; if_start_update(); - krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST); + krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1); if_end_update(); } + +/* Kernel sockets */ + static int krt_sock_hook(sock *sk, int size UNUSED) { struct ks_msg msg; int l = read(sk->fd, (char *)&msg, sizeof(msg)); - if(l <= 0) + if (l <= 0) log(L_ERR "krt-sock: read failed"); else - krt_read_msg((struct proto *)sk->data, &msg, 0); + krt_read_msg((struct proto *) sk->data, &msg, 0); return 0; } +static sock * +krt_sock_open(pool *pool, void *data, int table_id) +{ + sock *sk; + int fd; + + fd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); + if (fd < 0) + die("Cannot open kernel socket for routes"); + +#ifdef KRT_USE_SETFIB_SOCK + if (table_id > 0) + { + if (setsockopt(fd, SOL_SOCKET, SO_SETFIB, &table_id, sizeof(table_id)) < 0) + die("Cannot set FIB %d for kernel socket: %m", table_id); + } +#endif + + sk = sk_new(pool); + sk->type = SK_MAGIC; + sk->rx_hook = krt_sock_hook; + sk->fd = fd; + sk->data = data; + + if (sk_open(sk) < 0) + bug("krt-sock: sk_open failed"); + + return sk; +} + + +#ifdef KRT_SHARED_SOCKET + +static sock *krt_sock; +static int krt_sock_count; + + +static void +krt_sock_open_shared(void) +{ + if (!krt_sock_count) + krt_sock = krt_sock_open(krt_pool, NULL, -1); + + krt_sock_count++; +} + +static void +krt_sock_close_shared(void) +{ + krt_sock_count--; + + if (!krt_sock_count) + { + rfree(krt_sock); + krt_sock = NULL; + } +} + void -krt_sys_start(struct krt_proto *x, int first UNUSED) +krt_sys_start(struct krt_proto *p) { - sock *sk_rt; - static int ks_open_tried = 0; + krt_table_map[KRT_CF->sys.table_id] = p; - if (ks_open_tried) - return; + krt_sock_open_shared(); + p->sys.sk = krt_sock; +} - ks_open_tried = 1; +void +krt_sys_shutdown(struct krt_proto *p) +{ + krt_sock_close_shared(); + p->sys.sk = NULL; - DBG("KRT: Opening kernel socket\n"); + krt_table_map[KRT_CF->sys.table_id] = NULL; - if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) - die("Cannot open kernel socket for routes"); + krt_buffer_release(&p->p); +} - sk_rt = sk_new(krt_pool); - sk_rt->type = SK_MAGIC; - sk_rt->rx_hook = krt_sock_hook; - sk_rt->fd = rt_sock; - sk_rt->data = x; - if (sk_open(sk_rt)) - bug("krt-sock: sk_open failed"); +#else + +void +krt_sys_start(struct krt_proto *p) +{ + p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id); } void -krt_sys_shutdown(struct krt_proto *x UNUSED, int last UNUSED) +krt_sys_shutdown(struct krt_proto *p) { - if (!krt_buffer) - return; + rfree(p->sys.sk); + p->sys.sk = NULL; + + krt_buffer_release(&p->p); +} + +#endif /* KRT_SHARED_SOCKET */ + - mb_free(krt_buffer); - krt_buffer = NULL; +/* KRT configuration callbacks */ + +static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32]; + +int +krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o) +{ + return n->sys.table_id == o->sys.table_id; } +void +krt_sys_preconfig(struct config *c UNUSED) +{ + krt_max_tables = krt_get_max_tables(); + bzero(&krt_table_cf, sizeof(krt_table_cf)); +} void -kif_sys_start(struct kif_proto *p UNUSED) +krt_sys_postconfig(struct krt_config *x) { + u32 *tbl = krt_table_cf; + int id = x->sys.table_id; + + if (tbl[id/32] & (1 << (id%32))) + cf_error("Multiple kernel syncers defined for table #%d", id); + + tbl[id/32] |= (1 << (id%32)); } +void krt_sys_init_config(struct krt_config *c) +{ + c->sys.table_id = 0; /* Default table */ +} + +void krt_sys_copy_config(struct krt_config *d, struct krt_config *s) +{ + d->sys.table_id = s->sys.table_id; +} + + +/* KIF misc code */ + void -kif_sys_shutdown(struct kif_proto *p UNUSED) +kif_sys_start(struct kif_proto *p UNUSED) { - if (!kif_buffer) - return; +} - mb_free(kif_buffer); - kif_buffer = NULL; +void +kif_sys_shutdown(struct kif_proto *p) +{ + krt_buffer_release(&p->p); } diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h index 88915dd..9c0d497 100644 --- a/sysdep/bsd/krt-sys.h +++ b/sysdep/bsd/krt-sys.h @@ -9,13 +9,14 @@ #ifndef _BIRD_KRT_SYS_H_ #define _BIRD_KRT_SYS_H_ +struct birdsock; /* Kernel interfaces */ struct kif_params { }; -struct kif_status { +struct kif_state { }; @@ -30,20 +31,18 @@ static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_c /* Kernel routes */ +extern int krt_max_tables; + struct krt_params { + int table_id; /* Kernel table ID we sync with */ }; -struct krt_status { +struct krt_state { + struct birdsock *sk; }; static inline void krt_sys_init(struct krt_proto *p UNUSED) { } -static inline int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n UNUSED, struct krt_config *o UNUSED) { return 1; } - -static inline void krt_sys_preconfig(struct config *c UNUSED) { } -static inline void krt_sys_postconfig(struct krt_config *c UNUSED) { } -static inline void krt_sys_init_config(struct krt_config *c UNUSED) { } -static inline void krt_sys_copy_config(struct krt_config *d UNUSED, struct krt_config *s UNUSED) { } #endif diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h index b7f25f6..3403299 100644 --- a/sysdep/cf/bsd-v6.h +++ b/sysdep/cf/bsd-v6.h @@ -10,6 +10,7 @@ #define CONFIG_AUTO_ROUTES #define CONFIG_SELF_CONSCIOUS +#define CONFIG_MULTIPLE_TABLES #define CONFIG_SKIP_MC_BIND diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h index e7cc135..1101b22 100644 --- a/sysdep/cf/bsd.h +++ b/sysdep/cf/bsd.h @@ -8,6 +8,7 @@ #define CONFIG_AUTO_ROUTES #define CONFIG_SELF_CONSCIOUS +#define CONFIG_MULTIPLE_TABLES #define CONFIG_SKIP_MC_BIND diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index cdee7fe..7b3043a 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -15,7 +15,7 @@ struct kif_params { }; -struct kif_status { +struct kif_state { }; @@ -36,7 +36,7 @@ struct krt_params { int table_id; /* Kernel table ID we sync with */ }; -struct krt_status { +struct krt_state { }; diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index 51689ff..b0e3515 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -10,13 +10,13 @@ CF_HDR CF_DECLS -CF_KEYWORDS(ASYNC, KERNEL, TABLE, KRT_PREFSRC, KRT_REALM) +CF_KEYWORDS(KERNEL, TABLE, KRT_PREFSRC, KRT_REALM) CF_GRAMMAR -CF_ADDTO(kern_proto, kern_proto nl_item ';') +CF_ADDTO(kern_proto, kern_proto kern_sys_item ';') -nl_item: +kern_sys_item: KERNEL TABLE expr { if ($3 <= 0 || $3 >= NL_NUM_TABLES) cf_error("Kernel routing table number out of range"); diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 1d24ae0..f61e31a 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1086,18 +1086,16 @@ nl_open_async(void) static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8]; void -krt_sys_start(struct krt_proto *p, int first) +krt_sys_start(struct krt_proto *p) { nl_table_map[KRT_CF->sys.table_id] = p; - if (first) - { - nl_open(); - nl_open_async(); - } + + nl_open(); + nl_open_async(); } void -krt_sys_shutdown(struct krt_proto *p UNUSED, int last UNUSED) +krt_sys_shutdown(struct krt_proto *p UNUSED) { } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 3761ace..5429792 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -69,12 +69,14 @@ pool *krt_pool; static linpool *krt_filter_lp; +static list krt_proto_list; void krt_io_init(void) { krt_pool = rp_new(&root_pool, "Kernel Syncer"); krt_filter_lp = lp_new(krt_pool, 4080); + init_list(&krt_proto_list); } /* @@ -565,12 +567,6 @@ krt_dump_attrs(rte *e) * Routes */ -#ifdef CONFIG_ALL_TABLES_AT_ONCE -static timer *krt_scan_timer; -static int krt_instance_count; -static list krt_instance_list; -#endif - static void krt_flush_routes(struct krt_proto *p) { @@ -812,34 +808,88 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new) * Periodic scanning */ + +#ifdef CONFIG_ALL_TABLES_AT_ONCE + +static timer *krt_scan_timer; +static int krt_scan_count; + static void krt_scan(timer *t UNUSED) { struct krt_proto *p; kif_force_scan(); -#ifdef CONFIG_ALL_TABLES_AT_ONCE + + /* We need some node to decide whether to print the debug messages or not */ + p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list)); + KRT_TRACE(p, D_EVENTS, "Scanning routing table"); + + krt_do_scan(NULL); + + void *q; + WALK_LIST(q, krt_proto_list) { - void *q; - /* We need some node to decide whether to print the debug messages or not */ - p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list)); - if (p->instance_node.next) - KRT_TRACE(p, D_EVENTS, "Scanning routing table"); - krt_do_scan(NULL); - WALK_LIST(q, krt_instance_list) - { - p = SKIP_BACK(struct krt_proto, instance_node, q); - krt_prune(p); - } + p = SKIP_BACK(struct krt_proto, krt_node, q); + krt_prune(p); + } +} + +static void +krt_scan_timer_start(struct krt_proto *p) +{ + if (!krt_scan_count) + { + krt_scan_timer = tm_new_set(krt_pool, krt_scan, NULL, 0, KRT_CF->scan_time); + tm_start(krt_scan_timer, 0); + } + + krt_scan_count++; +} + +static void +krt_scan_timer_stop(struct krt_proto *p) +{ + krt_scan_count--; + + if (!krt_scan_count) + { + rfree(krt_scan_timer); + krt_scan_timer = NULL; } +} + #else - p = t->data; + +static void +krt_scan(timer *t) +{ + struct krt_proto *p = t->data; + + kif_force_scan(); + KRT_TRACE(p, D_EVENTS, "Scanning routing table"); krt_do_scan(p); krt_prune(p); -#endif } +static void +krt_scan_timer_start(struct krt_proto *p) +{ + p->scan_timer = tm_new_set(p->p.pool, krt_scan, p, 0, KRT_CF->scan_time); + tm_start(p->scan_timer, 0); +} + +static void +krt_scan_timer_stop(struct krt_proto *p) +{ + tm_stop(p->scan_timer); +} + +#endif + + + /* * Updates @@ -942,52 +992,20 @@ krt_init(struct proto_config *c) return &p->p; } -static timer * -krt_start_timer(struct krt_proto *p) -{ - timer *t; - - t = tm_new(p->krt_pool); - t->hook = krt_scan; - t->data = p; - t->recurrent = KRT_CF->scan_time; - tm_start(t, 0); - return t; -} - static int krt_start(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; - int first = 1; -#ifdef CONFIG_ALL_TABLES_AT_ONCE - if (!krt_instance_count++) - init_list(&krt_instance_list); - else - first = 0; - p->krt_pool = krt_pool; - add_tail(&krt_instance_list, &p->instance_node); -#else - p->krt_pool = P->pool; -#endif + add_tail(&krt_proto_list, &p->krt_node); #ifdef KRT_ALLOW_LEARN krt_learn_init(p); #endif - krt_sys_start(p, first); + krt_sys_start(p); - /* Start periodic routing table scanning */ -#ifdef CONFIG_ALL_TABLES_AT_ONCE - if (first) - krt_scan_timer = krt_start_timer(p); - else - tm_start(krt_scan_timer, 0); - p->scan_timer = krt_scan_timer; -#else - p->scan_timer = krt_start_timer(p); -#endif + krt_scan_timer_start(p); return PS_UP; } @@ -996,26 +1014,16 @@ static int krt_shutdown(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; - int last = 1; -#ifdef CONFIG_ALL_TABLES_AT_ONCE - rem_node(&p->instance_node); - if (--krt_instance_count) - last = 0; - else -#endif - tm_stop(p->scan_timer); + krt_scan_timer_stop(p); /* FIXME we should flush routes even when persist during reconfiguration */ if (p->initialized && !KRT_CF->persist) krt_flush_routes(p); - krt_sys_shutdown(p, last); + krt_sys_shutdown(p); -#ifdef CONFIG_ALL_TABLES_AT_ONCE - if (last) - rfree(krt_scan_timer); -#endif + rem_node(&p->krt_node); return PS_DOWN; } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index d6fbf72..446914d 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -52,15 +52,17 @@ struct krt_config { struct krt_proto { struct proto p; - struct krt_status sys; /* Sysdep state */ + struct krt_state sys; /* Sysdep state */ + #ifdef KRT_ALLOW_LEARN struct rtable krt_table; /* Internal table of inherited routes */ #endif - pool *krt_pool; /* Pool used for common krt data */ + +#ifndef CONFIG_ALL_TABLES_AT_ONCE timer *scan_timer; -#ifdef CONFIG_ALL_TABLES_AT_ONCE - node instance_node; /* Node in krt instance list */ #endif + + node krt_node; /* Node in krt_proto_list */ int initialized; /* First scan has already been finished */ }; @@ -103,7 +105,7 @@ struct kif_config { struct kif_proto { struct proto p; - struct kif_status sys; /* Sysdep state */ + struct kif_state sys; /* Sysdep state */ }; #define KIF_CF ((struct kif_config *)p->p.cf) @@ -114,8 +116,8 @@ struct proto_config * krt_init_config(int class); /* krt sysdep */ void krt_sys_init(struct krt_proto *); -void krt_sys_start(struct krt_proto *, int); -void krt_sys_shutdown(struct krt_proto *, int); +void krt_sys_start(struct krt_proto *); +void krt_sys_shutdown(struct krt_proto *); int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o); void krt_sys_preconfig(struct config *);