diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 39202098..0a758cff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ variables: LC_ALL: C.UTF-8 GIT_STRATEGY: fetch DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/" - IMG_BASE: registry.labs.nic.cz/labs/bird + IMG_BASE: registry.nic.cz/labs/bird TOOLS_DIR: /var/lib/gitlab-runner/bird-tools stages: @@ -16,7 +16,7 @@ stages: stage: image allow_failure: true script: - - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz + - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.nic.cz # Make sure we refresh the base image if it updates (eg. security updates, etc) # If we do just the build, cache is always reused and the freshness of the # base image is never checked. However, pull always asks and updates the @@ -154,9 +154,9 @@ docker_ubuntu-20_04-amd64: IMG_NAME: "ubuntu-20.04-amd64" <<: *docker_build -docker_ubuntu-20_10-amd64: +docker_ubuntu-21_10-amd64: variables: - IMG_NAME: "ubuntu-20.10-amd64" + IMG_NAME: "ubuntu-21.10-amd64" <<: *docker_build # GPG error @@ -224,135 +224,135 @@ docker_opensuse-15.3-amd64: build-debian-8-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-8-amd64 + image: registry.nic.cz/labs/bird:debian-8-amd64 build-debian-8-i386: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-8-i386 + image: registry.nic.cz/labs/bird:debian-8-i386 build-debian-9-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-9-amd64 + image: registry.nic.cz/labs/bird:debian-9-amd64 build-debian-9-i386: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-9-i386 + image: registry.nic.cz/labs/bird:debian-9-i386 build-debian-10-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-10-amd64 + image: registry.nic.cz/labs/bird:debian-10-amd64 build-debian-10-i386: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-10-i386 + image: registry.nic.cz/labs/bird:debian-10-i386 build-debian-11-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-11-amd64 + image: registry.nic.cz/labs/bird:debian-11-amd64 #build-debian-11-i386: # <<: *build-linux -# image: registry.labs.nic.cz/labs/bird:debian-11-i386 +# image: registry.nic.cz/labs/bird:debian-11-i386 build-debian-testing-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:debian-testing-amd64 + image: registry.nic.cz/labs/bird:debian-testing-amd64 #build-debian-testing-i386: # <<: *build-linux -# image: registry.labs.nic.cz/labs/bird:debian-testing-i386 +# image: registry.nic.cz/labs/bird:debian-testing-i386 build-fedora-25-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-25-amd64 + image: registry.nic.cz/labs/bird:fedora-25-amd64 build-fedora-26-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-26-amd64 + image: registry.nic.cz/labs/bird:fedora-26-amd64 build-fedora-27-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-27-amd64 + image: registry.nic.cz/labs/bird:fedora-27-amd64 build-fedora-28-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-28-amd64 + image: registry.nic.cz/labs/bird:fedora-28-amd64 build-fedora-29-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-29-amd64 + image: registry.nic.cz/labs/bird:fedora-29-amd64 build-fedora-30-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-30-amd64 + image: registry.nic.cz/labs/bird:fedora-30-amd64 build-fedora-31-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-31-amd64 + image: registry.nic.cz/labs/bird:fedora-31-amd64 build-fedora-32-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-32-amd64 + image: registry.nic.cz/labs/bird:fedora-32-amd64 build-fedora-33-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-33-amd64 + image: registry.nic.cz/labs/bird:fedora-33-amd64 build-fedora-34-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:fedora-33-amd64 + image: registry.nic.cz/labs/bird:fedora-33-amd64 build-centos-8-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:centos-8-amd64 + image: registry.nic.cz/labs/bird:centos-8-amd64 build-ubuntu-16_04-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:ubuntu-16.04-amd64 + image: registry.nic.cz/labs/bird:ubuntu-16.04-amd64 build-ubuntu-18_04-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:ubuntu-18.04-amd64 + image: registry.nic.cz/labs/bird:ubuntu-18.04-amd64 build-ubuntu-20_04-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:ubuntu-20.04-amd64 + image: registry.nic.cz/labs/bird:ubuntu-20.04-amd64 -build-ubuntu-20_10-amd64: +build-ubuntu-21_10-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:ubuntu-20.10-amd64 + image: registry.nic.cz/labs/bird:ubuntu-21.10-amd64 #build-ubuntu-21_04-amd64: # <<: *build-linux -# image: registry.labs.nic.cz/labs/bird:ubuntu-21.04-amd64 +# image: registry.nic.cz/labs/bird:ubuntu-21.04-amd64 build-opensuse-15.0-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:opensuse-15.0-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.0-amd64 build-opensuse-15.1-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:opensuse-15.1-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.1-amd64 build-opensuse-15.2-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:opensuse-15.2-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.2-amd64 build-opensuse-15.3-amd64: <<: *build-linux - image: registry.labs.nic.cz/labs/bird:opensuse-15.3-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.3-amd64 -build-freebsd-11-amd64: - <<: *build-base - tags: - - freebsd - - amd64 +#build-freebsd-11-amd64: +# <<: *build-base +# tags: +# - freebsd +# - amd64 -build-freebsd-11-i386: - <<: *build-base - tags: - - freebsd - - i386 +#build-freebsd-11-i386: +# <<: *build-base +# tags: +# - freebsd +# - i386 .pkg-deb: &pkg-deb @@ -390,60 +390,60 @@ build-freebsd-11-i386: #pkg-debian-8-amd64: # <<: *pkg-deb # needs: [build-debian-8-amd64] -# image: registry.labs.nic.cz/labs/bird:debian-8-amd64 +# image: registry.nic.cz/labs/bird:debian-8-amd64 # Dpkg error: PATH is not set #pkg-debian-8-i386: # <<: *pkg-deb # needs: [build-debian-8-i386] -# image: registry.labs.nic.cz/labs/bird:debian-8-i386 +# image: registry.nic.cz/labs/bird:debian-8-i386 # Dpkg error: PATH is not set pkg-debian-9-amd64: <<: *pkg-deb needs: [build-debian-9-amd64] - image: registry.labs.nic.cz/labs/bird:debian-9-amd64 + image: registry.nic.cz/labs/bird:debian-9-amd64 # Dpkg error: PATH is not set pkg-debian-9-i386: <<: *pkg-deb needs: [build-debian-9-i386] - image: registry.labs.nic.cz/labs/bird:debian-9-i386 + image: registry.nic.cz/labs/bird:debian-9-i386 pkg-debian-10-amd64: <<: *pkg-deb needs: [build-debian-10-amd64] - image: registry.labs.nic.cz/labs/bird:debian-10-amd64 + image: registry.nic.cz/labs/bird:debian-10-amd64 pkg-debian-10-i386: <<: *pkg-deb needs: [build-debian-10-i386] - image: registry.labs.nic.cz/labs/bird:debian-10-i386 + image: registry.nic.cz/labs/bird:debian-10-i386 pkg-debian-11-amd64: <<: *pkg-deb needs: [build-debian-11-amd64] - image: registry.labs.nic.cz/labs/bird:debian-11-amd64 + image: registry.nic.cz/labs/bird:debian-11-amd64 pkg-fedora-30-amd64: <<: *pkg-rpm-wa needs: [build-fedora-30-amd64] - image: registry.labs.nic.cz/labs/bird:fedora-30-amd64 + image: registry.nic.cz/labs/bird:fedora-30-amd64 pkg-fedora-31-amd64: <<: *pkg-rpm-wa needs: [build-fedora-31-amd64] - image: registry.labs.nic.cz/labs/bird:fedora-31-amd64 + image: registry.nic.cz/labs/bird:fedora-31-amd64 pkg-fedora-32-amd64: <<: *pkg-rpm-wa needs: [build-fedora-32-amd64] - image: registry.labs.nic.cz/labs/bird:fedora-32-amd64 + image: registry.nic.cz/labs/bird:fedora-32-amd64 pkg-fedora-33-amd64: <<: *pkg-rpm-wa needs: [build-fedora-33-amd64] - image: registry.labs.nic.cz/labs/bird:fedora-33-amd64 + image: registry.nic.cz/labs/bird:fedora-33-amd64 pkg-fedora-34-amd64: <<: *pkg-rpm @@ -453,42 +453,43 @@ pkg-fedora-34-amd64: pkg-centos-8-amd64: <<: *pkg-rpm-wa needs: [build-centos-8-amd64] - image: registry.labs.nic.cz/labs/bird:centos-8-amd64 + image: registry.nic.cz/labs/bird:centos-8-amd64 pkg-ubuntu-18.04-amd64: <<: *pkg-deb needs: [build-ubuntu-18_04-amd64] - image: registry.labs.nic.cz/labs/bird:ubuntu-18.04-amd64 + image: registry.nic.cz/labs/bird:ubuntu-18.04-amd64 pkg-ubuntu-20.04-amd64: <<: *pkg-deb needs: [build-ubuntu-20_04-amd64] - image: registry.labs.nic.cz/labs/bird:ubuntu-20.04-amd64 + image: registry.nic.cz/labs/bird:ubuntu-20.04-amd64 -pkg-ubuntu-20.10-amd64: + +pkg-ubuntu-21.10-amd64: <<: *pkg-deb - needs: [build-ubuntu-20_10-amd64] - image: registry.labs.nic.cz/labs/bird:ubuntu-20.10-amd64 + needs: [build-ubuntu-21_10-amd64] + image: registry.nic.cz/labs/bird:ubuntu-21.10-amd64 #pkg-ubuntu-21.04-amd64: # <<: *pkg-deb # needs: [build-ubuntu-21_04-amd64] -# image: registry.labs.nic.cz/labs/bird:ubuntu-21.04-amd64 +# image: registry.nic.cz/labs/bird:ubuntu-21.04-amd64 pkg-opensuse-15.1-amd64: <<: *pkg-rpm-wa needs: [build-opensuse-15.1-amd64] - image: registry.labs.nic.cz/labs/bird:opensuse-15.1-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.1-amd64 pkg-opensuse-15.2-amd64: <<: *pkg-rpm-wa needs: [build-opensuse-15.2-amd64] - image: registry.labs.nic.cz/labs/bird:opensuse-15.2-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.2-amd64 pkg-opensuse-15.3-amd64: <<: *pkg-rpm-wa needs: [build-opensuse-15.3-amd64] - image: registry.labs.nic.cz/labs/bird:opensuse-15.3-amd64 + image: registry.nic.cz/labs/bird:opensuse-15.3-amd64 build-birdlab: @@ -557,6 +558,11 @@ test-ospf-custom: variables: TEST_NAME: cf-ospf-custom +test-ospf-area: + <<: *test-base + variables: + TEST_NAME: cf-ospf-area + test-ospf-vrf: <<: *test-base variables: @@ -611,3 +617,8 @@ test-babel-auth: <<: *test-base variables: TEST_NAME: cf-babel-auth + +test-rip-base: + <<: *test-base + variables: + TEST_NAME: cf-rip-base diff --git a/Makefile.in b/Makefile.in index e0ff4a1d..0d55807b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -82,6 +82,9 @@ conf-lex-targets := $(addprefix $(objdir)/conf/,cf-lex.o) conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) cf-local = $(conf-y-targets): $(s)config.Y +# nest/Makefile declarations needed for all other modules +proto-build-c := $(addprefix $(objdir)/nest/,proto-build.c) + src-o-files = $(patsubst %.c,$(o)%.o,$(src)) tests-target-files = $(patsubst %.c,$(o)%,$(tests_src)) @@ -95,6 +98,13 @@ else o = $(patsubst $(srcdir)%,$(objdir)%,$(s)) endif +define proto-build_in = +PROTO_BUILD += $(1) +$(proto-build-c): $(lastword $(MAKEFILE_LIST)) +endef + +proto-build = $(eval $(call proto-build_in,$(1))) + define clean_in = clean:: rm -f $(addprefix $(o),$(1)) diff --git a/NEWS b/NEWS index 4a85c365..e61a0b74 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,46 @@ +Version 2.0.10 (2022-06-16) + o BGP performance improvements + o BFD: New 'strict bind' option + o RPKI: VRF support + o Allow use of 240.0.0.0/4 as a private range + o BIRD client uses exit status to report errors + o Important bugfixes + +Version 2.0.9 (2022-02-09) + o BGP: Flowspec validation procedure + o Babel: MAC authentication support + o Routing table configuration blocks + o Optional prefix trie in routing table for faster LPM/interval queries + o CLI: New 'show route in ' command + o Filter: Faster (16-way) prefix sets + o Filter: MPLS label route attribute + o Filter: Operators to pick community components + o Filter: Operators to find minimum and maximum element of lists + o BGP: New 'free bind' option + o BGP: Log route updates that were changed to withdraws + o BGP: Improved 'invalid next hop' error reporting + o OSPF: Allow ifaces with host address as unnumbered PtP or PtMP ifaces + o OSPF: All packets on PtP networks should be sent to AllSPFRouters address + o Scripts for apkg-powered upstream packaging for deb and rpm + o Support for Blake2s and Blake2b hash functions + o Security keys / passwords can be entered in hexadecimal digits + o Memory statistics split into Effective and Overhead + o Linux: New option 'netlink rx buffer' to specify netlink socket buffer size + o BSD: Assume onlink flag on ifaces with only host addresses + o Many bugfixes + + Notes: + + For OSPF on PtP network, BIRD now sends all packets to multicast AllSPFRouters + address (as required in RFC 2328 8.1). This likely breaks setups with multiple + neighbors on a network configured as PtP, which worked in previous versions. + Such links should be configured as PtMP. + + Since Linux 5.3, netlink socket can be flooded by route cache entries during + route table scan. This version mitigates that issue by using strict netlink + filtering. + + Version 2.0.8 (2021-03-18) o Automatic channel reloads based on RPKI changes o Multiple static routes with the same network diff --git a/aclocal.m4 b/aclocal.m4 index 3405b85b..cc45b54a 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -2,6 +2,32 @@ dnl ** Additional Autoconf tests for BIRD configure script dnl ** (c) 1999 Martin Mares dnl ** (c) 2021 Maria Matejka +AC_DEFUN([BIRD_CHECK_POINTER_ALIGNMENT], +[ + AC_CACHE_CHECK( + [how pointers are aligned], + [bird_cv_pointer_alignment], + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [ + _Static_assert(_Alignof(void *) == 8, "bad"); + ], [] + ) + ], + [bird_cv_pointer_alignment=8], + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM( + [ + _Static_assert(_Alignof(void *) == 4, "bad"); + ], [] + ) + ], + [bird_cv_pointer_alignment=4], + [bird_cv_pointer_alignment=unknown] + )) + ) +]) + AC_DEFUN([BIRD_CHECK_THREAD_LOCAL], [ AC_CACHE_CHECK( diff --git a/bird-gdb.py b/bird-gdb.py index c7351d6b..077703f9 100644 --- a/bird-gdb.py +++ b/bird-gdb.py @@ -25,7 +25,6 @@ class BIRDFValPrinter(BIRDPrinter): "T_ENUM_RTS": "i", "T_ENUM_BGP_ORIGIN": "i", "T_ENUM_SCOPE": "i", - "T_ENUM_RTC": "i", "T_ENUM_RTD": "i", "T_ENUM_ROA": "i", "T_ENUM_NETTYPE": "i", diff --git a/client/client.c b/client/client.c index 97cf6639..934e16e0 100644 --- a/client/client.c +++ b/client/client.c @@ -50,6 +50,7 @@ static byte *server_read_pos = server_read_buf; int init = 1; /* During intial sequence */ int busy = 1; /* Executing BIRD command */ int interactive; /* Whether stdin is terminal */ +int last_code; /* Last return code */ static int num_lines, skip_input; int term_lns, term_cls; @@ -196,7 +197,7 @@ init_commands(void) { /* Initial command is finished and we want to exit */ cleanup(); - exit(0); + exit((last_code < 8000) ? 0 : 1); } input_init(); @@ -283,6 +284,8 @@ server_got_reply(char *x) if (code) PRINTF(len, "%s\n", verbose ? x : x+5); + last_code = code; + if (x[4] == ' ') { busy = 0; diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 704a1750..04e0b3a5 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -42,7 +42,7 @@ #define PARSER 1 #include "nest/bird.h" -#include "nest/route.h" +#include "nest/rt.h" #include "nest/protocol.h" #include "filter/filter.h" #include "filter/f-inst.h" @@ -77,19 +77,22 @@ static uint cf_hash(const byte *c); #define SYM_NEXT(n) n->next #define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2 #define SYM_FN(k,s) cf_hash(k) -#define SYM_ORDER 6 /* Initial */ +#define SYM_ORDER 4 /* Initial */ #define SYM_REHASH sym_rehash -#define SYM_PARAMS /8, *1, 2, 2, 6, 20 +#define SYM_PARAMS /8, *1, 2, 2, 4, 20 HASH_DEFINE_REHASH_FN(SYM, struct symbol) HASH(struct keyword) kw_hash; - +HASH(struct ea_class) ea_name_hash; struct sym_scope *conf_this_scope; +static struct sym_scope global_root_scope__init = { .active = 1, }; +struct sym_scope *global_root_scope = &global_root_scope__init; + linpool *cfg_mem; int (*cf_read_hook)(byte *buf, unsigned int max, int fd); @@ -255,7 +258,7 @@ WHITE [ \t] return IP4; } -{XIGIT}{2}(:{XIGIT}{2}|{XIGIT}{2}){15,} { +{XIGIT}{2}((:{XIGIT}{2}){15,}|({XIGIT}{2}){15,}) { char *s = yytext; size_t len = 0, i; struct bytestring *bytes; @@ -347,7 +350,7 @@ else: { return DDOT; } -[={}:;,.()+*/%<>~\[\]?!\|-] { +[={}:;,.()+*/%<>~\[\]?!\|&-] { return yytext[0]; } @@ -574,6 +577,8 @@ check_eof(void) return 0; } +static inline void cf_swap_soft_scope(void); + static struct symbol * cf_new_symbol(const byte *c) { @@ -583,45 +588,64 @@ cf_new_symbol(const byte *c) if (l > SYM_MAX_LEN) cf_error("Symbol too long"); + cf_swap_soft_scope(); + s = cfg_allocz(sizeof(struct symbol) + l + 1); *s = (struct symbol) { .scope = conf_this_scope, .class = SYM_VOID, }; strcpy(s->name, c); - if (!new_config->sym_hash.data) - HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER); + if (!conf_this_scope->hash.data) + HASH_INIT(conf_this_scope->hash, new_config->pool, SYM_ORDER); - HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s); + HASH_INSERT2(conf_this_scope->hash, SYM, new_config->pool, s); - add_tail(&(new_config->symbols), &(s->n)); + if (conf_this_scope == new_config->root_scope) + add_tail(&(new_config->symbols), &(s->n)); return s; } +static struct symbol * +cf_root_symbol(const byte *c) +{ + uint l = strlen(c); + if (l > SYM_MAX_LEN) + bug("Root symbol %s too long", c); + + struct symbol *s = mb_alloc(&root_pool, sizeof(struct symbol) + l + 1); + *s = (struct symbol) { .scope = global_root_scope, .class = SYM_VOID, }; + memcpy(s->name, c, l+1); + + if (!global_root_scope->hash.data) + HASH_INIT(global_root_scope->hash, &root_pool, SYM_ORDER); + + HASH_INSERT2(global_root_scope->hash, SYM, &root_pool, s); + return s; +} + + /** - * cf_find_symbol - find a symbol by name - * @cfg: specificed config + * cf_find_symbol_scope - find a symbol by name + * @scope: config scope * @c: symbol name * - * This functions searches the symbol table in the config @cfg for a symbol of - * given name. First it examines the current scope, then the second recent one + * This functions searches the symbol table in the scope @scope for a symbol of + * given name. First it examines the current scope, then the underlying one * and so on until it either finds the symbol and returns a pointer to its * &symbol structure or reaches the end of the scope chain and returns %NULL to * signify no match. */ struct symbol * -cf_find_symbol(const struct config *cfg, const byte *c) +cf_find_symbol_scope(const struct sym_scope *scope, const byte *c) { struct symbol *s; - if (cfg->sym_hash.data && - (s = HASH_FIND(cfg->sym_hash, SYM, c, 1))) - return s; - - /* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */ - if (cfg->fallback && - cfg->fallback->sym_hash.data && - (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1))) - return s; + /* Find the symbol here or anywhere below */ + while (scope) + if (scope->hash.data && (s = HASH_FIND(scope->hash, SYM, c, 1))) + return s; + else + scope = scope->next; return NULL; } @@ -638,7 +662,7 @@ cf_find_symbol(const struct config *cfg, const byte *c) struct symbol * cf_get_symbol(const byte *c) { - return cf_find_symbol(new_config, c) ?: cf_new_symbol(c); + return cf_find_symbol_scope(conf_this_scope, c) ?: cf_new_symbol(c); } /** @@ -654,10 +678,10 @@ cf_localize_symbol(struct symbol *sym) /* If the symbol type is void, it has been recently allocated just in this scope. */ if (!sym->class) return sym; - + /* If the scope is the current, it is already defined in this scope. */ - if (sym->scope == conf_this_scope) - cf_error("Symbol already defined"); + if (cf_symbol_is_local(sym)) + cf_error("Symbol '%s' already defined", sym->name); /* Not allocated here yet, doing it now. */ return cf_new_symbol(sym->name); @@ -689,10 +713,7 @@ cf_lex_symbol(const char *data) struct symbol *sym = cf_get_symbol(data); cf_lval.s = sym; - if (sym->class != SYM_VOID) - return CF_SYM_KNOWN; - - /* Is it a keyword? */ + /* Is it a keyword? Prefer the keyword. */ struct keyword *k = HASH_FIND(kw_hash, KW, data); if (k) { @@ -705,9 +726,11 @@ cf_lex_symbol(const char *data) } } - /* OK, undefined symbol */ - cf_lval.s = sym; - return CF_SYM_UNDEFINED; + /* OK, only a symbol. */ + if (sym->class == SYM_VOID) + return CF_SYM_UNDEFINED; + else + return CF_SYM_KNOWN; } static void @@ -720,6 +743,34 @@ cf_lex_init_kh(void) HASH_INSERT(kw_hash, KW, k); } +void +ea_lex_register(struct ea_class *def) +{ + struct symbol *sym = cf_root_symbol(def->name); + sym->class = SYM_ATTRIBUTE; + sym->attribute = def; + def->sym = sym; +} + +void +ea_lex_unregister(struct ea_class *def) +{ + struct symbol *sym = def->sym; + HASH_REMOVE2(global_root_scope->hash, SYM, &root_pool, sym); + mb_free(sym); + def->sym = NULL; +} + +struct ea_class * +ea_class_find_by_name(const char *name) +{ + struct symbol *sym = cf_find_symbol(global_root_scope, name); + if (!sym || (sym->class != SYM_ATTRIBUTE)) + return NULL; + else + return sym->attribute; +} + /** * cf_lex_init - initialize the lexer * @is_cli: true if we're going to parse CLI command, false for configuration @@ -753,6 +804,11 @@ cf_lex_init(int is_cli, struct config *c) c->root_scope = cfg_allocz(sizeof(struct sym_scope)); conf_this_scope = c->root_scope; conf_this_scope->active = 1; + + if (is_cli) + conf_this_scope->next = config->root_scope; + else + conf_this_scope->next = global_root_scope; } /** @@ -787,12 +843,60 @@ cf_push_scope(struct symbol *sym) void cf_pop_scope(void) { + ASSERT(!conf_this_scope->soft_scopes); + conf_this_scope->active = 0; conf_this_scope = conf_this_scope->next; ASSERT(conf_this_scope); } +/** + * cf_push_soft_scope - enter new soft scope + * + * If we want to enter a new anonymous scope that most likely will not contain + * any symbols, we can use cf_push_soft_scope() insteas of cf_push_scope(). + * Such scope will be converted to a regular scope on first use. + */ +void +cf_push_soft_scope(void) +{ + if (conf_this_scope->soft_scopes < 0xfe) + conf_this_scope->soft_scopes++; + else + cf_push_scope(NULL); +} + +/** + * cf_pop_soft_scope - leave a soft scope + * + * Leave a soft scope entered by cf_push_soft_scope(). + */ +void +cf_pop_soft_scope(void) +{ + if (conf_this_scope->soft_scopes) + conf_this_scope->soft_scopes--; + else + cf_pop_scope(); +} + +/** + * cf_swap_soft_scope - convert soft scope to regular scope + * + * Soft scopes cannot hold symbols, so they must be converted to regular scopes + * on first use. It is done automatically by cf_new_symbol(). + */ +static inline void +cf_swap_soft_scope(void) +{ + if (conf_this_scope->soft_scopes) + { + conf_this_scope->soft_scopes--; + cf_push_scope(NULL); + } +} + /** * cf_symbol_class_name - get name of a symbol class * @sym: symbol diff --git a/conf/conf.c b/conf/conf.c index 58abcde1..17424402 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -46,7 +46,7 @@ #undef LOCAL_DEBUG #include "nest/bird.h" -#include "nest/route.h" +#include "nest/rt.h" #include "nest/protocol.h" #include "nest/iface.h" #include "lib/resource.h" @@ -140,6 +140,7 @@ config_parse(struct config *c) protos_preconfig(c); rt_preconfig(c); cf_parse(); + rt_postconfig(c); if (EMPTY_LIST(c->protos)) cf_error("No protocol is specified in the config file"); @@ -168,7 +169,6 @@ int cli_parse(struct config *c) { int done = 0; - c->fallback = config; new_config = c; cfg_mem = c->mem; if (setjmp(conf_jmpbuf)) @@ -179,7 +179,6 @@ cli_parse(struct config *c) done = 1; cleanup: - c->fallback = NULL; new_config = NULL; cfg_mem = NULL; return done; @@ -520,6 +519,8 @@ order_shutdown(int gr) memcpy(c, config, sizeof(struct config)); init_list(&c->protos); init_list(&c->tables); + init_list(&c->symbols); + memset(c->def_tables, 0, sizeof(c->def_tables)); c->shutdown = 1; c->gr_down = gr; diff --git a/conf/conf.h b/conf/conf.h index 4f6aa6eb..50e01bf5 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -16,7 +16,6 @@ #include "lib/timer.h" /* Configuration structure */ - struct config { pool *pool; /* Pool the configuration is stored in */ linpool *mem; /* Linear pool containing configuration data */ @@ -55,8 +54,7 @@ struct config { char *err_file_name; /* File name containing error */ char *file_name; /* Name of main configuration file */ int file_fd; /* File descriptor of main configuration file */ - HASH(struct symbol) sym_hash; /* Lexer: symbol hash table */ - struct config *fallback; /* Link to regular config for CLI parsing */ + struct sym_scope *root_scope; /* Scope for root symbols */ int obstacle_count; /* Number of items blocking freeing of this config */ int shutdown; /* This is a pseudo-config for daemon shutdown */ @@ -123,7 +121,7 @@ struct symbol { const struct f_line *function; /* For SYM_FUNCTION */ const struct filter *filter; /* For SYM_FILTER */ struct rtable_config *table; /* For SYM_TABLE */ - struct f_dynamic_attr *attribute; /* For SYM_ATTRIBUTE */ + struct ea_class *attribute; /* For SYM_ATTRIBUTE */ struct f_val *val; /* For SYM_CONSTANT */ uint offset; /* For SYM_VARIABLE */ }; @@ -134,10 +132,16 @@ struct symbol { struct sym_scope { struct sym_scope *next; /* Next on scope stack */ struct symbol *name; /* Name of this scope */ + + HASH(struct symbol) hash; /* Local symbol hash */ + uint slots; /* Variable slots */ - int active; /* Currently entered */ + byte active; /* Currently entered */ + byte soft_scopes; /* Number of soft scopes above */ }; +extern struct sym_scope *global_root_scope; + struct bytestring { size_t length; byte data[]; @@ -186,12 +190,22 @@ int cf_lex(void); void cf_lex_init(int is_cli, struct config *c); void cf_lex_unwind(void); -struct symbol *cf_find_symbol(const struct config *cfg, const byte *c); +struct symbol *cf_find_symbol_scope(const struct sym_scope *scope, const byte *c); +static inline struct symbol *cf_find_symbol_cfg(const struct config *cfg, const byte *c) +{ return cf_find_symbol_scope(cfg->root_scope, c); } + +#define cf_find_symbol(where, what) _Generic(*(where), \ + struct config: cf_find_symbol_cfg, \ + struct sym_scope: cf_find_symbol_scope \ + )((where), (what)) struct symbol *cf_get_symbol(const byte *c); struct symbol *cf_default_name(char *template, int *counter); struct symbol *cf_localize_symbol(struct symbol *sym); +static inline int cf_symbol_is_local(struct symbol *sym) +{ return (sym->scope == conf_this_scope) && !conf_this_scope->soft_scopes; } + /** * cf_define_symbol - define meaning of a symbol * @sym: symbol to be defined @@ -215,6 +229,9 @@ struct symbol *cf_localize_symbol(struct symbol *sym); void cf_push_scope(struct symbol *); void cf_pop_scope(void); +void cf_push_soft_scope(void); +void cf_pop_soft_scope(void); + char *cf_symbol_class_name(struct symbol *sym); /* Parser */ diff --git a/conf/confbase.Y b/conf/confbase.Y index 6985783b..241c332d 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -18,7 +18,7 @@ CF_HDR #include "lib/string.h" #include "nest/protocol.h" #include "nest/iface.h" -#include "nest/route.h" +#include "nest/rt.h" #include "nest/bfd.h" #include "nest/cli.h" #include "filter/filter.h" @@ -71,10 +71,12 @@ CF_DECLS } xp; enum filter_return fret; enum ec_subtype ecs; - struct f_dynamic_attr fda; + struct ea_class *ea_class; struct f_static_attr fsa; + struct f_attr_bit fab; struct f_lval flv; struct f_line *fl; + struct f_arg *fa; const struct filter *f; struct f_tree *e; struct f_trie *trie; @@ -91,7 +93,7 @@ CF_DECLS struct proto_spec ps; struct channel_limit cl; struct timeformat *tf; - mpls_label_stack *mls; + struct adata *ad; struct bytestring *bs; } @@ -110,16 +112,17 @@ CF_DECLS %type expr bool pxlen4 %type