From 9dbcb11cb50167e959536e5a564ee9aafae509c6 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Mon, 30 May 2016 14:28:22 +0200 Subject: [PATCH 01/45] Unix IO: Tried to fix strange behavior after POLLHUP or POLLERR. --- sysdep/unix/io.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 486319ff..8198743d 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1853,6 +1853,20 @@ sk_write(sock *s) } } +void +sk_err(sock *s, int revents) +{ + int se = 0, sse = sizeof(se); + if (revents & POLLERR) + if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &se, &sse) < 0) + { + log(L_ERR "IO: Socket error: SO_ERROR: %m"); + se = 0; + } + + s->err_hook(s, se); +} + void sk_dump_all(void) { @@ -2163,7 +2177,7 @@ io_loop(void) int steps; steps = MAX_STEPS; - if (s->fast_rx && (pfd[s->index].revents & (POLLIN | POLLHUP | POLLERR)) && s->rx_hook) + if (s->fast_rx && (pfd[s->index].revents & POLLIN) && s->rx_hook) do { steps--; @@ -2185,6 +2199,7 @@ io_loop(void) goto next; } while (e && steps); + current_sock = sk_next(s); next: ; } @@ -2208,18 +2223,26 @@ io_loop(void) goto next2; } - if (!s->fast_rx && (pfd[s->index].revents & (POLLIN | POLLHUP | POLLERR)) && s->rx_hook) + if (!s->fast_rx && (pfd[s->index].revents & POLLIN) && s->rx_hook) { count++; io_log_event(s->rx_hook, s->data); sk_read(s, pfd[s->index].revents); if (s != current_sock) - goto next2; + goto next2; } + + if (pfd[s->index].revents & (POLLHUP | POLLERR)) + { + sk_err(s, pfd[s->index].revents); + goto next2; + } + current_sock = sk_next(s); next2: ; } + stored_sock = current_sock; } } From 90dc0f08434323535f84d64e113dae84675c46b2 Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Sat, 4 Jun 2016 12:38:06 +0200 Subject: [PATCH 02/45] Small typo in documentation example, submitted by Felix Eckhofer. --- doc/bird.sgml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 014225d1..f3c34a14 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1035,7 +1035,7 @@ foot). or ipaddress/netmask. There are two special operators on prefixes: 1.2.0.0/16.pxlen = 16 is true. + So 1.2.0.0/16.len = 16 is true. Date: Wed, 8 Jun 2016 16:22:44 +0200 Subject: [PATCH 03/45] Add AS# ranges to bgpmask. --- doc/bird.sgml | 6 ++++-- filter/config.Y | 1 + filter/filter.c | 4 ++++ filter/test.conf | 9 ++++++--- nest/a-path.c | 26 ++++++++++++++++++-------- nest/attrs.h | 2 ++ 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index f3c34a14..de7041a9 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1165,8 +1165,10 @@ foot). is 4 3 2 1, then: bgp_path ˜ [= * 4 3 * =] is true, but bgp_path ˜ [= * 4 5 * =] is false. BGP mask expressions can also contain integer expressions enclosed in parenthesis - and integer variables, for example [= * 4 (1+2) a =]. There is - also old syntax that uses / .. / instead of [= .. =] and ? instead of *. + and integer variables, for example [= * 4 (1+2) a =]. You can + also use ranges, for example [= * 3..5 2 100..200 * =]. + There is also old (deprecated) syntax that uses / .. / instead of [= .. =] + and ? instead of *. next = $2; $$->kind = PM_ASN; $$->val = $1; } + | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; } | '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val = 0; } | '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val = 0; } | bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } diff --git a/filter/filter.c b/filter/filter.c index eddf4228..dce98e4d 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -79,6 +79,10 @@ pm_format(struct f_path_mask *p, buffer *buf) buffer_puts(buf, "* "); break; + case PM_ASN_RANGE: + buffer_print(buf, "%u..%u ", p->val, p->val2); + break; + case PM_ASN_EXPR: buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val)); break; diff --git a/filter/test.conf b/filter/test.conf index a99d0a51..ad8f9386 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -90,20 +90,23 @@ clist l2; eclist el; eclist el2; { + print "Entering path test..."; pm1 = / 4 3 2 1 /; - pm2 = [= 4 3 2 1 =]; + pm2 = [= 3..6 3 2 1..2 =]; print "Testing path masks: ", pm1, " ", pm2; p2 = prepend( + empty +, 1 ); p2 = prepend( p2, 2 ); p2 = prepend( p2, 3 ); p2 = prepend( p2, 4 ); - print "Testing paths: ", p2; + print "Testing path: (4 3 2 1) = ", p2; print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20]; print "4 = ", p2.len; p2 = prepend( p2, 5 ); - print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, ten..(2*ten)]; + print "Testing path: (5 4 3 2 1) = ", p2; + print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, ten..(2*ten)], " ", p2 ~ [= 1..4 4 3 2 1 =], " ", p2 ~ [= 5 4 4..100 2 1 =]; print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /; print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =]; + print "Should be true: ", p2 ~ [= 5..6 4..10 1..3 1..3 1..65536 =]; print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4); print "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1; print "5 = ", p2.len; diff --git a/nest/a-path.c b/nest/a-path.c index 32e2d27e..e1031b7b 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -435,18 +435,23 @@ parse_path(struct adata *path, struct pm_pos *pos) static int -pm_match(struct pm_pos *pos, u32 asn) +pm_match(struct pm_pos *pos, u32 asn, u32 asn2) { + u32 gas; if (! pos->set) - return pos->val.asn == asn; + return ((pos->val.asn >= asn) && (pos->val.asn <= asn2)); u8 *p = pos->val.sp; int len = *p++; int i; for (i = 0; i < len; i++) - if (get_as(p + i * BS) == asn) + { + gas = get_as(p + i * BS); + + if ((gas >= asn) && (gas <= asn2)) return 1; + } return 0; } @@ -490,7 +495,7 @@ pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh) * next part of mask, we advance each marked state. * We start with marked first position, when we * run out of marked positions, we reject. When - * we process the whole mask, we accept iff final position + * we process the whole mask, we accept if final position * (auxiliary position after last real position in AS path) * is marked. */ @@ -502,6 +507,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) int plen = parse_path(path, pos); int l, h, i, nh, nl; u32 val = 0; + u32 val2 = 0; /* l and h are bound of interval of positions where are marked states */ @@ -525,12 +531,16 @@ as_path_match(struct adata *path, struct f_path_mask *mask) h = plen; break; - case PM_ASN: - val = mask->val; + case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */ + val2 = val = mask->val; goto step; case PM_ASN_EXPR: - val = f_eval_asn((struct f_inst *) mask->val); + val2 = val = f_eval_asn((struct f_inst *) mask->val); goto step; + case PM_ASN_RANGE: + val = mask->val; + val2 = mask->val2; + goto step; case PM_QUESTION: step: nh = nl = -1; @@ -538,7 +548,7 @@ as_path_match(struct adata *path, struct f_path_mask *mask) if (pos[i].mark) { pos[i].mark = 0; - if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val)) + if ((mask->kind == PM_QUESTION) || pm_match(pos + i, val, val2)) pm_mark(pos, i, plen, &nl, &nh); } diff --git a/nest/attrs.h b/nest/attrs.h index 0171c6a8..670b048f 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -45,11 +45,13 @@ struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_ #define PM_QUESTION 1 #define PM_ASTERISK 2 #define PM_ASN_EXPR 3 +#define PM_ASN_RANGE 4 struct f_path_mask { struct f_path_mask *next; int kind; uintptr_t val; + uintptr_t val2; }; int as_path_match(struct adata *path, struct f_path_mask *mask); From 122deb6d5b14f46f3cfb25bf3f5726005d6a3b3e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 9 Jun 2016 00:30:41 +0200 Subject: [PATCH 04/45] Filters: Fixes pm_same() w.r.t. ASN ranges and ASN expressions This is necessary for proper detection of filter changes during reconfigurations. --- filter/config.Y | 16 ++++++++-------- filter/filter.c | 17 ++++++++++++++--- filter/test.conf | 3 +++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index e53d8def..da605710 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -626,17 +626,17 @@ bgp_path: ; bgp_path_tail1: - NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } - | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; } - | '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val = 0; } - | '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val = 0; } - | bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } - | { $$ = NULL; } + NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } + | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; } + | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; } + | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; } + | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } + | { $$ = NULL; } ; bgp_path_tail2: - NUM bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } - | '?' bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val = 0; } + NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } + | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; } | { $$ = NULL; } ; diff --git a/filter/filter.c b/filter/filter.c index dce98e4d..c61377b7 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -163,13 +163,24 @@ val_compare(struct f_val v1, struct f_val v2) } static int -pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2) +pm_same(struct f_path_mask *m1, struct f_path_mask *m2) { while (m1 && m2) { - if ((m1->kind != m2->kind) || (m1->val != m2->val)) + if (m1->kind != m2->kind) return 0; + if (m1->kind == PM_ASN_EXPR) + { + if (!i_same((struct f_inst *) m1->val, (struct f_inst *) m2->val)) + return 0; + } + else + { + if ((m1->val != m2->val) || (m1->val2 != m2->val2)) + return 0; + } + m1 = m1->next; m2 = m2->next; } @@ -199,7 +210,7 @@ val_same(struct f_val v1, struct f_val v2) switch (v1.type) { case T_PATH_MASK: - return pm_path_same(v1.val.path_mask, v2.val.path_mask); + return pm_same(v1.val.path_mask, v2.val.path_mask); case T_PATH: case T_CLIST: case T_ECLIST: diff --git a/filter/test.conf b/filter/test.conf index ad8f9386..f61f0658 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -109,6 +109,9 @@ eclist el2; print "Should be true: ", p2 ~ [= 5..6 4..10 1..3 1..3 1..65536 =]; print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4); print "Should be true: ", p2.len = 5, " ", p2.first = 5, " ", p2.last = 1; + print "Should be true: ", pm1 = [= 4 3 2 1 =], " ", pm1 != [= 4 3 1 2 =], " ", + pm2 = [= 3..6 3 2 1..2 =], " ", pm2 != [= 3..6 3 2 1..3 =], " ", + [= 1 2 (1+2) =] = [= 1 2 (1+2) =], " ", [= 1 2 (1+2) =] != [= 1 2 (2+1) =]; print "5 = ", p2.len; print "Delete 3: ", delete(p2, 3); print "Filter 1-3: ", filter(p2, [1..3]); From 8f01879c5629bd714dfeec968337cfcd4dbe6a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Tvrd=C3=ADk?= Date: Tue, 29 Mar 2016 10:37:31 +0200 Subject: [PATCH 05/45] cppcheck: fix va_end() functions --- client/util.c | 2 ++ conf/conf.c | 1 + sysdep/unix/log.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/client/util.c b/client/util.c index c35cf8f4..2d6c074d 100644 --- a/client/util.c +++ b/client/util.c @@ -40,6 +40,7 @@ bug(const char *msg, ...) fputs("Internal error: ", stderr); vlog(msg, args); vfprintf(stderr, msg, args); + va_end(args); exit(1); } @@ -51,5 +52,6 @@ die(const char *msg, ...) va_start(args, msg); cleanup(); vlog(msg, args); + va_end(args); exit(1); } diff --git a/conf/conf.c b/conf/conf.c index 825a8e9f..efaeedeb 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -512,6 +512,7 @@ cf_error(char *msg, ...) va_start(args, msg); if (bvsnprintf(buf, sizeof(buf), msg, args) < 0) strcpy(buf, ""); + va_end(args); new_config->err_msg = cfg_strdup(buf); new_config->err_lino = ifs->lino; new_config->err_file_name = ifs->file_name; diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 6665d035..631bd691 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -209,6 +209,7 @@ bug(const char *msg, ...) va_start(args, msg); vlog(L_BUG[0], msg, args); + va_end(args); abort(); } @@ -226,6 +227,7 @@ die(const char *msg, ...) va_start(args, msg); vlog(L_FATAL[0], msg, args); + va_end(args); exit(1); } From 775a5a81958e66a69663803dd2e731e3800da9e7 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 29 Jun 2016 14:11:03 +0200 Subject: [PATCH 06/45] BGP: Skip empty path segments in received AS_PATH Although RFC 4271 does not forbid empty path segments, they are useless and some implementations consider them invalid. It is clarified in RFC 7606, specifying that AS_PATH with empty segment is considered malformed. --- proto/bgp/attrs.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index d85afa8f..b8371f32 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -118,7 +118,7 @@ validate_path(struct bgp_proto *p, int as_path, int bs, byte *idata, uint *ileng { int res = 0; u8 *a, *dst; - int len, plen, copy; + int len, plen; dst = a = idata; len = *ilength; @@ -132,15 +132,20 @@ validate_path(struct bgp_proto *p, int as_path, int bs, byte *idata, uint *ileng if (len < plen) return -1; + if (a[1] == 0) + { + log(L_WARN "%s: %s_PATH attribute contains empty segment, skipping it", + p->p.name, as_path ? "AS" : "AS4"); + goto skip; + } + switch (a[0]) { case AS_PATH_SET: - copy = 1; res++; break; case AS_PATH_SEQUENCE: - copy = 1; res += a[1]; break; @@ -154,20 +159,17 @@ validate_path(struct bgp_proto *p, int as_path, int bs, byte *idata, uint *ileng log(L_WARN "%s: %s_PATH attribute contains AS_CONFED_* segment, skipping segment", p->p.name, as_path ? "AS" : "AS4"); - copy = 0; - break; + goto skip; default: return -1; } - if (copy) - { - if (dst != a) - memmove(dst, a, plen); - dst += plen; - } + if (dst != a) + memmove(dst, a, plen); + dst += plen; + skip: len -= plen; a += plen; } From f1f39bb9d8e2260fe181240dd8194b06bdcfb54f Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Fri, 1 Jul 2016 11:03:13 +0200 Subject: [PATCH 07/45] Filter: Fixes reconfiguration with last_nonaggregated operator --- filter/filter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/filter/filter.c b/filter/filter.c index c61377b7..30571e5a 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -1461,7 +1461,8 @@ i_same(struct f_inst *f1, struct f_inst *f2) case P('A','p'): TWOARGS; break; case P('C','a'): TWOARGS; break; case P('a','f'): - case P('a','l'): ONEARG; break; + case P('a','l'): + case P('a','L'): ONEARG; break; case P('R','C'): TWOARGS; /* Does not really make sense - ROA check resuls may change anyway */ From f0b822a831d0f0f593bbedf0a7f15b94c3ca1d43 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 11 Jul 2016 20:22:55 +0200 Subject: [PATCH 08/45] Log: Fix error handling of debug file open Logging is not yet initialized, we have to use fprintf() here. Thanks to Pavel Tvrdik for noticing and debugging it. --- sysdep/unix/log.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 631bd691..1fd64426 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "nest/bird.h" #include "nest/cli.h" @@ -314,7 +315,11 @@ log_init_debug(char *f) else if (!*f) dbgf = stderr; else if (!(dbgf = fopen(f, "a"))) - log(L_ERR "Error opening debug file `%s': %m", f); + { + /* Cannot use die() nor log() here, logging is not yet initialized */ + fprintf(stderr, "bird: Unable to open debug file %s: %s\n", f, strerror(errno)); + exit(1); + } if (dbgf) setvbuf(dbgf, NULL, _IONBF, 0); } From ea0cb652e91d871e7808e93aa15ef34fc453c4fc Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 11 Jul 2016 20:41:32 +0200 Subject: [PATCH 09/45] BGP: Fix extended messages Change attribute length limit to handle extended (64 kB) messages. Do not mix updates and withdraws (RFC 7606). --- proto/bgp/packets.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 72ca3728..0cf38edf 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -369,7 +369,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) } put_u16(buf, wd_size); - if (remains >= 3072) + if (!wd_size) { while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next) { @@ -382,7 +382,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) } DBG("Processing bucket %p\n", buck); - a_size = bgp_encode_attrs(p, w+2, buck->eattrs, 2048); + a_size = bgp_encode_attrs(p, w+2, buck->eattrs, remains - 1024); if (a_size < 0) { @@ -461,8 +461,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) w += size; remains -= size; } - - if (remains >= 3072) + else { while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next) { @@ -478,7 +477,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) rem_stored = remains; w_stored = w; - size = bgp_encode_attrs(p, w, buck->eattrs, 2048); + size = bgp_encode_attrs(p, w, buck->eattrs, remains - 1024); if (size < 0) { log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name); From 6887f409f0766c60dd8c3d3fdf01a1d989c090a5 Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Sun, 17 Jul 2016 14:54:52 +0200 Subject: [PATCH 10/45] Prepare for longer interface names - clean up of the code. --- nest/rt-table.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index c02e6dc9..50c01c88 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -50,7 +50,7 @@ static linpool *rte_update_pool; static list routing_tables; -static void rt_format_via(rte *e, byte *via); +static byte *rt_format_via(rte *e); static void rt_free_hostcache(rtable *tab); static void rt_notify_hostcache(rtable *tab, net *net); static void rt_update_hostcache(rtable *tab); @@ -227,10 +227,7 @@ rte_mergable(rte *pri, rte *sec) static void rte_trace(struct proto *p, rte *e, int dir, char *msg) { - byte via[STD_ADDRESS_P_LENGTH+32]; - - rt_format_via(e, via); - log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, via); + log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, rt_format_via(e)); } static inline void @@ -2364,11 +2361,14 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_add * CLI commands */ -static void -rt_format_via(rte *e, byte *via) +static byte * +rt_format_via(rte *e) { rta *a = e->attrs; + /* Max text length w/o IP addr and interface name is 16 */ + static byte via[STD_ADDRESS_P_LENGTH+sizeof(a->iface->name)+16]; + switch (a->dest) { case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break; @@ -2379,12 +2379,13 @@ rt_format_via(rte *e, byte *via) case RTD_MULTIPATH: bsprintf(via, "multipath"); break; default: bsprintf(via, "???"); } + return via; } static void rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa) { - byte via[STD_ADDRESS_P_LENGTH+32], from[STD_ADDRESS_P_LENGTH+8]; + byte from[STD_ADDRESS_P_LENGTH+8]; byte tm[TM_DATETIME_BUFFER_SIZE], info[256]; rta *a = e->attrs; int primary = (e->net->routes == e); @@ -2392,7 +2393,6 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); struct mpnh *nh; - rt_format_via(e, via); tm_format_datetime(tm, &config->tf_route, e->lastmod); if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw)) bsprintf(from, " from %I", a->from); @@ -2413,7 +2413,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm get_route_info(e, info, tmpa); else bsprintf(info, " (%d)", e->pref); - cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->src->proto->name, + cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rt_format_via(e), a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); for (nh = a->nexthops; nh; nh = nh->next) cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1); From 321ff8c4049ec6c2fa198858b4a7f1814ce05e39 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 19 Jul 2016 11:57:20 +0200 Subject: [PATCH 11/45] Babel: Make sure intervals do not overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intervals are carried as 16-bit centisecond values, but kept internally in 16-bit second values, which causes a potential for overflow. This adds some checks to make sure this does not happen. Signed-off-by: Toke Høiland-Jørgensen --- proto/babel/babel.h | 4 +++- proto/babel/config.Y | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/proto/babel/babel.h b/proto/babel/babel.h index aea0dd88..7b5037ab 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -50,10 +50,12 @@ #define BABEL_INITIAL_HOP_COUNT 255 #define BABEL_MAX_SEND_INTERVAL 5 #define BABEL_TIME_UNITS 100 /* On-wire times are counted in centiseconds */ - #define BABEL_SEQNO_REQUEST_EXPIRY 60 #define BABEL_GARBAGE_INTERVAL 300 +/* Max interval that will not overflow when carried as 16-bit centiseconds */ +#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS) + #define BABEL_OVERHEAD (SIZE_OF_IP_HEADER+UDP_HEADER_LENGTH) #define BABEL_MIN_MTU (512 + BABEL_OVERHEAD) diff --git a/proto/babel/config.Y b/proto/babel/config.Y index e7ce6a93..b6170852 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -77,17 +77,18 @@ babel_iface_finish: BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED; } + /* Make sure we do not overflow the 16-bit centisec fields */ if (!BABEL_IFACE->update_interval) - BABEL_IFACE->update_interval = BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR; - BABEL_IFACE->ihu_interval = BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR; + BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL); + BABEL_IFACE->ihu_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR, BABEL_MAX_INTERVAL); }; babel_iface_item: | PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); } | RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); } - | HELLO INTERVAL expr { BABEL_IFACE->hello_interval = $3; if (($3<1) || ($3>65535)) cf_error("Invalid hello interval"); } - | UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>65535)) cf_error("Invalid hello interval"); } + | HELLO INTERVAL expr { BABEL_IFACE->hello_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid hello interval"); } + | UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid update interval"); } | TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; } | TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; } | RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); } From 12640c149976e1eca54d9c22c593d07a27c49d42 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 19 Jul 2016 12:16:51 +0200 Subject: [PATCH 12/45] Babel: Documentation updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the documentation to correctly mention Babel when protocols are listed, and adds examples and route attribute documentation to the Babel section of the docs. Signed-off-by: Toke Høiland-Jørgensen --- doc/bird.sgml | 34 +++++++++++++++++++++++++++++++--- nest/config.Y | 2 +- nest/rt-attr.c | 2 +- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index de7041a9..b90f65d1 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -610,8 +610,8 @@ agreement"). options, in that case for given interface the first matching interface option is used. - This option is allowed in BFD, Direct, OSPF, RAdv and RIP protocols, but - in OSPF protocol it is used in the Route type (Currently ] { yes. +Attributes + +

