From: Ondrej Zajicek Date: Wed, 31 Jul 2013 16:03:35 +0000 (+0200) Subject: Merge commit 'c01a94663cc18f53fd741c5d44387eead9ca88af' into integrated X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=050de54105b7e0553ea90581e4d8a0482890461f;p=thirdparty%2Fbird.git Merge commit 'c01a94663cc18f53fd741c5d44387eead9ca88af' into integrated Conflicts: sysdep/bsd/krt-sock.c sysdep/bsd/krt-sys.h --- 050de54105b7e0553ea90581e4d8a0482890461f diff --cc sysdep/bsd/krt-sock.c index 49c45e668,08dfccc81..d33486cf3 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@@ -65,19 -160,15 +160,29 @@@ krt_capable(rte *e ); } ++ +static int +rt_to_af(int rt) +{ + if (rt == RT_IPV4) + return AF_INET; + else if (rt == RT_IPV6) + return AF_INET6; + + /* RT_IP (0) maps to 0 (every AF) */ + + return 0; +} + + #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)) @@@ -116,6 -207,15 +221,10 @@@ krt_send_route(struct krt_proto *p, in msg.rtm.rtm_addrs = RTA_DST; 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) msg.rtm.rtm_flags |= RTF_REJECT; @@@ -226,8 -297,8 +335,8 @@@ 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); + log(L_ERR "KRT: Error sending route %F to kernel: %m", &net->n); return -1; } @@@ -255,11 -326,13 +364,13 @@@ krt_replace_rte(struct krt_proto *p, ne #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; + struct sockaddr_in6 dst, gate, mask; ip_addr idst, igate, imask; void *body = (char *)msg->buf; int new = (msg->rtm.rtm_type == RTM_ADD); @@@ -689,52 -740,120 +812,120 @@@ krt_read_msg(struct proto *p, struct ks } } + + /* 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_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd, int af) + krt_buffer_release(struct proto *p) { - byte *next; - int mib[6]; - size_t obl, needed; + 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, int cmd, int table_id) ++krt_sysctl_scan(struct proto *p, int cmd, int af, int table_id) + { + 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; mib[2] = 0; - mib[3] = BIRD_PF; + mib[3] = af; 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); @@@ -749,16 -874,14 +946,14 @@@ void krt_do_scan(struct krt_proto *p) { - <<<<<<< HEAD:sysdep/bsd/krt-sock.c - krt_sysctl_scan(&p->p, p->krt_pool, &krt_buffer, &krt_buflen, - NET_RT_DUMP, rt_to_af(p->addr_type)); - krt_sysctl_scan(&p->p, NET_RT_DUMP, KRT_CF->sys.table_id); ++ krt_sysctl_scan(&p->p, NET_RT_DUMP, rt_to_af(p->addr_type), KRT_CF->sys.table_id); } void kif_do_scan(struct kif_proto *p) { if_start_update(); - krt_sysctl_scan(&p->p, p->p.pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST, 0); - krt_sysctl_scan(&p->p, NET_RT_IFLIST, -1); ++ krt_sysctl_scan(&p->p, NET_RT_IFLIST, 0, -1); if_end_update(); } @@@ -802,31 -989,54 +1061,56 @@@ krt_sys_start(struct krt_proto *p } void - krt_sys_shutdown(struct krt_proto *x UNUSED) + krt_sys_shutdown(struct krt_proto *p) { - if (!krt_buffer) - return; + rfree(p->sys.sk); + p->sys.sk = NULL; - mb_free(krt_buffer); - krt_buffer = NULL; + krt_buffer_release(&p->p); } - static u32 tables; + #endif /* KRT_SHARED_SOCKET */ + + + /* KRT configuration callbacks */ + -static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32]; ++static u32 krt_table4_cf[(KRT_MAX_TABLES+31) / 32]; ++static u32 krt_table6_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) { - tables = 0; + krt_max_tables = krt_get_max_tables(); - bzero(&krt_table_cf, sizeof(krt_table_cf)); ++ bzero(&krt_table4_cf, sizeof(krt_table4_cf)); ++ bzero(&krt_table6_cf, sizeof(krt_table6_cf)); } void krt_sys_postconfig(struct krt_config *x) { - u32 id = x->c.table->addr_type; - u32 *tbl = krt_table_cf; ++ u32 *tbl = (x->c.table->addr_type == RT_IPV4) ? krt_table4_cf : krt_table6_cf; + int id = x->sys.table_id; - if (tables & (1 << id)) - cf_error("Multiple kernel protocols defined for AF %d", id); - tables |= (1 << 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; } diff --cc sysdep/linux/netlink.c index 593f8c5be,f61e31a50..5b4698589 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@@ -1134,12 -1115,11 +1134,13 @@@ krt_sys_preconfig(struct config *c UNUS void krt_sys_postconfig(struct krt_config *x) { - int id = x->sys.table_id; + u32 *tbl = (x->c.table->addr_type == RT_IPV4) ? nl_table4_cf : nl_table6_cf; + u32 id = x->sys.table_id; - if (nl_cf_table[id/8] & (1 << (id%8))) + if (tbl[id/32] & (1 << (id%32))) cf_error("Multiple kernel syncers defined for table #%d", id); - nl_cf_table[id/8] |= (1 << (id%8)); ++ + tbl[id/32] |= (1 << (id%32)); } void