From: Maria Matejka Date: Thu, 12 Oct 2023 12:12:33 +0000 (+0200) Subject: Merge commit '5121101136cb80151a9361c63dc4822afeb44eef' into thread-next X-Git-Tag: v3.0.0~394 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=767b7b22a0ff2baed1f30877570e1fbf1383a2ea;p=thirdparty%2Fbird.git Merge commit '5121101136cb80151a9361c63dc4822afeb44eef' into thread-next --- 767b7b22a0ff2baed1f30877570e1fbf1383a2ea diff --cc .gitlab-ci.yml index 1c8aa8692,c913d0f81..dc3960a76 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@@ -284,8 -258,15 +254,8 @@@ pkg-fedora-33-amd64 pkg-fedora-34-amd64: <<: *pkg-rpm needs: [build-fedora-34-amd64] - image: registry.labs.nic.cz/labs/bird:fedora-34-amd64 + image: registry.nic.cz/labs/bird:fedora-34-amd64 -#pkg-centos-7-amd64: -# <<: *pkg-rpm-wa -# variables: -# LC_ALL: en_US.UTF-8 -# needs: [build-centos-7-amd64] -# image: registry.nic.cz/labs/bird:centos-7-amd64 - pkg-centos-8-amd64: <<: *pkg-rpm-wa needs: [build-centos-8-amd64] diff --cc NEWS index c0ccaa8e7,30f3b9326..5e51a2bdc --- a/NEWS +++ b/NEWS @@@ -1,34 -1,9 +1,40 @@@ +Version 3.0alpha2 (2023-05-11) + o Fixed memory leaks and use-after free bugs + o Simple thread work balancing + o MRT switched off + o Slow kernel route synchronization to be fixed later + +Version 3.0alpha1 (2023-04-18) + o Worker threads for BGP, Pipe, RPKI and BFD + o Configurable number of threads + o Asynchronous route export + o Flat attribute structure + o Inline import tables + o Export tables merged with BGP prefix / attribute buckets + o Fixed ROA check locking inversion in route table dumps + o MRT switched off + +Version 3.0-alpha0 (2022-02-07) + o Removal of fixed protocol-specific route attributes + o Asynchronous route export + o Explicit table import / export hooks + o Partially lockless route attribute cache + o Thread-safe resource management + o Thread-safe interface notifications + o Thread-safe protocol API + o Adoption of BFD IO loop for general use + o Parallel Pipe protocol + o Parallel RPKI protocol + o Parallel BGP protocol + o Lots of refactoring + o Bugfixes and improvements as they came along + + Version 2.13.1 (2023-06-23) + o BGP: Fix role check when no capability option is present + o Filter: Fixed segfault when a case option had an empty block + + This is a bugfix version. + Version 2.13 (2023-04-21) o Babel: IPv4 via IPv6 extension (RFC 9229) o Babel: Improve authentication on lossy networks diff --cc conf/confbase.Y index 8e5da9e3f,3dd5fed7f..4873696ca --- a/conf/confbase.Y +++ b/conf/confbase.Y @@@ -94,9 -93,8 +94,9 @@@ CF_DECL struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; - mpls_label_stack *mls; + struct settle_config settle; + struct adata *ad; - struct bytestring *bs; + const struct bytestring *bs; } %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT diff --cc filter/decl.m4 index 3179a331d,7c863bdc4..ed7630fc9 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@@ -200,8 -200,7 +200,8 @@@ FID_INTERPRET_BODY()' # Executing another filter line. This replaces the recursion # that was needed in the former implementation. m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()') - m4_define(LINEX_, `do { + m4_define(LINEX_, `do if ($1) { + if (fstk->ecnt + 1 >= fstk->elen) runtime("Filter execution stack overflow"); fstk->estk[fstk->ecnt].pos = 0; fstk->estk[fstk->ecnt].line = $1; fstk->estk[fstk->ecnt].ventry = fstk->vcnt; diff --cc lib/timer.h index 4a3a21083,0f87852bd..34b53aa6f --- a/lib/timer.h +++ b/lib/timer.h @@@ -39,22 -31,24 +39,25 @@@ typedef struct time struct timeloop { BUFFER_(timer *) timers; - btime last_time; - btime real_time; + struct domain_generic *domain; + struct birdloop *loop; }; +#define TLOCK_TIMER_ASSERT(loop) ASSERT_DIE((loop)->domain && DG_IS_LOCKED((loop)->domain)) +#define TLOCK_LOCAL_ASSERT(loop) ASSERT_DIE(!(loop)->domain || DG_IS_LOCKED((loop)->domain)) + static inline uint timers_count(struct timeloop *loop) -{ return loop->timers.used - 1; } +{ TLOCK_TIMER_ASSERT(loop); return loop->timers.used - 1; } static inline timer *timers_first(struct timeloop *loop) -{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; } - -extern struct timeloop main_timeloop; +{ TLOCK_TIMER_ASSERT(loop); return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; } -btime current_time(void); -btime current_real_time(void); +#define current_time() atomic_load_explicit(&last_time, memory_order_acquire) +#define current_real_time() atomic_load_explicit(&real_time, memory_order_acquire) + /* In sysdep code */ + btime current_time_now(void); + //#define now (current_time() TO_S) //#define now_real (current_real_time() TO_S) extern btime boot_time; diff --cc nest/Makefile index 1a71c2fbd,5a244c756..bb141f5c3 --- a/nest/Makefile +++ b/nest/Makefile @@@ -13,6 -9,6 +13,6 @@@ $(o)proto-build.c: Makefile $(lastword prepare: $(o)proto-build.c - tests_src := -tests_src := a-set_test.c a-path_test.c rt-fib_test.c ++tests_src := rt-fib_test.c tests_targets := $(tests_targets) $(tests-target-files) tests_objs := $(tests_objs) $(src-o-files) diff --cc nest/rt-fib_test.c index 000000000,2dd7ce8a3..b796cc682 mode 000000,100644..100644 --- a/nest/rt-fib_test.c +++ b/nest/rt-fib_test.c @@@ -1,0 -1,246 +1,240 @@@ + /* + * BIRD -- Forwarding Information Base -- Tests + * + * (c) 2023 CZ.NIC z.s.p.o. + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + + #include "test/birdtest.h" + #include "test/bt-utils.h" + -#include "nest/route.h" ++#include "nest/rt.h" + + + #define TESTS_NUM 10 + #define PREFIXES_NUM 400000 + #define PREFIX_TESTS_NUM 200000 + #define PREFIX_BENCH_MAX 1000000 + #define PREFIX_BENCH_NUM 10000000 + + struct test_node + { + int pos; + struct fib_node n; + }; + + static inline int net_match(struct test_node *tn, net_addr *query, net_addr *data) + { return (tn->pos < PREFIXES_NUM) && net_equal(query, &data[tn->pos]); } + + static int + t_match_random_net(void) + { - bt_bird_init(); + bt_config_parse(BT_CONFIG_SIMPLE); + + for (int round = 0; round < TESTS_NUM; round++) + { + int type = !(round & 1) ? NET_IP4 : NET_IP6; + - pool *p = rp_new(&root_pool, "FIB pool"); ++ pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool"); + net_addr *nets = bt_random_nets(type, PREFIXES_NUM); + + /* Make FIB structure */ + struct fib f; + fib_init(&f, &root_pool, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 4, NULL); + + for (int i = 0; i < PREFIXES_NUM; i++) + { + struct test_node *tn = fib_get(&f, &nets[i]); + bt_assert(!tn->pos || net_match(tn, &nets[i], nets)); + tn->pos = i; + } + + /* Test (mostly) negative matches */ + for (int i = 0; i < PREFIX_TESTS_NUM; i++) + { + net_addr net; + bt_random_net(&net, type); + + struct test_node *tn = fib_find(&f, &net); + bt_assert(!tn || net_match(tn, &net, nets)); + } + + /* Test positive matches */ + for (int i = 0; i < PREFIX_TESTS_NUM; i++) + { + int j = bt_random_n(PREFIXES_NUM); + + struct test_node *tn = fib_find(&f, &nets[j]); + bt_assert(tn && net_match(tn, &nets[j], nets)); + } + + rfree(p); + tmp_flush(); + } + - bt_bird_cleanup(); + return 1; + } + + static int + t_fib_walk(void) + { - bt_bird_init(); + bt_config_parse(BT_CONFIG_SIMPLE); + + for (int round = 0; round < TESTS_NUM; round++) + { + int type = !(round & 1) ? NET_IP4 : NET_IP6; + - pool *p = rp_new(&root_pool, "FIB pool"); ++ pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool"); + net_addr *nets = bt_random_nets(type, PREFIXES_NUM); + byte *marks = tmp_allocz(PREFIXES_NUM); + + /* Make FIB structure */ + struct fib f; + fib_init(&f, p, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 4, NULL); + + for (int i = 1; i < PREFIXES_NUM; i++) + { + struct test_node *tn = fib_get(&f, &nets[i]); + bt_assert(!tn->pos || net_match(tn, &nets[i], nets)); + if (tn->pos) + { + /* Mark dupicate nets */ + bt_assert(!marks[tn->pos]); + marks[tn->pos] = 1; + } + tn->pos = i; + } + + /* Walk FIB and mark nets */ + FIB_WALK(&f, struct test_node, tn) + { + bt_assert(!marks[tn->pos]); + marks[tn->pos] = 1; + } + FIB_WALK_END; + + /* Check in all nets are marked */ + for (int i = 1; i < PREFIXES_NUM; i++) + bt_assert(marks[i]); + + rfree(p); + tmp_flush(); + } + - bt_bird_cleanup(); + return 1; + } + + static int + benchmark_fib_dataset(const char *filename, int type) + { + net_addr *nets, *test_r, *test_s; + uint n = PREFIX_BENCH_MAX; + int tn = PREFIX_BENCH_NUM; + int match; + + bt_reset_suite_case_timer(); + bt_log_suite_case_result(1, "Reading %s", filename, n); + nets = bt_read_net_file(filename, type, &n); + bt_log_suite_case_result(1, "Read net data, %u nets", n); + bt_reset_suite_case_timer(); + - pool *p = rp_new(&root_pool, "FIB pool"); ++ pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool"); + + /* Make FIB structure */ + struct fib f; + fib_init(&f, p, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 0, NULL); + + for (int i = 0; i < (int) n; i++) + { + struct test_node *tn = fib_get(&f, &nets[i]); + tn->pos = i; + } + + bt_log_suite_case_result(1, "Fill FIB structure, %u nets, order %u", n, f.hash_order); + bt_reset_suite_case_timer(); + + /* Compute FIB size */ + size_t fib_size = rmemsize(p).effective * 1000 / (1024*1024); + bt_log_suite_case_result(1, "FIB size: %u.%03u MB", (uint) (fib_size / 1000), (uint) (fib_size % 1000)); + + /* Compute FIB histogram */ + uint hist[16] = {}; + uint sum = 0; + for (uint i = 0; i < f.hash_size; i++) + { + int len = 0; + for (struct fib_node *fn = f.hash_table[i]; fn; fn = fn->next) + len++; + + sum += len; + len = MIN(len, 15); + hist[len]++; + } + bt_log_suite_case_result(1, "FIB histogram:"); + for (uint i = 0; i < 16; i++) + if (hist[i]) + bt_log_suite_case_result(1, "%02u: %8u", i, hist[i]); + + uint avg = (sum * 1000) / (f.hash_size - hist[0]); + bt_log_suite_case_result(1, "FIB chain length: %u.%03u", (uint) (avg / 1000), (uint) (avg % 1000)); + bt_reset_suite_case_timer(); + + /* Make test data */ + test_r = bt_random_nets(type, tn); + test_s = bt_random_net_subset(nets, n, tn); + + bt_log_suite_case_result(1, "Make test data, 2x %u nets", tn); + bt_reset_suite_case_timer(); + + /* Test (mostly negative) random matches */ + match = 0; + for (int i = 0; i < tn; i++) + if (fib_find(&f, &test_r[i])) + match++; + + bt_log_suite_case_result(1, "Random match, %d / %d matches", match, tn); + bt_reset_suite_case_timer(); + + /* Test (positive) subset matches */ + match = 0; + for (int i = 0; i < tn; i++) + if (fib_find(&f, &test_s[i])) + match++; + + bt_log_suite_case_result(1, "Subset match, %d / %d matches", match, tn); + bt_log_suite_case_result(1, ""); + bt_reset_suite_case_timer(); + + rfree(p); + tmp_flush(); + return 1; + } + + static int UNUSED + t_bench_fib_datasets(void) + { - bt_bird_init(); + bt_config_parse(BT_CONFIG_SIMPLE); + + /* Specific datasets, not included */ + benchmark_fib_dataset("fib-data-bgp-v4-1", NET_IP4); + benchmark_fib_dataset("fib-data-bgp-v4-10", NET_IP4); + benchmark_fib_dataset("fib-data-bgp-v6-1", NET_IP6); + benchmark_fib_dataset("fib-data-bgp-v6-10", NET_IP6); + - bt_bird_cleanup(); - + return 1; + } + + int + main(int argc, char *argv[]) + { + bt_init(argc, argv); ++ bt_bird_init(); + + bt_test_suite(t_match_random_net, "Testing random prefix matching"); + bt_test_suite(t_fib_walk, "Testing FIB_WALK() on random FIB"); + + // bt_test_suite(t_bench_fib_datasets, "Benchmark FIB from datasets by random subset of nets"); + + return bt_exit_value(); + } diff --cc proto/babel/config.Y index 6d1ad7d0f,b8af02679..28bf8027b --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@@ -24,9 -24,9 +24,9 @@@ CF_DECL CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK, - NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS, + NEXT, HOP, IPV4, IPV6, SHOW, INTERFACES, NEIGHBORS, ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE, - EXTENDED) + EXTENDED, TUNNEL, RTT, MIN, MAX, DECAY, SEND, TIMESTAMPS) CF_GRAMMAR diff --cc proto/radv/config.Y index fb68d2e51,eeafe6f45..3c9755170 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@@ -33,7 -42,7 +42,7 @@@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MI RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE, - ROUTES) - ROUTES, RA_PREFERENCE, RA_LIFETIME, CUSTOM, OPTION, TYPE, VALUE) ++ ROUTES, CUSTOM, OPTION, TYPE, VALUE) CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH) diff --cc sysdep/linux/netlink.c index e8a86ce4f,e3298a0f5..3cc3bb9b2 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@@ -1760,17 -1655,15 +1758,15 @@@ nl_parse_route(struct nl_parse_state *s } if (a[RTA_GATEWAY]) - ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]); + nhad.nh.gw = rta_get_ipa(a[RTA_GATEWAY]); - #ifdef HAVE_MPLS_KERNEL if (a[RTA_VIA]) - ra->nh.gw = rta_get_via(a[RTA_VIA]); + nhad.nh.gw = rta_get_via(a[RTA_VIA]); - #endif if (i->rtm_flags & RTNH_F_ONLINK) - ra->nh.flags |= RNF_ONLINK; + nhad.nh.flags |= RNF_ONLINK; - if (ipa_nonzero(ra->nh.gw)) + if (ipa_nonzero(nhad.nh.gw)) { /* Silently skip strange 6to4 routes */ const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96); diff --cc sysdep/unix/io.c index 83149a964,6aedcfb66..11dfb2e4e --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@@ -259,25 -168,23 +259,38 @@@ times_update(void if (rv < 0) die("clock_gettime: %m"); - loop->real_time = ts.tv_sec S + ts.tv_nsec NS; + btime new_real_time = ts.tv_sec S + ts.tv_nsec NS; + + if (!atomic_compare_exchange_strong_explicit( + &last_time, + &old_time, + new_time, + memory_order_acq_rel, + memory_order_relaxed)) + DBG("Time update collision: last_time"); + + if (!atomic_compare_exchange_strong_explicit( + &real_time, + &old_real_time, + new_real_time, + memory_order_acq_rel, + memory_order_relaxed)) + DBG("Time update collision: real_time"); } + btime + current_time_now(void) + { + struct timespec ts; + int rv; + + rv = clock_gettime(CLOCK_MONOTONIC, &ts); + if (rv < 0) + die("clock_gettime: %m"); + + return ts.tv_sec S + ts.tv_nsec NS; + } + - /** * DOC: Sockets * diff --cc test/bt-utils.h index 758dbf48b,d29a0b7c8..031db6e88 --- a/test/bt-utils.h +++ b/test/bt-utils.h @@@ -26,8 -26,15 +26,14 @@@ uint bt_naive_pow(uint base, uint power); void bt_bytes_to_hex(char *buf, const byte *in_data, size_t size); + void bt_random_net(net_addr *net, int type); + net_addr *bt_random_nets(int type, uint n); + net_addr *bt_random_net_subset(net_addr *src, uint sn, uint dn); + void bt_read_net(const char *str, net_addr *net, int type); + net_addr *bt_read_nets(FILE *f, int type, uint *n); + net_addr *bt_read_net_file(const char *filename, int type, uint *n); void bt_bird_init(void); -void bt_bird_cleanup(void); struct config *bt_config_parse(const char *cfg); struct config *bt_config_file_parse(const char *filepath);