Babel defines just one attribute: the internal babel metric of the route. It +is exposed as the Example + +

+protocol babel { + interface "eth*" { + type wired; + }; + interface "wlan0", "wlan1" { + type wireless; + hello interval 1; + rxcost 512; + }; + interface "tap0"; + + # This matches the default of babeld: redistribute all addresses + # configured on local interfaces, plus re-distribute all routes received + # from other babel peers. + + export where (source = RTS_DEVICE) || (source = RTS_BABEL); +} + +

In Linux, there is also a plenty of obscure route attributes mostly focused diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 96688e34..6d6586d1 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -36,6 +36,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i) { return NULL; } #define EA_KRT_PREFSRC EA_CODE(EAP_KRT, 0x10) #define EA_KRT_REALM EA_CODE(EAP_KRT, 0x11) +#define EA_KRT_SCOPE EA_CODE(EAP_KRT, 0x12) #define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */ diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index a1c22f3e..f577244d 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -10,7 +10,7 @@ CF_HDR CF_DECLS -CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_MTU, KRT_WINDOW, +CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW, KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING, KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK, KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR, @@ -28,6 +28,7 @@ kern_sys_item: CF_ADDTO(dynamic_attr, KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); }) CF_ADDTO(dynamic_attr, KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); }) +CF_ADDTO(dynamic_attr, KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); }) CF_ADDTO(dynamic_attr, KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); }) CF_ADDTO(dynamic_attr, KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); }) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 9bdcc0d2..1490213e 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -899,7 +899,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d r.r.rtm_family = BIRD_AF; r.r.rtm_dst_len = net->n.pxlen; r.r.rtm_protocol = RTPROT_BIRD; - r.r.rtm_scope = RT_SCOPE_UNIVERSE; + r.r.rtm_scope = RT_SCOPE_NOWHERE; nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); /* @@ -928,6 +928,12 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d if (op == NL_OP_DELETE) goto dest; + /* Default scope is LINK for device routes, UNIVERSE otherwise */ + if (ea = ea_find(eattrs, EA_KRT_SCOPE)) + r.r.rtm_scope = ea->u.data; + else + r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); @@ -1135,6 +1141,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) u32 oif = ~0; u32 table; u32 priority = 0; + u32 def_scope = RT_SCOPE_UNIVERSE; int src; if (!(i = nl_checkin(h, sizeof(*i)))) @@ -1157,7 +1164,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } - if (a[RTA_DST]) { memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst)); @@ -1195,11 +1201,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) SKIP("strange class/scope\n"); - // ignore rtm_scope, it is not a real scope - // if (i->rtm_scope != RT_SCOPE_UNIVERSE) - // SKIP("scope %u\n", i->rtm_scope); - - switch (i->rtm_protocol) { case RTPROT_UNSPEC: @@ -1286,6 +1287,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) else { ra->dest = RTD_DEVICE; + def_scope = RT_SCOPE_LINK; } break; @@ -1304,6 +1306,19 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } + if (i->rtm_scope != def_scope) + { + ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr)); + ea->next = ra->eattrs; + ra->eattrs = ea; + ea->flags = EALF_SORTED; + ea->count = 1; + ea->attrs[0].id = EA_KRT_SCOPE; + ea->attrs[0].flags = 0; + ea->attrs[0].type = EAF_TYPE_INT; + ea->attrs[0].u.data = i->rtm_scope; + } + if (a[RTA_PREFSRC]) { ip_addr ps; @@ -1633,6 +1648,10 @@ krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED) bsprintf(buf, "realm"); return GA_NAME; + case EA_KRT_SCOPE: + bsprintf(buf, "scope"); + return GA_NAME; + case EA_KRT_LOCK: buf += bsprintf(buf, "lock:"); ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX); From 75ac3d199d1fd5b199dd753915234b8634c272e5 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 21 Sep 2016 12:07:59 +0200 Subject: [PATCH 40/45] Remove cvsignore We have gitignore --- .cvsignore | 1 - .gitignore | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 .cvsignore diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index dc557db3..00000000 --- a/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -bird.conf diff --git a/.gitignore b/.gitignore index 77dea498..52510836 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/autom4te.cache/ +/doc/*.html +/obj/ /Makefile /bird /birdc @@ -5,4 +8,5 @@ /config.log /config.status /configure -/obj/ +/bird.conf +/bird.log From 768d5e1058693d2bfb7c3bcbe04306097c3246a0 Mon Sep 17 00:00:00 2001 From: Pavel Tvrdik Date: Tue, 20 Sep 2016 15:13:01 +0200 Subject: [PATCH 41/45] Add !~ operator to filter grammar --- conf/cf-lex.l | 1 + conf/confbase.Y | 2 +- doc/bird.sgml | 38 +++++++++++++++++++------------------- filter/config.Y | 1 + filter/filter.c | 10 ++++++++++ 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 61ea4527..d2aa6402 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -246,6 +246,7 @@ else: { . \!\= return NEQ; +\!\~ return NMA; \<\= return LEQ; \>\= return GEQ; \&\& return AND; diff --git a/conf/confbase.Y b/conf/confbase.Y index 5f487c1d..c14c23c7 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -82,7 +82,7 @@ CF_DECLS %nonassoc PREFIX_DUMMY %left AND OR -%nonassoc '=' '<' '>' '~' GEQ LEQ NEQ PO PC +%nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC %left '+' '-' %left '*' '/' '%' %left '!' diff --git a/doc/bird.sgml b/doc/bird.sgml index af5b7980..07a2d470 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1016,9 +1016,9 @@ foot). of type @@ -1213,19 +1213,19 @@ foot).

The filter language supports common integer operators (+,-,*,/), parentheses There is one operator related to ROA infrastructure - ' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; } | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } + | term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; } | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; } | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } diff --git a/filter/filter.c b/filter/filter.c index ccdfed36..2f5f00d8 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -716,6 +716,16 @@ interpret(struct f_inst *what) runtime( "~ applied on unknown type pair" ); res.val.i = !!res.val.i; break; + + case P('!','~'): + TWOARGS; + res.type = T_BOOL; + res.val.i = val_in_range(v1, v2); + if (res.val.i == CMP_ERROR) + runtime( "!~ applied on unknown type pair" ); + res.val.i = !res.val.i; + break; + case P('d','e'): ONEARG; res.type = T_BOOL; From 79e2293ab2abbd92bb3326a95759a4ca32d9af81 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Thu, 22 Sep 2016 13:34:56 +0200 Subject: [PATCH 42/45] NEWS and version update --- NEWS | 13 +++++++++++++ misc/bird.spec | 2 +- sysdep/config.h | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index f689d195..525d7007 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,16 @@ +Version 1.6.1 (2016-09-22) + o Support for IPv6 ECMP + o Better handling of IPv6 tentative addresses + o Several updates and fixes in Babel protocol + o Filter: New !~ operator + o Filter: ASN ranges in bgpmask + o KRT: New kernel protocol option 'metric' + o KRT: New route attribute 'krt_scope' + o Improved BIRD help messages + o Fixes memory leak in BGP multipath + o Fixes handling of empty path segments in BGP AS_PATH + o Several bug fixes + Version 1.6.0 (2016-04-29) o Major RIP protocol redesign o New Babel routing protocol diff --git a/misc/bird.spec b/misc/bird.spec index 857f03e5..89531d64 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.6.0 +Version: 1.6.1 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/sysdep/config.h b/sysdep/config.h index a8d58349..e83a934f 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.6.0" +#define BIRD_VERSION "1.6.1" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" From ccd2a3eda24230df550e9880f4340fc6341c8f52 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Thu, 29 Sep 2016 12:00:53 +0200 Subject: [PATCH 43/45] Kernel socket missing err_hook fix Thanks to Tim Weippert for bugreport. --- sysdep/bsd/krt-sock.c | 7 +++++++ sysdep/linux/netlink.c | 7 +++++++ sysdep/unix/io.c | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 6ff3b2b7..f2ae81c3 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -911,6 +911,12 @@ krt_sock_hook(sock *sk, int size UNUSED) return 0; } +static void +krt_sock_err_hook(sock *sk, int e UNUSED) +{ + krt_sock_hook(sk, 0); +} + static sock * krt_sock_open(pool *pool, void *data, int table_id) { @@ -932,6 +938,7 @@ krt_sock_open(pool *pool, void *data, int table_id) sk = sk_new(pool); sk->type = SK_MAGIC; sk->rx_hook = krt_sock_hook; + sk->err_hook = krt_sock_err_hook; sk->fd = fd; sk->data = data; diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 1490213e..79dd1405 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1525,6 +1525,12 @@ nl_async_hook(sock *sk, int size UNUSED) return 1; } +static void +nl_async_err_hook(sock *sk, int e UNUSED) +{ + nl_async_hook(sk, 0); +} + static void nl_open_async(void) { @@ -1563,6 +1569,7 @@ nl_open_async(void) sk = nl_async_sk = sk_new(krt_pool); sk->type = SK_MAGIC; sk->rx_hook = nl_async_hook; + sk->err_hook = nl_async_err_hook; sk->fd = fd; if (sk_open(sk) < 0) bug("Netlink: sk_open failed"); diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 120eb906..3ceadd98 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1857,7 +1857,7 @@ void sk_err(sock *s, int revents) { int se = 0, sse = sizeof(se); - if (revents & POLLERR) + if ((s->type != SK_MAGIC) && (revents & POLLERR)) if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &se, &sse) < 0) { log(L_ERR "IO: Socket error: SO_ERROR: %m"); From 5bf35a9aee448ce7e3493ec7b80c84c8f5f39242 Mon Sep 17 00:00:00 2001 From: Pavel Tvrdik Date: Thu, 29 Sep 2016 13:28:18 +0200 Subject: [PATCH 44/45] Docs: fix BFD label BFD headline will appear in Table of Contents again. --- doc/bird.sgml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 07a2d470..26673f03 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1506,7 +1506,8 @@ protocol babel { -