From 13225f1dbff54619476f2d8f6bc779dbb4983e3e Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 5 Apr 2020 03:24:46 +0200 Subject: Filter: Faster prefix sets Use 16-way (4bit) branching in prefix trie instead of basic binary branching. The change makes IPv4 prefix sets almost 3x faster, but with more memory consumption and much more complicated algorithm. Together with a previous filter change, it makes IPv4 prefix sets about ~4.3x faster and slightly smaller (on my test data). --- filter/data.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index d296776d..21967deb 100644 --- a/filter/data.h +++ b/filter/data.h @@ -140,18 +140,22 @@ struct f_tree { void *data; }; +#define TRIE_STEP 4 + struct f_trie_node4 { ip4_addr addr, mask, accept; - uint plen; - struct f_trie_node4 *c[2]; + u16 plen; + u16 local; + struct f_trie_node4 *c[1 << TRIE_STEP]; }; struct f_trie_node6 { ip6_addr addr, mask, accept; - uint plen; - struct f_trie_node6 *c[2]; + u16 plen; + u16 local; + struct f_trie_node6 *c[1 << TRIE_STEP]; }; struct f_trie_node -- cgit v1.2.3 From 062e69bf520e5788913bdd564076ad9892b24a87 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Fri, 19 Nov 2021 18:04:32 +0100 Subject: Trie: Implement trie walking code Trie walking allows enumeration of prefixes in a trie in the usual lexicographic order. Optionally, trie enumeration can be restricted to a chosen subnet (and its descendants). --- filter/data.h | 23 ++++- filter/trie.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++- filter/trie_test.c | 158 ++++++++++++++++++++++++++++++++-- 3 files changed, 413 insertions(+), 13 deletions(-) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index 21967deb..4a0ee865 100644 --- a/filter/data.h +++ b/filter/data.h @@ -140,7 +140,8 @@ struct f_tree { void *data; }; -#define TRIE_STEP 4 +#define TRIE_STEP 4 +#define TRIE_STACK_LENGTH 33 struct f_trie_node4 { @@ -175,6 +176,16 @@ struct f_trie struct f_trie_node root; /* Root trie node */ }; +struct f_trie_walk_state +{ + u8 ipv4; + u8 accept_length; /* Current inter-node prefix position */ + u8 start_pos; /* Initial prefix position in stack[0] */ + u8 local_pos; /* Current intra-node prefix position */ + u8 stack_pos; /* Current node in stack below */ + const struct f_trie_node *stack[TRIE_STACK_LENGTH]; +}; + struct f_tree *f_new_tree(void); struct f_tree *build_tree(struct f_tree *); const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val); @@ -185,9 +196,19 @@ void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void struct f_trie *f_new_trie(linpool *lp, uint data_size); void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); int trie_match_net(const struct f_trie *t, const net_addr *n); +void trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *from); +int trie_walk_next(struct f_trie_walk_state *s, net_addr *net); int trie_same(const struct f_trie *t1, const struct f_trie *t2); void trie_format(const struct f_trie *t, buffer *buf); +#define TRIE_WALK(trie, net, from) ({ \ + net_addr net; \ + struct f_trie_walk_state tws_; \ + trie_walk_init(&tws_, trie, from); \ + while (trie_walk_next(&tws_, &net)) + +#define TRIE_WALK_END }) + #define F_CMP_ERROR 999 const char *f_type_name(enum f_type t); diff --git a/filter/trie.c b/filter/trie.c index 5d9cc952..21b5b5d7 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -1,8 +1,8 @@ /* * Filters: Trie for prefix sets * - * (c) 2009--2020 Ondrej Zajicek - * (c) 2009--2020 CZ.NIC z.s.p.o. + * (c) 2009--2021 Ondrej Zajicek + * (c) 2009--2021 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -82,6 +82,24 @@ * - we are still on path and keep walking (node length < &plen) * * The walking code in trie_match_net() is structured according to these cases. + * + * Iteration over prefixes in a trie can be done using TRIE_WALK() macro, or + * directly using trie_walk_init() and trie_walk_next() functions. The second + * approeach allows suspending the iteration and continuing in it later. + * Prefixes are enumerated in the usual lexicographic order and may be + * restricted to a subset of the trie (all subnets of a specified prefix). + * + * Note that the trie walk does not reliably enumerate `implicit' prefixes + * defined by &low and &high fields in prefix patterns, it is supposed to be + * used on tries constructed from `explicit' prefixes (&low == &plen == &high + * in call to trie_add_prefix()). + * + * The trie walk has three basic state variables stored in the struct + * &f_trie_walk_state -- the current node in &stack[stack_pos], &accept_length + * for iteration over inter-node prefixes (non-branching prefixes on compressed + * path between the current node and its parent node, stored in the bitmap + * &accept of the current node) and &local_pos for iteration over intra-node + * prefixes (stored in the bitmap &local). */ #include "nest/bird.h" @@ -224,7 +242,7 @@ trie_amask_to_local(ip_addr px, ip_addr amask, uint nlen) #define ADD_LOCAL(N,X,V) ({ uint v_ = (V); if (X) (N)->v4.local |= v_; else (N)->v6.local |= v_; }) -#define GET_CHILD(N,F,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I]) +#define GET_CHILD(N,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I]) static void * @@ -312,7 +330,7 @@ trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint /* n->plen < plen and plen <= 32 (128) */ o = n; - n = GET_CHILD(n, c, v4, ipa_getbits(paddr, nlen, TRIE_STEP)); + n = GET_CHILD(n, v4, ipa_getbits(paddr, nlen, TRIE_STEP)); } /* We add new tail node 'a' after node 'o' */ @@ -522,6 +540,225 @@ trie_match_net(const struct f_trie *t, const net_addr *n) } } + +#define SAME_PREFIX(A,B,X,L) ((X) ? ip4_prefix_equal((A)->v4.addr, net4_prefix(B), (L)) : ip6_prefix_equal((A)->v6.addr, net6_prefix(B), (L))) +#define GET_NET_BITS(N,X,A,B) ((X) ? ip4_getbits(net4_prefix(N), (A), (B)) : ip6_getbits(net6_prefix(N), (A), (B))) + +/** + * trie_walk_init + * @s: walk state + * @t: trie + * @net: optional subnet for walk + * + * Initialize walk state for subsequent walk through nodes of the trie @t by + * trie_walk_next(). The argument @net allows to restrict walk to given subnet, + * otherwise full walk over all nodes is used. This is done by finding node at + * or below @net and starting position in it. + */ +void +trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *net) +{ + *s = (struct f_trie_walk_state) { + .ipv4 = t->ipv4, + .accept_length = 0, + .start_pos = 1, + .local_pos = 1, + .stack_pos = 0, + .stack[0] = &t->root + }; + + if (!net) + return; + + /* We want to find node of level at least plen */ + int plen = ROUND_DOWN_POW2(net->pxlen, TRIE_STEP); + const struct f_trie_node *n = &t->root; + const int v4 = t->ipv4; + + while (n) + { + int nlen = v4 ? n->v4.plen : n->v6.plen; + + /* We are out of path */ + if (!SAME_PREFIX(n, net, v4, MIN(net->pxlen, nlen))) + break; + + /* We found final node */ + if (nlen >= plen) + { + if (nlen == plen) + { + /* Find proper local_pos, while accept_length is not used */ + int step = net->pxlen - plen; + s->start_pos = s->local_pos = (1u << step) + GET_NET_BITS(net, v4, plen, step); + s->accept_length = plen; + } + else + { + /* Start from pos 1 in local node, but first try accept mask */ + s->accept_length = net->pxlen; + } + + s->stack[0] = n; + return; + } + + /* Choose child */ + n = GET_CHILD(n, v4, GET_NET_BITS(net, v4, nlen, TRIE_STEP)); + } + + s->stack[0] = NULL; + return; +} + +#define GET_ACCEPT_BIT(N,X,B) ((X) ? ip4_getbit((N)->v4.accept, (B)) : ip6_getbit((N)->v6.accept, (B))) +#define GET_LOCAL_BIT(N,X,B) (((X) ? (N)->v4.local : (N)->v6.local) & (1u << (B))) + +/** + * trie_walk_next + * @s: walk state + * @net: return value + * + * Find the next prefix in the trie walk and return it in the buffer @net. + * Prefixes are walked in the usual lexicographic order and may be restricted + * to a subset of the trie during walk setup by trie_walk_init(). Note that the + * trie walk does not iterate reliably over 'implicit' prefixes defined by &low + * and &high fields in prefix patterns, it is supposed to be used on tries + * constructed from 'explicit' prefixes (&low == &plen == &high in call to + * trie_add_prefix()). + * + * Result: 1 if the next prefix was found, 0 for the end of walk. + */ +int +trie_walk_next(struct f_trie_walk_state *s, net_addr *net) +{ + const struct f_trie_node *n = s->stack[s->stack_pos]; + int len = s->accept_length; + int pos = s->local_pos; + int v4 = s->ipv4; + + /* + * The walk has three basic state variables -- n, len and pos. In each node n, + * we first walk superprefixes (by len in &accept bitmask), and then we walk + * internal positions (by pos in &local bitmask). These positions are: + * + * 1 + * 2 3 + * 4 5 6 7 + * 8 9 A B C D E F + * + * We walk them depth-first, including virtual positions 10-1F that are + * equivalent of position 1 in child nodes 0-F. + */ + + if (!n) + { + memset(net, 0, v4 ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6)); + return 0; + } + +next_node:; + /* Current node prefix length */ + int nlen = v4 ? n->v4.plen : n->v6.plen; + + /* First, check for accept prefix */ + for (; len < nlen; len++) + if (GET_ACCEPT_BIT(n, v4, len - 1)) + { + if (v4) + net_fill_ip4(net, ip4_and(n->v4.addr, ip4_mkmask(len)), len); + else + net_fill_ip6(net, ip6_and(n->v6.addr, ip6_mkmask(len)), len); + + s->local_pos = pos; + s->accept_length = len + 1; + return 1; + } + +next_pos: + /* Bottom of this node */ + if (pos >= (1 << TRIE_STEP)) + { + const struct f_trie_node *child = GET_CHILD(n, v4, pos - (1 << TRIE_STEP)); + int dir = 0; + + /* No child node */ + if (!child) + { + /* Step up until return from left child (pos is even) */ + do + { + /* Step up from start node */ + if ((s->stack_pos == 0) && (pos == s->start_pos)) + { + s->stack[0] = NULL; + memset(net, 0, v4 ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6)); + return 0; + } + + /* Top of this node */ + if (pos == 1) + { + ASSERT(s->stack_pos); + const struct f_trie_node *old = n; + + /* Move to parent node */ + s->stack_pos--; + n = s->stack[s->stack_pos]; + nlen = v4 ? n->v4.plen : n->v6.plen; + + pos = v4 ? + ip4_getbits(old->v4.addr, nlen, TRIE_STEP) : + ip6_getbits(old->v6.addr, nlen, TRIE_STEP); + pos += (1 << TRIE_STEP); + len = nlen; + + ASSERT(GET_CHILD(n, v4, pos - (1 << TRIE_STEP)) == old); + } + + /* Step up */ + dir = pos % 2; + pos = pos / 2; + } + while (dir); + + /* Continue with step down to the right child */ + pos = 2 * pos + 1; + goto next_pos; + } + + /* Move to child node */ + pos = 1; + len = nlen + TRIE_STEP; + + s->stack_pos++; + n = s->stack[s->stack_pos] = child; + goto next_node; + } + + /* Check for local prefix */ + if (GET_LOCAL_BIT(n, v4, pos)) + { + /* Convert pos to address of local network */ + int x = (pos >= 2) + (pos >= 4) + (pos >= 8); + int y = pos & ((1u << x) - 1); + + if (v4) + net_fill_ip4(net, !x ? n->v4.addr : ip4_setbits(n->v4.addr, nlen + x - 1, y), nlen + x); + else + net_fill_ip6(net, !x ? n->v6.addr : ip6_setbits(n->v6.addr, nlen + x - 1, y), nlen + x); + + s->local_pos = 2 * pos; + s->accept_length = len; + return 1; + } + + /* Step down */ + pos = 2 * pos; + goto next_pos; +} + + static int trie_node_same4(const struct f_trie_node4 *t1, const struct f_trie_node4 *t2) { diff --git a/filter/trie_test.c b/filter/trie_test.c index 3e8ce84d..bb9a2f26 100644 --- a/filter/trie_test.c +++ b/filter/trie_test.c @@ -45,6 +45,13 @@ get_exp_random(void) return n; } +static int +compare_prefixes(const void *a, const void *b) +{ + return net_compare(&((const struct f_prefix *) a)->net, + &((const struct f_prefix *) b)->net); +} + static inline int matching_ip4_nets(const net_addr_ip4 *a, const net_addr_ip4 *b) { @@ -106,11 +113,15 @@ get_random_net(net_addr *net, int v6) } static void -get_random_prefix(struct f_prefix *px, int v6) +get_random_prefix(struct f_prefix *px, int v6, int tight) { get_random_net(&px->net, v6); - if (bt_random() % 2) + if (tight) + { + px->lo = px->hi = px->net.pxlen; + } + else if (bt_random() % 2) { px->lo = 0; px->hi = px->net.pxlen; @@ -238,7 +249,7 @@ get_outer_net(net_addr *net, const struct f_prefix *src) } static list * -make_random_prefix_list(linpool *lp, int num, int v6) +make_random_prefix_list(linpool *lp, int num, int v6, int tight) { list *prefixes = lp_allocz(lp, sizeof(struct f_prefix_node)); init_list(prefixes); @@ -246,7 +257,7 @@ make_random_prefix_list(linpool *lp, int num, int v6) for (int i = 0; i < num; i++) { struct f_prefix_node *px = lp_allocz(lp, sizeof(struct f_prefix_node)); - get_random_prefix(&px->prefix, v6); + get_random_prefix(&px->prefix, v6, tight); add_tail(prefixes, &px->n); char buf[64]; @@ -429,7 +440,7 @@ t_match_random_net(void) linpool *lp = lp_new_default(&root_pool); for (int round = 0; round < TESTS_NUM; round++) { - list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6); + list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0); struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes); for (int i = 0; i < PREFIX_TESTS_NUM; i++) @@ -457,7 +468,7 @@ t_match_inner_net(void) linpool *lp = lp_new_default(&root_pool); for (int round = 0; round < TESTS_NUM; round++) { - list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6); + list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0); struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes); struct f_prefix_node *n = HEAD(*prefixes); @@ -488,7 +499,7 @@ t_match_outer_net(void) linpool *lp = lp_new_default(&root_pool); for (int round = 0; round < TESTS_NUM; round++) { - list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6); + list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0); struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes); struct f_prefix_node *n = HEAD(*prefixes); @@ -613,7 +624,7 @@ t_trie_same(void) linpool *lp = lp_new_default(&root_pool); for (int round = 0; round < TESTS_NUM*4; round++) { - list *prefixes = make_random_prefix_list(lp, 100 * PREFIXES_NUM, v6); + list *prefixes = make_random_prefix_list(lp, 100 * PREFIXES_NUM, v6, 0); struct f_trie *trie1 = f_new_trie(lp, 0); struct f_trie *trie2 = f_new_trie(lp, 0); @@ -630,6 +641,136 @@ t_trie_same(void) lp_flush(lp); } + bt_bird_cleanup(); + return 1; +} + +static inline void +log_networks(const net_addr *a, const net_addr *b) +{ + if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL) + { + char buf0[64]; + char buf1[64]; + bt_format_net(buf0, 64, a); + bt_format_net(buf1, 64, b); + bt_debug("Found %s expected %s\n", buf0, buf1); + } +} + +static int +t_trie_walk(void) +{ + bt_bird_init(); + bt_config_parse(BT_CONFIG_SIMPLE); + + linpool *lp = lp_new_default(&root_pool); + for (int round = 0; round < TESTS_NUM*8; round++) + { + int level = round / TESTS_NUM; + int v6 = level % 2; + int num = PREFIXES_NUM * (int[]){1, 10, 100, 1000}[level / 2]; + int pos = 0, end = 0; + list *prefixes = make_random_prefix_list(lp, num, v6, 1); + struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes); + struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix)); + + struct f_prefix_node *n; + WALK_LIST(n, *prefixes) + pxset[pos++] = n->prefix; + memset(&pxset[pos], 0, sizeof (struct f_prefix)); + + qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes); + + + /* Full walk */ + bt_debug("Full walk (round %d, %d nets)\n", round, num); + + pos = 0; + TRIE_WALK(trie, net, NULL) + { + log_networks(&net, &pxset[pos].net); + bt_assert(net_equal(&net, &pxset[pos].net)); + + /* Skip possible duplicates */ + while (net_equal(&pxset[pos].net, &pxset[pos + 1].net)) + pos++; + + pos++; + } + TRIE_WALK_END; + + bt_assert(pos == num); + bt_debug("Full walk done\n"); + + + /* Prepare net for subnet walk - start with random prefix */ + pos = bt_random() % num; + end = pos + (int[]){2, 2, 3, 4}[level / 2]; + end = MIN(end, num); + + struct f_prefix from = pxset[pos]; + + /* Find a common superprefix to several subsequent prefixes */ + for (; pos < end; pos++) + { + if (net_equal(&from.net, &pxset[pos].net)) + continue; + + int common = !v6 ? + ip4_pxlen(net4_prefix(&from.net), net4_prefix(&pxset[pos].net)) : + ip6_pxlen(net6_prefix(&from.net), net6_prefix(&pxset[pos].net)); + from.net.pxlen = MIN(from.net.pxlen, common); + + if (!v6) + ((net_addr_ip4 *) &from.net)->prefix = + ip4_and(net4_prefix(&from.net), net4_prefix(&pxset[pos].net)); + else + ((net_addr_ip6 *) &from.net)->prefix = + ip6_and(net6_prefix(&from.net), net6_prefix(&pxset[pos].net)); + } + + /* Fix irrelevant bits */ + if (!v6) + ((net_addr_ip4 *) &from.net)->prefix = + ip4_and(net4_prefix(&from.net), ip4_mkmask(net4_pxlen(&from.net))); + else + ((net_addr_ip6 *) &from.net)->prefix = + ip6_and(net6_prefix(&from.net), ip6_mkmask(net6_pxlen(&from.net))); + + + /* Find initial position for final prefix */ + for (pos = 0; pos < num; pos++) + if (compare_prefixes(&pxset[pos], &from) >= 0) + break; + + int p0 = pos; + char buf0[64]; + bt_format_net(buf0, 64, &from.net); + bt_debug("Subnet walk for %s (round %d, %d nets)\n", buf0, round, num); + + /* Subnet walk */ + TRIE_WALK(trie, net, &from.net) + { + log_networks(&net, &pxset[pos].net); + bt_assert(net_equal(&net, &pxset[pos].net)); + bt_assert(net_in_netX(&net, &from.net)); + + /* Skip possible duplicates */ + while (net_equal(&pxset[pos].net, &pxset[pos + 1].net)) + pos++; + + pos++; + } + TRIE_WALK_END; + + bt_assert((pos == num) || !net_in_netX(&pxset[pos].net, &from.net)); + bt_debug("Subnet walk done for %s (found %d nets)\n", buf0, pos - p0); + + lp_flush(lp); + } + + bt_bird_cleanup(); return 1; } @@ -642,6 +783,7 @@ main(int argc, char *argv[]) bt_test_suite(t_match_inner_net, "Testing random inner prefix matching"); bt_test_suite(t_match_outer_net, "Testing random outer prefix matching"); bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward."); + bt_test_suite(t_trie_walk, "Testing TRIE_WALK() on random tries"); // bt_test_suite(t_bench_trie_datasets_subset, "Benchmark tries from datasets by random subset of nets"); // bt_test_suite(t_bench_trie_datasets_random, "Benchmark tries from datasets by generated addresses"); -- cgit v1.2.3 From 14fc24f3a53ebc5525b854ccdc93274aa74a400f Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Fri, 26 Nov 2021 03:26:36 +0100 Subject: Trie: Implement longest-prefix-match queries and walks The prefix trie now supports longest-prefix-match query by function trie_match_longest_ipX() and it can be extended to iteration over all covering prefixes for a given prefix (from longest to shortest) using TRIE_WALK_TO_ROOT_IPx() macro. --- filter/data.h | 51 ++++++++++++++ filter/trie.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++- filter/trie_test.c | 115 ++++++++++++++++++++++++++++++++ test/birdtest.c | 5 +- 4 files changed, 359 insertions(+), 2 deletions(-) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index 4a0ee865..28c7a888 100644 --- a/filter/data.h +++ b/filter/data.h @@ -196,11 +196,61 @@ void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void struct f_trie *f_new_trie(linpool *lp, uint data_size); void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h); int trie_match_net(const struct f_trie *t, const net_addr *n); +int trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0); +int trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0); void trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *from); int trie_walk_next(struct f_trie_walk_state *s, net_addr *net); int trie_same(const struct f_trie *t1, const struct f_trie *t2); void trie_format(const struct f_trie *t, buffer *buf); +static inline int +trie_match_next_longest_ip4(net_addr_ip4 *n, ip4_addr *found) +{ + while (n->pxlen) + { + n->pxlen--; + ip4_clrbit(&n->prefix, n->pxlen); + + if (ip4_getbit(*found, n->pxlen)) + return 1; + } + + return 0; +} + +static inline int +trie_match_next_longest_ip6(net_addr_ip6 *n, ip6_addr *found) +{ + while (n->pxlen) + { + n->pxlen--; + ip6_clrbit(&n->prefix, n->pxlen); + + if (ip6_getbit(*found, n->pxlen)) + return 1; + } + + return 0; +} + + +#define TRIE_WALK_TO_ROOT_IP4(trie, net, dst) ({ \ + net_addr_ip4 dst; \ + ip4_addr _found; \ + for (int _n = trie_match_longest_ip4(trie, net, &dst, &_found); \ + _n; \ + _n = trie_match_next_longest_ip4(&dst, &_found)) + +#define TRIE_WALK_TO_ROOT_IP6(trie, net, dst) ({ \ + net_addr_ip6 dst; \ + ip6_addr _found; \ + for (int _n = trie_match_longest_ip6(trie, net, &dst, &_found); \ + _n; \ + _n = trie_match_next_longest_ip6(&dst, &_found)) + +#define TRIE_WALK_TO_ROOT_END }) + + #define TRIE_WALK(trie, net, from) ({ \ net_addr net; \ struct f_trie_walk_state tws_; \ @@ -209,6 +259,7 @@ void trie_format(const struct f_trie *t, buffer *buf); #define TRIE_WALK_END }) + #define F_CMP_ERROR 999 const char *f_type_name(enum f_type t); diff --git a/filter/trie.c b/filter/trie.c index 21b5b5d7..66b56297 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -85,7 +85,7 @@ * * Iteration over prefixes in a trie can be done using TRIE_WALK() macro, or * directly using trie_walk_init() and trie_walk_next() functions. The second - * approeach allows suspending the iteration and continuing in it later. + * approach allows suspending the iteration and continuing in it later. * Prefixes are enumerated in the usual lexicographic order and may be * restricted to a subset of the trie (all subnets of a specified prefix). * @@ -100,6 +100,13 @@ * path between the current node and its parent node, stored in the bitmap * &accept of the current node) and &local_pos for iteration over intra-node * prefixes (stored in the bitmap &local). + * + * The trie also supports longest-prefix-match query by trie_match_longest_ip4() + * and it can be extended to iteration over all covering prefixes for a given + * prefix (from longest to shortest) using TRIE_WALK_TO_ROOT_IP4() macro. There + * are also IPv6 versions (for practical reasons, these functions and macros are + * separate for IPv4 and IPv6). There is the same limitation to enumeration of + * `implicit' prefixes like with the previous TRIE_WALK() macro. */ #include "nest/bird.h" @@ -541,6 +548,187 @@ trie_match_net(const struct f_trie *t, const net_addr *n) } +/** + * trie_match_longest_ip4 + * @t: trie + * @net: net address + * @dst: return value + * @found0: optional returned bitmask of found nodes + * + * Perform longest prefix match for the address @net and return the resulting + * prefix in the buffer @dst. The bitmask @found0 is used to report lengths of + * prefixes on the path from the root to the resulting prefix. E.g., if there is + * also a /20 shorter matching prefix, then 20-th bit is set in @found0. This + * can be used to enumerate all matching prefixes for the network @net using + * function trie_match_next_longest_ip4() or macro TRIE_WALK_TO_ROOT_IP4(). + * + * This function assumes IPv4 trie, there is also an IPv6 variant. + * + * Result: 1 if a matching prefix was found, 0 if not. + */ +int +trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0) +{ + ASSERT(t->ipv4); + + const struct f_trie_node4 *n = &t->root.v4; + int len = 0; + + ip4_addr found = IP4_NONE; + int last = -1; + + while (n) + { + /* We are out of path */ + if (!ip4_prefix_equal(net->prefix, n->addr, MIN(net->pxlen, n->plen))) + goto done; + + /* Check accept mask */ + for (; len < n->plen; len++) + { + if (len > net->pxlen) + goto done; + + if (ip4_getbit(n->accept, len - 1)) + { + /* len is always < 32 due to len < n->plen */ + ip4_setbit(&found, len); + last = len; + } + } + + /* Special case for max length, there is only one valid local position */ + if (len == IP4_MAX_PREFIX_LENGTH) + { + if (n->local & (1u << 1)) + last = len; + + goto done; + } + + /* Check local mask */ + for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip4_getbit(net->prefix, len), len++) + { + if (len > net->pxlen) + goto done; + + if (n->local & (1u << pos)) + { + /* len is always < 32 due to special case above */ + ip4_setbit(&found, len); + last = len; + } + } + + /* Choose child */ + n = n->c[ip4_getbits(net->prefix, n->plen, TRIE_STEP)]; + } + +done: + if (last < 0) + return 0; + + net_copy_ip4(dst, net); + dst->prefix = ip4_and(dst->prefix, ip4_mkmask(last)); + dst->pxlen = last; + + if (found0) + *found0 = found; + + return 1; +} + + +/** + * trie_match_longest_ip6 + * @t: trie + * @net: net address + * @dst: return value + * @found0: optional returned bitmask of found nodes + * + * Perform longest prefix match for the address @net and return the resulting + * prefix in the buffer @dst. The bitmask @found0 is used to report lengths of + * prefixes on the path from the root to the resulting prefix. E.g., if there is + * also a /20 shorter matching prefix, then 20-th bit is set in @found0. This + * can be used to enumerate all matching prefixes for the network @net using + * function trie_match_next_longest_ip6() or macro TRIE_WALK_TO_ROOT_IP6(). + * + * This function assumes IPv6 trie, there is also an IPv4 variant. + * + * Result: 1 if a matching prefix was found, 0 if not. + */ +int +trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0) +{ + ASSERT(!t->ipv4); + + const struct f_trie_node6 *n = &t->root.v6; + int len = 0; + + ip6_addr found = IP6_NONE; + int last = -1; + + while (n) + { + /* We are out of path */ + if (!ip6_prefix_equal(net->prefix, n->addr, MIN(net->pxlen, n->plen))) + goto done; + + /* Check accept mask */ + for (; len < n->plen; len++) + { + if (len > net->pxlen) + goto done; + + if (ip6_getbit(n->accept, len - 1)) + { + /* len is always < 128 due to len < n->plen */ + ip6_setbit(&found, len); + last = len; + } + } + + /* Special case for max length, there is only one valid local position */ + if (len == IP6_MAX_PREFIX_LENGTH) + { + if (n->local & (1u << 1)) + last = len; + + goto done; + } + + /* Check local mask */ + for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip6_getbit(net->prefix, len), len++) + { + if (len > net->pxlen) + goto done; + + if (n->local & (1u << pos)) + { + /* len is always < 128 due to special case above */ + ip6_setbit(&found, len); + last = len; + } + } + + /* Choose child */ + n = n->c[ip6_getbits(net->prefix, n->plen, TRIE_STEP)]; + } + +done: + if (last < 0) + return 0; + + net_copy_ip6(dst, net); + dst->prefix = ip6_and(dst->prefix, ip6_mkmask(last)); + dst->pxlen = last; + + if (found0) + *found0 = found; + + return 1; +} + #define SAME_PREFIX(A,B,X,L) ((X) ? ip4_prefix_equal((A)->v4.addr, net4_prefix(B), (L)) : ip6_prefix_equal((A)->v6.addr, net6_prefix(B), (L))) #define GET_NET_BITS(N,X,A,B) ((X) ? ip4_getbits(net4_prefix(N), (A), (B)) : ip6_getbits(net6_prefix(N), (A), (B))) diff --git a/filter/trie_test.c b/filter/trie_test.c index bb9a2f26..eee48284 100644 --- a/filter/trie_test.c +++ b/filter/trie_test.c @@ -774,6 +774,120 @@ t_trie_walk(void) return 1; } +static int +find_covering_nets(struct f_prefix *prefixes, int num, const net_addr *net, net_addr *found) +{ + struct f_prefix key; + net_addr *n = &key.net; + int found_num = 0; + + net_copy(n, net); + + while (1) + { + struct f_prefix *px = + bsearch(&key, prefixes, num, sizeof(struct f_prefix), compare_prefixes); + + if (px) + { + net_copy(&found[found_num], n); + found_num++; + } + + if (n->pxlen == 0) + return found_num; + + n->pxlen--; + + if (n->type == NET_IP4) + ip4_clrbit(&((net_addr_ip4 *) n)->prefix, n->pxlen); + else + ip6_clrbit(&((net_addr_ip6 *) n)->prefix, n->pxlen); + } +} + +static int +t_trie_walk_to_root(void) +{ + bt_bird_init(); + bt_config_parse(BT_CONFIG_SIMPLE); + + linpool *lp = lp_new_default(&root_pool); + for (int round = 0; round < TESTS_NUM * 4; round++) + { + int level = round / TESTS_NUM; + int v6 = level % 2; + int num = PREFIXES_NUM * (int[]){32, 512}[level / 2]; + int pos = 0; + int st = 0, sn = 0, sm = 0; + + list *prefixes = make_random_prefix_list(lp, num, v6, 1); + struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes); + struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix)); + + struct f_prefix_node *pxn; + WALK_LIST(pxn, *prefixes) + pxset[pos++] = pxn->prefix; + memset(&pxset[pos], 0, sizeof (struct f_prefix)); + + qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes); + + int i; + for (i = 0; i < (PREFIX_TESTS_NUM / 10); i++) + { + net_addr from; + get_random_net(&from, v6); + + net_addr found[129]; + int found_num = find_covering_nets(pxset, num, &from, found); + int n = 0; + + if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL) + { + char buf[64]; + bt_format_net(buf, 64, &from); + bt_debug("Lookup for %s (expect %d)\n", buf, found_num); + } + + /* Walk to root, separate for IPv4 and IPv6 */ + if (!v6) + { + TRIE_WALK_TO_ROOT_IP4(trie, (net_addr_ip4 *) &from, net) + { + log_networks((net_addr *) &net, &found[n]); + bt_assert((n < found_num) && net_equal((net_addr *) &net, &found[n])); + n++; + } + TRIE_WALK_TO_ROOT_END; + } + else + { + TRIE_WALK_TO_ROOT_IP6(trie, (net_addr_ip6 *) &from, net) + { + log_networks((net_addr *) &net, &found[n]); + bt_assert((n < found_num) && net_equal((net_addr *) &net, &found[n])); + n++; + } + TRIE_WALK_TO_ROOT_END; + } + + bt_assert(n == found_num); + + /* Stats */ + st += n; + sn += !!n; + sm = MAX(sm, n); + } + + bt_debug("Success in %d / %d, sum %d, max %d\n", sn, i, st, sm); + + lp_flush(lp); + } + + bt_bird_cleanup(); + return 1; +} + int main(int argc, char *argv[]) { @@ -784,6 +898,7 @@ main(int argc, char *argv[]) bt_test_suite(t_match_outer_net, "Testing random outer prefix matching"); bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward."); bt_test_suite(t_trie_walk, "Testing TRIE_WALK() on random tries"); + bt_test_suite(t_trie_walk_to_root, "Testing TRIE_WALK_TO_ROOT() on random tries"); // bt_test_suite(t_bench_trie_datasets_subset, "Benchmark tries from datasets by random subset of nets"); // bt_test_suite(t_bench_trie_datasets_random, "Benchmark tries from datasets by generated addresses"); diff --git a/test/birdtest.c b/test/birdtest.c index 053954e1..6ad743ce 100644 --- a/test/birdtest.c +++ b/test/birdtest.c @@ -510,7 +510,10 @@ bt_fmt_ipa(char *buf, size_t size, const void *data) void bt_format_net(char *buf, size_t size, const void *data) { - bsnprintf(buf, size, "%N", (const net_addr *) data); + if (data) + bsnprintf(buf, size, "%N", (const net_addr *) data); + else + bsnprintf(buf, size, "(null)"); } int -- cgit v1.2.3 From 0e1fd7ea6af8aaeb68a23e320c2a0a0a8480d6de Mon Sep 17 00:00:00 2001 From: Alexander Zubkov Date: Tue, 28 Dec 2021 04:05:05 +0100 Subject: Filter: Add operators to find minimum and maximum element of sets Add operators .min and .max to find minumum or maximum element in sets of types: clist, eclist, lclist. Example usage: bgp_community.min bgp_ext_community.max filter(bgp_large_community, [(as1, as2, *)]).min Signed-off-by: Alexander Zubkov --- filter/config.Y | 3 ++ filter/data.c | 11 +++++ filter/data.h | 2 + filter/f-inst.c | 68 +++++++++++++++++++++++++++++ filter/test.conf | 18 ++++++++ nest/a-set.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ nest/attrs.h | 6 +++ 7 files changed, 238 insertions(+) (limited to 'filter/data.h') diff --git a/filter/config.Y b/filter/config.Y index 2fb55e4e..8916ea97 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -287,6 +287,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, DEFINED, ADD, DELETE, CONTAINS, RESET, PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, + MIN, MAX, EMPTY, FILTER, WHERE, EVAL, ATTRIBUTE, BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) @@ -800,6 +801,8 @@ term: | term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); } | term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); } | term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); } + | term '.' MIN { $$ = f_new_inst(FI_MIN, $1); } + | term '.' MAX { $$ = f_new_inst(FI_MAX, $1); } /* Communities */ /* This causes one shift/reduce conflict diff --git a/filter/data.c b/filter/data.c index 7c33d2cb..56c1fb17 100644 --- a/filter/data.c +++ b/filter/data.c @@ -68,6 +68,17 @@ f_type_name(enum f_type t) return "?"; } +enum f_type +f_type_element_type(enum f_type t) +{ + switch(t) { + case T_CLIST: return T_PAIR; + case T_ECLIST: return T_EC; + case T_LCLIST: return T_LC; + default: return T_VOID; + }; +} + const struct f_val f_const_empty_path = { .type = T_PATH, .val.ad = &null_adata, diff --git a/filter/data.h b/filter/data.h index d296776d..bb815c34 100644 --- a/filter/data.h +++ b/filter/data.h @@ -188,6 +188,8 @@ void trie_format(const struct f_trie *t, buffer *buf); const char *f_type_name(enum f_type t); +enum f_type f_type_element_type(enum f_type t); + int val_same(const struct f_val *v1, const struct f_val *v2); int val_compare(const struct f_val *v1, const struct f_val *v2); void val_format(const struct f_val *v, buffer *buf); diff --git a/filter/f-inst.c b/filter/f-inst.c index 7e9e77d2..901d2939 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -983,6 +983,74 @@ RESULT(T_INT, i, v1.val.lc.ldp2); } + INST(FI_MIN, 1, 1) { /* Get minimum element from set */ + ARG_ANY(1); + RESULT_TYPE(f_type_element_type(v1.type)); + switch(v1.type) + { + case T_CLIST: + { + u32 val = 0; + int_set_min(v1.val.ad, &val); + RESULT_(T_PAIR, i, val); + } + break; + + case T_ECLIST: + { + u64 val = 0; + ec_set_min(v1.val.ad, &val); + RESULT_(T_EC, ec, val); + } + break; + + case T_LCLIST: + { + lcomm val = { 0, 0, 0 }; + lc_set_min(v1.val.ad, &val); + RESULT_(T_LC, lc, val); + } + break; + + default: + runtime( "Clist or lclist expected" ); + } + } + + INST(FI_MAX, 1, 1) { /* Get maximum element from set */ + ARG_ANY(1); + RESULT_TYPE(f_type_element_type(v1.type)); + switch(v1.type) + { + case T_CLIST: + { + u32 val = 0; + int_set_max(v1.val.ad, &val); + RESULT_(T_PAIR, i, val); + } + break; + + case T_ECLIST: + { + u64 val = 0; + ec_set_max(v1.val.ad, &val); + RESULT_(T_EC, ec, val); + } + break; + + case T_LCLIST: + { + lcomm val = { 0, 0, 0 }; + lc_set_max(v1.val.ad, &val); + RESULT_(T_LC, lc, val); + } + break; + + default: + runtime( "Clist or lclist expected" ); + } + } + INST(FI_RETURN, 1, 1) { NEVER_CONSTANT; /* Acquire the return value */ diff --git a/filter/test.conf b/filter/test.conf index 6f2f6fb5..6a28e4b3 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -781,6 +781,12 @@ clist r; r = filter(l, [(3,1), (*,2)]); bt_assert(r = add(add(-empty-, (3,1)), (3,2))); bt_assert(format(r) = "(clist (3,1) (3,2))"); + + # minimim & maximum element + r = add(add(add(add(add(-empty-, (2,1)), (1,3)), (2,2)), (3,1)), (2,3)); + bt_assert(format(r) = "(clist (2,1) (1,3) (2,2) (3,1) (2,3))"); + bt_assert(r.min = (1,3)); + bt_assert(r.max = (3,1)); } bt_test_suite(t_clist, "Testing lists of communities"); @@ -886,6 +892,12 @@ eclist r; r = filter(el, [(rt, 10, 1), (rt, 10, 25..30), (ro, 10, 40)]); bt_assert(r = add(add(--empty--, (rt, 10, 1)), (rt, 10, 30))); bt_assert(format(r) = "(eclist (rt, 10, 1) (rt, 10, 30))"); + + # minimim & maximum element + r = add(add(add(add(add(--empty--, (rt, 2, 1)), (rt, 1, 3)), (rt, 2, 2)), (rt, 3, 1)), (rt, 2, 3)); + bt_assert(format(r) = "(eclist (rt, 2, 1) (rt, 1, 3) (rt, 2, 2) (rt, 3, 1) (rt, 2, 3))"); + bt_assert(r.min = (rt, 1, 3)); + bt_assert(r.max = (rt, 3, 1)); } bt_test_suite(t_eclist, "Testing lists of extended communities"); @@ -995,6 +1007,12 @@ lclist r; r = filter(ll, [(5..15, *, *), (20, 15..25, *)]); bt_assert(r = add(add(---empty---, (10, 10, 10)), (20, 20, 20))); bt_assert(format(r) = "(lclist (10, 10, 10) (20, 20, 20))"); + + # minimim & maximum element + r = add(add(add(add(add(---empty---, (2, 3, 3)), (1, 2, 3)), (2, 3, 1)), (3, 1, 2)), (2, 1, 3)); + bt_assert(format(r) = "(lclist (2, 3, 3) (1, 2, 3) (2, 3, 1) (3, 1, 2) (2, 1, 3))"); + bt_assert(r.min = (1, 2, 3)); + bt_assert(r.max = (3, 1, 2)); } bt_test_suite(t_lclist, "Testing lists of large communities"); diff --git a/nest/a-set.c b/nest/a-set.c index 1186eb56..71fbac94 100644 --- a/nest/a-set.c +++ b/nest/a-set.c @@ -516,6 +516,48 @@ int_set_sort(struct linpool *pool, const struct adata *src) return dst; } +int +int_set_min(const struct adata *list, u32 *val) +{ + if (!list) + return 0; + + u32 *l = (u32 *) list->data; + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + *val = *l++; + for (i = 1; i < len; i++, l++) + if (int_set_cmp(val, l) > 0) + *val = *l; + + return 1; +} + +int +int_set_max(const struct adata *list, u32 *val) +{ + if (!list) + return 0; + + u32 *l = (u32 *) list->data; + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + *val = *l++; + for (i = 1; i < len; i++, l++) + if (int_set_cmp(val, l) < 0) + *val = *l; + + return 1; +} + static int ec_set_cmp(const void *X, const void *Y) @@ -541,6 +583,50 @@ ec_set_sort_x(struct adata *set) qsort(set->data, set->length / 8, 8, ec_set_cmp); } +int +ec_set_min(const struct adata *list, u64 *val) +{ + if (!list) + return 0; + + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + u32 *res = l; l += 2; + for (i = 2; i < len; i += 2, l += 2) + if (ec_set_cmp(res, l) > 0) + res = l; + + *val = ec_generic(res[0], res[1]); + return 1; +} + +int +ec_set_max(const struct adata *list, u64 *val) +{ + if (!list) + return 0; + + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + u32 *res = l; l += 2; + for (i = 2; i < len; i += 2, l += 2) + if (ec_set_cmp(res, l) < 0) + res = l; + + *val = ec_generic(res[0], res[1]); + return 1; +} + static int lc_set_cmp(const void *X, const void *Y) @@ -563,3 +649,47 @@ lc_set_sort(struct linpool *pool, const struct adata *src) qsort(dst->data, dst->length / LCOMM_LENGTH, LCOMM_LENGTH, lc_set_cmp); return dst; } + +int +lc_set_min(const struct adata *list, lcomm *val) +{ + if (!list) + return 0; + + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + u32 *res = l; l += 3; + for (i = 3; i < len; i += 3, l += 3) + if (lc_set_cmp(res, l) > 0) + res = l; + + *val = (lcomm) { res[0], res[1], res[2] }; + return 1; +} + +int +lc_set_max(const struct adata *list, lcomm *val) +{ + if (!list) + return 0; + + u32 *l = int_set_get_data(list); + int len = int_set_get_size(list); + int i; + + if (len < 1) + return 0; + + u32 *res = l; l += 3; + for (i = 3; i < len; i += 3, l += 3) + if (lc_set_cmp(res, l) < 0) + res = l; + + *val = (lcomm) { res[0], res[1], res[2] }; + return 1; +} diff --git a/nest/attrs.h b/nest/attrs.h index 50da817b..ef2b95e6 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -218,6 +218,12 @@ struct adata *ec_set_del_nontrans(struct linpool *pool, const struct adata *set) struct adata *int_set_sort(struct linpool *pool, const struct adata *src); struct adata *ec_set_sort(struct linpool *pool, const struct adata *src); struct adata *lc_set_sort(struct linpool *pool, const struct adata *src); +int int_set_min(const struct adata *list, u32 *val); +int ec_set_min(const struct adata *list, u64 *val); +int lc_set_min(const struct adata *list, lcomm *val); +int int_set_max(const struct adata *list, u32 *val); +int ec_set_max(const struct adata *list, u64 *val); +int lc_set_max(const struct adata *list, lcomm *val); void ec_set_sort_x(struct adata *set); /* Sort in place */ -- cgit v1.2.3 From ba5aec94cdf643350677f6b0ac4d335039c22396 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 2 Feb 2022 05:06:49 +0100 Subject: Trie: Add prefix counter Add counter of prefixes stored in trie. Works only for 'restricted' tries composed of explicit prefixes (pxlen == l == h), like ones used in rtables. --- filter/data.h | 1 + filter/trie.c | 8 ++++++++ filter/trie_test.c | 3 +++ 3 files changed, 12 insertions(+) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index 28c7a888..ecbc3d4f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -173,6 +173,7 @@ struct f_trie u8 zero; s8 ipv4; /* -1 for undefined / empty */ u16 data_size; /* Additional data for each trie node */ + u32 prefix_count; /* Works only for restricted tries (pxlen == l == h) */ struct f_trie_node root; /* Root trie node */ }; diff --git a/filter/trie.c b/filter/trie.c index 50d349fe..57a0cc2a 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -247,6 +247,7 @@ trie_amask_to_local(ip_addr px, ip_addr amask, uint nlen) #define GET_ADDR(N,F,X) ((X) ? ipt_from_ip4((N)->v4.F) : ipa_from_ip6((N)->v6.F)) #define SET_ADDR(N,F,X,V) ({ if (X) (N)->v4.F =ipt_to_ip4(V); else (N)->v6.F =ipa_to_ip6(V); }) +#define GET_LOCAL(N,X) ((X) ? (N)->v4.local : (N)->v6.local) #define ADD_LOCAL(N,X,V) ({ uint v_ = (V); if (X) (N)->v4.local |= v_; else (N)->v6.local |= v_; }) #define GET_CHILD(N,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I]) @@ -299,6 +300,7 @@ trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint attach_node(o, b, v4); attach_node(b, n, v4); attach_node(b, a, v4); + t->prefix_count++; DBG("Case 1\n"); return a; @@ -312,6 +314,7 @@ trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint struct f_trie_node *a = new_node(t, plen, local, paddr, pmask, amask); attach_node(o, a, v4); attach_node(a, n, v4); + t->prefix_count++; DBG("Case 2\n"); return a; @@ -322,6 +325,10 @@ trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint /* We already found added node in trie. Just update accept and local mask */ accept = ipa_or(accept, amask); SET_ADDR(n, accept, v4, accept); + + if ((GET_LOCAL(n, v4) & local) != local) + t->prefix_count++; + ADD_LOCAL(n, v4, local); DBG("Case 3\n"); @@ -343,6 +350,7 @@ trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint /* We add new tail node 'a' after node 'o' */ struct f_trie_node *a = new_node(t, plen, local, paddr, pmask, amask); attach_node(o, a, v4); + t->prefix_count++; DBG("Case 4\n"); return a; diff --git a/filter/trie_test.c b/filter/trie_test.c index eee48284..c7775006 100644 --- a/filter/trie_test.c +++ b/filter/trie_test.c @@ -687,6 +687,7 @@ t_trie_walk(void) bt_debug("Full walk (round %d, %d nets)\n", round, num); pos = 0; + uint pxc = 0; TRIE_WALK(trie, net, NULL) { log_networks(&net, &pxset[pos].net); @@ -697,10 +698,12 @@ t_trie_walk(void) pos++; pos++; + pxc++; } TRIE_WALK_END; bt_assert(pos == num); + bt_assert(pxc == trie->prefix_count); bt_debug("Full walk done\n"); -- cgit v1.2.3 From 80272d4b64a38ee6f04a1c4e8566cac3a2293176 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sat, 26 Mar 2022 12:40:46 +0100 Subject: Opaque types are named opaque also in filters --- filter/data.h | 4 +++- filter/f-inst.c | 2 +- proto/bgp/config.Y | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index 6d588204..924bbf3e 100644 --- a/filter/data.h +++ b/filter/data.h @@ -20,6 +20,9 @@ enum f_type { /* Nothing. Simply nothing. */ T_VOID = 0, +/* Something but inaccessible. */ + T_OPAQUE = 0xee, + /* User visible types, which fit in int */ T_INT = 0x10, T_BOOL = 0x11, @@ -41,7 +44,6 @@ enum f_type { T_ENUM_AF = 0x38, /* new enums go here */ - T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */ #define T_ENUM T_ENUM_LO ... T_ENUM_HI diff --git a/filter/f-inst.c b/filter/f-inst.c index 11ca1e28..75a53499 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -704,7 +704,7 @@ RESULT_(T_QUAD, i, e->u.data); break; case EAF_TYPE_OPAQUE: - RESULT_(T_ENUM_EMPTY, i, 0); + RESULT_(T_OPAQUE, ad, e->u.ptr); break; case EAF_TYPE_IP_ADDRESS: RESULT_(T_IP, ip, *((ip_addr *) e->u.ptr->data)); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 04920941..86124bfb 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -328,9 +328,9 @@ dynamic_attr: BGP_MED dynamic_attr: BGP_LOCAL_PREF { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; dynamic_attr: BGP_ATOMIC_AGGR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; dynamic_attr: BGP_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; dynamic_attr: BGP_ORIGINATOR_ID @@ -340,7 +340,7 @@ dynamic_attr: BGP_CLUSTER_LIST dynamic_attr: BGP_EXT_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; dynamic_attr: BGP_AIGP - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ; + { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ; dynamic_attr: BGP_LARGE_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; -- cgit v1.2.3 From 0d0f6554a5c233bf2bf830ae319191c4b1808d49 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sat, 26 Mar 2022 11:56:02 +0100 Subject: Unified attribute and filter types This commit removes the EAF_TYPE_* namespace completely and also for route attributes, filter-based types T_* are used. This simplifies fetching and setting route attributes from filters. Also, there is now union bval which serves as an universal value holder instead of private unions held separately by eattr and filter code. --- filter/config.Y | 25 +- filter/data.c | 20 +- filter/data.h | 84 +- filter/decl.m4 | 4 +- filter/f-inst.c | 128 +-- filter/f-inst.h | 12 +- filter/f-util.c | 27 +- filter/filter.h | 2 +- filter/test.conf | 6 +- lib/type.h | 87 ++ nest/config.Y | 2 +- nest/route.h | 47 +- nest/rt-attr.c | 23 +- proto/babel/babel.c | 6 +- proto/babel/config.Y | 2 +- proto/bgp/attrs.c | 40 +- proto/bgp/bgp.h | 16 +- proto/bgp/config.Y | 26 +- proto/ospf/config.Y | 8 +- proto/ospf/rt.c | 8 +- proto/radv/config.Y | 4 +- proto/rip/config.Y | 4 +- proto/rip/rip.c | 6 +- sysdep/bsd/krt-sock.c | 2 +- sysdep/linux/netlink.Y | 32 +- sysdep/linux/netlink.c | 12 +- sysdep/linux/netlink.c.orig | 2179 ------------------------------------------- sysdep/unix/krt.Y | 4 +- 28 files changed, 299 insertions(+), 2517 deletions(-) create mode 100644 lib/type.h delete mode 100644 sysdep/linux/netlink.c.orig (limited to 'filter/data.h') diff --git a/filter/config.Y b/filter/config.Y index fb331c16..22981945 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -163,26 +163,11 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) static inline struct f_inst * f_generate_empty(struct f_dynamic_attr dyn) { - struct f_val empty; + const struct f_val *empty = f_get_empty(dyn.type); + if (!empty) + cf_error("Can't empty that attribute"); - switch (dyn.type) { - case EAF_TYPE_AS_PATH: - empty = f_const_empty_path; - break; - case EAF_TYPE_INT_SET: - empty = f_const_empty_clist; - break; - case EAF_TYPE_EC_SET: - empty = f_const_empty_eclist; - break; - case EAF_TYPE_LC_SET: - empty = f_const_empty_lclist; - break; - default: - cf_error("Can't empty that attribute"); - } - - return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); + return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, *empty), dyn); } #define BA_AS_PATH 0x02 @@ -190,7 +175,7 @@ f_generate_empty(struct f_dynamic_attr dyn) static inline struct f_inst * f_implicit_roa_check(struct rtable_config *tab) { - struct f_dynamic_attr fda = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + struct f_dynamic_attr fda = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1); diff --git a/filter/data.c b/filter/data.c index 56c1fb17..c3f8bf57 100644 --- a/filter/data.c +++ b/filter/data.c @@ -27,6 +27,8 @@ static const char * const f_type_str[] = { [T_VOID] = "void", + [T_OPAQUE] = "opaque byte string", + [T_IFACE] = "interface", [T_INT] = "int", [T_BOOL] = "bool", @@ -47,6 +49,7 @@ static const char * const f_type_str[] = { [T_NET] = "prefix", [T_STRING] = "string", [T_PATH_MASK] = "bgpmask", + [T_PATH_MASK_ITEM] = "bgpmask item", [T_PATH] = "bgppath", [T_CLIST] = "clist", [T_EC] = "ec", @@ -54,22 +57,19 @@ static const char * const f_type_str[] = { [T_LC] = "lc", [T_LCLIST] = "lclist", [T_RD] = "rd", + + [T_SET] = "set", + [T_PREFIX_SET] = "prefix set", }; const char * -f_type_name(enum f_type t) +f_type_name(btype t) { - if (t < ARRAY_SIZE(f_type_str)) - return f_type_str[t] ?: "?"; - - if ((t == T_SET) || (t == T_PREFIX_SET)) - return "set"; - - return "?"; + return (t < ARRAY_SIZE(f_type_str)) ? (f_type_str[t] ?: "?") : "?"; } -enum f_type -f_type_element_type(enum f_type t) +btype +f_type_element_type(btype t) { switch(t) { case T_CLIST: return T_PAIR; diff --git a/filter/data.h b/filter/data.h index 924bbf3e..0b1e8e57 100644 --- a/filter/data.h +++ b/filter/data.h @@ -11,65 +11,15 @@ #define _BIRD_FILTER_DATA_H_ #include "nest/bird.h" - -/* Type numbers must be in 0..0xff range */ -#define T_MASK 0xff - -/* Internal types */ -enum f_type { -/* Nothing. Simply nothing. */ - T_VOID = 0, - -/* Something but inaccessible. */ - T_OPAQUE = 0xee, - -/* User visible types, which fit in int */ - T_INT = 0x10, - T_BOOL = 0x11, - T_PAIR = 0x12, /* Notice that pair is stored as integer: first << 16 | second */ - T_QUAD = 0x13, - -/* Put enumerational types in 0x30..0x3f range */ - T_ENUM_LO = 0x30, - T_ENUM_HI = 0x3f, - - T_ENUM_RTS = 0x30, - T_ENUM_BGP_ORIGIN = 0x31, - T_ENUM_SCOPE = 0x32, - T_ENUM_RTC = 0x33, - T_ENUM_RTD = 0x34, - T_ENUM_ROA = 0x35, - T_ENUM_NETTYPE = 0x36, - T_ENUM_RA_PREFERENCE = 0x37, - T_ENUM_AF = 0x38, - -/* new enums go here */ - -#define T_ENUM T_ENUM_LO ... T_ENUM_HI - -/* Bigger ones */ - T_IP = 0x20, - T_NET = 0x21, - T_STRING = 0x22, - T_PATH_MASK = 0x23, /* mask for BGP path */ - T_PATH = 0x24, /* BGP path */ - T_CLIST = 0x25, /* Community list */ - T_EC = 0x26, /* Extended community value, u64 */ - T_ECLIST = 0x27, /* Extended community list */ - T_LC = 0x28, /* Large community value, lcomm */ - T_LCLIST = 0x29, /* Large community list */ - T_RD = 0x2a, /* Route distinguisher for VPN addresses */ - T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ - - T_SET = 0x80, - T_PREFIX_SET = 0x81, -} PACKED; +#include "lib/type.h" /* Filter value; size of this affects filter memory consumption */ struct f_val { - enum f_type type; /* T_* */ + btype type; /* T_* */ union { - uint i; + union bval bval; + BVAL_ITEMS; + u64 ec; lcomm lc; ip_addr ip; @@ -77,17 +27,17 @@ struct f_val { const char *s; const struct f_tree *t; const struct f_trie *ti; - const struct adata *ad; const struct f_path_mask *path_mask; struct f_path_mask_item pmi; } val; }; +#define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; }) + /* Dynamic attribute definition (eattrs) */ struct f_dynamic_attr { - u8 type; /* EA type (EAF_*) */ + btype type; /* EA type (EAF_*) */ u8 bit; /* For bitfield accessors */ - enum f_type f_type; /* Filter type */ uint ea_code; /* EA code */ }; @@ -108,9 +58,9 @@ enum f_sa_code { /* Static attribute definition (members of struct rta) */ struct f_static_attr { - enum f_type f_type; /* Filter type */ + btype type; /* Data type */ enum f_sa_code sa_code; /* Static attribute id */ - int readonly:1; /* Don't allow writing */ + int readonly:1; /* Don't allow writing */ }; /* Filter l-value type */ @@ -266,9 +216,9 @@ trie_match_next_longest_ip6(net_addr_ip6 *n, ip6_addr *found) #define F_CMP_ERROR 999 -const char *f_type_name(enum f_type t); +const char *f_type_name(btype t); -enum f_type f_type_element_type(enum f_type t); +enum btype f_type_element_type(btype t); int val_same(const struct f_val *v1, const struct f_val *v2); int val_compare(const struct f_val *v1, const struct f_val *v2); @@ -301,6 +251,16 @@ undef_value(struct f_val v) } extern const struct f_val f_const_empty_path, f_const_empty_clist, f_const_empty_eclist, f_const_empty_lclist; +static inline const struct f_val *f_get_empty(btype t) +{ + switch (t) { + case T_PATH: return &f_const_empty_path; + case T_CLIST: return &f_const_empty_clist; + case T_ECLIST: return &f_const_empty_eclist; + case T_LCLIST: return &f_const_empty_lclist; + default: return NULL; + } +} enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); diff --git a/filter/decl.m4 b/filter/decl.m4 index 44537aaa..2e4fb235 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -490,7 +490,7 @@ fi_constant(struct f_inst *what, struct f_val val) } static int -f_const_promotion(struct f_inst *arg, enum f_type want) +f_const_promotion(struct f_inst *arg, btype want) { if (arg->fi_code != FI_CONSTANT) return 0; @@ -640,7 +640,7 @@ FID_WR_PUT(4)m4_dnl struct f_inst { struct f_inst *next; /* Next instruction */ enum f_instruction_code fi_code; /* Instruction code */ - enum f_type type; /* Type of returned value, if known */ + btype type; /* Type of returned value, if known */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ union { diff --git a/filter/f-inst.c b/filter/f-inst.c index 75a53499..e0bad833 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -533,21 +533,21 @@ switch (sa.sa_code) { - case SA_FROM: RESULT(sa.f_type, ip, rta->from); break; - case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break; - case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break; - case SA_PROTO: RESULT(sa.f_type, s, (*fs->rte)->src->proto->name); break; - case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break; - case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break; - case SA_DEST: RESULT(sa.f_type, i, rta->dest); break; - case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break; - case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break; - case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break; - case SA_PREF: RESULT(sa.f_type, i, rta->pref); break; - case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break; + case SA_FROM: RESULT(sa.type, ip, rta->from); break; + case SA_GW: RESULT(sa.type, ip, rta->nh.gw); break; + case SA_NET: RESULT(sa.type, net, (*fs->rte)->net->n.addr); break; + case SA_PROTO: RESULT(sa.type, s, (*fs->rte)->src->proto->name); break; + case SA_SOURCE: RESULT(sa.type, i, rta->source); break; + case SA_SCOPE: RESULT(sa.type, i, rta->scope); break; + case SA_DEST: RESULT(sa.type, i, rta->dest); break; + case SA_IFNAME: RESULT(sa.type, s, rta->nh.iface ? rta->nh.iface->name : ""); break; + case SA_IFINDEX: RESULT(sa.type, i, rta->nh.iface ? rta->nh.iface->index : 0); break; + case SA_WEIGHT: RESULT(sa.type, i, rta->nh.weight + 1); break; + case SA_PREF: RESULT(sa.type, i, rta->pref); break; + case SA_GW_MPLS: RESULT(sa.type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break; default: - bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); + bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code); } } } @@ -556,7 +556,7 @@ ACCESS_RTE; ARG_ANY(1); STATIC_ATTR; - ARG_TYPE(1, sa.f_type); + ARG_TYPE(1, sa.type); f_rta_cow(fs); { @@ -653,7 +653,7 @@ break; default: - bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); + bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code); } } } @@ -662,68 +662,30 @@ DYNAMIC_ATTR; ACCESS_RTE; ACCESS_EATTRS; - RESULT_TYPE(da.f_type); + RESULT_TYPE(da.type); { + const struct f_val *empty; eattr *e = ea_find(*fs->eattrs, da.ea_code); - if (!e) { - /* A special case: undefined as_path looks like empty as_path */ - if (da.type == EAF_TYPE_AS_PATH) { - RESULT_(T_PATH, ad, &null_adata); - break; - } - - /* The same special case for int_set */ - if (da.type == EAF_TYPE_INT_SET) { - RESULT_(T_CLIST, ad, &null_adata); - break; - } - - /* The same special case for ec_set */ - if (da.type == EAF_TYPE_EC_SET) { - RESULT_(T_ECLIST, ad, &null_adata); - break; - } + if (e) + { + ASSERT_DIE(e->type == da.type); - /* The same special case for lc_set */ - if (da.type == EAF_TYPE_LC_SET) { - RESULT_(T_LCLIST, ad, &null_adata); - break; + switch (e->type) { + case T_IP: + RESULT_(T_IP, ip, *((const ip_addr *) e->u.ptr->data)); + break; + default: + RESULT_VAL([[(struct f_val) { + .type = e->type, + .val.bval = e->u, + }]]); } - - /* Undefined value */ - RESULT_VOID; - break; - } - - switch (e->type) { - case EAF_TYPE_INT: - RESULT_(da.f_type, i, e->u.data); - break; - case EAF_TYPE_ROUTER_ID: - RESULT_(T_QUAD, i, e->u.data); - break; - case EAF_TYPE_OPAQUE: - RESULT_(T_OPAQUE, ad, e->u.ptr); - break; - case EAF_TYPE_IP_ADDRESS: - RESULT_(T_IP, ip, *((ip_addr *) e->u.ptr->data)); - break; - case EAF_TYPE_AS_PATH: - RESULT_(T_PATH, ad, e->u.ptr); - break; - case EAF_TYPE_INT_SET: - RESULT_(T_CLIST, ad, e->u.ptr); - break; - case EAF_TYPE_EC_SET: - RESULT_(T_ECLIST, ad, e->u.ptr); - break; - case EAF_TYPE_LC_SET: - RESULT_(T_LCLIST, ad, e->u.ptr); - break; - default: - bug("Unknown dynamic attribute type"); } + else if (empty = f_get_empty(da.type)) + RESULT_VAL(*empty); + else + RESULT_VOID; } } @@ -732,7 +694,7 @@ ACCESS_EATTRS; ARG_ANY(1); DYNAMIC_ATTR; - ARG_TYPE(1, da.f_type); + ARG_TYPE(1, da.type); { struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); @@ -746,17 +708,16 @@ l->attrs[0].fresh = 1; l->attrs[0].undef = 0; - switch (da.type) { - case EAF_TYPE_INT: - case EAF_TYPE_ROUTER_ID: - l->attrs[0].u.data = v1.val.i; - break; + if (da.type >= EAF_TYPE__MAX) + bug("Unsupported attribute type"); - case EAF_TYPE_OPAQUE: + switch (da.type) { + case T_OPAQUE: + case T_IFACE: runtime( "Setting opaque attribute is not allowed" ); break; - case EAF_TYPE_IP_ADDRESS:; + case T_IP:; int len = sizeof(ip_addr); struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len); ad->length = len; @@ -764,15 +725,10 @@ l->attrs[0].u.ptr = ad; break; - case EAF_TYPE_AS_PATH: - case EAF_TYPE_INT_SET: - case EAF_TYPE_EC_SET: - case EAF_TYPE_LC_SET: - l->attrs[0].u.ptr = v1.val.ad; + default: + l->attrs[0].u = v1.val.bval; break; - default: - bug("Unknown dynamic attribute type"); } f_rta_cow(fs); diff --git a/filter/f-inst.h b/filter/f-inst.h index 9265ecec..32da4653 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -87,12 +87,12 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit); struct filter *f_new_where(struct f_inst *); -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ -{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ -static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */ -{ return (struct f_dynamic_attr) { .type = EAF_TYPE_INT, .bit = bit, .f_type = T_INT, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */ -static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly) -{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; } +static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, uint code) +{ return (struct f_dynamic_attr) { .type = type, .ea_code = code }; } +static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, uint code) +{ return (struct f_dynamic_attr) { .type = T_INT, .bit = bit, .ea_code = code }; } +static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly) +{ return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; } struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); diff --git a/filter/f-util.c b/filter/f-util.c index 410999a6..79cf3452 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -82,8 +82,8 @@ static void ca_dump(resource *r) { struct custom_attribute *ca = (void *) r; - debug("name \"%s\" id 0x%04x ea_type 0x%02x f_type 0x%02x\n", - ca->name, ca->fda->ea_code, ca->fda->type, ca->fda->f_type); + debug("name \"%s\" id 0x%04x ea_type 0x%02x\n", + ca->name, ca->fda->ea_code, ca->fda->type); } static struct resclass ca_class = { @@ -96,31 +96,16 @@ static struct resclass ca_class = { }; struct custom_attribute * -ca_lookup(pool *p, const char *name, int f_type) +ca_lookup(pool *p, const char *name, btype type) { - int ea_type; - - switch (f_type) { + switch (type) { case T_INT: - ea_type = EAF_TYPE_INT; - break; case T_IP: - ea_type = EAF_TYPE_IP_ADDRESS; - break; case T_QUAD: - ea_type = EAF_TYPE_ROUTER_ID; - break; case T_PATH: - ea_type = EAF_TYPE_AS_PATH; - break; case T_CLIST: - ea_type = EAF_TYPE_INT_SET; - break; case T_ECLIST: - ea_type = EAF_TYPE_EC_SET; - break; case T_LCLIST: - ea_type = EAF_TYPE_LC_SET; break; default: cf_error("Custom route attribute of unsupported type"); @@ -137,7 +122,7 @@ ca_lookup(pool *p, const char *name, int f_type) inited++; } - struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, ea_type); + struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, type); if (cas) { cas->uc++; } else { @@ -153,7 +138,7 @@ ca_lookup(pool *p, const char *name, int f_type) } cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1); - cas->fda = f_new_dynamic_attr(ea_type, f_type, EA_CUSTOM(id)); + cas->fda = f_new_dynamic_attr(type, EA_CUSTOM(id)); cas->uc = 1; strcpy(cas->name, name); diff --git a/filter/filter.h b/filter/filter.h index 26c1037b..e9c9d917 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -77,6 +77,6 @@ struct custom_attribute { const char *name; }; -struct custom_attribute *ca_lookup(pool *p, const char *name, int ea_type); +struct custom_attribute *ca_lookup(pool *p, const char *name, btype type); #endif diff --git a/filter/test.conf b/filter/test.conf index ee2f5be4..062756b1 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -406,9 +406,9 @@ bt_test_suite(t_ip_set, "Testing sets of ip address"); function t_enum() { - bt_assert(format(RTS_STATIC) = "(enum 30)1"); - bt_assert(format(NET_IP4) = "(enum 36)1"); - bt_assert(format(NET_VPN6) = "(enum 36)4"); + bt_assert(format(RTS_STATIC) = "(enum 31)1"); + bt_assert(format(NET_IP4) = "(enum 3b)1"); + bt_assert(format(NET_VPN6) = "(enum 3b)4"); bt_assert(RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE]); bt_assert(RTS_BGP !~ [RTS_STATIC, RTS_DEVICE]); diff --git a/lib/type.h b/lib/type.h new file mode 100644 index 00000000..d0a887d8 --- /dev/null +++ b/lib/type.h @@ -0,0 +1,87 @@ +/* + * BIRD Internet Routing Daemon -- Internal Data Types + * + * (c) 2022 Maria Matejka + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_TYPE_H_ +#define _BIRD_TYPE_H_ + +#include "lib/birdlib.h" + +union bval { +#define BVAL_ITEMS \ + u32 data; /* Integer type inherited from eattrs */ \ + u32 i; /* Integer type inherited from filters */ \ + const struct adata *ptr; /* Generic attribute data inherited from eattrs */ \ + const struct adata *ad; /* Generic attribute data inherited from filters */ \ + + BVAL_ITEMS +}; + +/* Internal types */ +enum btype { +/* Nothing. Simply nothing. */ + T_VOID = 0, + +/* Something but inaccessible. */ + T_OPAQUE = 0x02, /* Opaque byte string (not filterable) */ + T_IFACE = 0x0c, /* Pointer to an interface (inside adata) */ + +/* Types shared with eattrs */ + T_INT = 0x01, /* 32-bit unsigned integer number */ + T_IP = 0x04, /* IP address */ + T_QUAD = 0x05, /* Router ID (IPv4 address) */ + T_PATH = 0x06, /* BGP AS path (encoding per RFC 1771:4.3) */ + T_CLIST = 0x0a, /* Set of u32's (e.g., a community list) */ + T_ECLIST = 0x0e, /* Set of pairs of u32's - ext. community list */ + T_LCLIST = 0x08, /* Set of triplets of u32's - large community list */ + + T_ENUM_BGP_ORIGIN = 0x11, /* BGP Origin enum */ + T_ENUM_RA_PREFERENCE = 0x13, /* RA Preference enum */ + +#define EAF_TYPE__MAX 0x1f +#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ + /* Otherwise, attribute data is adata */ + +/* Other user visible types which fit in int */ + T_BOOL = 0xa0, + T_PAIR = 0xa4, /* Notice that pair is stored as integer: first << 16 | second */ + +/* Put enumerational types in 0x20..0x3f range */ + T_ENUM_LO = 0x10, + T_ENUM_HI = 0x3f, + + T_ENUM_RTS = 0x31, + T_ENUM_SCOPE = 0x33, + T_ENUM_RTC = 0x35, + T_ENUM_RTD = 0x37, + T_ENUM_ROA = 0x39, + T_ENUM_NETTYPE = 0x3b, + T_ENUM_AF = 0x3d, + +/* new enums go here */ + +#define T_ENUM T_ENUM_LO ... T_ENUM_HI + +/* Bigger ones */ + T_NET = 0xb0, + T_STRING = 0xb4, + T_PATH_MASK = 0xb8, /* mask for BGP path */ + T_EC = 0xbc, /* Extended community value, u64 */ + T_LC = 0xc0, /* Large community value, lcomm */ + T_RD = 0xc4, /* Route distinguisher for VPN addresses */ + T_PATH_MASK_ITEM = 0xc8, /* Path mask item for path mask constructors */ + + T_SET = 0x80, + T_PREFIX_SET = 0x84, +} PACKED; + +typedef enum btype btype; + +STATIC_ASSERT(sizeof(btype) == sizeof(byte)); + + +#endif diff --git a/nest/config.Y b/nest/config.Y index 92a80589..b597b332 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -921,7 +921,7 @@ proto_patt2: | TEXT { $$.ptr = $1; $$.patt = 1; } ; -dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ; +dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_GEN_IGP_METRIC); } ; CF_CODE diff --git a/nest/route.h b/nest/route.h index d2f60f41..da8c723f 100644 --- a/nest/route.h +++ b/nest/route.h @@ -13,6 +13,7 @@ #include "lib/bitmap.h" #include "lib/resource.h" #include "lib/net.h" +#include "lib/type.h" struct ea_list; struct protocol; @@ -506,10 +507,8 @@ typedef struct eattr { byte originated:1; /* The attribute has originated locally */ byte fresh:1; /* An uncached attribute (e.g. modified in export filter) */ byte undef:1; /* Explicitly undefined */ - union { - uintptr_t data; - const struct adata *ptr; /* Attribute data elsewhere */ - } u; + + union bval u; } eattr; @@ -530,22 +529,6 @@ const char *ea_custom_name(uint ea); #define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */ #define EA_BIT_GET(ea) ((ea) >> 24) -#define EAF_TYPE_MASK 0x1f /* Mask with this to get type */ -#define EAF_TYPE_INT 0x01 /* 32-bit unsigned integer number */ -#define EAF_TYPE_OPAQUE 0x02 /* Opaque byte string (not filterable) */ -#define EAF_TYPE_IP_ADDRESS 0x04 /* IP address */ -#define EAF_TYPE_ROUTER_ID 0x05 /* Router ID (IPv4 address) */ -#define EAF_TYPE_AS_PATH 0x06 /* BGP AS path (encoding per RFC 1771:4.3) */ -#define EAF_TYPE_INT_SET 0x0a /* Set of u32's (e.g., a community list) */ -#define EAF_TYPE_EC_SET 0x0e /* Set of pairs of u32's - ext. community list */ -#define EAF_TYPE_LC_SET 0x08 /* Set of triplets of u32's - large community list */ -#define EAF_TYPE_IFACE 0x0c /* Interface pointer stored in adata */ -#define EAF_TYPE_BGP_ORIGIN 0x11 /* BGP Origin enum */ -#define EAF_TYPE_RA_PREFERENCE 0x13 /* RA Preference enum */ - -#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */ - /* Otherwise, attribute data is adata */ - typedef struct adata { uint length; /* Length of data */ byte data[0]; @@ -591,7 +574,7 @@ struct ea_walk_state { eattr *ea_find(ea_list *, unsigned ea); eattr *ea_walk(struct ea_walk_state *s, uint id, uint max); -uintptr_t ea_get_int(ea_list *, unsigned ea, uintptr_t def); +u32 ea_get_int(ea_list *, unsigned ea, u32 def); void ea_dump(ea_list *); void ea_sort(ea_list *); /* Sort entries in all sub-lists */ unsigned ea_scan(ea_list *); /* How many bytes do we need for merged ea_list */ @@ -618,7 +601,7 @@ struct ea_one_attr_list { }; static inline eattr * -ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, uintptr_t val) +ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, union bval val) { struct ea_one_attr_list *ea = lp_alloc(pool, sizeof(*ea)); *ea = (struct ea_one_attr_list) { @@ -631,11 +614,7 @@ ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, .a.flags = flags, }; - if (type & EAF_EMBEDDED) - ea->a.u.data = val; - else - ea->a.u.ptr = (struct adata *) val; - + ea->a.u = val; *to = &ea->l; return &ea->a; @@ -659,19 +638,19 @@ ea_unset_attr(ea_list **to, struct linpool *pool, _Bool local, uint code) } static inline void -ea_set_attr_u32(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, u32 val) -{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); } - -static inline void -ea_set_attr_ptr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, struct adata *val) -{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); } +ea_set_attr_u32(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, u32 data) +{ + union bval bv = { .data = data }; + ea_set_attr(to, pool, id, flags, type, bv); +} static inline void ea_set_attr_data(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, void *data, uint len) { struct adata *a = lp_alloc_adata(pool, len); memcpy(a->data, data, len); - ea_set_attr(to, pool, id, flags, type, (uintptr_t) a); + union bval bv = { .ptr = a, }; + ea_set_attr(to, pool, id, flags, type, bv); } diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 25548dca..de45dfa1 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -539,8 +539,8 @@ ea_walk(struct ea_walk_state *s, uint id, uint max) * by calling ea_find() to find the attribute, extracting its value or returning * a provided default if no such attribute is present. */ -uintptr_t -ea_get_int(ea_list *e, unsigned id, uintptr_t def) +u32 +ea_get_int(ea_list *e, unsigned id, u32 def) { eattr *a = ea_find(e, id); if (!a) @@ -950,30 +950,33 @@ ea_show(struct cli *c, const eattr *e) else switch (e->type) { - case EAF_TYPE_INT: + case T_INT: bsprintf(pos, "%u", e->u.data); break; - case EAF_TYPE_OPAQUE: + case T_OPAQUE: opaque_format(ad, pos, end - pos); break; - case EAF_TYPE_IP_ADDRESS: + case T_IP: bsprintf(pos, "%I", *(ip_addr *) ad->data); break; - case EAF_TYPE_ROUTER_ID: + case T_QUAD: bsprintf(pos, "%R", e->u.data); break; - case EAF_TYPE_AS_PATH: + case T_PATH: as_path_format(ad, pos, end - pos); break; - case EAF_TYPE_INT_SET: + case T_CLIST: ea_show_int_set(c, ad, 1, pos, buf, end); return; - case EAF_TYPE_EC_SET: + case T_ECLIST: ea_show_ec_set(c, ad, pos, buf, end); return; - case EAF_TYPE_LC_SET: + case T_LCLIST: ea_show_lc_set(c, ad, pos, buf, end); return; + case T_IFACE: + bsprintf(pos, "%s", ((struct iface *) e->u.ptr)->name); + return; default: bsprintf(pos, "", e->type); } diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 8040345f..a6cc7aa3 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -654,7 +654,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) *a0.eattrs = (ea_list) { .count = 3 }; a0.eattrs->attrs[0] = (eattr) { .id = EA_BABEL_METRIC, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = r->metric, }; @@ -663,13 +663,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) memcpy(ad->data, &(r->router_id), sizeof(u64)); a0.eattrs->attrs[1] = (eattr) { .id = EA_BABEL_ROUTER_ID, - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .u.ptr = ad, }; a0.eattrs->attrs[2] = (eattr) { .id = EA_BABEL_SEQNO, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = r->seqno, }; diff --git a/proto/babel/config.Y b/proto/babel/config.Y index 05210fa4..fa745993 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -163,7 +163,7 @@ babel_iface_opt_list: babel_iface: babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish; -dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BABEL_METRIC); } ; +dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_BABEL_METRIC); } ; CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index b514f1b9..1bae942d 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -80,7 +80,7 @@ static const struct bgp_attr_desc bgp_attr_table[]; static inline int bgp_attr_known(uint code); eattr * -bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintptr_t val) +bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, union bval val) { ASSERT(bgp_attr_known(code)); @@ -976,7 +976,7 @@ static inline void bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to) { /* Cannot use bgp_set_attr_data() as it works on known attributes only */ - ea_set_attr_data(to, s->pool, EA_CODE(PROTOCOL_BGP, code), flags, EAF_TYPE_OPAQUE, data, len); + ea_set_attr_data(to, s->pool, EA_CODE(PROTOCOL_BGP, code), flags, T_OPAQUE, data, len); } @@ -987,7 +987,7 @@ bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, static const struct bgp_attr_desc bgp_attr_table[] = { [BA_ORIGIN] = { .name = "origin", - .type = EAF_TYPE_BGP_ORIGIN, + .type = T_ENUM_BGP_ORIGIN, .flags = BAF_TRANSITIVE, .export = bgp_export_origin, .encode = bgp_encode_u8, @@ -996,14 +996,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_AS_PATH] = { .name = "as_path", - .type = EAF_TYPE_AS_PATH, + .type = T_PATH, .flags = BAF_TRANSITIVE, .encode = bgp_encode_as_path, .decode = bgp_decode_as_path, }, [BA_NEXT_HOP] = { .name = "next_hop", - .type = EAF_TYPE_IP_ADDRESS, + .type = T_IP, .flags = BAF_TRANSITIVE, .encode = bgp_encode_next_hop, .decode = bgp_decode_next_hop, @@ -1011,14 +1011,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_MULTI_EXIT_DISC] = { .name = "med", - .type = EAF_TYPE_INT, + .type = T_INT, .flags = BAF_OPTIONAL, .encode = bgp_encode_u32, .decode = bgp_decode_med, }, [BA_LOCAL_PREF] = { .name = "local_pref", - .type = EAF_TYPE_INT, + .type = T_INT, .flags = BAF_TRANSITIVE, .export = bgp_export_local_pref, .encode = bgp_encode_u32, @@ -1026,14 +1026,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_ATOMIC_AGGR] = { .name = "atomic_aggr", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_TRANSITIVE, .encode = bgp_encode_raw, .decode = bgp_decode_atomic_aggr, }, [BA_AGGREGATOR] = { .name = "aggregator", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_aggregator, .decode = bgp_decode_aggregator, @@ -1041,7 +1041,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_COMMUNITY] = { .name = "community", - .type = EAF_TYPE_INT_SET, + .type = T_CLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_community, .encode = bgp_encode_u32s, @@ -1049,7 +1049,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_ORIGINATOR_ID] = { .name = "originator_id", - .type = EAF_TYPE_ROUTER_ID, + .type = T_QUAD, .flags = BAF_OPTIONAL, .export = bgp_export_originator_id, .encode = bgp_encode_u32, @@ -1057,7 +1057,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_CLUSTER_LIST] = { .name = "cluster_list", - .type = EAF_TYPE_INT_SET, + .type = T_CLIST, .flags = BAF_OPTIONAL, .export = bgp_export_cluster_list, .encode = bgp_encode_u32s, @@ -1066,19 +1066,19 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_MP_REACH_NLRI] = { .name = "mp_reach_nlri", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_OPTIONAL, .decode = bgp_decode_mp_reach_nlri, }, [BA_MP_UNREACH_NLRI] = { .name = "mp_unreach_nlri", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_OPTIONAL, .decode = bgp_decode_mp_unreach_nlri, }, [BA_EXT_COMMUNITY] = { .name = "ext_community", - .type = EAF_TYPE_EC_SET, + .type = T_ECLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_ext_community, .encode = bgp_encode_u32s, @@ -1086,14 +1086,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_AS4_PATH] = { .name = "as4_path", - .type = EAF_TYPE_AS_PATH, + .type = T_PATH, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_raw, .decode = bgp_decode_as4_path, }, [BA_AS4_AGGREGATOR] = { .name = "as4_aggregator", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_raw, .decode = bgp_decode_as4_aggregator, @@ -1101,7 +1101,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_AIGP] = { .name = "aigp", - .type = EAF_TYPE_OPAQUE, + .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_DECODE_FLAGS, .export = bgp_export_aigp, .encode = bgp_encode_raw, @@ -1110,7 +1110,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_LARGE_COMMUNITY] = { .name = "large_community", - .type = EAF_TYPE_LC_SET, + .type = T_LCLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_large_community, .encode = bgp_encode_u32s, @@ -1118,7 +1118,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, [BA_MPLS_LABEL_STACK] = { .name = "mpls_label_stack", - .type = EAF_TYPE_INT_SET, + .type = T_CLIST, .export = bgp_export_mpls_label_stack, .encode = bgp_encode_mpls_label_stack, .decode = bgp_decode_mpls_label_stack, diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 8a44514c..6f209595 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -545,22 +545,28 @@ bgp_find_attr(ea_list *attrs, uint code) } eattr * -bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintptr_t val); +bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, union bval val); static inline void bgp_set_attr_u32(ea_list **to, struct linpool *pool, uint code, uint flags, u32 val) -{ bgp_set_attr(to, pool, code, flags, (uintptr_t) val); } +{ + union bval bv = { .data = val }; + bgp_set_attr(to, pool, code, flags, bv); +} static inline void -bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, const struct adata *val) -{ bgp_set_attr(to, pool, code, flags, (uintptr_t) val); } +bgp_set_attr_ptr(ea_list **to, struct linpool *pool, uint code, uint flags, const struct adata *ad) +{ + union bval bv = { .ptr = ad }; + bgp_set_attr(to, pool, code, flags, bv); +} static inline void bgp_set_attr_data(ea_list **to, struct linpool *pool, uint code, uint flags, void *data, uint len) { struct adata *a = lp_alloc_adata(pool, len); bmemcpy(a->data, data, len); - bgp_set_attr(to, pool, code, flags, (uintptr_t) a); + bgp_set_attr_ptr(to, pool, code, flags, a); } #define bgp_unset_attr(to, pool, code) ea_unset_attr(to, pool, 0, code) diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 86124bfb..6a78f79b 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -318,31 +318,31 @@ bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; dynamic_attr: BGP_ORIGIN - { $$ = f_new_dynamic_attr(EAF_TYPE_BGP_ORIGIN, T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; + { $$ = f_new_dynamic_attr(T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; dynamic_attr: BGP_PATH - { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; + { $$ = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; dynamic_attr: BGP_NEXT_HOP - { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; + { $$ = f_new_dynamic_attr(T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; dynamic_attr: BGP_MED - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; + { $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; dynamic_attr: BGP_LOCAL_PREF - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; + { $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; dynamic_attr: BGP_ATOMIC_AGGR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; + { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; + { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; dynamic_attr: BGP_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; dynamic_attr: BGP_ORIGINATOR_ID - { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; + { $$ = f_new_dynamic_attr(T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; dynamic_attr: BGP_CLUSTER_LIST - { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; + { $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; dynamic_attr: BGP_EXT_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; dynamic_attr: BGP_AIGP - { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ; + { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ; dynamic_attr: BGP_LARGE_COMMUNITY - { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; + { $$ = f_new_dynamic_attr(T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 4b7d5a36..a8972d2c 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -505,10 +505,10 @@ ospf_iface: ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } ; -dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC1); } ; -dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_METRIC2); } ; -dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_OSPF_TAG); } ; -dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_OSPF_ROUTER_ID); } ; +dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC1); } ; +dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC2); } ; +dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_TAG); } ; +dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(T_QUAD, EA_OSPF_ROUTER_ID); } ; CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); CF_CLI(SHOW OSPF, optproto, [], [[Show information about OSPF protocol]]) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 471bb586..8643f456 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2072,27 +2072,27 @@ again1: a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { .id = EA_OSPF_METRIC1, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = nf->n.metric1, }; if (nf->n.type == RTS_OSPF_EXT2) a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { .id = EA_OSPF_METRIC2, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = nf->n.metric2, }; if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2)) a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { .id = EA_OSPF_TAG, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = nf->n.tag, }; a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { .id = EA_OSPF_ROUTER_ID, - .type = EAF_TYPE_ROUTER_ID, + .type = T_QUAD, .u.data = nf->n.rid, }; diff --git a/proto/radv/config.Y b/proto/radv/config.Y index f16b897d..0a339cb4 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -336,8 +336,8 @@ radv_sensitive: | SENSITIVE bool { $$ = $2; } ; -dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_RA_PREFERENCE, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; -dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ; +dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; +dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(T_INT, EA_RA_LIFETIME); } ; CF_CODE diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 28ee9609..3934d337 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -190,8 +190,8 @@ rip_iface: rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish; -dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ; -dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ; +dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_RIP_METRIC); } ; +dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(T_INT, EA_RIP_TAG); } ; CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 6ca7a6b5..fa5b1289 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -202,17 +202,17 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .e = { { .id = EA_RIP_METRIC, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = rt_metric, }, { .id = EA_RIP_TAG, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = rt_tag, }, { .id = EA_RIP_FROM, - .type = EAF_TYPE_IFACE, + .type = T_IFACE, .u.ptr = &ea_block.riad.ad, } }, diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index efdb18a3..3b1d2299 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -589,7 +589,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) ea->attrs[0] = (eattr) { .id = EA_KRT_SOURCE, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = src2, }; diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index 7390be73..f31b88c7 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -28,23 +28,23 @@ kern_sys_item: | NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; } ; -dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ; -dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } ; -dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } ; +dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(T_IP, EA_KRT_PREFSRC); } ; +dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REALM); } ; +dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SCOPE); } ; -dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } ; -dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } ; -dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } ; -dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } ; -dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } ; -dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } ; -dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } ; -dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } ; -dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } ; -dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } ; -dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } ; -dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } ; -dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } ; +dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(T_INT, EA_KRT_MTU); } ; +dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(T_INT, EA_KRT_WINDOW); } ; +dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTT); } ; +dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTTVAR); } ; +dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SSTRESH); } ; +dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_CWND); } ; +dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(T_INT, EA_KRT_ADVMSS); } ; +dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REORDERING); } ; +dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_HOPLIMIT); } ; +dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITCWND); } ; +dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTO_MIN); } ; +dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITRWND); } ; +dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(T_INT, EA_KRT_QUICKACK); } ; /* Bits of EA_KRT_LOCK, based on RTAX_* constants */ diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 6c8228fd..eb4be711 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1587,12 +1587,12 @@ nl_announce_route(struct nl_parse_state *s) ea->attrs[0] = (eattr) { .id = EA_KRT_SOURCE, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = s->krt_proto, }; ea->attrs[1] = (eattr) { .id = EA_KRT_METRIC, - .type = EAF_TYPE_INT, + .type = T_INT, .u.data = s->krt_metric, }; @@ -1873,7 +1873,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) 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].type = T_INT; ea->attrs[0].u.data = i->rtm_scope; } @@ -1888,7 +1888,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) ea->count = 1; ea->attrs[0].id = EA_KRT_PREFSRC; ea->attrs[0].flags = 0; - ea->attrs[0].type = EAF_TYPE_IP_ADDRESS; + ea->attrs[0].type = T_IP; struct adata *ad = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps)); ad->length = sizeof(ps); @@ -1907,7 +1907,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) ea->count = 1; ea->attrs[0].id = EA_KRT_REALM; ea->attrs[0].flags = 0; - ea->attrs[0].type = EAF_TYPE_INT; + ea->attrs[0].type = T_INT; ea->attrs[0].u.data = s->rta_flow; } @@ -1928,7 +1928,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) { ea->attrs[n].id = EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t); ea->attrs[n].flags = 0; - ea->attrs[n].type = EAF_TYPE_INT; + ea->attrs[n].type = T_INT; ea->attrs[n].u.data = metrics[t]; n++; } diff --git a/sysdep/linux/netlink.c.orig b/sysdep/linux/netlink.c.orig deleted file mode 100644 index 7cea5322..00000000 --- a/sysdep/linux/netlink.c.orig +++ /dev/null @@ -1,2179 +0,0 @@ -/* - * BIRD -- Linux Netlink Interface - * - * (c) 1999--2000 Martin Mares - * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -#include -#include -#include -#include -#include -#include -#include - -#undef LOCAL_DEBUG - -#include "nest/bird.h" -#include "nest/route.h" -#include "nest/protocol.h" -#include "nest/iface.h" -#include "lib/alloca.h" -#include "sysdep/unix/unix.h" -#include "sysdep/unix/krt.h" -#include "lib/socket.h" -#include "lib/string.h" -#include "lib/hash.h" -#include "conf/conf.h" - -#include -#include -#include -#include - -#ifdef HAVE_MPLS_KERNEL -#include -#endif - -#ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */ -#define MSG_TRUNC 0x20 -#endif - -#ifndef IFA_FLAGS -#define IFA_FLAGS 8 -#endif - -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 -#endif - -#ifndef RTA_TABLE -#define RTA_TABLE 15 -#endif - -#ifndef RTA_VIA -#define RTA_VIA 18 -#endif - -#ifndef RTA_NEWDST -#define RTA_NEWDST 19 -#endif - -#ifndef RTA_ENCAP_TYPE -#define RTA_ENCAP_TYPE 21 -#endif - -#ifndef RTA_ENCAP -#define RTA_ENCAP 22 -#endif - -#define krt_ipv4(p) ((p)->af == AF_INET) -#define krt_ecmp6(p) ((p)->af == AF_INET6) - -const int rt_default_ecmp = 16; - -/* - * Structure nl_parse_state keeps state of received route processing. Ideally, - * we could just independently parse received Netlink messages and immediately - * propagate received routes to the rest of BIRD, but older Linux kernel (before - * version 4.11) represents and announces IPv6 ECMP routes not as one route with - * multiple next hops (like RTA_MULTIPATH in IPv4 ECMP), but as a sequence of - * routes with the same prefix. More recent kernels work as with IPv4. - * - * Therefore, BIRD keeps currently processed route in nl_parse_state structure - * and postpones its propagation until we expect it to be final; i.e., when - * non-matching route is received or when the scan ends. When another matching - * route is received, it is merged with the already processed route to form an - * ECMP route. Note that merging is done only for IPv6 (merge == 1), but the - * postponing is done in both cases (for simplicity). All IPv4 routes or IPv6 - * routes with RTA_MULTIPATH set are just considered non-matching. - * - * This is ignored for asynchronous notifications (every notification is handled - * as a separate route). It is not an issue for our routes, as we ignore such - * notifications anyways. But importing alien IPv6 ECMP routes does not work - * properly with older kernels. - * - * Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes - * for the same prefix. - */ - -struct nl_parse_state -{ - struct linpool *pool; - int scan; - int merge; - - net *net; - rta *attrs; - struct krt_proto *proto; - s8 new; - s8 krt_src; - u8 krt_type; - u8 krt_proto; - u32 krt_metric; - - u32 rta_flow; /* Used during parsing */ -}; - -/* - * Synchronous Netlink interface - */ - -struct nl_sock -{ - int fd; - u32 seq; - byte *rx_buffer; /* Receive buffer */ - struct nlmsghdr *last_hdr; /* Recently received packet */ - uint last_size; -}; - -#define NL_RX_SIZE 8192 - -#define NL_OP_DELETE 0 -#define NL_OP_ADD (NLM_F_CREATE|NLM_F_EXCL) -#define NL_OP_REPLACE (NLM_F_CREATE|NLM_F_REPLACE) -#define NL_OP_APPEND (NLM_F_CREATE|NLM_F_APPEND) - -static linpool *nl_linpool; - -static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */ -static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */ - -static void -nl_open_sock(struct nl_sock *nl) -{ - if (nl->fd < 0) - { - nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (nl->fd < 0) - die("Unable to open rtnetlink socket: %m"); - nl->seq = (u32) (current_time() TO_S); /* Or perhaps random_u32() ? */ - nl->rx_buffer = xmalloc(NL_RX_SIZE); - nl->last_hdr = NULL; - nl->last_size = 0; - } -} - -static void -nl_open(void) -{ - nl_open_sock(&nl_scan); - nl_open_sock(&nl_req); -} - -static void -nl_send(struct nl_sock *nl, struct nlmsghdr *nh) -{ - struct sockaddr_nl sa; - - memset(&sa, 0, sizeof(sa)); - sa.nl_family = AF_NETLINK; - nh->nlmsg_pid = 0; - nh->nlmsg_seq = ++(nl->seq); - nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len); - if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) - die("rtnetlink sendto: %m"); - nl->last_hdr = NULL; -} - -static void -nl_request_dump(int af, int cmd) -{ - struct { - struct nlmsghdr nh; - struct rtgenmsg g; - } req = { - .nh.nlmsg_type = cmd, - .nh.nlmsg_len = sizeof(req), - .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, - .g.rtgen_family = af - }; - nl_send(&nl_scan, &req.nh); -} - -static struct nlmsghdr * -nl_get_reply(struct nl_sock *nl) -{ - for(;;) - { - if (!nl->last_hdr) - { - struct iovec iov = { nl->rx_buffer, NL_RX_SIZE }; - struct sockaddr_nl sa; - struct msghdr m = { - .msg_name = &sa, - .msg_namelen = sizeof(sa), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - int x = recvmsg(nl->fd, &m, 0); - if (x < 0) - die("nl_get_reply: %m"); - if (sa.nl_pid) /* It isn't from the kernel */ - { - DBG("Non-kernel packet\n"); - continue; - } - nl->last_size = x; - nl->last_hdr = (void *) nl->rx_buffer; - if (m.msg_flags & MSG_TRUNC) - bug("nl_get_reply: got truncated reply which should be impossible"); - } - if (NLMSG_OK(nl->last_hdr, nl->last_size)) - { - struct nlmsghdr *h = nl->last_hdr; - nl->last_hdr = NLMSG_NEXT(h, nl->last_size); - if (h->nlmsg_seq != nl->seq) - { - log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)", - h->nlmsg_seq, nl->seq); - continue; - } - return h; - } - if (nl->last_size) - log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size); - nl->last_hdr = NULL; - } -} - -static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS; - -static int -nl_error(struct nlmsghdr *h, int ignore_esrch) -{ - struct nlmsgerr *e; - int ec; - - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) - { - log(L_WARN "Netlink: Truncated error message received"); - return ENOBUFS; - } - e = (struct nlmsgerr *) NLMSG_DATA(h); - ec = -e->error; - if (ec && !(ignore_esrch && (ec == ESRCH))) - log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec)); - return ec; -} - -static struct nlmsghdr * -nl_get_scan(void) -{ - struct nlmsghdr *h = nl_get_reply(&nl_scan); - - if (h->nlmsg_type == NLMSG_DONE) - return NULL; - if (h->nlmsg_type == NLMSG_ERROR) - { - nl_error(h, 0); - return NULL; - } - return h; -} - -static int -nl_exchange(struct nlmsghdr *pkt, int ignore_esrch) -{ - struct nlmsghdr *h; - - nl_send(&nl_req, pkt); - for(;;) - { - h = nl_get_reply(&nl_req); - if (h->nlmsg_type == NLMSG_ERROR) - break; - log(L_WARN "nl_exchange: Unexpected reply received"); - } - return nl_error(h, ignore_esrch) ? -1 : 0; -} - -/* - * Netlink attributes - */ - -static int nl_attr_len; - -static void * -nl_checkin(struct nlmsghdr *h, int lsize) -{ - nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize); - if (nl_attr_len < 0) - { - log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len); - return NULL; - } - return NLMSG_DATA(h); -} - -struct nl_want_attrs { - u8 defined:1; - u8 checksize:1; - u8 size; -}; - - -#define BIRD_IFLA_MAX (IFLA_WIRELESS+1) - -static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = { - [IFLA_IFNAME] = { 1, 0, 0 }, - [IFLA_MTU] = { 1, 1, sizeof(u32) }, - [IFLA_MASTER] = { 1, 1, sizeof(u32) }, - [IFLA_WIRELESS] = { 1, 0, 0 }, -}; - - -#define BIRD_IFA_MAX (IFA_FLAGS+1) - -static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = { - [IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) }, - [IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) }, - [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) }, - [IFA_FLAGS] = { 1, 1, sizeof(u32) }, -}; - -static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { - [IFA_ADDRESS] = { 1, 1, sizeof(ip6_addr) }, - [IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) }, - [IFA_FLAGS] = { 1, 1, sizeof(u32) }, -}; - - -#define BIRD_RTA_MAX (RTA_ENCAP+1) - -static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = { - [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, - [RTA_VIA] = { 1, 0, 0 }, - [RTA_FLOW] = { 1, 1, sizeof(u32) }, - [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, - [RTA_ENCAP] = { 1, 0, 0 }, -}; - -static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = { - [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, - [RTA_VIA] = { 1, 0, 0 }, - [RTA_FLOW] = { 1, 1, sizeof(u32) }, - [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, - [RTA_ENCAP] = { 1, 0, 0 }, -}; - -#ifdef HAVE_MPLS_KERNEL -static struct nl_want_attrs nexthop_attr_want_mpls[BIRD_RTA_MAX] = { - [RTA_VIA] = { 1, 0, 0 }, - [RTA_NEWDST] = { 1, 0, 0 }, -}; - -static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = { - [RTA_DST] = { 1, 0, 0 }, -}; -#endif - -static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = { - [RTA_DST] = { 1, 1, sizeof(ip4_addr) }, - [RTA_OIF] = { 1, 1, sizeof(u32) }, - [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, - [RTA_PRIORITY] = { 1, 1, sizeof(u32) }, - [RTA_PREFSRC] = { 1, 1, sizeof(ip4_addr) }, - [RTA_METRICS] = { 1, 0, 0 }, - [RTA_MULTIPATH] = { 1, 0, 0 }, - [RTA_FLOW] = { 1, 1, sizeof(u32) }, - [RTA_TABLE] = { 1, 1, sizeof(u32) }, - [RTA_VIA] = { 1, 0, 0 }, - [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, - [RTA_ENCAP] = { 1, 0, 0 }, -}; - -static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = { - [RTA_DST] = { 1, 1, sizeof(ip6_addr) }, - [RTA_SRC] = { 1, 1, sizeof(ip6_addr) }, - [RTA_IIF] = { 1, 1, sizeof(u32) }, - [RTA_OIF] = { 1, 1, sizeof(u32) }, - [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, - [RTA_PRIORITY] = { 1, 1, sizeof(u32) }, - [RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) }, - [RTA_METRICS] = { 1, 0, 0 }, - [RTA_MULTIPATH] = { 1, 0, 0 }, - [RTA_FLOW] = { 1, 1, sizeof(u32) }, - [RTA_TABLE] = { 1, 1, sizeof(u32) }, - [RTA_VIA] = { 1, 0, 0 }, - [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, - [RTA_ENCAP] = { 1, 0, 0 }, -}; - -#ifdef HAVE_MPLS_KERNEL -static struct nl_want_attrs rtm_attr_want_mpls[BIRD_RTA_MAX] = { - [RTA_DST] = { 1, 1, sizeof(u32) }, - [RTA_IIF] = { 1, 1, sizeof(u32) }, - [RTA_OIF] = { 1, 1, sizeof(u32) }, - [RTA_PRIORITY] = { 1, 1, sizeof(u32) }, - [RTA_METRICS] = { 1, 0, 0 }, - [RTA_MULTIPATH] = { 1, 0, 0 }, - [RTA_FLOW] = { 1, 1, sizeof(u32) }, - [RTA_TABLE] = { 1, 1, sizeof(u32) }, - [RTA_VIA] = { 1, 0, 0 }, - [RTA_NEWDST] = { 1, 0, 0 }, -}; -#endif - - -static int -nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k, int ksize) -{ - int max = ksize / sizeof(struct rtattr *); - bzero(k, ksize); - - for ( ; RTA_OK(a, nl_attr_len); a = RTA_NEXT(a, nl_attr_len)) - { - if ((a->rta_type >= max) || !want[a->rta_type].defined) - continue; - - if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size)) - { - log(L_ERR "nl_parse_attrs: Malformed attribute received"); - return 0; - } - - k[a->rta_type] = a; - } - - if (nl_attr_len) - { - log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len); - return 0; - } - - return 1; -} - -static inline u16 rta_get_u16(struct rtattr *a) -{ return *(u16 *) RTA_DATA(a); } - -static inline u32 rta_get_u32(struct rtattr *a) -{ return *(u32 *) RTA_DATA(a); } - -static inline ip4_addr rta_get_ip4(struct rtattr *a) -{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); } - -static inline ip6_addr rta_get_ip6(struct rtattr *a) -{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); } - -static inline ip_addr rta_get_ipa(struct rtattr *a) -{ - if (RTA_PAYLOAD(a) == sizeof(ip4_addr)) - return ipa_from_ip4(rta_get_ip4(a)); - else - return ipa_from_ip6(rta_get_ip6(a)); -} - -#ifdef HAVE_MPLS_KERNEL -static inline ip_addr rta_get_via(struct rtattr *a) -{ - struct rtvia *v = RTA_DATA(a); - switch(v->rtvia_family) { - case AF_INET: return ipa_from_ip4(ip4_ntoh(*(ip4_addr *) v->rtvia_addr)); - case AF_INET6: return ipa_from_ip6(ip6_ntoh(*(ip6_addr *) v->rtvia_addr)); - } - return IPA_NONE; -} - -static u32 rta_mpls_stack[MPLS_MAX_LABEL_STACK]; -static inline int rta_get_mpls(struct rtattr *a, u32 *stack) -{ - if (!a) - return 0; - - if (RTA_PAYLOAD(a) % 4) - log(L_WARN "KRT: Strange length of received MPLS stack: %u", RTA_PAYLOAD(a)); - - int labels = mpls_get(RTA_DATA(a), RTA_PAYLOAD(a) & ~0x3, stack); - - if (labels < 0) - { - log(L_WARN "KRT: Too long MPLS stack received, ignoring"); - labels = 0; - } - - return labels; -} -#endif - -struct rtattr * -nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen) -{ - uint pos = NLMSG_ALIGN(h->nlmsg_len); - uint len = RTA_LENGTH(dlen); - - if (pos + len > bufsize) - bug("nl_add_attr: packet buffer overflow"); - - struct rtattr *a = (struct rtattr *)((char *)h + pos); - a->rta_type = code; - a->rta_len = len; - h->nlmsg_len = pos + len; - - if (dlen > 0) - memcpy(RTA_DATA(a), data, dlen); - - return a; -} - -static inline struct rtattr * -nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code) -{ - return nl_add_attr(h, bufsize, code, NULL, 0); -} - -static inline void -nl_close_attr(struct nlmsghdr *h, struct rtattr *a) -{ - a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a; -} - -static inline void -nl_add_attr_u16(struct nlmsghdr *h, uint bufsize, int code, u16 data) -{ - nl_add_attr(h, bufsize, code, &data, 2); -} - -static inline void -nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data) -{ - nl_add_attr(h, bufsize, code, &data, 4); -} - -static inline void -nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4) -{ - ip4 = ip4_hton(ip4); - nl_add_attr(h, bufsize, code, &ip4, sizeof(ip4)); -} - -static inline void -nl_add_attr_ip6(struct nlmsghdr *h, uint bufsize, int code, ip6_addr ip6) -{ - ip6 = ip6_hton(ip6); - nl_add_attr(h, bufsize, code, &ip6, sizeof(ip6)); -} - -static inline void -nl_add_attr_ipa(struct nlmsghdr *h, uint bufsize, int code, ip_addr ipa) -{ - if (ipa_is_ip4(ipa)) - nl_add_attr_ip4(h, bufsize, code, ipa_to_ip4(ipa)); - else - nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa)); -} - -#ifdef HAVE_MPLS_KERNEL -static inline void -nl_add_attr_mpls(struct nlmsghdr *h, uint bufsize, int code, int len, u32 *stack) -{ - char buf[len*4]; - mpls_put(buf, len, stack); - nl_add_attr(h, bufsize, code, buf, len*4); -} - -static inline void -nl_add_attr_mpls_encap(struct nlmsghdr *h, uint bufsize, int len, u32 *stack) -{ - nl_add_attr_u16(h, bufsize, RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_MPLS); - - struct rtattr *nest = nl_open_attr(h, bufsize, RTA_ENCAP); - nl_add_attr_mpls(h, bufsize, RTA_DST, len, stack); - nl_close_attr(h, nest); -} - -static inline void -nl_add_attr_via(struct nlmsghdr *h, uint bufsize, ip_addr ipa) -{ - struct rtvia *via = alloca(sizeof(struct rtvia) + 16); - - if (ipa_is_ip4(ipa)) - { - via->rtvia_family = AF_INET; - put_ip4(via->rtvia_addr, ipa_to_ip4(ipa)); - nl_add_attr(h, bufsize, RTA_VIA, via, sizeof(struct rtvia) + 4); - } - else - { - via->rtvia_family = AF_INET6; - put_ip6(via->rtvia_addr, ipa_to_ip6(ipa)); - nl_add_attr(h, bufsize, RTA_VIA, via, sizeof(struct rtvia) + 16); - } -} -#endif - -static inline struct rtnexthop * -nl_open_nexthop(struct nlmsghdr *h, uint bufsize) -{ - uint pos = NLMSG_ALIGN(h->nlmsg_len); - uint len = RTNH_LENGTH(0); - - if (pos + len > bufsize) - bug("nl_open_nexthop: packet buffer overflow"); - - h->nlmsg_len = pos + len; - - return (void *)h + pos; -} - -static inline void -nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh) -{ - nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh; -} - -static inline void -nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUSED) -{ -#ifdef HAVE_MPLS_KERNEL - if (nh->labels > 0) - if (af == AF_MPLS) - nl_add_attr_mpls(h, bufsize, RTA_NEWDST, nh->labels, nh->label); - else - nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label); - - if (ipa_nonzero(nh->gw)) - { - if (af == (ipa_is_ip4(nh->gw) ? AF_INET : AF_INET6)) - nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw); - else - nl_add_attr_via(h, bufsize, nh->gw); - } -#else - - if (ipa_nonzero(nh->gw)) - nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw); -#endif -} - -static void -nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs) -{ - struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH); - eattr *flow = ea_find(eattrs, EA_KRT_REALM); - - for (; nh; nh = nh->next) - { - struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize); - - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = nh->weight; - rtnh->rtnh_ifindex = nh->iface->index; - - nl_add_nexthop(h, bufsize, nh, af); - - if (nh->flags & RNF_ONLINK) - rtnh->rtnh_flags |= RTNH_F_ONLINK; - - /* Our KRT_REALM is per-route, but kernel RTA_FLOW is per-nexthop. - Therefore, we need to attach the same attribute to each nexthop. */ - if (flow) - nl_add_attr_u32(h, bufsize, RTA_FLOW, flow->u.data); - - nl_close_nexthop(h, rtnh); - } - - nl_close_attr(h, a); -} - -static struct nexthop * -nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr *n, struct rtattr *ra, int af, int krt_src) -{ - struct rtattr *a[BIRD_RTA_MAX]; - struct rtnexthop *nh = RTA_DATA(ra); - struct nexthop *rv, *first, **last; - unsigned len = RTA_PAYLOAD(ra); - - first = NULL; - last = &first; - - while (len) - { - /* Use RTNH_OK(nh,len) ?? */ - if ((len < sizeof(*nh)) || (len < nh->rtnh_len)) - goto err; - - if ((nh->rtnh_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD)) - goto next; - - *last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE); - last = &(rv->next); - - rv->weight = nh->rtnh_hops; - rv->iface = if_find_by_index(nh->rtnh_ifindex); - if (!rv->iface) - { - log(L_ERR "KRT: Received route %N with unknown ifindex %u", n, nh->rtnh_ifindex); - return NULL; - } - - /* Nonexistent RTNH_PAYLOAD ?? */ - nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0); - switch (af) - { - case AF_INET: - if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a))) - goto err; - break; - - case AF_INET6: - if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want6, a, sizeof(a))) - goto err; - break; - -#ifdef HAVE_MPLS_KERNEL - case AF_MPLS: - if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want_mpls, a, sizeof(a))) - goto err; - - if (a[RTA_NEWDST]) - rv->labels = rta_get_mpls(a[RTA_NEWDST], rv->label); - - break; -#endif - - default: - goto err; - } - - if (a[RTA_GATEWAY]) - rv->gw = rta_get_ipa(a[RTA_GATEWAY]); - - if (a[RTA_FLOW]) - s->rta_flow = rta_get_u32(a[RTA_FLOW]); - -#ifdef HAVE_MPLS_KERNEL - if (a[RTA_VIA]) - rv->gw = rta_get_via(a[RTA_VIA]); -#endif - - if (ipa_nonzero(rv->gw)) - { - if (nh->rtnh_flags & RTNH_F_ONLINK) - rv->flags |= RNF_ONLINK; - - neighbor *nbr; - nbr = neigh_find(&p->p, rv->gw, rv->iface, - (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0); - if (!nbr || (nbr->scope == SCOPE_HOST)) - { - log(L_ERR "KRT: Received route %N with strange next-hop %I", n, rv->gw); - return NULL; - } - } - -#ifdef HAVE_MPLS_KERNEL - if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE]) - { - if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) - { - log(L_WARN "KRT: Received route %N with unknown encapsulation method %d", - n, rta_get_u16(a[RTA_ENCAP_TYPE])); - return NULL; - } - - struct rtattr *enca[BIRD_RTA_MAX]; - nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]); - nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca)); - rv->labels = rta_get_mpls(enca[RTA_DST], rv->label); - } -#endif - - next: - len -= NLMSG_ALIGN(nh->rtnh_len); - nh = RTNH_NEXT(nh); - } - - /* Ensure nexthops are sorted to satisfy nest invariant */ - if (!nexthop_is_sorted(first)) - first = nexthop_sort(first); - - return first; - -err: - log(L_ERR "KRT: Received strange multipath route %N", n); - return NULL; -} - -static void -nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max) -{ - struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS); - int t; - - for (t = 1; t < max; t++) - if (metrics[0] & (1 << t)) - nl_add_attr_u32(h, bufsize, t, metrics[t]); - - nl_close_attr(h, a); -} - -static int -nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max) -{ - struct rtattr *a = RTA_DATA(hdr); - int len = RTA_PAYLOAD(hdr); - - metrics[0] = 0; - for (; RTA_OK(a, len); a = RTA_NEXT(a, len)) - { - if (a->rta_type == RTA_UNSPEC) - continue; - - if (a->rta_type >= max) - continue; - - if (RTA_PAYLOAD(a) != 4) - return -1; - - metrics[0] |= 1 << a->rta_type; - metrics[a->rta_type] = rta_get_u32(a); - } - - if (len > 0) - return -1; - - return 0; -} - - -/* - * Scanning of interfaces - */ - -static void -nl_parse_link(struct nlmsghdr *h, int scan) -{ - struct ifinfomsg *i; - struct rtattr *a[BIRD_IFLA_MAX]; - int new = h->nlmsg_type == RTM_NEWLINK; - struct iface f = {}; - struct iface *ifi; - char *name; - u32 mtu, master = 0; - uint fl; - - if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a))) - return; - if (!a[IFLA_IFNAME] || (RTA_PAYLOAD(a[IFLA_IFNAME]) < 2) || !a[IFLA_MTU]) - { - /* - * IFLA_IFNAME and IFLA_MTU are required, in fact, but there may also come - * a message with IFLA_WIRELESS set, where (e.g.) no IFLA_IFNAME exists. - * We simply ignore all such messages with IFLA_WIRELESS without notice. - */ - - if (a[IFLA_WIRELESS]) - return; - - log(L_ERR "KIF: Malformed message received"); - return; - } - - name = RTA_DATA(a[IFLA_IFNAME]); - mtu = rta_get_u32(a[IFLA_MTU]); - - if (a[IFLA_MASTER]) - master = rta_get_u32(a[IFLA_MASTER]); - - ifi = if_find_by_index(i->ifi_index); - if (!new) - { - DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name); - if (!ifi) - return; - - if_delete(ifi); - } - else - { - DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags); - if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1)) - if_delete(ifi); - - strncpy(f.name, name, sizeof(f.name)-1); - f.index = i->ifi_index; - f.mtu = mtu; - - f.master_index = master; - f.master = if_find_by_index(master); - - fl = i->ifi_flags; - if (fl & IFF_UP) - f.flags |= IF_ADMIN_UP; - if (fl & IFF_LOWER_UP) - f.flags |= IF_LINK_UP; - if (fl & IFF_LOOPBACK) /* Loopback */ - f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE; - else if (fl & IFF_POINTOPOINT) /* PtP */ - f.flags |= IF_MULTICAST; - else if (fl & IFF_BROADCAST) /* Broadcast */ - f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST; - else - f.flags |= IF_MULTIACCESS; /* NBMA */ - - if (fl & IFF_MULTICAST) - f.flags |= IF_MULTICAST; - - ifi = if_update(&f); - - if (!scan) - if_end_partial_update(ifi); - } -} - -static void -nl_parse_addr4(struct ifaddrmsg *i, int scan, int new) -{ - struct rtattr *a[BIRD_IFA_MAX]; - struct iface *ifi; - u32 ifa_flags; - int scope; - - if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a))) - return; - - if (!a[IFA_LOCAL]) - { - log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)"); - return; - } - if (!a[IFA_ADDRESS]) - { - log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)"); - return; - } - - ifi = if_find_by_index(i->ifa_index); - if (!ifi) - { - log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index); - return; - } - - if (a[IFA_FLAGS]) - ifa_flags = rta_get_u32(a[IFA_FLAGS]); - else - ifa_flags = i->ifa_flags; - - struct ifa ifa; - bzero(&ifa, sizeof(ifa)); - ifa.iface = ifi; - if (ifa_flags & IFA_F_SECONDARY) - ifa.flags |= IA_SECONDARY; - - ifa.ip = rta_get_ipa(a[IFA_LOCAL]); - - if (i->ifa_prefixlen > IP4_MAX_PREFIX_LENGTH) - { - log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen); - new = 0; - } - if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH) - { - ifa.brd = rta_get_ipa(a[IFA_ADDRESS]); - net_fill_ip4(&ifa.prefix, rta_get_ip4(a[IFA_ADDRESS]), i->ifa_prefixlen); - - /* It is either a host address or a peer address */ - if (ipa_equal(ifa.ip, ifa.brd)) - ifa.flags |= IA_HOST; - else - { - ifa.flags |= IA_PEER; - ifa.opposite = ifa.brd; - } - } - else - { - net_fill_ip4(&ifa.prefix, ipa_to_ip4(ifa.ip), i->ifa_prefixlen); - net_normalize(&ifa.prefix); - - if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 1) - ifa.opposite = ipa_opposite_m1(ifa.ip); - - if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 2) - ifa.opposite = ipa_opposite_m2(ifa.ip); - - if (ifi->flags & IF_BROADCAST) - { - /* If kernel offers us a broadcast address, we trust it */ - if (a[IFA_BROADCAST]) - ifa.brd = ipa_from_ip4(rta_get_ip4(a[IFA_BROADCAST])); - /* Otherwise we create one (except for /31) */ - else if (i->ifa_prefixlen < (IP4_MAX_PREFIX_LENGTH - 1)) - ifa.brd = ipa_from_ip4(ip4_or(ipa_to_ip4(ifa.ip), - ip4_not(ip4_mkmask(i->ifa_prefixlen)))); - } - } - - scope = ipa_classify(ifa.ip); - if (scope < 0) - { - log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name); - return; - } - ifa.scope = scope & IADDR_SCOPE_MASK; - - DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n", - ifi->index, ifi->name, - new ? "added" : "removed", - ifa.ip, ifa.flags, &ifa.prefix, ifa.brd, ifa.opposite); - - if (new) - ifa_update(&ifa); - else - ifa_delete(&ifa); - - if (!scan) - if_end_partial_update(ifi); -} - -static void -nl_parse_addr6(struct ifaddrmsg *i, int scan, int new) -{ - struct rtattr *a[BIRD_IFA_MAX]; - struct iface *ifi; - u32 ifa_flags; - int scope; - - if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a))) - return; - - if (!a[IFA_ADDRESS]) - { - log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)"); - return; - } - - ifi = if_find_by_index(i->ifa_index); - if (!ifi) - { - log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index); - return; - } - - if (a[IFA_FLAGS]) - ifa_flags = rta_get_u32(a[IFA_FLAGS]); - else - ifa_flags = i->ifa_flags; - - struct ifa ifa; - bzero(&ifa, sizeof(ifa)); - ifa.iface = ifi; - if (ifa_flags & IFA_F_SECONDARY) - ifa.flags |= IA_SECONDARY; - - /* Ignore tentative addresses silently */ - if (ifa_flags & IFA_F_TENTATIVE) - return; - - /* IFA_LOCAL can be unset for IPv6 interfaces */ - ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_ADDRESS]); - - if (i->ifa_prefixlen > IP6_MAX_PREFIX_LENGTH) - { - log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen); - new = 0; - } - if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH) - { - ifa.brd = rta_get_ipa(a[IFA_ADDRESS]); - net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen); - - /* It is either a host address or a peer address */ - if (ipa_equal(ifa.ip, ifa.brd)) - ifa.flags |= IA_HOST; - else - { - ifa.flags |= IA_PEER; - ifa.opposite = ifa.brd; - } - } - else - { - net_fill_ip6(&ifa.prefix, ipa_to_ip6(ifa.ip), i->ifa_prefixlen); - net_normalize(&ifa.prefix); - - if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH - 1) - ifa.opposite = ipa_opposite_m1(ifa.ip); - } - - scope = ipa_classify(ifa.ip); - if (scope < 0) - { - log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name); - return; - } - ifa.scope = scope & IADDR_SCOPE_MASK; - - DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n", - ifi->index, ifi->name, - new ? "added" : "removed", - ifa.ip, ifa.flags, &ifa.prefix, ifa.brd, ifa.opposite); - - if (new) - ifa_update(&ifa); - else - ifa_delete(&ifa); - - if (!scan) - if_end_partial_update(ifi); -} - -static void -nl_parse_addr(struct nlmsghdr *h, int scan) -{ - struct ifaddrmsg *i; - - if (!(i = nl_checkin(h, sizeof(*i)))) - return; - - int new = (h->nlmsg_type == RTM_NEWADDR); - - switch (i->ifa_family) - { - case AF_INET: - return nl_parse_addr4(i, scan, new); - - case AF_INET6: - return nl_parse_addr6(i, scan, new); - } -} - -void -kif_do_scan(struct kif_proto *p UNUSED) -{ - struct nlmsghdr *h; - - if_start_update(); - - nl_request_dump(AF_UNSPEC, RTM_GETLINK); - while (h = nl_get_scan()) - if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK) - nl_parse_link(h, 1); - else - log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); - - /* Re-resolve master interface for slaves */ - struct iface *i; - WALK_LIST(i, iface_list) - if (i->master_index) - { - struct iface f = { - .flags = i->flags, - .mtu = i->mtu, - .index = i->index, - .master_index = i->master_index, - .master = if_find_by_index(i->master_index) - }; - - if (f.master != i->master) - { - memcpy(f.name, i->name, sizeof(f.name)); - if_update(&f); - } - } - - nl_request_dump(AF_INET, RTM_GETADDR); - while (h = nl_get_scan()) - if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) - nl_parse_addr(h, 1); - else - log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); - - nl_request_dump(AF_INET6, RTM_GETADDR); - while (h = nl_get_scan()) - if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) - nl_parse_addr(h, 1); - else - log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type); - - if_end_update(); -} - -/* - * Routes - */ - -static inline u32 -krt_table_id(struct krt_proto *p) -{ - return KRT_CF->sys.table_id; -} - -static HASH(struct krt_proto) nl_table_map; - -#define RTH_KEY(p) p->af, krt_table_id(p) -#define RTH_NEXT(p) p->sys.hash_next -#define RTH_EQ(a1,i1,a2,i2) a1 == a2 && i1 == i2 -#define RTH_FN(a,i) a ^ u32_hash(i) - -#define RTH_REHASH rth_rehash -#define RTH_PARAMS /8, *2, 2, 2, 6, 20 - -HASH_DEFINE_REHASH_FN(RTH, struct krt_proto) - -int -krt_capable(rte *e) -{ - rta *a = e->attrs; - - switch (a->dest) - { - case RTD_UNICAST: - case RTD_BLACKHOLE: - case RTD_UNREACHABLE: - case RTD_PROHIBIT: - return 1; - - default: - return 0; - } -} - -static inline int -nh_bufsize(struct nexthop *nh) -{ - int rv = 0; - for (; nh != NULL; nh = nh->next) - rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr))); - return rv; -} - -static int -nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) -{ - eattr *ea; - net *net = e->net; - rta *a = e->attrs; - ea_list *eattrs = a->eattrs; - int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh)); - u32 priority = 0; - - struct { - struct nlmsghdr h; - struct rtmsg r; - char buf[0]; - } *r; - - int rsize = sizeof(*r) + bufsize; - r = alloca(rsize); - - DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op); - - bzero(&r->h, sizeof(r->h)); - bzero(&r->r, sizeof(r->r)); - r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE; - r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK; - - r->r.rtm_family = p->af; - r->r.rtm_dst_len = net_pxlen(net->n.addr); - r->r.rtm_protocol = RTPROT_BIRD; - r->r.rtm_scope = RT_SCOPE_NOWHERE; -#ifdef HAVE_MPLS_KERNEL - if (p->af == AF_MPLS) - { - /* - * Kernel MPLS code is a bit picky. We must: - * 1) Always set RT_SCOPE_UNIVERSE and RTN_UNICAST (even for RTM_DELROUTE) - * 2) Never use RTA_PRIORITY - */ - - u32 label = net_mpls(net->n.addr); - nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label); - r->r.rtm_scope = RT_SCOPE_UNIVERSE; - r->r.rtm_type = RTN_UNICAST; - } - else -#endif - { - nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr)); - - /* Add source address for IPv6 SADR routes */ - if (net->n.addr->type == NET_IP6_SADR) - { - net_addr_ip6_sadr *a = (void *) &net->n.addr; - nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix); - r->r.rtm_src_len = a->src_pxlen; - } - } - - /* - * Strange behavior for RTM_DELROUTE: - * 1) rtm_family is ignored in IPv6, works for IPv4 - * 2) not setting RTA_PRIORITY is different from setting default value (on IPv6) - * 3) not setting RTA_PRIORITY is equivalent to setting 0, which is wildcard - */ - - if (krt_table_id(p) < 256) - r->r.rtm_table = krt_table_id(p); - else - nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p)); - - if (p->af == AF_MPLS) - priority = 0; - else if (a->source == RTS_DUMMY) - priority = e->u.krt.metric; - else if (KRT_CF->sys.metric) - priority = KRT_CF->sys.metric; - else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC))) - priority = ea->u.data; - - if (priority) - nl_add_attr_u32(&r->h, rsize, RTA_PRIORITY, priority); - - /* For route delete, we do not specify remaining route attributes */ - if (op == NL_OP_DELETE) - goto dest; - - /* Default scope is LINK for device routes, UNIVERSE otherwise */ - if (p->af == AF_MPLS) - r->r.rtm_scope = RT_SCOPE_UNIVERSE; - else if (ea = ea_find(eattrs, EA_KRT_SCOPE)) - r->r.rtm_scope = ea->u.data; - else - r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; - - if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) - nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); - - if (ea = ea_find(eattrs, EA_KRT_REALM)) - nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data); - - - u32 metrics[KRT_METRICS_MAX]; - metrics[0] = 0; - - struct ea_walk_state ews = { .eattrs = eattrs }; - while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX)) - { - int id = ea->id - EA_KRT_METRICS; - metrics[0] |= 1 << id; - metrics[id] = ea->u.data; - } - - if (metrics[0]) - nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX); - - -dest: - switch (dest) - { - case RTD_UNICAST: - r->r.rtm_type = RTN_UNICAST; - if (nh->next && !krt_ecmp6(p)) - nl_add_multipath(&r->h, rsize, nh, p->af, eattrs); - else - { - nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index); - nl_add_nexthop(&r->h, rsize, nh, p->af); - - if (nh->flags & RNF_ONLINK) - r->r.rtm_flags |= RTNH_F_ONLINK; - } - break; - case RTD_BLACKHOLE: - r->r.rtm_type = RTN_BLACKHOLE; - break; - case RTD_UNREACHABLE: - r->r.rtm_type = RTN_UNREACHABLE; - break; - case RTD_PROHIBIT: - r->r.rtm_type = RTN_PROHIBIT; - break; - case RTD_NONE: - break; - default: - bug("krt_capable inconsistent with nl_send_route"); - } - - /* Ignore missing for DELETE */ - return nl_exchange(&r->h, (op == NL_OP_DELETE)); -} - -static inline int -nl_add_rte(struct krt_proto *p, rte *e) -{ - rta *a = e->attrs; - int err = 0; - - if (krt_ecmp6(p) && a->nh.next) - { - struct nexthop *nh = &(a->nh); - - err = nl_send_route(p, e, NL_OP_ADD, RTD_UNICAST, nh); - if (err < 0) - return err; - - for (nh = nh->next; nh; nh = nh->next) - err += nl_send_route(p, e, NL_OP_APPEND, RTD_UNICAST, nh); - - return err; - } - - return nl_send_route(p, e, NL_OP_ADD, a->dest, &(a->nh)); -} - -static inline int -nl_delete_rte(struct krt_proto *p, rte *e) -{ - int err = 0; - - /* For IPv6, we just repeatedly request DELETE until we get error */ - do - err = nl_send_route(p, e, NL_OP_DELETE, RTD_NONE, NULL); - while (krt_ecmp6(p) && !err); - - return err; -} - -static inline int -nl_replace_rte(struct krt_proto *p, rte *e) -{ - rta *a = e->attrs; - return nl_send_route(p, e, NL_OP_REPLACE, a->dest, &(a->nh)); -} - - -void -krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old) -{ - int err = 0; - - /* - * We use NL_OP_REPLACE for IPv4, it has an issue with not checking for - * matching rtm_protocol, but that is OK when dedicated priority is used. - * - * We do not use NL_OP_REPLACE for IPv6, as it has broken semantics for ECMP - * and with some kernel versions ECMP replace crashes kernel. Would need more - * testing and checks for kernel versions. - * - * For IPv6, we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the - * old route value, so we do not try to optimize IPv6 ECMP reconfigurations. - */ - - if (krt_ipv4(p) && old && new) - { - err = nl_replace_rte(p, new); - } - else - { - if (old) - nl_delete_rte(p, old); - - if (new) - err = nl_add_rte(p, new); - } - - if (new) - { - if (err < 0) - bmap_clear(&p->sync_map, new->id); - else - bmap_set(&p->sync_map, new->id); - } -} - -static int -nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family) -{ - /* Route merging is used for IPv6 scans */ - if (!s->scan || (rtm_family != AF_INET6)) - return 0; - - /* Saved and new route must have same network, proto/table, and priority */ - if ((s->net != net) || (s->proto != p) || (s->krt_metric != priority)) - return 0; - - /* Both must be regular unicast routes */ - if ((s->krt_type != RTN_UNICAST) || (krt_type != RTN_UNICAST)) - return 0; - - return 1; -} - -static void -nl_announce_route(struct nl_parse_state *s) -{ - rte *e = rte_get_temp(s->attrs); - e->net = s->net; - e->u.krt.src = s->krt_src; - e->u.krt.proto = s->krt_proto; - e->u.krt.seen = 0; - e->u.krt.best = 0; - e->u.krt.metric = s->krt_metric; - - if (s->scan) - krt_got_route(s->proto, e); - else - krt_got_route_async(s->proto, e, s->new); - - s->net = NULL; - s->attrs = NULL; - s->proto = NULL; - lp_flush(s->pool); -} - -static inline void -nl_parse_begin(struct nl_parse_state *s, int scan) -{ - memset(s, 0, sizeof (struct nl_parse_state)); - s->pool = nl_linpool; - s->scan = scan; -} - -static inline void -nl_parse_end(struct nl_parse_state *s) -{ - if (s->net) - nl_announce_route(s); -} - - -#define SKIP0(ARG, ...) do { DBG("KRT: Ignoring route - " ARG, ##__VA_ARGS__); return; } while(0) -#define SKIP(ARG, ...) do { DBG("KRT: Ignoring route %N - " ARG, &dst, ##__VA_ARGS__); return; } while(0) - -static void -nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) -{ - struct krt_proto *p; - struct rtmsg *i; - struct rtattr *a[BIRD_RTA_MAX]; - int new = h->nlmsg_type == RTM_NEWROUTE; - - net_addr dst, src = {}; - u32 oif = ~0; - u32 table_id; - u32 priority = 0; - u32 def_scope = RT_SCOPE_UNIVERSE; - int krt_src; - - if (!(i = nl_checkin(h, sizeof(*i)))) - return; - - switch (i->rtm_family) - { - case AF_INET: - if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a))) - return; - - if (a[RTA_DST]) - net_fill_ip4(&dst, rta_get_ip4(a[RTA_DST]), i->rtm_dst_len); - else - net_fill_ip4(&dst, IP4_NONE, 0); - break; - - case AF_INET6: - if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a))) - return; - - if (a[RTA_DST]) - net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len); - else - net_fill_ip6(&dst, IP6_NONE, 0); - - if (a[RTA_SRC]) - net_fill_ip6(&src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len); - else - net_fill_ip6(&src, IP6_NONE, 0); - break; - -#ifdef HAVE_MPLS_KERNEL - case AF_MPLS: - if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want_mpls, a, sizeof(a))) - return; - - if (!a[RTA_DST]) - SKIP0("MPLS route without RTA_DST\n"); - - if (rta_get_mpls(a[RTA_DST], rta_mpls_stack) != 1) - SKIP0("MPLS route with multi-label RTA_DST\n"); - - net_fill_mpls(&dst, rta_mpls_stack[0]); - break; -#endif - - default: - return; - } - - if (a[RTA_OIF]) - oif = rta_get_u32(a[RTA_OIF]); - - if (a[RTA_TABLE]) - table_id = rta_get_u32(a[RTA_TABLE]); - else - table_id = i->rtm_table; - - if (i->rtm_flags & RTM_F_CLONED) - SKIP("cloned\n"); - - /* Do we know this table? */ - p = HASH_FIND(nl_table_map, RTH, i->rtm_family, table_id); - if (!p) - SKIP("unknown table %u\n", table_id); - - if (a[RTA_SRC] && (p->p.net_type != NET_IP6_SADR)) - SKIP("src prefix for non-SADR channel\n"); - - if (a[RTA_IIF]) - SKIP("IIF set\n"); - - if (i->rtm_tos != 0) /* We don't support TOS */ - SKIP("TOS %02x\n", i->rtm_tos); - - if (s->scan && !new) - SKIP("RTM_DELROUTE in scan\n"); - - if (a[RTA_PRIORITY]) - priority = rta_get_u32(a[RTA_PRIORITY]); - - int c = net_classify(&dst); - if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) - SKIP("strange class/scope\n"); - - switch (i->rtm_protocol) - { - case RTPROT_UNSPEC: - SKIP("proto unspec\n"); - - case RTPROT_REDIRECT: - krt_src = KRT_SRC_REDIRECT; - break; - - case RTPROT_KERNEL: - krt_src = KRT_SRC_KERNEL; - return; - - case RTPROT_BIRD: - if (!s->scan) - SKIP("echo\n"); - krt_src = KRT_SRC_BIRD; - break; - - case RTPROT_BOOT: - default: - krt_src = KRT_SRC_ALIEN; - } - - net_addr *n = &dst; - if (p->p.net_type == NET_IP6_SADR) - { - n = alloca(sizeof(net_addr_ip6_sadr)); - net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst), - net6_prefix(&src), net6_pxlen(&src)); - } - - net *net = net_get(p->p.main_channel->table, n); - - if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type, i->rtm_family)) - nl_announce_route(s); - - rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE); - ra->src = p->p.main_source; - ra->source = RTS_INHERIT; - ra->scope = SCOPE_UNIVERSE; - - if (a[RTA_FLOW]) - s->rta_flow = rta_get_u32(a[RTA_FLOW]); - else - s->rta_flow = 0; - - switch (i->rtm_type) - { - case RTN_UNICAST: - ra->dest = RTD_UNICAST; - - if (a[RTA_MULTIPATH]) - { - struct nexthop *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src); - if (!nh) - SKIP("strange RTA_MULTIPATH\n"); - - nexthop_link(ra, nh); - break; - } - - if ((i->rtm_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD)) - SKIP("ignore RTNH_F_DEAD\n"); - - ra->nh.iface = if_find_by_index(oif); - if (!ra->nh.iface) - { - log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif); - return; - } - - if (a[RTA_GATEWAY]) - ra->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]); -#endif - - if (ipa_nonzero(ra->nh.gw)) - { - /* Silently skip strange 6to4 routes */ - const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96); - if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit)) - return; - - if (i->rtm_flags & RTNH_F_ONLINK) - ra->nh.flags |= RNF_ONLINK; - - neighbor *nbr; - nbr = neigh_find(&p->p, ra->nh.gw, ra->nh.iface, - (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0); - if (!nbr || (nbr->scope == SCOPE_HOST)) - { - log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, - ra->nh.gw); - return; - } - } - - break; - case RTN_BLACKHOLE: - ra->dest = RTD_BLACKHOLE; - break; - case RTN_UNREACHABLE: - ra->dest = RTD_UNREACHABLE; - break; - case RTN_PROHIBIT: - ra->dest = RTD_PROHIBIT; - break; - /* FIXME: What about RTN_THROW? */ - default: - SKIP("type %d\n", i->rtm_type); - return; - } - -#ifdef HAVE_MPLS_KERNEL - if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !ra->nh.next) - ra->nh.labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label); - - if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !ra->nh.next) - { - switch (rta_get_u16(a[RTA_ENCAP_TYPE])) - { - case LWTUNNEL_ENCAP_MPLS: - { - struct rtattr *enca[BIRD_RTA_MAX]; - nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]); - nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca)); - ra->nh.labels = rta_get_mpls(enca[RTA_DST], ra->nh.label); - break; - } - default: - SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE])); - break; - } - } -#endif - - 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 = rta_get_ipa(a[RTA_PREFSRC]); - - 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_PREFSRC; - ea->attrs[0].flags = 0; - ea->attrs[0].type = EAF_TYPE_IP_ADDRESS; - - struct adata *ad = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps)); - ad->length = sizeof(ps); - memcpy(ad->data, &ps, sizeof(ps)); - - ea->attrs[0].u.ptr = ad; - } - - /* Can be set per-route or per-nexthop */ - if (s->rta_flow) - { - 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_REALM; - ea->attrs[0].flags = 0; - ea->attrs[0].type = EAF_TYPE_INT; - ea->attrs[0].u.data = s->rta_flow; - } - - if (a[RTA_METRICS]) - { - u32 metrics[KRT_METRICS_MAX]; - ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr)); - int t, n = 0; - - if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0) - { - log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr); - return; - } - - for (t = 1; t < KRT_METRICS_MAX; t++) - if (metrics[0] & (1 << t)) - { - ea->attrs[n].id = EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t); - ea->attrs[n].flags = 0; - ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */ - ea->attrs[n].u.data = metrics[t]; - n++; - } - - if (n > 0) - { - ea->next = ra->eattrs; - ea->flags = EALF_SORTED; - ea->count = n; - ra->eattrs = ea; - } - } - - /* - * Ideally, now we would send the received route to the rest of kernel code. - * But IPv6 ECMP routes before 4.11 are sent as a sequence of routes, so we - * postpone it and merge next hops until the end of the sequence. Note that - * when doing merging of next hops, we expect the new route to be unipath. - * Otherwise, we ignore additional next hops in nexthop_insert(). - */ - - if (!s->net) - { - /* Store the new route */ - s->net = net; - s->attrs = ra; - s->proto = p; - s->new = new; - s->krt_src = krt_src; - s->krt_type = i->rtm_type; - s->krt_proto = i->rtm_protocol; - s->krt_metric = priority; - } - else - { - /* Merge next hops with the stored route */ - rta *oa = s->attrs; - - struct nexthop *nhs = &oa->nh; - nexthop_insert(&nhs, &ra->nh); - - /* Perhaps new nexthop is inserted at the first position */ - if (nhs == &ra->nh) - { - /* Swap rtas */ - s->attrs = ra; - - /* Keep old eattrs */ - ra->eattrs = oa->eattrs; - } - } -} - -void -krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */ -{ - struct nlmsghdr *h; - struct nl_parse_state s; - - nl_parse_begin(&s, 1); - nl_request_dump(AF_UNSPEC, RTM_GETROUTE); - while (h = nl_get_scan()) - if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE) - nl_parse_route(&s, h); - else - log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type); - nl_parse_end(&s); -} - -/* - * Asynchronous Netlink interface - */ - -static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */ -static byte *nl_async_rx_buffer; /* Receive buffer */ - -static void -nl_async_msg(struct nlmsghdr *h) -{ - struct nl_parse_state s; - - switch (h->nlmsg_type) - { - case RTM_NEWROUTE: - case RTM_DELROUTE: - DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type); - nl_parse_begin(&s, 0); - nl_parse_route(&s, h); - nl_parse_end(&s); - break; - case RTM_NEWLINK: - case RTM_DELLINK: - DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type); - if (kif_proto) - nl_parse_link(h, 0); - break; - case RTM_NEWADDR: - case RTM_DELADDR: - DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type); - if (kif_proto) - nl_parse_addr(h, 0); - break; - default: - DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type); - } -} - -static int -nl_async_hook(sock *sk, uint size UNUSED) -{ - struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE }; - struct sockaddr_nl sa; - struct msghdr m = { - .msg_name = &sa, - .msg_namelen = sizeof(sa), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - struct nlmsghdr *h; - int x; - uint len; - - x = recvmsg(sk->fd, &m, 0); - if (x < 0) - { - if (errno == ENOBUFS) - { - /* - * Netlink reports some packets have been thrown away. - * One day we might react to it by asking for route table - * scan in near future. - */ - log(L_WARN "Kernel dropped some netlink messages, will resync on next scan."); - return 1; /* More data are likely to be ready */ - } - else if (errno != EWOULDBLOCK) - log(L_ERR "Netlink recvmsg: %m"); - return 0; - } - if (sa.nl_pid) /* It isn't from the kernel */ - { - DBG("Non-kernel packet\n"); - return 1; - } - h = (void *) nl_async_rx_buffer; - len = x; - if (m.msg_flags & MSG_TRUNC) - { - log(L_WARN "Netlink got truncated asynchronous message"); - return 1; - } - while (NLMSG_OK(h, len)) - { - nl_async_msg(h); - h = NLMSG_NEXT(h, len); - } - if (len) - log(L_WARN "nl_async_hook: Found packet remnant of size %d", len); - return 1; -} - -static void -nl_async_err_hook(sock *sk, int e UNUSED) -{ - nl_async_hook(sk, 0); -} - -static void -nl_open_async(void) -{ - sock *sk; - struct sockaddr_nl sa; - int fd; - - if (nl_async_sk) - return; - - DBG("KRT: Opening async netlink socket\n"); - - fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd < 0) - { - log(L_ERR "Unable to open asynchronous rtnetlink socket: %m"); - return; - } - - bzero(&sa, sizeof(sa)); - sa.nl_family = AF_NETLINK; - sa.nl_groups = RTMGRP_LINK | - RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | - RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; - - if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) - { - log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m"); - close(fd); - return; - } - - nl_async_rx_buffer = xmalloc(NL_RX_SIZE); - - 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"); -} - - -/* - * Interface to the UNIX krt module - */ - -void -krt_sys_io_init(void) -{ - nl_linpool = lp_new_default(krt_pool); - HASH_INIT(nl_table_map, krt_pool, 6); -} - -int -krt_sys_start(struct krt_proto *p) -{ - struct krt_proto *old = HASH_FIND(nl_table_map, RTH, p->af, krt_table_id(p)); - - if (old) - { - log(L_ERR "%s: Kernel table %u already registered by %s", - p->p.name, krt_table_id(p), old->p.name); - return 0; - } - - HASH_INSERT2(nl_table_map, RTH, krt_pool, p); - - nl_open(); - nl_open_async(); - - return 1; -} - -void -krt_sys_shutdown(struct krt_proto *p) -{ - HASH_REMOVE2(nl_table_map, RTH, krt_pool, p); -} - -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) && (n->sys.metric == o->sys.metric); -} - -void -krt_sys_init_config(struct krt_config *cf) -{ - cf->sys.table_id = RT_TABLE_MAIN; - cf->sys.metric = 32; -} - -void -krt_sys_copy_config(struct krt_config *d, struct krt_config *s) -{ - d->sys.table_id = s->sys.table_id; - d->sys.metric = s->sys.metric; -} - -static const char *krt_metrics_names[KRT_METRICS_MAX] = { - NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss", - "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack" -}; - -static const char *krt_features_names[KRT_FEATURES_MAX] = { - "ecn", NULL, NULL, "allfrag" -}; - -int -krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED) -{ - switch (a->id) - { - case EA_KRT_PREFSRC: - bsprintf(buf, "prefsrc"); - return GA_NAME; - - case EA_KRT_REALM: - 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); - return GA_FULL; - - case EA_KRT_FEATURES: - buf += bsprintf(buf, "features:"); - ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX); - return GA_FULL; - - default:; - int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET; - if (id > 0 && id < KRT_METRICS_MAX) - { - bsprintf(buf, "%s", krt_metrics_names[id]); - return GA_NAME; - } - - return GA_UNKNOWN; - } -} - - - -void -kif_sys_start(struct kif_proto *p UNUSED) -{ - nl_open(); - nl_open_async(); -} - -void -kif_sys_shutdown(struct kif_proto *p UNUSED) -{ -} - -int -kif_update_sysdep_addr(struct iface *i UNUSED) -{ - return 0; -} diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 95b54d65..2a3f41de 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -122,8 +122,8 @@ kif_iface: kif_iface_start iface_patt_list_nopx kif_iface_opt_list; -dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SOURCE); } ; -dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_METRIC); } ; +dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SOURCE); } ; +dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_KRT_METRIC); } ; CF_CODE -- cgit v1.2.3 From 0b871c170472202770691af8995766ee57920fdc Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 31 Mar 2022 19:29:17 +0200 Subject: Moved filter value union to lib --- filter/data.h | 15 +-------------- lib/attrs.h | 20 +++++++++++++++++++- lib/route.h | 21 ++------------------- lib/type.h | 19 ++++++++++++++++++- 4 files changed, 40 insertions(+), 35 deletions(-) (limited to 'filter/data.h') diff --git a/filter/data.h b/filter/data.h index 0b1e8e57..9ffa1b61 100644 --- a/filter/data.h +++ b/filter/data.h @@ -16,20 +16,7 @@ /* Filter value; size of this affects filter memory consumption */ struct f_val { btype type; /* T_* */ - union { - union bval bval; - BVAL_ITEMS; - - u64 ec; - lcomm lc; - ip_addr ip; - const net_addr *net; - const char *s; - const struct f_tree *t; - const struct f_trie *ti; - const struct f_path_mask *path_mask; - struct f_path_mask_item pmi; - } val; + union bval_long val; }; #define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; }) diff --git a/lib/attrs.h b/lib/attrs.h index e0595846..97a9630f 100644 --- a/lib/attrs.h +++ b/lib/attrs.h @@ -11,7 +11,25 @@ #include #include "lib/unaligned.h" -#include "lib/route.h" + +typedef struct adata { + uint length; /* Length of data */ + byte data[0]; +} adata; + +extern const adata null_adata; /* adata of length 0 */ + +static inline struct adata * +lp_alloc_adata(struct linpool *pool, uint len) +{ + struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); + ad->length = len; + return ad; +} + +static inline int adata_same(const struct adata *a, const struct adata *b) +{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } + /* a-path.c */ diff --git a/lib/route.h b/lib/route.h index 47355abc..8e60f749 100644 --- a/lib/route.h +++ b/lib/route.h @@ -10,6 +10,8 @@ #ifndef _BIRD_LIB_ROUTE_H_ #define _BIRD_LIB_ROUTE_H_ +#include "lib/type.h" + struct network; struct proto; struct cli; @@ -163,25 +165,6 @@ const char *ea_custom_name(uint ea); #define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */ #define EA_BIT_GET(ea) ((ea) >> 24) -typedef struct adata { - uint length; /* Length of data */ - byte data[0]; -} adata; - -extern const adata null_adata; /* adata of length 0 */ - -static inline struct adata * -lp_alloc_adata(struct linpool *pool, uint len) -{ - struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len); - ad->length = len; - return ad; -} - -static inline int adata_same(const struct adata *a, const struct adata *b) -{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } - - typedef struct ea_list { struct ea_list *next; /* In case we have an override list */ byte flags; /* Flags: EALF_... */ diff --git a/lib/type.h b/lib/type.h index d0a887d8..6d19a250 100644 --- a/lib/type.h +++ b/lib/type.h @@ -10,6 +10,7 @@ #define _BIRD_TYPE_H_ #include "lib/birdlib.h" +#include "lib/attrs.h" union bval { #define BVAL_ITEMS \ @@ -18,9 +19,25 @@ union bval { const struct adata *ptr; /* Generic attribute data inherited from eattrs */ \ const struct adata *ad; /* Generic attribute data inherited from filters */ \ - BVAL_ITEMS + BVAL_ITEMS; }; +union bval_long { + union bval bval; /* For direct assignments */ + BVAL_ITEMS; /* For item-wise access */ + + u64 ec; + lcomm lc; + ip_addr ip; + const net_addr *net; + const char *s; + const struct f_tree *t; + const struct f_trie *ti; + const struct f_path_mask *path_mask; + struct f_path_mask_item pmi; +}; + + /* Internal types */ enum btype { /* Nothing. Simply nothing. */ -- cgit v1.2.3 From f2f3163f6c3fba7f9ef03640d7b2f6323873d2cc Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sun, 10 Apr 2022 18:55:15 +0200 Subject: Filters always allocate from tmp_linpool --- conf/confbase.Y | 6 ++--- filter/config.Y | 2 +- filter/data.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ filter/data.h | 4 ++- filter/f-inst.c | 6 ++--- filter/filter.c | 29 +++++++-------------- filter/filter.h | 6 ++--- filter/filter_test.c | 2 +- lib/attrs.h | 2 ++ nest/cmds.c | 2 +- nest/rt-show.c | 4 +-- nest/rt-table.c | 18 +++++-------- proto/mrt/mrt.c | 2 +- proto/static/static.c | 11 +------- sysdep/unix/krt.c | 2 +- 15 files changed, 110 insertions(+), 58 deletions(-) (limited to 'filter/data.h') diff --git a/conf/confbase.Y b/conf/confbase.Y index 3fdacb12..a81560dc 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -152,9 +152,9 @@ conf: definition ; definition: DEFINE symbol '=' term ';' { - struct f_val *val = cfg_allocz(sizeof(struct f_val)); - if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error"); - cf_define_symbol($2, SYM_CONSTANT | val->type, val, val); + struct f_val val; + if (f_eval(f_linearize($4), &val) > F_RETURN) cf_error("Runtime error"); + cf_define_symbol($2, SYM_CONSTANT | val.type, val, lp_val_copy(cfg_mem, &val)); } ; diff --git a/filter/config.Y b/filter/config.Y index 22981945..92656f7c 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -529,7 +529,7 @@ set_atom: | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | '(' term ')' { - if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); + if (f_eval(f_linearize($2), &($$)) > F_RETURN) cf_error("Runtime error"); if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); } | CF_SYM_KNOWN { diff --git a/filter/data.c b/filter/data.c index 381448fa..425dfdd3 100644 --- a/filter/data.c +++ b/filter/data.c @@ -602,3 +602,75 @@ val_dump(const struct f_val *v) { return val_dump_buffer; } + +struct f_val * +lp_val_copy(struct linpool *lp, const struct f_val *v) +{ + switch (v->type) + { + case T_VOID: + case T_BOOL: + case T_INT: + case T_IP: + case T_PAIR: + case T_QUAD: + case T_EC: + case T_LC: + case T_RD: + case T_ENUM: + case T_PATH_MASK_ITEM: + /* These aren't embedded but there is no need to copy them */ + case T_SET: + case T_PREFIX_SET: + case T_PATH_MASK: + case T_IFACE: + { + struct f_val *out = lp_alloc(lp, sizeof(*out)); + *out = *v; + return out; + } + + case T_NET: + { + struct { + struct f_val val; + net_addr net[0]; + } *out = lp_alloc(lp, sizeof(*out) + v->val.net->length); + out->val = *v; + out->val.val.net = out->net; + net_copy(out->net, v->val.net); + return &out->val; + } + + case T_STRING: + { + uint len = strlen(v->val.s); + struct { + struct f_val val; + char buf[0]; + } *out = lp_alloc(lp, sizeof(*out) + len + 1); + out->val = *v; + out->val.val.s = out->buf; + memcpy(out->buf, v->val.s, len+1); + return &out->val; + } + + case T_PATH: + case T_CLIST: + case T_ECLIST: + case T_LCLIST: + { + struct { + struct f_val val; + struct adata ad; + } *out = lp_alloc(lp, sizeof(*out) + v->val.ad->length); + out->val = *v; + out->val.val.ad = &out->ad; + memcpy(&out->ad, v->val.ad, v->val.ad->length); + return &out->val; + } + + default: + bug("Unknown type in value copy: %d", v->type); + } +} diff --git a/filter/data.h b/filter/data.h index 9ffa1b61..cba47d6a 100644 --- a/filter/data.h +++ b/filter/data.h @@ -213,6 +213,8 @@ void val_format(const struct f_val *v, buffer *buf); char *val_format_str(struct linpool *lp, const struct f_val *v); const char *val_dump(const struct f_val *v); +struct f_val *lp_val_copy(struct linpool *lp, const struct f_val *v); + static inline int val_is_ip4(const struct f_val *v) { return (v->type == T_IP) && ipa_is_ip4(v->val.ip); } int val_in_range(const struct f_val *v1, const struct f_val *v2); @@ -249,6 +251,6 @@ static inline const struct f_val *f_get_empty(btype t) } } -enum filter_return f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres); +enum filter_return f_eval(const struct f_line *expr, struct f_val *pres); #endif diff --git a/filter/f-inst.c b/filter/f-inst.c index 7b3db1c7..3a2554fd 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -696,7 +696,7 @@ DYNAMIC_ATTR; ARG_TYPE(1, da.type); { - struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr)); + struct ea_list *l = tmp_alloc(sizeof(struct ea_list) + sizeof(eattr)); l->next = NULL; l->flags = EALF_SORTED; @@ -718,7 +718,7 @@ break; case T_IP: - l->attrs[0].u.ptr = lp_store_adata(fs->pool, &v1.val.ip, sizeof(ip_addr)); + l->attrs[0].u.ptr = tmp_store_adata(&v1.val.ip, sizeof(ip_addr)); break; default: @@ -739,7 +739,7 @@ ACCESS_EATTRS; f_rta_cow(fs); - ea_unset_attr(fs->eattrs, fs->pool, 1, da.ea_code); + ea_unset_attr(fs->eattrs, tmp_linpool, 1, da.ea_code); } INST(FI_LENGTH, 1, 1) { /* Get length of */ diff --git a/filter/filter.c b/filter/filter.c index 8f946f5b..9bedb938 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -82,9 +82,6 @@ struct filter_state { /* Cached pointer to ea_list */ struct ea_list **eattrs; - /* Linpool for adata allocation */ - struct linpool *pool; - /* Buffer for log output */ struct buffer buf; @@ -134,7 +131,7 @@ f_rta_cow(struct filter_state *fs) * at the end of f_run()), also the lock of hostentry is inherited (we * suppose hostentry is not changed by filters). */ - (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool); + (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, tmp_linpool); /* Re-cache the ea_list */ f_cache_eattrs(fs); @@ -202,8 +199,8 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) return F_ERROR; \ } while(0) -#define falloc(size) lp_alloc(fs->pool, size) -#define fpool fs->pool +#define falloc(size) tmp_alloc(size) +#define fpool tmp_linpool #define ACCESS_EATTRS do { if (!fs->eattrs) f_cache_eattrs(fs); } while (0) @@ -268,7 +265,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) * modified in place, old cached rta is possibly freed. */ enum filter_return -f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) +f_run(const struct filter *filter, struct rte **rte, int flags) { if (filter == FILTER_ACCEPT) return F_ACCEPT; @@ -282,7 +279,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i /* Initialize the filter state */ filter_state = (struct filter_state) { .rte = rte, - .pool = tmp_pool, .flags = flags, }; @@ -343,11 +339,10 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i */ enum filter_return -f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) +f_eval_rte(const struct f_line *expr, struct rte **rte) { filter_state = (struct filter_state) { .rte = rte, - .pool = tmp_pool, }; f_stack_init(filter_state); @@ -367,11 +362,9 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool * @pres: here the output will be stored */ enum filter_return -f_eval(const struct f_line *expr, struct linpool *tmp_pool, struct f_val *pres) +f_eval(const struct f_line *expr, struct f_val *pres) { - filter_state = (struct filter_state) { - .pool = tmp_pool, - }; + filter_state = (struct filter_state) {}; f_stack_init(filter_state); @@ -390,9 +383,7 @@ uint f_eval_int(const struct f_line *expr) { /* Called independently in parse-time to eval expressions */ - filter_state = (struct filter_state) { - .pool = cfg_mem, - }; + filter_state = (struct filter_state) {}; f_stack_init(filter_state); @@ -413,10 +404,10 @@ f_eval_int(const struct f_line *expr) * f_eval_buf - get a value of a term and print it to the supplied buffer */ enum filter_return -f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf) +f_eval_buf(const struct f_line *expr, buffer *buf) { struct f_val val; - enum filter_return fret = f_eval(expr, tmp_pool, &val); + enum filter_return fret = f_eval(expr, &val); if (fret <= F_RETURN) val_format(&val, buf); return fret; diff --git a/filter/filter.h b/filter/filter.h index 385f1179..43c04443 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -51,10 +51,10 @@ struct filter { struct rte; -enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); -enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool); +enum filter_return f_run(const struct filter *filter, struct rte **rte, int flags); +enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte); uint f_eval_int(const struct f_line *expr); -enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf); +enum filter_return f_eval_buf(const struct f_line *expr, buffer *buf); const char *filter_name(const struct filter *filter); int filter_same(const struct filter *new, const struct filter *old); diff --git a/filter/filter_test.c b/filter/filter_test.c index e8e8b747..63764964 100644 --- a/filter/filter_test.c +++ b/filter/filter_test.c @@ -46,7 +46,7 @@ run_function(const void *arg) if (t->cmp) return t->result == f_same(t->fn, t->cmp); - enum filter_return fret = f_eval(t->fn, tmp_linpool, NULL); + enum filter_return fret = f_eval(t->fn, NULL); return (fret < F_REJECT); } diff --git a/lib/attrs.h b/lib/attrs.h index fcb70230..d2638f3f 100644 --- a/lib/attrs.h +++ b/lib/attrs.h @@ -37,6 +37,8 @@ lp_store_adata(struct linpool *pool, const void *buf, uint len) return ad; } +#define tmp_store_adata(buf, len) lp_store_adata(tmp_linpool, buf, len) + static inline int adata_same(const struct adata *a, const struct adata *b) { return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } diff --git a/nest/cmds.c b/nest/cmds.c index 3e59cb6f..99a7bbfe 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -133,7 +133,7 @@ cmd_eval(const struct f_line *expr) buffer buf; LOG_BUFFER_INIT(buf); - if (f_eval_buf(expr, this_cli->parser_pool, &buf) > F_RETURN) + if (f_eval_buf(expr, &buf) > F_RETURN) { cli_msg(8008, "runtime error"); return; diff --git a/nest/rt-show.c b/nest/rt-show.c index 4e0c5602..7d02f52e 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -169,7 +169,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) * command may change the export filter and do not update routes. */ int do_export = (ic > 0) || - (f_run(ec->out_filter, &e, c->show_pool, FF_SILENT) <= F_ACCEPT); + (f_run(ec->out_filter, &e, FF_SILENT) <= F_ACCEPT); if (do_export != (d->export_mode == RSEM_EXPORT)) goto skip; @@ -182,7 +182,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (d->show_protocol && (d->show_protocol != e->src->proto)) goto skip; - if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT) + if (f_run(d->filter, &e, 0) > F_ACCEPT) goto skip; if (d->stats < 2) diff --git a/nest/rt-table.c b/nest/rt-table.c index 031e462b..049b7a7f 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -713,7 +713,7 @@ rte_trace_out(uint flag, struct channel *c, rte *e, char *msg) } static rte * -export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent) +export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent) { struct proto *p = c->proto; const struct filter *filter = c->out_filter; @@ -743,7 +743,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si } v = filter && ((filter == FILTER_REJECT) || - (f_run(filter, &rt, pool, + (f_run(filter, &rt, (silent ? FF_SILENT : 0)) > F_ACCEPT)); if (v) { @@ -767,12 +767,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si return NULL; } -static inline rte * -export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent) -{ - return export_filter_(c, rt0, rt_free, rte_update_pool, silent); -} - static void do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) { @@ -963,7 +957,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int if (!rte_is_valid(best0)) return NULL; - best = export_filter_(c, best0, rt_free, pool, silent); + best = export_filter(c, best0, rt_free, silent); if (!best || !rte_is_reachable(best)) return best; @@ -973,7 +967,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int if (!rte_mergable(best0, rt0)) continue; - rt = export_filter_(c, rt0, &tmp, pool, 1); + rt = export_filter(c, rt0, &tmp, 1); if (!rt) continue; @@ -1592,7 +1586,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) } else if (filter) { - int fr = f_run(filter, &new, rte_update_pool, 0); + int fr = f_run(filter, &new, 0); if (fr > F_ACCEPT) { stats->imp_updates_filtered++; @@ -1696,7 +1690,7 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter) /* Rest is stripped down export_filter() */ int v = p->preexport ? p->preexport(p, rt) : 0; if (v == RIC_PROCESS) - v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); + v = (f_run(filter, &rt, FF_SILENT) <= F_ACCEPT); /* Discard temporary rte */ if (rt != n->routes) diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index 760cfa73..c595f298 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -525,7 +525,7 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) continue; } - if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT) + if (f_run(s->filter, &rt, 0) <= F_ACCEPT) mrt_rib_table_entry(s, rt); if (rt != rt0) diff --git a/proto/static/static.c b/proto/static/static.c index 3a0d9257..42febcd4 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -47,8 +47,6 @@ #include "static.h" -static linpool *static_lp; - static inline struct rte_src * static_get_source(struct static_proto *p, uint i) { return i ? rt_get_source(&p->p, i) : p->p.main_source; } @@ -114,7 +112,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r) net_copy(e->net->n.addr, r->net); /* Evaluate the filter */ - f_eval_rte(r->cmds, &e, static_lp); + f_eval_rte(r->cmds, &e); /* Remove the temporary node */ e->net = NULL; @@ -122,10 +120,6 @@ static_announce_rte(struct static_proto *p, struct static_route *r) rte_update2(p->p.main_channel, r->net, e, src); r->state = SRS_CLEAN; - - if (r->cmds) - lp_flush(static_lp); - return; withdraw: @@ -485,9 +479,6 @@ static_start(struct proto *P) struct static_config *cf = (void *) P->cf; struct static_route *r; - if (!static_lp) - static_lp = lp_new(&root_pool); - if (p->igp_table_ip4) rt_lock_table(p->igp_table_ip4); diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 671e91fe..0ebc4fb3 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -589,7 +589,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free) if (filter == FILTER_ACCEPT) goto accept; - if (f_run(filter, &rt, krt_filter_lp, FF_SILENT) > F_ACCEPT) + if (f_run(filter, &rt, FF_SILENT) > F_ACCEPT) goto reject; -- cgit v1.2.3 From 17f91f9e6e70f7e3f29502e854823c0d48571eaa Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sat, 19 Mar 2022 16:23:42 +0100 Subject: Explicit definition structures of route attributes Changes in internal API: * Every route attribute must be defined as struct ea_class somewhere. * Registration of route attributes known at startup must be done by ea_register_init() from protocol build functions. * Every attribute has now its symbol registered in a global symbol table defined as SYM_ATTRIBUTE * All attribute ID's are dynamically allocated. * Attribute value custom formatting hook is defined in the ea_class. * Attribute names are the same for display and filters, always prefixed by protocol name. Also added some unit testing code for filters with route attributes. --- conf/cf-lex.l | 54 ++++++++- conf/conf.h | 2 +- conf/confbase.Y | 3 +- filter/config.Y | 88 +++++++++----- filter/data.h | 10 +- filter/decl.m4 | 4 +- filter/f-inst.c | 20 ++-- filter/f-inst.h | 12 +- filter/f-util.c | 128 +------------------- filter/filter.h | 9 -- filter/test.conf | 151 +++++++++++++++++++++++- lib/event_test.c | 2 +- lib/mempool.c | 2 - lib/resource.c | 19 +++ lib/resource.h | 13 ++- lib/route.h | 108 ++++++++++------- nest/config.Y | 5 +- nest/proto.c | 4 - nest/protocol.h | 26 +---- nest/rt-attr.c | 221 ++++++++++++++++++++++++++--------- nest/rt-dev.c | 1 - nest/rt-table.c | 10 +- proto/babel/babel.c | 76 ++++++------ proto/babel/babel.h | 4 - proto/babel/config.Y | 2 - proto/bfd/bfd.c | 1 - proto/bgp/attrs.c | 308 +++++++++++++++++++++++++------------------------ proto/bgp/bgp.c | 3 +- proto/bgp/bgp.h | 54 ++++----- proto/bgp/config.Y | 30 ----- proto/mrt/mrt.c | 1 - proto/ospf/config.Y | 5 - proto/ospf/ospf.c | 71 +++++++----- proto/ospf/ospf.h | 7 +- proto/ospf/rt.c | 8 +- proto/ospf/topology.c | 6 +- proto/perf/perf.c | 1 - proto/pipe/pipe.c | 1 - proto/radv/config.Y | 3 - proto/radv/radv.c | 42 ++++--- proto/radv/radv.h | 4 - proto/rip/config.Y | 3 - proto/rip/rip.c | 65 ++++++----- proto/rip/rip.h | 4 - proto/rpki/rpki.c | 1 - proto/static/static.c | 11 +- sysdep/linux/krt-sys.h | 32 ----- sysdep/linux/netlink.Y | 45 +++----- sysdep/linux/netlink.c | 197 ++++++++++++++++++------------- sysdep/unix/krt.Y | 3 - sysdep/unix/krt.c | 35 +++--- sysdep/unix/krt.h | 4 + sysdep/unix/main.c | 2 +- test/bt-utils.c | 5 +- 54 files changed, 1052 insertions(+), 874 deletions(-) (limited to 'filter/data.h') diff --git a/conf/cf-lex.l b/conf/cf-lex.l index bd424c69..e84e1d9d 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -86,9 +86,12 @@ static uint cf_hash(const byte *c); 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; -struct sym_scope *global_root_scope; + +static struct sym_scope global_root_scope__init = { .active = 1, }; +struct sym_scope *global_root_scope = &global_root_scope__init; linpool *cfg_mem; @@ -598,6 +601,25 @@ cf_new_symbol(const byte *c) 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_scope - find a symbol by name * @scope: config scope @@ -652,7 +674,7 @@ 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"); @@ -716,8 +738,34 @@ cf_lex_init_kh(void) struct keyword *k; for (k=keyword_list; k->name; k++) 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; +} - global_root_scope = mb_allocz(&root_pool, sizeof(*global_root_scope)); +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; } /** diff --git a/conf/conf.h b/conf/conf.h index 2700295b..18de8def 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -120,7 +120,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 */ }; diff --git a/conf/confbase.Y b/conf/confbase.Y index a81560dc..2286b257 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -71,8 +71,9 @@ 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; const struct filter *f; diff --git a/filter/config.Y b/filter/config.Y index 92656f7c..f21f1c8e 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -22,6 +22,13 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; } #define f_generate_complex(fi_code, da, arg) \ f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) +#define f_generate_complex_sym(fi_code, sym, arg) ({ \ + if (sym->class != SYM_ATTRIBUTE) \ + cf_error("Can't empty %s: not an attribute", sym->name); \ + f_generate_complex(fi_code, sym->attribute, arg); \ +}) + + /* * Sets and their items are during parsing handled as lists, linked * through left ptr. The first item in a list also contains a pointer @@ -161,27 +168,31 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) } static inline struct f_inst * -f_generate_empty(struct f_dynamic_attr dyn) +f_generate_empty(const struct symbol *sym) { - const struct f_val *empty = f_get_empty(dyn.type); + if (sym->class != SYM_ATTRIBUTE) + cf_error("Can't empty %s: not an attribute", sym->name); + + const struct ea_class *def = sym->attribute; + const struct f_val *empty = f_get_empty(def->type); if (!empty) - cf_error("Can't empty that attribute"); + cf_error("Can't empty attribute %s", def->name); - return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, *empty), dyn); + return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, *empty), def); } -#define BA_AS_PATH 0x02 - static inline struct f_inst * f_implicit_roa_check(struct rtable_config *tab) { - struct f_dynamic_attr fda = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + const struct ea_class *def = ea_class_find("bgp_path"); + if (!def) + cf_error("Fatal: Couldn't find BGP path attribute definition."); struct f_static_attr fsa = f_new_static_attr(T_NET, SA_NET, 1); return f_new_inst(FI_ROA_CHECK, f_new_inst(FI_RTA_GET, fsa), - f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, fda)), + f_new_inst(FI_AS_PATH_LAST, f_new_inst(FI_EA_GET, def)), tab); } @@ -293,8 +304,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %type cmds_int cmd_prep %type term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail -%type dynamic_attr attr_bit %type static_attr +%type attr_bit %type filter where_filter %type filter_body function_body %type lvalue @@ -335,7 +346,14 @@ filter_eval: conf: custom_attr ; custom_attr: ATTRIBUTE type symbol ';' { - cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda); + if (($3->class == SYM_ATTRIBUTE) && ($3->scope == new_config->root_scope)) + cf_error("Duplicate attribute %s definition", $3->name); + + cf_define_symbol($3, SYM_ATTRIBUTE, attribute, + ea_register_alloc(new_config->pool, (struct ea_class) { + .name = $3->name, + .type = $2, + })->class); }; conf: bt_test_suite ; @@ -736,7 +754,7 @@ symbol_value: CF_SYM_KNOWN $$ = f_new_inst(FI_VAR_GET, $1); break; case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_GET, *$1->attribute); + $$ = f_new_inst(FI_EA_GET, $1->attribute); break; default: cf_error("Can't get value of symbol %s", $1->name); @@ -785,11 +803,9 @@ term: | constructor { $$ = $1; } | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } - - | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } | attr_bit { struct f_inst *c = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)}); - $$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1), c)); + $$ = f_new_inst(FI_EQ, c, f_new_inst(FI_BITAND, f_new_inst(FI_EA_GET, $1.class), c)); } | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); } @@ -833,8 +849,6 @@ term: | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); } -/* | term '.' LEN { $$->code = P('P','l'); } */ - | function_call ; @@ -867,7 +881,9 @@ cmd: $$ = f_new_inst(FI_VAR_SET, $3, $1); break; case SYM_ATTRIBUTE: - $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); + if ($1->attribute->readonly) + cf_error("Attribute %s is read-only", $1->attribute->name); + $$ = f_new_inst(FI_EA_SET, $3, $1->attribute); break; default: cf_error("Can't assign to symbol %s", $1->name); @@ -877,22 +893,23 @@ cmd: DBG( "Ook, we'll return the value\n" ); $$ = f_new_inst(FI_RETURN, $2); } - | dynamic_attr '=' term ';' { - $$ = f_new_inst(FI_EA_SET, $3, $1); - } | static_attr '=' term ';' { if ($1.readonly) cf_error( "This static attribute is read-only."); $$ = f_new_inst(FI_RTA_SET, $3, $1); } - | UNSET '(' dynamic_attr ')' ';' { - $$ = f_new_inst(FI_EA_UNSET, $3); + | UNSET '(' CF_SYM_KNOWN ')' ';' { + if ($3->class != SYM_ATTRIBUTE) + cf_error("Can't unset %s", $3->name); + if ($3->attribute->readonly) + cf_error("Attribute %s is read-only", $3->attribute->name); + $$ = f_new_inst(FI_EA_UNSET, $3->attribute); } | attr_bit '=' term ';' { $$ = f_new_inst(FI_CONDITION, $3, - f_generate_complex(FI_BITOR, $1, + f_generate_complex(FI_BITOR, $1.class, f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = (1U << $1.bit)})), - f_generate_complex(FI_BITAND, $1, + f_generate_complex(FI_BITAND, $1.class, f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = ~(1U << $1.bit)})) ); } @@ -919,11 +936,11 @@ cmd: $$ = f_new_inst(FI_SWITCH, $2, build_tree($4)); } - | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); } - | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); } - | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); } - | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); } - | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); } + | CF_SYM_KNOWN '.' EMPTY ';' { $$ = f_generate_empty($1); } + | CF_SYM_KNOWN '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex_sym( FI_PATH_PREPEND, $1, $5 ); } + | CF_SYM_KNOWN '.' ADD '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_ADD, $1, $5 ); } + | CF_SYM_KNOWN '.' DELETE '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_DEL, $1, $5 ); } + | CF_SYM_KNOWN '.' FILTER '(' term ')' ';' { $$ = f_generate_complex_sym( FI_CLIST_FILTER, $1, $5 ); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); } ; @@ -934,8 +951,17 @@ get_cf_position: }; lvalue: - CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } + CF_SYM_KNOWN { + switch ($1->class) { + case SYM_VARIABLE_RANGE: + $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; + break; + case SYM_ATTRIBUTE: + $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1->attribute }; + break; + } + } | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } - | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; + ; CF_END diff --git a/filter/data.h b/filter/data.h index cba47d6a..4d2622ab 100644 --- a/filter/data.h +++ b/filter/data.h @@ -21,13 +21,6 @@ struct f_val { #define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; }) -/* Dynamic attribute definition (eattrs) */ -struct f_dynamic_attr { - btype type; /* EA type (EAF_*) */ - u8 bit; /* For bitfield accessors */ - uint ea_code; /* EA code */ -}; - enum f_sa_code { SA_FROM = 1, SA_GW, @@ -53,7 +46,6 @@ struct f_static_attr { /* Filter l-value type */ enum f_lval_type { F_LVAL_VARIABLE, - F_LVAL_PREFERENCE, F_LVAL_SA, F_LVAL_EA, }; @@ -63,7 +55,7 @@ struct f_lval { enum f_lval_type type; union { struct symbol *sym; - struct f_dynamic_attr da; + const struct ea_class *da; struct f_static_attr sa; }; }; diff --git a/filter/decl.m4 b/filter/decl.m4 index 2e4fb235..c59cd7f3 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -94,7 +94,7 @@ FID_DUMP_BODY()m4_dnl debug("%s" $4 "\n", INDENT, $5); ]]) FID_INTERPRET_EXEC()m4_dnl -const $1 $2 = whati->$2 +$1 $2 = whati->$2 FID_INTERPRET_BODY') # Instruction arguments are needed only until linearization is done. @@ -256,7 +256,7 @@ FID_INTERPRET_BODY()') m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)') m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)') m4_define(STATIC_ATTR, `FID_MEMBER(struct f_static_attr, sa, f1->sa.sa_code != f2->sa.sa_code,,)') -m4_define(DYNAMIC_ATTR, `FID_MEMBER(struct f_dynamic_attr, da, f1->da.ea_code != f2->da.ea_code,,)') +m4_define(DYNAMIC_ATTR, `FID_MEMBER(const struct ea_class *, da, f1->da != f2->da,,)') m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access"); } while (0)]],NEVER_CONSTANT())') # 2) Code wrapping diff --git a/filter/f-inst.c b/filter/f-inst.c index 7b34ef91..c5947955 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -662,14 +662,14 @@ DYNAMIC_ATTR; ACCESS_RTE; ACCESS_EATTRS; - RESULT_TYPE(da.type); + RESULT_TYPE(da->type); { const struct f_val *empty; - eattr *e = ea_find(*fs->eattrs, da.ea_code); + const eattr *e = ea_find(*fs->eattrs, da->id); if (e) { - ASSERT_DIE(e->type == da.type); + ASSERT_DIE(e->type == da->type); switch (e->type) { case T_IP: @@ -682,7 +682,7 @@ }]]); } } - else if (empty = f_get_empty(da.type)) + else if (empty = f_get_empty(da->type)) RESULT_VAL(*empty); else RESULT_VOID; @@ -694,16 +694,16 @@ ACCESS_EATTRS; ARG_ANY(1); DYNAMIC_ATTR; - ARG_TYPE(1, da.type); + ARG_TYPE(1, da->type); { struct eattr *a; - if (da.type >= EAF_TYPE__MAX) + if (da->type >= EAF_TYPE__MAX) bug("Unsupported attribute type"); f_rta_cow(fs); - switch (da.type) { + switch (da->type) { case T_OPAQUE: case T_IFACE: runtime( "Setting opaque attribute is not allowed" ); @@ -711,12 +711,12 @@ case T_IP: a = ea_set_attr(fs->eattrs, - EA_LITERAL_STORE_ADATA(da.ea_code, da.type, 0, &v1.val.ip, sizeof(ip_addr))); + EA_LITERAL_STORE_ADATA(da, 0, &v1.val.ip, sizeof(ip_addr))); break; default: a = ea_set_attr(fs->eattrs, - EA_LITERAL_GENERIC(da.ea_code, da.type, 0, .u = v1.val.bval)); + EA_LITERAL_GENERIC(da->id, da->type, 0, .u = v1.val.bval)); break; } @@ -731,7 +731,7 @@ ACCESS_EATTRS; f_rta_cow(fs); - ea_unset_attr(fs->eattrs, 1, da.ea_code); + ea_unset_attr(fs->eattrs, 1, da); } INST(FI_LENGTH, 1, 1) { /* Get length of */ diff --git a/filter/f-inst.h b/filter/f-inst.h index 32da4653..047a66c9 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -87,15 +87,17 @@ void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit); struct filter *f_new_where(struct f_inst *); -static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, uint code) -{ return (struct f_dynamic_attr) { .type = type, .ea_code = code }; } -static inline struct f_dynamic_attr f_new_dynamic_attr_bit(u8 bit, uint code) -{ return (struct f_dynamic_attr) { .type = T_INT, .bit = bit, .ea_code = code }; } static inline struct f_static_attr f_new_static_attr(btype type, int code, int readonly) { return (struct f_static_attr) { .type = type, .sa_code = code, .readonly = readonly }; } -struct f_inst *f_generate_complex(enum f_instruction_code fi_code, struct f_dynamic_attr da, struct f_inst *argument); struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); +struct f_attr_bit { + const struct ea_class *class; + uint bit; +}; + +#define f_new_dynamic_attr_bit(_bit, _name) ((struct f_attr_bit) { .bit = _bit, .class = ea_class_find(_name) }) + /* Hook for call bt_assert() function in configuration */ extern void (*bt_assert_hook)(int result, const struct f_line_item *assert); diff --git a/filter/f-util.c b/filter/f-util.c index 83ae01f6..fb93ee80 100644 --- a/filter/f-util.c +++ b/filter/f-util.c @@ -2,7 +2,7 @@ * Filters: utility functions * * Copyright 1998 Pavel Machek - * 2017 Jan Maria Matejka + * 2017 Maria Matejka * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -40,129 +40,3 @@ struct filter *f_new_where(struct f_inst *where) f->root = f_linearize(cond); return f; } - -#define CA_KEY(n) n->name, n->fda.type -#define CA_NEXT(n) n->next -#define CA_EQ(na,ta,nb,tb) (!strcmp(na,nb) && (ta == tb)) -#define CA_FN(n,t) (mem_hash(n, strlen(n)) ^ (t*0xaae99453U)) -#define CA_ORDER 8 /* Fixed */ - -struct ca_storage { - struct ca_storage *next; - struct f_dynamic_attr fda; - u32 uc; - char name[0]; -}; - -HASH(struct ca_storage) ca_hash; - -static struct idm ca_idm; -static struct ca_storage **ca_storage; -static uint ca_storage_max; - -static void -ca_free(resource *r) -{ - struct custom_attribute *ca = (void *) r; - struct ca_storage *cas = HASH_FIND(ca_hash, CA, ca->name, ca->fda->type); - ASSERT(cas); - - ca->name = NULL; - ca->fda = NULL; - if (!--cas->uc) { - uint id = EA_CUSTOM_ID(cas->fda.ea_code); - idm_free(&ca_idm, id); - HASH_REMOVE(ca_hash, CA, cas); - ca_storage[id] = NULL; - mb_free(cas); - } -} - -static void -ca_dump(resource *r) -{ - struct custom_attribute *ca = (void *) r; - debug("name \"%s\" id 0x%04x ea_type 0x%02x\n", - ca->name, ca->fda->ea_code, ca->fda->type); -} - -static struct resclass ca_class = { - .name = "Custom attribute", - .size = sizeof(struct custom_attribute), - .free = ca_free, - .dump = ca_dump, - .lookup = NULL, - .memsize = NULL, -}; - -struct custom_attribute * -ca_lookup(pool *p, const char *name, btype type) -{ - switch (type) { - case T_INT: - case T_IP: - case T_QUAD: - case T_PATH: - case T_CLIST: - case T_ECLIST: - case T_LCLIST: - break; - default: - cf_error("Custom route attribute of unsupported type"); - } - - static int inited = 0; - if (!inited) { - idm_init(&ca_idm, &root_pool, 8); - HASH_INIT(ca_hash, &root_pool, CA_ORDER); - - ca_storage_max = 256; - ca_storage = mb_allocz(&root_pool, sizeof(struct ca_storage *) * ca_storage_max); - - inited++; - } - - struct ca_storage *cas = HASH_FIND(ca_hash, CA, name, type); - if (cas) { - cas->uc++; - } else { - - uint id = idm_alloc(&ca_idm); - - if (id >= EA_CUSTOM_BIT) - cf_error("Too many custom attributes."); - - if (id >= ca_storage_max) { - ca_storage_max *= 2; - ca_storage = mb_realloc(ca_storage, sizeof(struct ca_storage *) * ca_storage_max * 2); - } - - cas = mb_allocz(&root_pool, sizeof(struct ca_storage) + strlen(name) + 1); - cas->fda = f_new_dynamic_attr(type, EA_CUSTOM(id)); - cas->uc = 1; - - strcpy(cas->name, name); - ca_storage[id] = cas; - - HASH_INSERT(ca_hash, CA, cas); - } - - struct custom_attribute *ca = ralloc(p, &ca_class); - ca->fda = &(cas->fda); - ca->name = cas->name; - return ca; -} - -const char * -ea_custom_name(uint ea) -{ - uint id = EA_CUSTOM_ID(ea); - if (id >= ca_storage_max) - return NULL; - - if (!ca_storage[id]) - return NULL; - - return ca_storage[id]->name; -} - diff --git a/filter/filter.h b/filter/filter.h index 43c04443..0273ef15 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -70,13 +70,4 @@ void filters_dump_all(void); #define FF_SILENT 2 /* Silent filter execution */ -/* Custom route attributes */ -struct custom_attribute { - resource r; - struct f_dynamic_attr *fda; - const char *name; -}; - -struct custom_attribute *ca_lookup(pool *p, const char *name, btype type); - #endif diff --git a/filter/test.conf b/filter/test.conf index 062756b1..21e7330f 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -9,7 +9,109 @@ router id 62.168.0.1; /* We have to setup any protocol */ protocol device { } - +/* Setting some custom attributes, enough to force BIRD to reallocate the attribute idmap */ +attribute int test_ca_int1; +attribute int test_ca_int2; +attribute int test_ca_int3; +attribute int test_ca_int4; +attribute int test_ca_int5; +attribute int test_ca_int6; +attribute int test_ca_int7; +attribute int test_ca_int8; +attribute int test_ca_int9; +attribute int test_ca_int10; + +attribute ip test_ca_ip1; +attribute ip test_ca_ip2; +attribute ip test_ca_ip3; +attribute ip test_ca_ip4; +attribute ip test_ca_ip5; +attribute ip test_ca_ip6; +attribute ip test_ca_ip7; +attribute ip test_ca_ip8; +attribute ip test_ca_ip9; +attribute ip test_ca_ip10; + +attribute quad test_ca_quad1; +attribute quad test_ca_quad2; +attribute quad test_ca_quad3; +attribute quad test_ca_quad4; +attribute quad test_ca_quad5; +attribute quad test_ca_quad6; +attribute quad test_ca_quad7; +attribute quad test_ca_quad8; +attribute quad test_ca_quad9; +attribute quad test_ca_quad10; + +attribute bgppath test_ca_bgppath1; +attribute bgppath test_ca_bgppath2; +attribute bgppath test_ca_bgppath3; +attribute bgppath test_ca_bgppath4; +attribute bgppath test_ca_bgppath5; +attribute bgppath test_ca_bgppath6; +attribute bgppath test_ca_bgppath7; +attribute bgppath test_ca_bgppath8; +attribute bgppath test_ca_bgppath9; +attribute bgppath test_ca_bgppath10; + +attribute clist test_ca_clist1; +attribute clist test_ca_clist2; +attribute clist test_ca_clist3; +attribute clist test_ca_clist4; +attribute clist test_ca_clist5; +attribute clist test_ca_clist6; +attribute clist test_ca_clist7; +attribute clist test_ca_clist8; +attribute clist test_ca_clist9; +attribute clist test_ca_clist10; + +attribute eclist test_ca_eclist1; +attribute eclist test_ca_eclist2; +attribute eclist test_ca_eclist3; +attribute eclist test_ca_eclist4; +attribute eclist test_ca_eclist5; +attribute eclist test_ca_eclist6; +attribute eclist test_ca_eclist7; +attribute eclist test_ca_eclist8; +attribute eclist test_ca_eclist9; +attribute eclist test_ca_eclist10; + +attribute lclist test_ca_lclist1; +attribute lclist test_ca_lclist2; +attribute lclist test_ca_lclist3; +attribute lclist test_ca_lclist4; +attribute lclist test_ca_lclist5; +attribute lclist test_ca_lclist6; +attribute lclist test_ca_lclist7; +attribute lclist test_ca_lclist8; +attribute lclist test_ca_lclist9; +attribute lclist test_ca_lclist10; + +attribute lclist test_ca_lclist_max1; +attribute lclist test_ca_lclist_max2; +attribute lclist test_ca_lclist_max3; +attribute lclist test_ca_lclist_max4; +attribute lclist test_ca_lclist_max5; +attribute lclist test_ca_lclist_max6; +attribute lclist test_ca_lclist_max7; +attribute lclist test_ca_lclist_max8; +attribute lclist test_ca_lclist_max9; +attribute lclist test_ca_lclist_max10; +attribute lclist test_ca_lclist_max11; +attribute lclist test_ca_lclist_max12; +attribute lclist test_ca_lclist_max13; +attribute lclist test_ca_lclist_max14; +attribute lclist test_ca_lclist_max15; +attribute lclist test_ca_lclist_max16; +attribute lclist test_ca_lclist_max17; +attribute lclist test_ca_lclist_max18; +attribute lclist test_ca_lclist_max19; +attribute lclist test_ca_lclist_max20; +attribute lclist test_ca_lclist_max21; + + +/* Uncomment this to get an error */ +#attribute int bgp_path; /* * Common definitions and functions @@ -1331,6 +1433,7 @@ function __test2() filter testf int j; +bool t; { print "Heya, filtering route to ", net.ip, " prefixlen ", net.len, " source ", source; print "This route was from ", from; @@ -1342,6 +1445,52 @@ int j; rip_metric = 14; unset(rip_metric); + test_ca_int1 = 42; + test_ca_ip2 = 1.3.5.7; + test_ca_quad3 = 2.4.6.8; + test_ca_bgppath4 = +empty+; + test_ca_clist5 = -empty-; + test_ca_eclist6 = --empty--; + test_ca_lclist7 = ---empty---; + + igp_metric = 53; + babel_metric = 64; + t = defined(babel_router_id); + j = babel_seqno; + + bgp_origin = ORIGIN_IGP; + bgp_path = +empty+; + bgp_next_hop = 3456:789a:bcde:f012::3456:789a; + bgp_med = 71; + bgp_local_pref = 942; + t = defined(bgp_atomic_aggr); + t = defined(bgp_aggregator); + bgp_community = -empty-; + bgp_originator_id = 9.7.5.3; + bgp_cluster_list = -empty-; + t = defined(bgp_mp_reach_nlri); + t = defined(bgp_mp_unreach_nlri); + bgp_ext_community = --empty--; + bgp_as4_path = +empty+; + t = defined(bgp_as4_aggregator); + t = defined(bgp_aigp); + bgp_large_community = ---empty---; + t = defined(bgp_mpls_label_stack); + + ospf_metric1 = 64; + ospf_metric2 = 111; + ospf_tag = 654432; + + radv_preference = RA_PREF_LOW; + radv_lifetime = 28; + + rip_metric = 2; + rip_tag = 4; + t = defined(rip_from); + + krt_source = 17; + krt_metric = 19; + # krt_lock_mtu = false; # krt_lock_window = true; # krt_lock_rtt = krt_lock_rttvar && krt_lock_sstresh || krt_lock_cwnd; diff --git a/lib/event_test.c b/lib/event_test.c index e14d0b95..3070327d 100644 --- a/lib/event_test.c +++ b/lib/event_test.c @@ -55,8 +55,8 @@ t_ev_run_list(void) olock_init(); timer_init(); - io_init(); rt_init(); + io_init(); if_init(); // roa_init(); config_init(); diff --git a/lib/mempool.c b/lib/mempool.c index 325b1ecf..33eaec86 100644 --- a/lib/mempool.c +++ b/lib/mempool.c @@ -41,8 +41,6 @@ struct linpool { uint total, total_large; }; -_Thread_local linpool *tmp_linpool; - static void lp_free(resource *); static void lp_dump(resource *); static resource *lp_lookup(resource *, unsigned long); diff --git a/lib/resource.c b/lib/resource.c index 89e559b4..c31d9889 100644 --- a/lib/resource.c +++ b/lib/resource.c @@ -292,6 +292,25 @@ resource_init(void) tmp_init(&root_pool); } +_Thread_local struct tmp_resources tmp_res; + +void +tmp_init(pool *p) +{ + tmp_res.lp = lp_new_default(p); + tmp_res.parent = p; + tmp_res.pool = rp_new(p, "TMP"); +} + +void +tmp_flush(void) +{ + lp_flush(tmp_linpool); + rfree(tmp_res.pool); + tmp_res.pool = rp_new(tmp_res.parent, "TMP"); +} + + /** * DOC: Memory blocks * diff --git a/lib/resource.h b/lib/resource.h index a4e110a5..4cedbf00 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -80,14 +80,21 @@ void lp_flush(linpool *); /* Free everything, but leave linpool */ void lp_save(linpool *m, lp_state *p); /* Save state */ void lp_restore(linpool *m, lp_state *p); /* Restore state */ -extern _Thread_local linpool *tmp_linpool; /* Temporary linpool autoflushed regularily */ +struct tmp_resources { + pool *pool, *parent; + linpool *lp; +}; + +extern _Thread_local struct tmp_resources tmp_res; +#define tmp_linpool tmp_res.lp #define tmp_alloc(sz) lp_alloc(tmp_linpool, sz) #define tmp_allocu(sz) lp_allocu(tmp_linpool, sz) #define tmp_allocz(sz) lp_allocz(tmp_linpool, sz) -#define tmp_init(p) tmp_linpool = lp_new_default(p) -#define tmp_flush() lp_flush(tmp_linpool) +void tmp_init(pool *p); +void tmp_flush(void); + #define lp_new_default lp_new diff --git a/lib/route.h b/lib/route.h index ad3f3fb7..f24fd555 100644 --- a/lib/route.h +++ b/lib/route.h @@ -150,19 +150,7 @@ typedef struct eattr { } eattr; -#define EA_CODE(proto,id) (((proto) << 8) | (id)) -#define EA_ID(ea) ((ea) & 0xff) -#define EA_PROTO(ea) ((ea) >> 8) -#define EA_CUSTOM(id) ((id) | EA_CUSTOM_BIT) -#define EA_IS_CUSTOM(ea) ((ea) & EA_CUSTOM_BIT) -#define EA_CUSTOM_ID(ea) ((ea) & ~EA_CUSTOM_BIT) - -const char *ea_custom_name(uint ea); - -#define EA_GEN_IGP_METRIC EA_CODE(PROTOCOL_NONE, 0) - #define EA_CODE_MASK 0xffff -#define EA_CUSTOM_BIT 0x8000 #define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */ #define EA_BIT(n) ((n) << 24) /* Used in bitfield accessors */ #define EA_BIT_GET(ea) ((ea) >> 24) @@ -179,32 +167,67 @@ typedef struct ea_list { #define EALF_BISECT 2 /* Use interval bisection for searching */ #define EALF_CACHED 4 /* Attributes belonging to cached rta */ +struct ea_class { +#define EA_CLASS_INSIDE \ + const char *name; /* Name (both print and filter) */ \ + struct symbol *sym; /* Symbol to export to configs */ \ + uint id; /* Autoassigned attribute ID */ \ + uint uc; /* Reference count */ \ + btype type; /* Data type ID */ \ + uint readonly:1; /* This attribute can't be changed by filters */ \ + uint conf:1; /* Requested by config */ \ + void (*format)(const eattr *ea, byte *buf, uint size); \ + + EA_CLASS_INSIDE; +}; + +struct ea_class_ref { + resource r; + struct ea_class *class; +}; + +extern struct ea_class ea_gen_igp_metric; + +void ea_register_init(struct ea_class *); +struct ea_class_ref *ea_register_alloc(pool *, struct ea_class); + +#define EA_REGISTER_ALL_HELPER(x) ea_register_init(x); +#define EA_REGISTER_ALL(...) MACRO_FOREACH(EA_REGISTER_ALL_HELPER, __VA_ARGS__) + +struct ea_class *ea_class_find_by_id(uint id); +struct ea_class *ea_class_find_by_name(const char *name); +static inline struct ea_class *ea_class_self(struct ea_class *self) { return self; } +#define ea_class_find(_arg) _Generic((_arg), \ + uint: ea_class_find_by_id, \ + word: ea_class_find_by_id, \ + char *: ea_class_find_by_name, \ + const char *: ea_class_find_by_name, \ + struct ea_class *: ea_class_self)(_arg) + struct ea_walk_state { ea_list *eattrs; /* Ccurrent ea_list, initially set by caller */ eattr *ea; /* Current eattr, initially NULL */ u32 visited[4]; /* Bitfield, limiting max to 128 */ }; -eattr *ea_find(ea_list *, unsigned ea); -eattr *ea_walk(struct ea_walk_state *s, uint id, uint max); - -/** - * ea_get_int - fetch an integer attribute - * @e: attribute list - * @id: attribute ID - * @def: default value - * - * This function is a shortcut for retrieving a value of an integer attribute - * by calling ea_find() to find the attribute, extracting its value or returning - * a provided default if no such attribute is present. - */ -static inline u32 -ea_get_int(ea_list *e, unsigned id, u32 def) +#define ea_find(_l, _arg) _Generic((_arg), uint: ea_find_by_id, struct ea_class *: ea_find_by_class, char *: ea_find_by_name)(_l, _arg) +eattr *ea_find_by_id(ea_list *, unsigned ea); +static inline eattr *ea_find_by_class(ea_list *l, const struct ea_class *def) +{ return ea_find_by_id(l, def->id); } +static inline eattr *ea_find_by_name(ea_list *l, const char *name) { - eattr *a = ea_find(e, id); - return a ? a->u.data : def; + const struct ea_class *def = ea_class_find_by_name(name); + return def ? ea_find_by_class(l, def) : NULL; } +#define ea_get_int(_l, _ident, _def) ({ \ + struct ea_class *cls = ea_class_find((_ident)); \ + ASSERT_DIE(cls->type & EAF_EMBEDDED); \ + const eattr *ea = ea_find((_l), cls->id); \ + (ea ? ea->u.data : (_def)); \ + }) + +eattr *ea_walk(struct ea_walk_state *s, uint id, uint max); void ea_dump(ea_list *); int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */ @@ -219,19 +242,22 @@ void ea_list_copy(ea_list *dest, ea_list *src, uint size); #define EA_LOCAL_LIST(N) struct { ea_list l; eattr a[N]; } -#define EA_LITERAL_EMBEDDED(_id, _type, _flags, _val) ({ \ +#define EA_LITERAL_EMBEDDED(_class, _flags, _val) ({ \ + btype _type = (_class)->type; \ ASSERT_DIE(_type & EAF_EMBEDDED); \ - EA_LITERAL_GENERIC(_id, _type, _flags, .u.i = _val); \ + EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.i = _val); \ }) -#define EA_LITERAL_STORE_ADATA(_id, _type, _flags, _buf, _len) ({ \ +#define EA_LITERAL_STORE_ADATA(_class, _flags, _buf, _len) ({ \ + btype _type = (_class)->type; \ ASSERT_DIE(!(_type & EAF_EMBEDDED)); \ - EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = tmp_store_adata((_buf), (_len))); \ + EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.ad = tmp_store_adata((_buf), (_len))); \ }) -#define EA_LITERAL_DIRECT_ADATA(_id, _type, _flags, _adata) ({ \ +#define EA_LITERAL_DIRECT_ADATA(_class, _flags, _adata) ({ \ + btype _type = (_class)->type; \ ASSERT_DIE(!(_type & EAF_EMBEDDED)); \ - EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = _adata); \ + EA_LITERAL_GENERIC((_class)->id, _type, _flags, .u.ad = _adata); \ }) #define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \ @@ -253,19 +279,19 @@ ea_set_attr(ea_list **to, eattr a) } static inline void -ea_unset_attr(ea_list **to, _Bool local, uint code) +ea_unset_attr(ea_list **to, _Bool local, const struct ea_class *def) { - ea_set_attr(to, EA_LITERAL_GENERIC(code, 0, 0, + ea_set_attr(to, EA_LITERAL_GENERIC(def->id, 0, 0, .fresh = local, .originated = local, .undef = 1)); } static inline void -ea_set_attr_u32(ea_list **to, uint id, uint flags, uint type, u32 data) -{ ea_set_attr(to, EA_LITERAL_EMBEDDED(id, type, flags, data)); } +ea_set_attr_u32(ea_list **to, const struct ea_class *def, uint flags, u64 data) +{ ea_set_attr(to, EA_LITERAL_EMBEDDED(def, flags, data)); } static inline void -ea_set_attr_data(ea_list **to, uint id, uint flags, uint type, void *data, uint len) -{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(id, type, flags, data, len)); } +ea_set_attr_data(ea_list **to, const struct ea_class *def, uint flags, void *data, uint len) +{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(def, flags, data, len)); } #define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK) diff --git a/nest/config.Y b/nest/config.Y index 12fd01a2..c2913506 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -120,7 +120,7 @@ CF_KEYWORDS(PASSWORD, KEY, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CH CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512) CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE) CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION) -CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) +CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, CLASS, DSCP) CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS) CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE) @@ -921,9 +921,6 @@ proto_patt2: | TEXT { $$.ptr = $1; $$.patt = 1; } ; -dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_GEN_IGP_METRIC); } ; - - CF_CODE CF_END diff --git a/nest/proto.c b/nest/proto.c index 95c319db..72613f8d 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -26,7 +26,6 @@ pool *proto_pool; list STATIC_LIST_INIT(proto_list); static list STATIC_LIST_INIT(protocol_list); -struct protocol *class_to_protocol[PROTOCOL__MAX]; #define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); }) #define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); }) @@ -1637,9 +1636,6 @@ void proto_build(struct protocol *p) { add_tail(&protocol_list, &p->n); - ASSERT(p->class); - ASSERT(!class_to_protocol[p->class]); - class_to_protocol[p->class] = p; } /* FIXME: convert this call to some protocol hook */ diff --git a/nest/protocol.h b/nest/protocol.h index 7fb08992..8f0cc4b4 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -37,38 +37,20 @@ struct symbol; * Routing Protocol */ -enum protocol_class { - PROTOCOL_NONE, - PROTOCOL_BABEL, - PROTOCOL_BFD, - PROTOCOL_BGP, - PROTOCOL_DEVICE, - PROTOCOL_DIRECT, - PROTOCOL_KERNEL, - PROTOCOL_OSPF, - PROTOCOL_MRT, - PROTOCOL_PERF, - PROTOCOL_PIPE, - PROTOCOL_RADV, - PROTOCOL_RIP, - PROTOCOL_RPKI, - PROTOCOL_STATIC, - PROTOCOL__MAX -}; - -extern struct protocol *class_to_protocol[PROTOCOL__MAX]; struct protocol { node n; char *name; char *template; /* Template for automatic generation of names */ int name_counter; /* Counter for automatic name generation */ - enum protocol_class class; /* Machine readable protocol class */ uint preference; /* Default protocol preference */ uint channel_mask; /* Mask of accepted channel types (NB_*) */ uint proto_size; /* Size of protocol data structure */ uint config_size; /* Size of protocol config data structure */ + uint eattr_begin; /* First ID of registered eattrs */ + uint eattr_end; /* End of eattr id zone */ + void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ void (*postconfig)(struct proto_config *); /* After configuring each instance */ struct proto * (*init)(struct proto_config *); /* Create new instance */ @@ -79,7 +61,7 @@ struct protocol { void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */ void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */ void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */ - int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ +// int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */ void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ }; diff --git a/nest/rt-attr.c b/nest/rt-attr.c index afa95eec..a763db4d 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -60,6 +60,11 @@ const adata null_adata; /* adata of length 0 */ +struct ea_class ea_gen_igp_metric = { + .name = "igp_metric", + .type = T_INT, +}; + const char * const rta_src_names[RTS_MAX] = { [RTS_STATIC] = "static", [RTS_INHERIT] = "inherit", @@ -401,6 +406,117 @@ nexthop_free(struct nexthop *o) * Extended Attributes */ +#define EA_CLASS_INITIAL_MAX 128 +static struct ea_class **ea_class_global = NULL; +static uint ea_class_max; +static struct idm ea_class_idm; + +/* Config parser lex register function */ +void ea_lex_register(struct ea_class *def); +void ea_lex_unregister(struct ea_class *def); + +static void +ea_class_free(struct ea_class *cl) +{ + /* No more ea class references. Unregister the attribute. */ + idm_free(&ea_class_idm, cl->id); + ea_class_global[cl->id] = NULL; + ea_lex_unregister(cl); +} + +static void +ea_class_ref_free(resource *r) +{ + struct ea_class_ref *ref = SKIP_BACK(struct ea_class_ref, r, r); + if (!--ref->class->uc) + ea_class_free(ref->class); +} + +static void +ea_class_ref_dump(resource *r) +{ + struct ea_class_ref *ref = SKIP_BACK(struct ea_class_ref, r, r); + debug("name \"%s\", type=%d\n", ref->class->name, ref->class->type); +} + +static struct resclass ea_class_ref_class = { + .name = "Attribute class reference", + .size = sizeof(struct ea_class_ref), + .free = ea_class_ref_free, + .dump = ea_class_ref_dump, + .lookup = NULL, + .memsize = NULL, +}; + +static void +ea_class_init(void) +{ + idm_init(&ea_class_idm, rta_pool, EA_CLASS_INITIAL_MAX); + ea_class_global = mb_allocz(rta_pool, + sizeof(*ea_class_global) * (ea_class_max = EA_CLASS_INITIAL_MAX)); +} + +static struct ea_class_ref * +ea_ref_class(pool *p, struct ea_class *def) +{ + def->uc++; + struct ea_class_ref *ref = ralloc(p, &ea_class_ref_class); + ref->class = def; + return ref; +} + +static struct ea_class_ref * +ea_register(pool *p, struct ea_class *def) +{ + def->id = idm_alloc(&ea_class_idm); + + ASSERT_DIE(ea_class_global); + while (def->id >= ea_class_max) + ea_class_global = mb_realloc(ea_class_global, sizeof(*ea_class_global) * (ea_class_max *= 2)); + + ASSERT_DIE(def->id < ea_class_max); + ea_class_global[def->id] = def; + + ea_lex_register(def); + + return ea_ref_class(p, def); +} + +struct ea_class_ref * +ea_register_alloc(pool *p, struct ea_class cl) +{ + struct ea_class *clp = ea_class_find_by_name(cl.name); + if (clp && clp->type == cl.type) + return ea_ref_class(p, clp); + + uint namelen = strlen(cl.name) + 1; + + struct { + struct ea_class cl; + char name[0]; + } *cla = mb_alloc(rta_pool, sizeof(struct ea_class) + namelen); + cla->cl = cl; + memcpy(cla->name, cl.name, namelen); + cla->cl.name = cla->name; + + return ea_register(p, &cla->cl); +} + +void +ea_register_init(struct ea_class *clp) +{ + ASSERT_DIE(!ea_class_find_by_name(clp->name)); + ea_register(&root_pool, clp); +} + +struct ea_class * +ea_class_find_by_id(uint id) +{ + ASSERT_DIE(id < ea_class_max); + ASSERT_DIE(ea_class_global[id]); + return ea_class_global[id]; +} + static inline eattr * ea__find(ea_list *e, unsigned id) { @@ -444,7 +560,7 @@ ea__find(ea_list *e, unsigned id) * to its &eattr structure or %NULL if no such attribute exists. */ eattr * -ea_find(ea_list *e, unsigned id) +ea_find_by_id(ea_list *e, unsigned id) { eattr *a = ea__find(e, id & EA_CODE_MASK); @@ -784,26 +900,44 @@ ea_list_copy(ea_list *n, ea_list *o, uint elen) ASSERT_DIE(adpos == elen); } -static inline void -ea_free(ea_list *o) +static void +ea_list_ref(ea_list *l) { - if (o) + for(uint i=0; icount; i++) { - ASSERT(!o->next); - mb_free(o); + eattr *a = &l->attrs[i]; + ASSERT_DIE(a->id < ea_class_max); + + struct ea_class *cl = ea_class_global[a->id]; + ASSERT_DIE(cl && cl->uc); + cl->uc++; } } -static int -get_generic_attr(const eattr *a, byte **buf, int buflen UNUSED) +static void +ea_list_unref(ea_list *l) { - if (a->id == EA_GEN_IGP_METRIC) + for(uint i=0; icount; i++) { - *buf += bsprintf(*buf, "igp_metric"); - return GA_NAME; + eattr *a = &l->attrs[i]; + ASSERT_DIE(a->id < ea_class_max); + + struct ea_class *cl = ea_class_global[a->id]; + ASSERT_DIE(cl && cl->uc); + if (!--cl->uc) + ea_class_free(cl); } +} - return GA_UNKNOWN; +static inline void +ea_free(ea_list *o) +{ + if (o) + { + ea_list_unref(o); + ASSERT(!o->next); + mb_free(o); + } } void @@ -905,47 +1039,27 @@ ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte void ea_show(struct cli *c, const eattr *e) { - struct protocol *p; - int status = GA_UNKNOWN; const struct adata *ad = (e->type & EAF_EMBEDDED) ? NULL : e->u.ptr; byte buf[CLI_MSG_SIZE]; byte *pos = buf, *end = buf + sizeof(buf); - if (EA_IS_CUSTOM(e->id)) - { - const char *name = ea_custom_name(e->id); - if (name) - { - pos += bsprintf(pos, "%s", name); - status = GA_NAME; - } - else - pos += bsprintf(pos, "%02x.", EA_PROTO(e->id)); - } - else if (p = class_to_protocol[EA_PROTO(e->id)]) - { - pos += bsprintf(pos, "%s.", p->name); - if (p->get_attr) - status = p->get_attr(e, pos, end - pos); - pos += strlen(pos); - } - else if (EA_PROTO(e->id)) - pos += bsprintf(pos, "%02x.", EA_PROTO(e->id)); - else - status = get_generic_attr(e, &pos, end - pos); + ASSERT_DIE(e->id < ea_class_max); - if (status < GA_NAME) - pos += bsprintf(pos, "%02x", EA_ID(e->id)); - if (status < GA_FULL) - { - *pos++ = ':'; - *pos++ = ' '; + struct ea_class *cls = ea_class_global[e->id]; + ASSERT_DIE(cls); - if (e->undef) - bsprintf(pos, "undefined"); - else - switch (e->type) - { + pos += bsprintf(pos, "%s", cls->name); + + *pos++ = ':'; + *pos++ = ' '; + + if (e->undef) + bsprintf(pos, "undefined (should not happen)"); + else if (cls->format) + cls->format(e, buf, end - buf); + else + switch (e->type) + { case T_INT: bsprintf(pos, "%u", e->u.data); break; @@ -970,13 +1084,10 @@ ea_show(struct cli *c, const eattr *e) case T_LCLIST: ea_show_lc_set(c, ad, pos, buf, end); return; - case T_IFACE: - bsprintf(pos, "%s", ((struct iface *) e->u.ptr)->name); - return; default: bsprintf(pos, "", e->type); - } - } + } + cli_printf(c, -1012, "\t%s", buf); } @@ -1006,7 +1117,7 @@ ea_dump(ea_list *e) for(i=0; icount; i++) { eattr *a = &e->attrs[i]; - debug(" %02x:%02x.%02x", EA_PROTO(a->id), EA_ID(a->id), a->flags); + debug(" %04x.%02x", a->id, a->flags); debug("=%c", "?iO?IRP???S??pE?" "??L???N?????????" @@ -1157,6 +1268,7 @@ rta_copy(rta *o) uint elen = ea_list_size(o->eattrs); r->eattrs = mb_alloc(rta_pool, elen); ea_list_copy(r->eattrs, o->eattrs, elen); + ea_list_ref(r->eattrs); r->eattrs->flags |= EALF_CACHED; return r; } @@ -1357,6 +1469,9 @@ rta_init(void) rta_alloc_hash(); rte_src_init(); + ea_class_init(); + + ea_register_init(&ea_gen_igp_metric); } /* diff --git a/nest/rt-dev.c b/nest/rt-dev.c index 82533321..bdf8584d 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -185,7 +185,6 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src) struct protocol proto_device = { .name = "Direct", .template = "direct%d", - .class = PROTOCOL_DIRECT, .preference = DEF_PREF_DIRECT, .channel_mask = NB_IP | NB_IP6_SADR, .proto_size = sizeof(struct rt_dev_proto), diff --git a/nest/rt-table.c b/nest/rt-table.c index 049b7a7f..af59d63b 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2536,14 +2536,14 @@ net_flow_has_dst_prefix(const net_addr *n) static inline int rta_as_path_is_empty(rta *a) { - eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + eattr *e = ea_find(a->eattrs, "bgp_path"); return !e || (as_path_getlen(e->u.ptr) == 0); } static inline u32 rta_get_first_asn(rta *a) { - eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + eattr *e = ea_find(a->eattrs, "bgp_path"); u32 asn; return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0; @@ -2587,8 +2587,8 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i return 0; /* Find ORIGINATOR_ID values */ - u32 orig_a = ea_get_int(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0); - u32 orig_b = ea_get_int(rb->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0); + u32 orig_a = ea_get_int(a->eattrs, "bgp_originator_id", 0); + u32 orig_b = ea_get_int(rb->attrs->eattrs, "bgp_originator_id", 0); /* Originator is either ORIGINATOR_ID (if present), or BGP neighbor address (if not) */ if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal(a->from, rb->attrs->from))) @@ -3458,7 +3458,7 @@ if_local_addr(ip_addr a, struct iface *i) u32 rt_get_igp_metric(rte *rt) { - eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC); + eattr *ea = ea_find(rt->attrs->eattrs, "igp_metric"); if (ea) return ea->u.data; diff --git a/proto/babel/babel.c b/proto/babel/babel.c index db710a0d..97dca4ac 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -37,6 +37,7 @@ #include #include "babel.h" +#include "lib/macro.h" #define LOG_PKT_AUTH(msg, args...) \ log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args) @@ -58,6 +59,8 @@ static void babel_update_cost(struct babel_neighbor *n); static inline void babel_kick_timer(struct babel_proto *p); static inline void babel_iface_kick_timer(struct babel_iface *ifa); +static struct ea_class ea_babel_metric, ea_babel_router_id, ea_babel_seqno; + /* * Functions to maintain data structures */ @@ -646,9 +649,9 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) } eattrs = { .l.count = 3, .a = { - EA_LITERAL_EMBEDDED(EA_BABEL_METRIC, T_INT, 0, r->metric), - EA_LITERAL_STORE_ADATA(EA_BABEL_ROUTER_ID, T_OPAQUE, 0, &r->router_id, sizeof(r->router_id)), - EA_LITERAL_EMBEDDED(EA_BABEL_SEQNO, T_INT, 0, r->seqno), + EA_LITERAL_EMBEDDED(&ea_babel_metric, 0, r->metric), + EA_LITERAL_STORE_ADATA(&ea_babel_router_id, 0, &r->router_id, sizeof(r->router_id)), + EA_LITERAL_EMBEDDED(&ea_babel_seqno, 0, r->seqno), } }; @@ -2018,38 +2021,40 @@ static void babel_get_route_info(rte *rte, byte *buf) { u64 rid = 0; - eattr *e = ea_find(rte->attrs->eattrs, EA_BABEL_ROUTER_ID); + eattr *e = ea_find(rte->attrs->eattrs, &ea_babel_router_id); if (e) memcpy(&rid, e->u.ptr->data, sizeof(u64)); buf += bsprintf(buf, " (%d/%d) [%lR]", rte->attrs->pref, - ea_get_int(rte->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY), rid); + ea_get_int(rte->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY), rid); } -static int -babel_get_attr(const eattr *a, byte *buf, int buflen UNUSED) +static void +babel_router_id_format(const eattr *a, byte *buf, uint len) { - switch (a->id) - { - case EA_BABEL_SEQNO: - return GA_FULL; + u64 rid = 0; + memcpy(&rid, a->u.ptr->data, sizeof(u64)); + bsnprintf(buf, len, "%lR", rid); +} - case EA_BABEL_METRIC: - bsprintf(buf, "metric: %d", a->u.data); - return GA_FULL; +static struct ea_class ea_babel_metric = { + .name = "babel_metric", + .type = T_INT, +}; - case EA_BABEL_ROUTER_ID: - { - u64 rid = 0; - memcpy(&rid, a->u.ptr->data, sizeof(u64)); - bsprintf(buf, "router_id: %lR", rid); - return GA_FULL; - } +static struct ea_class ea_babel_router_id = { + .name = "babel_router_id", + .type = T_OPAQUE, + .readonly = 1, + .format = babel_router_id_format, +}; + +static struct ea_class ea_babel_seqno = { + .name = "babel_seqno", + .type = T_INT, + .readonly = 1, +}; - default: - return GA_UNKNOWN; - } -} void babel_show_interfaces(struct proto *P, const char *iff) @@ -2272,13 +2277,13 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, { /* Update */ uint rt_seqno; - uint rt_metric = ea_get_int(new->attrs->eattrs, EA_BABEL_METRIC, 0); + uint rt_metric = ea_get_int(new->attrs->eattrs, &ea_babel_metric, 0); u64 rt_router_id = 0; if (new->src->proto == P) { - rt_seqno = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data; - eattr *e = ea_find(new->attrs->eattrs, EA_BABEL_ROUTER_ID); + rt_seqno = ea_get_int(new->attrs->eattrs, &ea_babel_seqno, 0); + eattr *e = ea_find(new->attrs->eattrs, &ea_babel_router_id); if (e) memcpy(&rt_router_id, e->u.ptr->data, sizeof(u64)); } @@ -2329,8 +2334,8 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, static int babel_rte_better(struct rte *new, struct rte *old) { - uint new_metric = ea_find(new->attrs->eattrs, EA_BABEL_SEQNO)->u.data; - uint old_metric = ea_find(old->attrs->eattrs, EA_BABEL_SEQNO)->u.data; + uint new_metric = ea_get_int(new->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY); + uint old_metric = ea_get_int(old->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY); return new_metric < old_metric; } @@ -2338,7 +2343,7 @@ babel_rte_better(struct rte *new, struct rte *old) static u32 babel_rte_igp_metric(struct rte *rt) { - return ea_get_int(rt->attrs->eattrs, EA_BABEL_METRIC, BABEL_INFINITY); + return ea_get_int(rt->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY); } @@ -2466,11 +2471,9 @@ babel_reconfigure(struct proto *P, struct proto_config *CF) return 1; } - struct protocol proto_babel = { .name = "Babel", .template = "babel%d", - .class = PROTOCOL_BABEL, .preference = DEF_PREF_BABEL, .channel_mask = NB_IP | NB_IP6_SADR, .proto_size = sizeof(struct babel_proto), @@ -2482,11 +2485,16 @@ struct protocol proto_babel = { .shutdown = babel_shutdown, .reconfigure = babel_reconfigure, .get_route_info = babel_get_route_info, - .get_attr = babel_get_attr }; void babel_build(void) { proto_build(&proto_babel); + + EA_REGISTER_ALL( + &ea_babel_metric, + &ea_babel_router_id, + &ea_babel_seqno + ); } diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 00814641..a980d1da 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -26,10 +26,6 @@ #include "lib/string.h" #include "lib/timer.h" -#define EA_BABEL_METRIC EA_CODE(PROTOCOL_BABEL, 0) -#define EA_BABEL_ROUTER_ID EA_CODE(PROTOCOL_BABEL, 1) -#define EA_BABEL_SEQNO EA_CODE(PROTOCOL_BABEL, 2) - #define BABEL_MAGIC 42 #define BABEL_VERSION 2 #define BABEL_PORT 6696 diff --git a/proto/babel/config.Y b/proto/babel/config.Y index fa745993..82419b20 100644 --- a/proto/babel/config.Y +++ b/proto/babel/config.Y @@ -163,8 +163,6 @@ babel_iface_opt_list: babel_iface: babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish; -dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_BABEL_METRIC); } ; - CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]); CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [] [\"\"], [[Show information about Babel interfaces]]) diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index d1e97cd5..1a2104ad 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1170,7 +1170,6 @@ bfd_show_sessions(struct proto *P) struct protocol proto_bfd = { .name = "BFD", .template = "bfd%d", - .class = PROTOCOL_BFD, .proto_size = sizeof(struct bfd_proto), .config_size = sizeof(struct bfd_config), .init = bfd_init, diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 4c67b161..72a4f68a 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -21,6 +21,7 @@ #include "lib/resource.h" #include "lib/string.h" #include "lib/unaligned.h" +#include "lib/macro.h" #include "bgp.h" @@ -64,28 +65,37 @@ * format - Optional hook that converts eattr to textual representation. */ - -struct bgp_attr_desc { - const char *name; - uint type; - uint flags; - void (*export)(struct bgp_export_state *s, eattr *a); - int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size); - void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to); - void (*format)(const eattr *ea, byte *buf, uint size); +union bgp_attr_desc { + struct ea_class class; + struct { + EA_CLASS_INSIDE; + uint flags; + void (*export)(struct bgp_export_state *s, eattr *a); + int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size); + void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to); + }; }; -static const struct bgp_attr_desc bgp_attr_table[]; +static union bgp_attr_desc bgp_attr_table[]; +static inline const union bgp_attr_desc *bgp_find_attr_desc(eattr *a) +{ + const struct ea_class *class = ea_class_find(a->id); + + if ((class < &bgp_attr_table[0].class) || (class >= &bgp_attr_table[BGP_ATTR_MAX].class)) + return NULL; + + return (const union bgp_attr_desc *) class; +} -static inline int bgp_attr_known(uint code); +#define BGP_EA_ID(code) (bgp_attr_table[code].id) +#define EA_BGP_ID(code) (((union bgp_attr_desc *) ea_class_find(code)) - bgp_attr_table) void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val) { - ASSERT(bgp_attr_known(code)); + const union bgp_attr_desc *desc = &bgp_attr_table[code]; ea_set_attr(to, EA_LITERAL_EMBEDDED( - EA_CODE(PROTOCOL_BGP, code), - bgp_attr_table[code].type, + &desc->class, flags & ~BAF_EXT_LEN, val )); @@ -93,11 +103,10 @@ void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val) void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *ad) { - ASSERT(bgp_attr_known(code)); + const union bgp_attr_desc *desc = &bgp_attr_table[code]; ea_set_attr(to, EA_LITERAL_DIRECT_ADATA( - EA_CODE(PROTOCOL_BGP, code), - bgp_attr_table[code].type, + &desc->class, flags & ~BAF_EXT_LEN, ad )); @@ -106,17 +115,23 @@ void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *a void bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len) { - ASSERT(bgp_attr_known(code)); + const union bgp_attr_desc *desc = &bgp_attr_table[code]; ea_set_attr(to, EA_LITERAL_STORE_ADATA( - EA_CODE(PROTOCOL_BGP, code), - bgp_attr_table[code].type, + &desc->class, flags & ~BAF_EXT_LEN, data, len )); } +void +bgp_unset_attr(ea_list **to, uint code) +{ + const union bgp_attr_desc *desc = &bgp_attr_table[code]; + ea_unset_attr(to, 0, &desc->class); +} + #define REPORT(msg, args...) \ ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); }) @@ -172,7 +187,7 @@ bgp_encode_u8(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size) if (size < (3+1)) return -1; - bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 1); + bgp_put_attr_hdr3(buf, EA_BGP_ID(a->id), a->flags, 1); buf[3] = a->u.data; return 3+1; @@ -184,7 +199,7 @@ bgp_encode_u32(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size) if (size < (3+4)) return -1; - bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 4); + bgp_put_attr_hdr3(buf, EA_BGP_ID(a->id), a->flags, 4); put_u32(buf+3, a->u.data); return 3+4; @@ -198,7 +213,7 @@ bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size if (size < (4+len)) return -1; - uint hdr = bgp_put_attr_hdr(buf, EA_ID(a->id), a->flags, len); + uint hdr = bgp_put_attr_hdr(buf, EA_BGP_ID(a->id), a->flags, len); put_u32s(buf + hdr, (u32 *) a->u.ptr->data, len / 4); return hdr + len; @@ -219,7 +234,7 @@ bgp_put_attr(byte *buf, uint size, uint code, uint flags, const byte *data, uint static int bgp_encode_raw(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size) { - return bgp_put_attr(buf, size, EA_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length); + return bgp_put_attr(buf, size, EA_BGP_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length); } @@ -359,7 +374,7 @@ bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric) int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad) { - eattr *a = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP)); + eattr *a = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_AIGP)); if (!a) return 0; @@ -993,11 +1008,30 @@ bgp_format_mpls_label_stack(const eattr *a, byte *buf, uint size) pos[lnum ? -1 : 0] = 0; } +static inline void +bgp_export_unknown(struct bgp_export_state *s UNUSED, eattr *a) +{ + if (!(a->flags & BAF_TRANSITIVE)) + UNSET(a); + + a->flags |= BAF_PARTIAL; +} + static inline void bgp_decode_unknown(struct bgp_parse_state *s UNUSED, uint code, uint flags, byte *data, uint len, ea_list **to) { + if (!(flags & BAF_OPTIONAL)) + WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags); + /* Cannot use bgp_set_attr_data() as it works on known attributes only */ - ea_set_attr_data(to, EA_CODE(PROTOCOL_BGP, code), flags, T_OPAQUE, data, len); + ea_set_attr_data(to, &bgp_attr_table[code].class, flags, data, len); +} + +static inline void +bgp_format_unknown(const eattr *a, byte *buf, uint size) +{ + if (a->flags & BAF_TRANSITIVE) + bsnprintf(buf, size, "(transitive)"); } @@ -1005,9 +1039,9 @@ bgp_decode_unknown(struct bgp_parse_state *s UNUSED, uint code, uint flags, byte * Attribute table */ -static const struct bgp_attr_desc bgp_attr_table[] = { +static union bgp_attr_desc bgp_attr_table[BGP_ATTR_MAX] = { [BA_ORIGIN] = { - .name = "origin", + .name = "bgp_origin", .type = T_ENUM_BGP_ORIGIN, .flags = BAF_TRANSITIVE, .export = bgp_export_origin, @@ -1016,14 +1050,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_origin, }, [BA_AS_PATH] = { - .name = "as_path", + .name = "bgp_path", .type = T_PATH, .flags = BAF_TRANSITIVE, .encode = bgp_encode_as_path, .decode = bgp_decode_as_path, }, [BA_NEXT_HOP] = { - .name = "next_hop", + .name = "bgp_next_hop", .type = T_IP, .flags = BAF_TRANSITIVE, .encode = bgp_encode_next_hop, @@ -1031,14 +1065,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_next_hop, }, [BA_MULTI_EXIT_DISC] = { - .name = "med", + .name = "bgp_med", .type = T_INT, .flags = BAF_OPTIONAL, .encode = bgp_encode_u32, .decode = bgp_decode_med, }, [BA_LOCAL_PREF] = { - .name = "local_pref", + .name = "bgp_local_pref", .type = T_INT, .flags = BAF_TRANSITIVE, .export = bgp_export_local_pref, @@ -1046,14 +1080,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_local_pref, }, [BA_ATOMIC_AGGR] = { - .name = "atomic_aggr", + .name = "bgp_atomic_aggr", .type = T_OPAQUE, .flags = BAF_TRANSITIVE, .encode = bgp_encode_raw, .decode = bgp_decode_atomic_aggr, }, [BA_AGGREGATOR] = { - .name = "aggregator", + .name = "bgp_aggregator", .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_aggregator, @@ -1061,7 +1095,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_aggregator, }, [BA_COMMUNITY] = { - .name = "community", + .name = "bgp_community", .type = T_CLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_community, @@ -1069,7 +1103,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_community, }, [BA_ORIGINATOR_ID] = { - .name = "originator_id", + .name = "bgp_originator_id", .type = T_QUAD, .flags = BAF_OPTIONAL, .export = bgp_export_originator_id, @@ -1077,7 +1111,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_originator_id, }, [BA_CLUSTER_LIST] = { - .name = "cluster_list", + .name = "bgp_cluster_list", .type = T_CLIST, .flags = BAF_OPTIONAL, .export = bgp_export_cluster_list, @@ -1086,19 +1120,19 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_cluster_list, }, [BA_MP_REACH_NLRI] = { - .name = "mp_reach_nlri", + .name = "bgp_mp_reach_nlri", .type = T_OPAQUE, .flags = BAF_OPTIONAL, .decode = bgp_decode_mp_reach_nlri, }, [BA_MP_UNREACH_NLRI] = { - .name = "mp_unreach_nlri", + .name = "bgp_mp_unreach_nlri", .type = T_OPAQUE, .flags = BAF_OPTIONAL, .decode = bgp_decode_mp_unreach_nlri, }, [BA_EXT_COMMUNITY] = { - .name = "ext_community", + .name = "bgp_ext_community", .type = T_ECLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_ext_community, @@ -1106,14 +1140,14 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_ext_community, }, [BA_AS4_PATH] = { - .name = "as4_path", + .name = "bgp_as4_path", .type = T_PATH, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_raw, .decode = bgp_decode_as4_path, }, [BA_AS4_AGGREGATOR] = { - .name = "as4_aggregator", + .name = "bgp_as4_aggregator", .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .encode = bgp_encode_raw, @@ -1121,7 +1155,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_aggregator, }, [BA_AIGP] = { - .name = "aigp", + .name = "bgp_aigp", .type = T_OPAQUE, .flags = BAF_OPTIONAL | BAF_DECODE_FLAGS, .export = bgp_export_aigp, @@ -1130,7 +1164,7 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .format = bgp_format_aigp, }, [BA_LARGE_COMMUNITY] = { - .name = "large_community", + .name = "bgp_large_community", .type = T_LCLIST, .flags = BAF_OPTIONAL | BAF_TRANSITIVE, .export = bgp_export_large_community, @@ -1138,8 +1172,9 @@ static const struct bgp_attr_desc bgp_attr_table[] = { .decode = bgp_decode_large_community, }, [BA_MPLS_LABEL_STACK] = { - .name = "mpls_label_stack", + .name = "bgp_mpls_label_stack", .type = T_CLIST, + .readonly = 1, .export = bgp_export_mpls_label_stack, .encode = bgp_encode_mpls_label_stack, .decode = bgp_decode_mpls_label_stack, @@ -1147,12 +1182,32 @@ static const struct bgp_attr_desc bgp_attr_table[] = { }, }; -static inline int -bgp_attr_known(uint code) +eattr * +bgp_find_attr(ea_list *attrs, uint code) { - return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name; + return ea_find(attrs, BGP_EA_ID(code)); } +void +bgp_register_attrs(void) +{ + for (uint i=0; iid) != PROTOCOL_BGP) + const union bgp_attr_desc *desc = bgp_find_attr_desc(a); + if (!desc) return; - uint code = EA_ID(a->id); - - if (bgp_attr_known(code)) - { - const struct bgp_attr_desc *desc = &bgp_attr_table[code]; - - /* The flags might have been zero if the attr was added by filters */ - a->flags = (a->flags & BAF_PARTIAL) | desc->flags; - - /* Set partial bit if new opt-trans attribute is attached to non-local route */ - if ((s->src != NULL) && (a->originated) && - (a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE)) - a->flags |= BAF_PARTIAL; + /* The flags might have been zero if the attr was added locally */ + a->flags = (a->flags & BAF_PARTIAL) | desc->flags; - /* Call specific hook */ - CALL(desc->export, s, a); + /* Set partial bit if new opt-trans attribute is attached to non-local route */ + if ((s->src != NULL) && (a->originated) && + (a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE)) + a->flags |= BAF_PARTIAL; - /* Attribute might become undefined in hook */ - if (a->undef) - return; - } - else - { - /* Don't re-export unknown non-transitive attributes */ - if (!(a->flags & BAF_TRANSITIVE)) - return; + /* Call specific hook */ + CALL(desc->export, s, a); - a->flags |= BAF_PARTIAL; - } + /* Attribute might become undefined in hook */ + if (a->undef) + return; /* Append updated attribute */ to->attrs[to->count++] = *a; @@ -1240,14 +1281,9 @@ bgp_export_attrs(struct bgp_export_state *s, const ea_list *a) static inline int bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size) { - ASSERT(EA_PROTO(a->id) == PROTOCOL_BGP); - - uint code = EA_ID(a->id); - - if (bgp_attr_known(code)) - return bgp_attr_table[code].encode(s, a, buf, size); - else - return bgp_encode_raw(s, a, buf, size); + const union bgp_attr_desc *desc = bgp_find_attr_desc(a); + ASSERT_DIE(desc); + return desc->encode(s, a, buf, size); } /** @@ -1312,7 +1348,7 @@ bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs) } static inline void -bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to) +bgp_decode_attr(struct bgp_parse_state *s, byte code, byte flags, byte *data, uint len, ea_list **to) { /* Handle duplicate attributes; RFC 7606 3 (g) */ if (BIT32_TEST(s->attrs_seen, code)) @@ -1324,24 +1360,15 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui } BIT32_SET(s->attrs_seen, code); - if (bgp_attr_known(code)) - { - const struct bgp_attr_desc *desc = &bgp_attr_table[code]; + ASSERT_DIE(bgp_attr_table[code].id); + const union bgp_attr_desc *desc = &bgp_attr_table[code]; - /* Handle conflicting flags; RFC 7606 3 (c) */ - if (((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE)) && - !(desc->flags & BAF_DECODE_FLAGS)) - WITHDRAW("Malformed %s attribute - conflicting flags (%02x)", desc->name, flags); + /* Handle conflicting flags; RFC 7606 3 (c) */ + if (((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE)) && + !(desc->flags & BAF_DECODE_FLAGS)) + WITHDRAW("Malformed %s attribute - conflicting flags (%02x, expected %02x)", desc->name, flags, desc->flags); - desc->decode(s, code, flags, data, len, to); - } - else /* Unknown attribute */ - { - if (!(flags & BAF_OPTIONAL)) - WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags); - - bgp_decode_unknown(s, code, flags, data, len, to); - } + desc->decode(s, code, flags, data, len, to); } /** @@ -1359,7 +1386,8 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) { struct bgp_proto *p = s->proto; ea_list *attrs = NULL; - uint code, flags, alen; + uint alen; + byte code, flags; byte *pos = data; /* Parse the attributes */ @@ -1703,7 +1731,7 @@ bgp_preexport(struct proto *P, rte *e) /* Handle well-known communities, RFC 1997 */ struct eattr *c; if (p->cf->interpret_communities && - (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)))) + (c = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY)))) { const struct adata *d = c->u.ptr; @@ -1880,7 +1908,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) static inline u32 bgp_get_neighbor(rte *r) { - eattr *e = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + eattr *e = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); u32 as; if (e && as_path_get_first_regular(e->u.ptr, &as)) @@ -1901,7 +1929,7 @@ rte_stale(rte *r) return 0; /* If staleness is unknown, compute and cache it */ - eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); + eattr *a = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY)); if (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE)) { r->pflags |= BGP_REF_STALE; @@ -1947,8 +1975,8 @@ bgp_rte_better(rte *new, rte *old) return 1; /* Start with local preferences */ - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF)); n = x ? x->u.data : new_bgp->cf->default_local_pref; o = y ? y->u.data : old_bgp->cf->default_local_pref; if (n > o) @@ -1967,8 +1995,8 @@ bgp_rte_better(rte *new, rte *old) /* RFC 4271 9.1.2.2. a) Use AS path lengths */ if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths) { - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN; o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN; if (n < o) @@ -1978,8 +2006,8 @@ bgp_rte_better(rte *new, rte *old) } /* RFC 4271 9.1.2.2. b) Use origins */ - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_ORIGIN)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_ORIGIN)); n = x ? x->u.data : ORIGIN_INCOMPLETE; o = y ? y->u.data : ORIGIN_INCOMPLETE; if (n < o) @@ -2001,8 +2029,8 @@ bgp_rte_better(rte *new, rte *old) if (new_bgp->cf->med_metric || old_bgp->cf->med_metric || (bgp_get_neighbor(new) == bgp_get_neighbor(old))) { - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC)); n = x ? x->u.data : new_bgp->cf->default_med; o = y ? y->u.data : old_bgp->cf->default_med; if (n < o) @@ -2027,8 +2055,8 @@ bgp_rte_better(rte *new, rte *old) /* RFC 4271 9.1.2.2. f) Compare BGP identifiers */ /* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighbor ID */ - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_ORIGINATOR_ID)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_ORIGINATOR_ID)); n = x ? x->u.data : new_bgp->remote_id; o = y ? y->u.data : old_bgp->remote_id; @@ -2045,8 +2073,8 @@ bgp_rte_better(rte *new, rte *old) return 0; /* RFC 4456 9. b) Compare cluster list lengths */ - x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); - y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); + x = ea_find(new->attrs->eattrs, BGP_EA_ID(BA_CLUSTER_LIST)); + y = ea_find(old->attrs->eattrs, BGP_EA_ID(BA_CLUSTER_LIST)); n = x ? int_set_get_size(x->u.ptr) : 0; o = y ? int_set_get_size(y->u.ptr) : 0; if (n < o) @@ -2080,8 +2108,8 @@ bgp_rte_mergable(rte *pri, rte *sec) return 0; /* Start with local preferences */ - x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); - y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); + x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF)); + y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_LOCAL_PREF)); p = x ? x->u.data : pri_bgp->cf->default_local_pref; s = y ? y->u.data : sec_bgp->cf->default_local_pref; if (p != s) @@ -2090,8 +2118,8 @@ bgp_rte_mergable(rte *pri, rte *sec) /* RFC 4271 9.1.2.2. a) Use AS path lengths */ if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths) { - x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); - y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); + y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN; s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN; @@ -2103,8 +2131,8 @@ bgp_rte_mergable(rte *pri, rte *sec) } /* RFC 4271 9.1.2.2. b) Use origins */ - x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); - y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); + x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_ORIGIN)); + y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_ORIGIN)); p = x ? x->u.data : ORIGIN_INCOMPLETE; s = y ? y->u.data : ORIGIN_INCOMPLETE; if (p != s) @@ -2114,8 +2142,8 @@ bgp_rte_mergable(rte *pri, rte *sec) if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric || (bgp_get_neighbor(pri) == bgp_get_neighbor(sec))) { - x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); - y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); + x = ea_find(pri->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC)); + y = ea_find(sec->attrs->eattrs, BGP_EA_ID(BA_MULTI_EXIT_DISC)); p = x ? x->u.data : pri_bgp->cf->default_med; s = y ? y->u.data : sec_bgp->cf->default_med; if (p != s) @@ -2281,7 +2309,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) struct rte * bgp_rte_modify_stale(struct rte *r, struct linpool *pool) { - eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); + eattr *a = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY)); const struct adata *ad = a ? a->u.ptr : NULL; uint flags = a ? a->flags : BAF_PARTIAL; @@ -2346,37 +2374,11 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool) } } -int -bgp_get_attr(const eattr *a, byte *buf, int buflen) -{ - uint i = EA_ID(a->id); - const struct bgp_attr_desc *d; - int len; - - if (bgp_attr_known(i)) - { - d = &bgp_attr_table[i]; - len = bsprintf(buf, "%s", d->name); - buf += len; - if (d->format) - { - *buf++ = ':'; - *buf++ = ' '; - d->format(a, buf, buflen - len - 2); - return GA_FULL; - } - return GA_NAME; - } - - bsprintf(buf, "%02x%s", i, (a->flags & BAF_TRANSITIVE) ? " [t]" : ""); - return GA_NAME; -} - void bgp_get_route_info(rte *e, byte *buf) { - eattr *p = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); - eattr *o = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); + eattr *p = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_AS_PATH)); + eattr *o = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_ORIGIN)); u32 origas; buf += bsprintf(buf, " (%d", e->attrs->pref); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index aec78a45..bd4c68b7 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -2576,7 +2576,6 @@ struct channel_class channel_bgp = { struct protocol proto_bgp = { .name = "BGP", .template = "bgp%d", - .class = PROTOCOL_BGP, .preference = DEF_PREF_BGP, .channel_mask = NB_IP | NB_VPN | NB_FLOW, .proto_size = sizeof(struct bgp_proto), @@ -2588,7 +2587,6 @@ struct protocol proto_bgp = { .reconfigure = bgp_reconfigure, .copy_config = bgp_copy_config, .get_status = bgp_get_status, - .get_attr = bgp_get_attr, .get_route_info = bgp_get_route_info, .show_proto_info = bgp_show_proto_info }; @@ -2596,4 +2594,5 @@ struct protocol proto_bgp = { void bgp_build(void) { proto_build(&proto_bgp); + bgp_register_attrs(); } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index de5bd836..e04e3bd0 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -538,17 +538,13 @@ rte_resolvable(rte *rt) /* attrs.c */ -static inline eattr * -bgp_find_attr(ea_list *attrs, uint code) -{ - return ea_find(attrs, EA_CODE(PROTOCOL_BGP, code)); -} +eattr * +bgp_find_attr(ea_list *attrs, uint code); void bgp_set_attr_u32(ea_list **to, uint code, uint flags, u32 val); void bgp_set_attr_ptr(ea_list **to, uint code, uint flags, const struct adata *ad); void bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len); - -#define bgp_unset_attr(to, code) ea_unset_attr(to, 0, code) +void bgp_unset_attr(ea_list **to, uint code); int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint size); @@ -573,7 +569,6 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool); u32 bgp_rte_igp_metric(struct rte *); void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); int bgp_preexport(struct proto *, struct rte *); -int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); void bgp_get_route_info(struct rte *, byte *buf); int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); @@ -590,6 +585,8 @@ bgp_total_aigp_metric(rte *r) return metric; } +void bgp_register_attrs(void); + /* packets.c */ @@ -626,26 +623,31 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to); #define BAF_DECODE_FLAGS 0x0100 /* Private flag - attribute flags are handled by the decode hook */ -#define BA_ORIGIN 0x01 /* RFC 4271 */ /* WM */ -#define BA_AS_PATH 0x02 /* WM */ -#define BA_NEXT_HOP 0x03 /* WM */ -#define BA_MULTI_EXIT_DISC 0x04 /* ON */ -#define BA_LOCAL_PREF 0x05 /* WD */ -#define BA_ATOMIC_AGGR 0x06 /* WD */ -#define BA_AGGREGATOR 0x07 /* OT */ -#define BA_COMMUNITY 0x08 /* RFC 1997 */ /* OT */ -#define BA_ORIGINATOR_ID 0x09 /* RFC 4456 */ /* ON */ -#define BA_CLUSTER_LIST 0x0a /* RFC 4456 */ /* ON */ -#define BA_MP_REACH_NLRI 0x0e /* RFC 4760 */ -#define BA_MP_UNREACH_NLRI 0x0f /* RFC 4760 */ -#define BA_EXT_COMMUNITY 0x10 /* RFC 4360 */ -#define BA_AS4_PATH 0x11 /* RFC 6793 */ -#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */ -#define BA_AIGP 0x1a /* RFC 7311 */ -#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */ +enum bgp_attr_id { + BA_ORIGIN = 0x01, /* RFC 4271 */ /* WM */ + BA_AS_PATH = 0x02, /* WM */ + BA_NEXT_HOP = 0x03, /* WM */ + BA_MULTI_EXIT_DISC = 0x04, /* ON */ + BA_LOCAL_PREF = 0x05, /* WD */ + BA_ATOMIC_AGGR = 0x06, /* WD */ + BA_AGGREGATOR = 0x07, /* OT */ + BA_COMMUNITY = 0x08, /* RFC 1997 */ /* OT */ + BA_ORIGINATOR_ID = 0x09, /* RFC 4456 */ /* ON */ + BA_CLUSTER_LIST = 0x0a, /* RFC 4456 */ /* ON */ + BA_MP_REACH_NLRI = 0x0e, /* RFC 4760 */ + BA_MP_UNREACH_NLRI = 0x0f, /* RFC 4760 */ + BA_EXT_COMMUNITY = 0x10, /* RFC 4360 */ + BA_AS4_PATH = 0x11, /* RFC 6793 */ + BA_AS4_AGGREGATOR = 0x12, /* RFC 6793 */ + BA_AIGP = 0x1a, /* RFC 7311 */ + BA_LARGE_COMMUNITY = 0x20, /* RFC 8092 */ /* Bird's private internal BGP attributes */ -#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */ + BA_MPLS_LABEL_STACK = 0x100, /* MPLS label stack transfer attribute */ + +/* Maximum */ + BGP_ATTR_MAX, +}; /* BGP connection states */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 6a78f79b..db261bbb 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -316,36 +316,6 @@ bgp_channel_end: bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end; - -dynamic_attr: BGP_ORIGIN - { $$ = f_new_dynamic_attr(T_ENUM_BGP_ORIGIN, EA_CODE(PROTOCOL_BGP, BA_ORIGIN)); } ; -dynamic_attr: BGP_PATH - { $$ = f_new_dynamic_attr(T_PATH, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); } ; -dynamic_attr: BGP_NEXT_HOP - { $$ = f_new_dynamic_attr(T_IP, EA_CODE(PROTOCOL_BGP, BA_NEXT_HOP)); } ; -dynamic_attr: BGP_MED - { $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); } ; -dynamic_attr: BGP_LOCAL_PREF - { $$ = f_new_dynamic_attr(T_INT, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); } ; -dynamic_attr: BGP_ATOMIC_AGGR - { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ; -dynamic_attr: BGP_AGGREGATOR - { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ; -dynamic_attr: BGP_COMMUNITY - { $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ; -dynamic_attr: BGP_ORIGINATOR_ID - { $$ = f_new_dynamic_attr(T_QUAD, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID)); } ; -dynamic_attr: BGP_CLUSTER_LIST - { $$ = f_new_dynamic_attr(T_CLIST, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST)); } ; -dynamic_attr: BGP_EXT_COMMUNITY - { $$ = f_new_dynamic_attr(T_ECLIST, EA_CODE(PROTOCOL_BGP, BA_EXT_COMMUNITY)); } ; -dynamic_attr: BGP_AIGP - { $$ = f_new_dynamic_attr(T_OPAQUE, EA_CODE(PROTOCOL_BGP, BA_AIGP)); } ; -dynamic_attr: BGP_LARGE_COMMUNITY - { $$ = f_new_dynamic_attr(T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ; - - - CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE) CF_CODE diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index c595f298..e45f7cb7 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -907,7 +907,6 @@ mrt_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSE struct protocol proto_mrt = { .name = "MRT", .template = "mrt%d", - .class = PROTOCOL_MRT, .proto_size = sizeof(struct mrt_proto), .config_size = sizeof(struct mrt_config), .init = mrt_init, diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index a8972d2c..136e1dcb 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -505,11 +505,6 @@ ospf_iface: ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); } ; -dynamic_attr: OSPF_METRIC1 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC1); } ; -dynamic_attr: OSPF_METRIC2 { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_METRIC2); } ; -dynamic_attr: OSPF_TAG { $$ = f_new_dynamic_attr(T_INT, EA_OSPF_TAG); } ; -dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(T_QUAD, EA_OSPF_ROUTER_ID); } ; - CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]); CF_CLI(SHOW OSPF, optproto, [], [[Show information about OSPF protocol]]) { PROTO_WALK_CMD($3, &proto_ospf, p) ospf_sh(p); }; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index d8bcc838..66d0eba6 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -106,6 +106,7 @@ #include #include "ospf.h" +#include "lib/macro.h" static int ospf_preexport(struct proto *P, rte *new); static void ospf_reload_routes(struct channel *C); @@ -386,7 +387,7 @@ ospf_init(struct proto_config *CF) static int ospf_rte_better(struct rte *new, struct rte *old) { - u32 new_metric1 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY); + u32 new_metric1 = ea_get_int(new->attrs->eattrs, &ea_ospf_metric1, LSINFINITY); if (new_metric1 == LSINFINITY) return 0; @@ -396,13 +397,13 @@ ospf_rte_better(struct rte *new, struct rte *old) if(new->attrs->source == RTS_OSPF_EXT2) { - u32 old_metric2 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY); - u32 new_metric2 = ea_get_int(new->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY); + u32 old_metric2 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric2, LSINFINITY); + u32 new_metric2 = ea_get_int(new->attrs->eattrs, &ea_ospf_metric2, LSINFINITY); if(new_metric2 < old_metric2) return 1; if(new_metric2 > old_metric2) return 0; } - u32 old_metric1 = ea_get_int(old->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY); + u32 old_metric1 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric1, LSINFINITY); if (new_metric1 < old_metric1) return 1; @@ -415,7 +416,7 @@ ospf_rte_igp_metric(struct rte *rt) if (rt->attrs->source == RTS_OSPF_EXT2) return IGP_METRIC_UNKNOWN; - return ea_get_int(rt->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY); + return ea_get_int(rt->attrs->eattrs, &ea_ospf_metric1, LSINFINITY); } void @@ -587,42 +588,26 @@ ospf_get_route_info(rte * rte, byte * buf) } buf += bsprintf(buf, " %s", type); - buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC1, LSINFINITY)); + buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, &ea_ospf_metric1, LSINFINITY)); if (rte->attrs->source == RTS_OSPF_EXT2) - buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, EA_OSPF_METRIC2, LSINFINITY)); + buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, &ea_ospf_metric2, LSINFINITY)); buf += bsprintf(buf, ")"); if (rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) { - eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_TAG); + eattr *ea = ea_find(rte->attrs->eattrs, &ea_ospf_tag); if (ea && (ea->u.data > 0)) buf += bsprintf(buf, " [%x]", ea->u.data); } - eattr *ea = ea_find(rte->attrs->eattrs, EA_OSPF_ROUTER_ID); + eattr *ea = ea_find(rte->attrs->eattrs, &ea_ospf_router_id); if (ea) buf += bsprintf(buf, " [%R]", ea->u.data); } -static int -ospf_get_attr(const eattr * a, byte * buf, int buflen UNUSED) +static void +ospf_tag_format(const eattr * a, byte * buf, uint buflen) { - switch (a->id) - { - case EA_OSPF_METRIC1: - bsprintf(buf, "metric1"); - return GA_NAME; - case EA_OSPF_METRIC2: - bsprintf(buf, "metric2"); - return GA_NAME; - case EA_OSPF_TAG: - bsprintf(buf, "tag: 0x%08x", a->u.data); - return GA_FULL; - case EA_OSPF_ROUTER_ID: - bsprintf(buf, "router_id"); - return GA_NAME; - default: - return GA_UNKNOWN; - } + bsnprintf(buf, buflen, "0x%08x", a->u.data); } static void @@ -1520,7 +1505,6 @@ ospf_sh_lsadb(struct lsadb_show_data *ld) struct protocol proto_ospf = { .name = "OSPF", .template = "ospf%d", - .class = PROTOCOL_OSPF, .preference = DEF_PREF_OSPF, .channel_mask = NB_IP, .proto_size = sizeof(struct ospf_proto), @@ -1531,12 +1515,39 @@ struct protocol proto_ospf = { .shutdown = ospf_shutdown, .reconfigure = ospf_reconfigure, .get_status = ospf_get_status, - .get_attr = ospf_get_attr, .get_route_info = ospf_get_route_info }; +struct ea_class ea_ospf_metric1 = { + .name = "ospf_metric1", + .type = T_INT, +}; + +struct ea_class ea_ospf_metric2 = { + .name = "ospf_metric2", + .type = T_INT, +}; + +struct ea_class ea_ospf_tag = { + .name = "ospf_tag", + .type = T_INT, + .format = ospf_tag_format, +}; + +struct ea_class ea_ospf_router_id = { + .name = "ospf_router_id", + .type = T_QUAD, +}; + void ospf_build(void) { proto_build(&proto_ospf); + + EA_REGISTER_ALL( + &ea_ospf_metric1, + &ea_ospf_metric2, + &ea_ospf_tag, + &ea_ospf_router_id + ); } diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 3d0d57d9..7bed5c85 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -939,12 +939,7 @@ struct lsadb_show_data { u32 router; /* Advertising router, 0 -> all */ }; - -#define EA_OSPF_METRIC1 EA_CODE(PROTOCOL_OSPF, 0) -#define EA_OSPF_METRIC2 EA_CODE(PROTOCOL_OSPF, 1) -#define EA_OSPF_TAG EA_CODE(PROTOCOL_OSPF, 2) -#define EA_OSPF_ROUTER_ID EA_CODE(PROTOCOL_OSPF, 3) - +extern struct ea_class ea_ospf_metric1, ea_ospf_metric2, ea_ospf_tag, ea_ospf_router_id; /* * For regular networks, neighbor address must match network prefix. diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 5969b7c7..55bad599 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2075,18 +2075,18 @@ again1: eattrs.l = (ea_list) {}; eattrs.a[eattrs.l.count++] = - EA_LITERAL_EMBEDDED(EA_OSPF_METRIC1, T_INT, 0, nf->n.metric1); + EA_LITERAL_EMBEDDED(&ea_ospf_metric1, 0, nf->n.metric1); if (nf->n.type == RTS_OSPF_EXT2) eattrs.a[eattrs.l.count++] = - EA_LITERAL_EMBEDDED(EA_OSPF_METRIC2, T_INT, 0, nf->n.metric2); + EA_LITERAL_EMBEDDED(&ea_ospf_metric2, 0, nf->n.metric2); if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2)) eattrs.a[eattrs.l.count++] = - EA_LITERAL_EMBEDDED(EA_OSPF_TAG, T_INT, 0, nf->n.tag); + EA_LITERAL_EMBEDDED(&ea_ospf_tag, 0, nf->n.tag); eattrs.a[eattrs.l.count++] = - EA_LITERAL_EMBEDDED(EA_OSPF_ROUTER_ID, T_QUAD, 0, nf->n.rid); + EA_LITERAL_EMBEDDED(&ea_ospf_router_id, 0, nf->n.rid); a0.eattrs = &eattrs.l; diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 9fe68264..db423dc8 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1338,8 +1338,8 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte /* Get route attributes */ rta *a = new->attrs; - eattr *m1a = ea_find(a->eattrs, EA_OSPF_METRIC1); - eattr *m2a = ea_find(a->eattrs, EA_OSPF_METRIC2); + eattr *m1a = ea_find(a->eattrs, &ea_ospf_metric1); + eattr *m2a = ea_find(a->eattrs, &ea_ospf_metric2); uint m1 = m1a ? m1a->u.data : 0; uint m2 = m2a ? m2a->u.data : 10000; @@ -1363,7 +1363,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte uint ebit = m2a || !m1a; uint metric = ebit ? m2 : m1; - uint tag = ea_get_int(a->eattrs, EA_OSPF_TAG, 0); + uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0); ip_addr fwd = IPA_NONE; if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface)) diff --git a/proto/perf/perf.c b/proto/perf/perf.c index dde7e473..2978100b 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -306,7 +306,6 @@ perf_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUS struct protocol proto_perf = { .name = "Perf", .template = "perf%d", - .class = PROTOCOL_PERF, .channel_mask = NB_IP, .proto_size = sizeof(struct perf_proto), .config_size = sizeof(struct perf_config), diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 483ece67..7a39beff 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -293,7 +293,6 @@ pipe_update_debug(struct proto *P) struct protocol proto_pipe = { .name = "Pipe", .template = "pipe%d", - .class = PROTOCOL_PIPE, .proto_size = sizeof(struct pipe_proto), .config_size = sizeof(struct pipe_config), .postconfig = pipe_postconfig, diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 0a339cb4..f40fdcca 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -336,9 +336,6 @@ radv_sensitive: | SENSITIVE bool { $$ = $2; } ; -dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; -dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(T_INT, EA_RA_LIFETIME); } ; - CF_CODE CF_END diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 7985997a..5734dbc9 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -10,6 +10,7 @@ #include #include "radv.h" +#include "lib/macro.h" /** * DOC: Router Advertisements @@ -42,6 +43,8 @@ * RFC 6106 - DNS extensions (RDDNS, DNSSL) */ +static struct ea_class ea_radv_preference, ea_radv_lifetime; + static void radv_prune_prefixes(struct radv_iface *ifa); static void radv_prune_routes(struct radv_proto *p); @@ -444,11 +447,11 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte { /* Update */ - ea = ea_find(new->attrs->eattrs, EA_RA_PREFERENCE); + ea = ea_find(new->attrs->eattrs, &ea_radv_preference); uint preference = ea ? ea->u.data : RA_PREF_MEDIUM; uint preference_set = !!ea; - ea = ea_find(new->attrs->eattrs, EA_RA_LIFETIME); + ea = ea_find(new->attrs->eattrs, &ea_radv_lifetime); uint lifetime = ea ? ea->u.data : 0; uint lifetime_set = !!ea; @@ -738,27 +741,26 @@ radv_pref_str(u32 pref) } } -/* The buffer has some minimal size */ -static int -radv_get_attr(const eattr *a, byte *buf, int buflen UNUSED) +static void +radv_preference_format(const eattr *a, byte *buf, uint buflen) { - switch (a->id) - { - case EA_RA_PREFERENCE: - bsprintf(buf, "preference: %s", radv_pref_str(a->u.data)); - return GA_FULL; - case EA_RA_LIFETIME: - bsprintf(buf, "lifetime"); - return GA_NAME; - default: - return GA_UNKNOWN; - } + bsnprintf(buf, buflen, "%s", radv_pref_str(a->u.data)); } +static struct ea_class ea_radv_preference = { + .name = "radv_preference", + .type = T_ENUM_RA_PREFERENCE, + .format = radv_preference_format, +}; + +static struct ea_class ea_radv_lifetime = { + .name = "radv_lifetime", + .type = T_INT, +}; + struct protocol proto_radv = { .name = "RAdv", .template = "radv%d", - .class = PROTOCOL_RADV, .channel_mask = NB_IP6, .proto_size = sizeof(struct radv_proto), .config_size = sizeof(struct radv_config), @@ -769,11 +771,15 @@ struct protocol proto_radv = { .reconfigure = radv_reconfigure, .copy_config = radv_copy_config, .get_status = radv_get_status, - .get_attr = radv_get_attr }; void radv_build(void) { proto_build(&proto_radv); + + EA_REGISTER_ALL( + &ea_radv_preference, + &ea_radv_lifetime + ); } diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 5cca3aca..c9219bda 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -195,10 +195,6 @@ struct radv_iface #define RA_PREF_HIGH 0x08 #define RA_PREF_MASK 0x18 -/* Attributes */ -#define EA_RA_PREFERENCE EA_CODE(PROTOCOL_RADV, 0) -#define EA_RA_LIFETIME EA_CODE(PROTOCOL_RADV, 1) - #ifdef LOCAL_DEBUG #define RADV_FORCE_DEBUG 1 #else diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 3934d337..234e9029 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -190,9 +190,6 @@ rip_iface: rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish; -dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_RIP_METRIC); } ; -dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(T_INT, EA_RIP_TAG); } ; - CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]); CF_CLI(SHOW RIP INTERFACES, optproto opttext, [] [\"\"], [[Show information about RIP interfaces]]) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 2b5babcb..52a3bd2c 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -78,6 +78,7 @@ #include #include "rip.h" +#include "lib/macro.h" static inline void rip_lock_neighbor(struct rip_neighbor *n); @@ -88,6 +89,7 @@ static inline void rip_iface_kick_timer(struct rip_iface *ifa); static void rip_iface_timer(timer *timer); static void rip_trigger_update(struct rip_proto *p); +static struct ea_class ea_rip_metric, ea_rip_tag, ea_rip_from; /* * RIP routes @@ -200,9 +202,9 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) } ea_block = { .l.count = 3, .a = { - EA_LITERAL_EMBEDDED(EA_RIP_METRIC, T_INT, 0, rt_metric), - EA_LITERAL_EMBEDDED(EA_RIP_TAG, T_INT, 0, rt_tag), - EA_LITERAL_DIRECT_ADATA(EA_RIP_FROM, T_IFACE, 0, &ea_block.riad.ad), + EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt_metric), + EA_LITERAL_EMBEDDED(&ea_rip_tag, 0, rt_tag), + EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &ea_block.riad.ad), }, .riad = { .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) }, @@ -326,9 +328,9 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s if (new) { /* Update */ - u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0); - u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1); - const eattr *rie = ea_find(new->attrs->eattrs, EA_RIP_FROM); + u32 rt_tag = ea_get_int(new->attrs->eattrs, &ea_rip_tag, 0); + u32 rt_metric = ea_get_int(new->attrs->eattrs, &ea_rip_metric, 1); + const eattr *rie = ea_find(new->attrs->eattrs, &ea_rip_from); struct iface *rt_from = rie ? ((struct rip_iface_adata *) rie->u.ptr)->iface : NULL; if (rt_metric > p->infinity) @@ -1095,8 +1097,8 @@ rip_rte_better(struct rte *new, struct rte *old) ASSERT_DIE(new->src == old->src); struct rip_proto *p = (struct rip_proto *) new->src->proto; - u32 new_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, p->infinity); - u32 old_metric = ea_get_int(old->attrs->eattrs, EA_RIP_METRIC, p->infinity); + u32 new_metric = ea_get_int(new->attrs->eattrs, &ea_rip_metric, p->infinity); + u32 old_metric = ea_get_int(old->attrs->eattrs, &ea_rip_metric, p->infinity); return new_metric < old_metric; } @@ -1104,7 +1106,7 @@ rip_rte_better(struct rte *new, struct rte *old) static u32 rip_rte_igp_metric(struct rte *rt) { - return ea_get_int(rt->attrs->eattrs, EA_RIP_METRIC, IGP_METRIC_UNKNOWN); + return ea_get_int(rt->attrs->eattrs, &ea_rip_metric, IGP_METRIC_UNKNOWN); } static void @@ -1205,8 +1207,8 @@ static void rip_get_route_info(rte *rte, byte *buf) { struct rip_proto *p = (struct rip_proto *) rte->src->proto; - u32 rt_metric = ea_get_int(rte->attrs->eattrs, EA_RIP_METRIC, p->infinity); - u32 rt_tag = ea_get_int(rte->attrs->eattrs, EA_RIP_TAG, 0); + u32 rt_metric = ea_get_int(rte->attrs->eattrs, &ea_rip_metric, p->infinity); + u32 rt_tag = ea_get_int(rte->attrs->eattrs, &ea_rip_tag, 0); buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rt_metric); @@ -1214,23 +1216,28 @@ rip_get_route_info(rte *rte, byte *buf) bsprintf(buf, " [%04x]", rt_tag); } -static int -rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED) +static void +rip_tag_format(const eattr *a, byte *buf, uint buflen) { - switch (a->id) - { - case EA_RIP_METRIC: - bsprintf(buf, "metric: %d", a->u.data); - return GA_FULL; + bsnprintf(buf, buflen, "tag: %04x", a->u.data); +} - case EA_RIP_TAG: - bsprintf(buf, "tag: %04x", a->u.data); - return GA_FULL; +static struct ea_class ea_rip_metric = { + .name = "rip_metric", + .type = T_INT, +}; - default: - return GA_UNKNOWN; - } -} +static struct ea_class ea_rip_tag = { + .name = "rip_tag", + .type = T_INT, + .format = rip_tag_format, +}; + +static struct ea_class ea_rip_from = { + .name = "rip_from", + .type = T_IFACE, + .readonly = 1, +}; void rip_show_interfaces(struct proto *P, const char *iff) @@ -1334,7 +1341,6 @@ rip_dump(struct proto *P) struct protocol proto_rip = { .name = "RIP", .template = "rip%d", - .class = PROTOCOL_RIP, .preference = DEF_PREF_RIP, .channel_mask = NB_IP, .proto_size = sizeof(struct rip_proto), @@ -1346,11 +1352,16 @@ struct protocol proto_rip = { .shutdown = rip_shutdown, .reconfigure = rip_reconfigure, .get_route_info = rip_get_route_info, - .get_attr = rip_get_attr }; void rip_build(void) { proto_build(&proto_rip); + + EA_REGISTER_ALL( + &ea_rip_metric, + &ea_rip_tag, + &ea_rip_from + ); } diff --git a/proto/rip/rip.h b/proto/rip/rip.h index a6fa3326..a01f8d3b 100644 --- a/proto/rip/rip.h +++ b/proto/rip/rip.h @@ -195,10 +195,6 @@ struct rip_rte #define RIP_ENTRY_VALID 1 /* Valid outgoing route */ #define RIP_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */ -#define EA_RIP_METRIC EA_CODE(PROTOCOL_RIP, 0) -#define EA_RIP_TAG EA_CODE(PROTOCOL_RIP, 1) -#define EA_RIP_FROM EA_CODE(PROTOCOL_RIP, 2) - static inline int rip_is_v2(struct rip_proto *p) { return p->rip2; } diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 6e111a81..d4e95a83 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -935,7 +935,6 @@ rpki_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUS struct protocol proto_rpki = { .name = "RPKI", .template = "rpki%d", - .class = PROTOCOL_RPKI, .preference = DEF_PREF_RPKI, .proto_size = sizeof(struct rpki_proto), .config_size = sizeof(struct rpki_config), diff --git a/proto/static/static.c b/proto/static/static.c index 42febcd4..090ec875 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -408,16 +408,16 @@ static_reload_routes(struct channel *C) static int static_rte_better(rte *new, rte *old) { - u32 n = ea_get_int(new->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); - u32 o = ea_get_int(old->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); + u32 n = ea_get_int(new->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN); + u32 o = ea_get_int(old->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN); return n < o; } static int static_rte_mergable(rte *pri, rte *sec) { - u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); - u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); + u32 a = ea_get_int(pri->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN); + u32 b = ea_get_int(sec->attrs->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN); return a == b; } @@ -711,7 +711,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src) static void static_get_route_info(rte *rte, byte *buf) { - eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC); + eattr *a = ea_find(rte->attrs->eattrs, &ea_gen_igp_metric); if (a) buf += bsprintf(buf, " (%d/%u)", rte->attrs->pref, a->u.data); else @@ -769,7 +769,6 @@ static_show(struct proto *P) struct protocol proto_static = { .name = "Static", .template = "static%d", - .class = PROTOCOL_STATIC, .preference = DEF_PREF_STATIC, .channel_mask = NB_ANY, .proto_size = sizeof(struct static_proto), diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h index 8897f889..aa90f6e4 100644 --- a/sysdep/linux/krt-sys.h +++ b/sysdep/linux/krt-sys.h @@ -34,38 +34,6 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N #define KRT_ALLOW_MERGE_PATHS 1 -#define EA_KRT_PREFSRC EA_CODE(PROTOCOL_KERNEL, 0x10) -#define EA_KRT_REALM EA_CODE(PROTOCOL_KERNEL, 0x11) -#define EA_KRT_SCOPE EA_CODE(PROTOCOL_KERNEL, 0x12) - - -#define KRT_METRICS_MAX 0x10 /* RTAX_QUICKACK+1 */ -#define KRT_METRICS_OFFSET 0x20 /* Offset of EA_KRT_* vs RTAX_* */ - -#define KRT_FEATURES_MAX 4 - -/* - * Following attributes are parts of RTA_METRICS kernel route attribute, their - * ids must be consistent with their RTAX_* constants (+ KRT_METRICS_OFFSET) - */ -#define EA_KRT_METRICS EA_CODE(PROTOCOL_KERNEL, 0x20) /* Dummy one */ -#define EA_KRT_LOCK EA_CODE(PROTOCOL_KERNEL, 0x21) -#define EA_KRT_MTU EA_CODE(PROTOCOL_KERNEL, 0x22) -#define EA_KRT_WINDOW EA_CODE(PROTOCOL_KERNEL, 0x23) -#define EA_KRT_RTT EA_CODE(PROTOCOL_KERNEL, 0x24) -#define EA_KRT_RTTVAR EA_CODE(PROTOCOL_KERNEL, 0x25) -#define EA_KRT_SSTRESH EA_CODE(PROTOCOL_KERNEL, 0x26) -#define EA_KRT_CWND EA_CODE(PROTOCOL_KERNEL, 0x27) -#define EA_KRT_ADVMSS EA_CODE(PROTOCOL_KERNEL, 0x28) -#define EA_KRT_REORDERING EA_CODE(PROTOCOL_KERNEL, 0x29) -#define EA_KRT_HOPLIMIT EA_CODE(PROTOCOL_KERNEL, 0x2a) -#define EA_KRT_INITCWND EA_CODE(PROTOCOL_KERNEL, 0x2b) -#define EA_KRT_FEATURES EA_CODE(PROTOCOL_KERNEL, 0x2c) -#define EA_KRT_RTO_MIN EA_CODE(PROTOCOL_KERNEL, 0x2d) -#define EA_KRT_INITRWND EA_CODE(PROTOCOL_KERNEL, 0x2e) -#define EA_KRT_QUICKACK EA_CODE(PROTOCOL_KERNEL, 0x2f) - - struct krt_params { u32 table_id; /* Kernel table ID we sync with */ u32 metric; /* Kernel metric used for all routes */ diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y index f31b88c7..17e17789 100644 --- a/sysdep/linux/netlink.Y +++ b/sysdep/linux/netlink.Y @@ -28,39 +28,22 @@ kern_sys_item: | NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; } ; -dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(T_IP, EA_KRT_PREFSRC); } ; -dynamic_attr: KRT_REALM { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REALM); } ; -dynamic_attr: KRT_SCOPE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SCOPE); } ; - -dynamic_attr: KRT_MTU { $$ = f_new_dynamic_attr(T_INT, EA_KRT_MTU); } ; -dynamic_attr: KRT_WINDOW { $$ = f_new_dynamic_attr(T_INT, EA_KRT_WINDOW); } ; -dynamic_attr: KRT_RTT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTT); } ; -dynamic_attr: KRT_RTTVAR { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTTVAR); } ; -dynamic_attr: KRT_SSTRESH { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SSTRESH); } ; -dynamic_attr: KRT_CWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_CWND); } ; -dynamic_attr: KRT_ADVMSS { $$ = f_new_dynamic_attr(T_INT, EA_KRT_ADVMSS); } ; -dynamic_attr: KRT_REORDERING { $$ = f_new_dynamic_attr(T_INT, EA_KRT_REORDERING); } ; -dynamic_attr: KRT_HOPLIMIT { $$ = f_new_dynamic_attr(T_INT, EA_KRT_HOPLIMIT); } ; -dynamic_attr: KRT_INITCWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITCWND); } ; -dynamic_attr: KRT_RTO_MIN { $$ = f_new_dynamic_attr(T_INT, EA_KRT_RTO_MIN); } ; -dynamic_attr: KRT_INITRWND { $$ = f_new_dynamic_attr(T_INT, EA_KRT_INITRWND); } ; -dynamic_attr: KRT_QUICKACK { $$ = f_new_dynamic_attr(T_INT, EA_KRT_QUICKACK); } ; - /* Bits of EA_KRT_LOCK, based on RTAX_* constants */ -attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, EA_KRT_LOCK); } ; -attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, EA_KRT_LOCK); } ; - -attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, EA_KRT_FEATURES); } ; -attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, EA_KRT_FEATURES); } ; +attr_bit: KRT_LOCK_MTU { $$ = f_new_dynamic_attr_bit(2, "krt_lock"); } ; +attr_bit: KRT_LOCK_WINDOW { $$ = f_new_dynamic_attr_bit(3, "krt_lock"); } ; +attr_bit: KRT_LOCK_RTT { $$ = f_new_dynamic_attr_bit(4, "krt_lock"); } ; +attr_bit: KRT_LOCK_RTTVAR { $$ = f_new_dynamic_attr_bit(5, "krt_lock"); } ; +attr_bit: KRT_LOCK_SSTRESH { $$ = f_new_dynamic_attr_bit(6, "krt_lock"); } ; +attr_bit: KRT_LOCK_CWND { $$ = f_new_dynamic_attr_bit(7, "krt_lock"); } ; +attr_bit: KRT_LOCK_ADVMSS { $$ = f_new_dynamic_attr_bit(8, "krt_lock"); } ; +attr_bit: KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr_bit(9, "krt_lock"); } ; +attr_bit: KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr_bit(10, "krt_lock"); } ; +attr_bit: KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr_bit(13, "krt_lock"); } ; + +/* Bits of EA_KRT_FEATURES */ +attr_bit: KRT_FEATURE_ECN { $$ = f_new_dynamic_attr_bit(0, "krt_features"); } ; +attr_bit: KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr_bit(3, "krt_features"); } ; CF_CODE diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 81e02b4c..23d41b56 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -26,6 +26,7 @@ #include "lib/socket.h" #include "lib/string.h" #include "lib/hash.h" +#include "lib/macro.h" #include "conf/conf.h" #include @@ -121,6 +122,101 @@ struct nl_parse_state u32 rta_flow; /* Used during parsing */ }; +/* + * Netlink eattr definitions + */ + +#define KRT_METRICS_MAX ARRAY_SIZE(ea_krt_metrics) +#define KRT_FEATURES_MAX 4 + +static void krt_bitfield_format(const eattr *e, byte *buf, uint buflen); + +static struct ea_class + ea_krt_prefsrc = { + .name = "krt_prefsrc", + .type = T_IP, + }, + ea_krt_realm = { + .name = "krt_realm", + .type = T_INT, + }, + ea_krt_scope = { + .name = "krt_scope", + .type = T_INT, + }; + +static struct ea_class ea_krt_metrics[] = { + [RTAX_LOCK] = { + .name = "krt_lock", + .type = T_INT, + .format = krt_bitfield_format, + }, + [RTAX_FEATURES] = { + .name = "krt_features", + .type = T_INT, + .format = krt_bitfield_format, + }, +#define KRT_METRIC_INT(_rtax, _name) [_rtax] = { .name = _name, .type = T_INT } + KRT_METRIC_INT(RTAX_MTU, "krt_mtu"), + KRT_METRIC_INT(RTAX_WINDOW, "krt_window"), + KRT_METRIC_INT(RTAX_RTT, "krt_rtt"), + KRT_METRIC_INT(RTAX_RTTVAR, "krt_rttvar"), + KRT_METRIC_INT(RTAX_SSTHRESH, "krt_sstresh"), + KRT_METRIC_INT(RTAX_CWND, "krt_cwnd"), + KRT_METRIC_INT(RTAX_ADVMSS, "krt_advmss"), + KRT_METRIC_INT(RTAX_REORDERING, "krt_reordering"), + KRT_METRIC_INT(RTAX_HOPLIMIT, "krt_hoplimit"), + KRT_METRIC_INT(RTAX_INITCWND, "krt_initcwnd"), + KRT_METRIC_INT(RTAX_RTO_MIN, "krt_rto_min"), + KRT_METRIC_INT(RTAX_INITRWND, "krt_initrwnd"), + KRT_METRIC_INT(RTAX_QUICKACK, "krt_quickack"), +#undef KRT_METRIC_INT +}; + +static const char *krt_metrics_names[KRT_METRICS_MAX] = { + NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss", + "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack" +}; + +static const char *krt_features_names[KRT_FEATURES_MAX] = { + "ecn", NULL, NULL, "allfrag" +}; + +static void +krt_bitfield_format(const eattr *a, byte *buf, uint buflen) +{ + if (a->id == ea_krt_metrics[RTAX_LOCK].id) + ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX); + else if (a->id == ea_krt_metrics[RTAX_FEATURES].id) + ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX); +} + +static void +nl_ea_register(void) +{ + EA_REGISTER_ALL( + &ea_krt_prefsrc, + &ea_krt_realm, + &ea_krt_scope + ); + + for (uint i = 0; i < KRT_METRICS_MAX; i++) + { + if (!ea_krt_metrics[i].name) + ea_krt_metrics[i] = (struct ea_class) { + .name = mb_sprintf(&root_pool, "krt_metric_%d", i), + .type = T_INT, + }; + + ea_register_init(&ea_krt_metrics[i]); + } + + for (uint i = 1; i < KRT_METRICS_MAX; i++) + ASSERT_DIE(ea_krt_metrics[i].id == ea_krt_metrics[0].id + i); +} + + + /* * Synchronous Netlink interface */ @@ -734,7 +830,7 @@ static void nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs) { struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH); - eattr *flow = ea_find(eattrs, EA_KRT_REALM); + eattr *flow = ea_find(eattrs, &ea_krt_realm); for (; nh; nh = nh->next) { @@ -1399,7 +1495,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) priority = 0; else if (KRT_CF->sys.metric) priority = KRT_CF->sys.metric; - else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC))) + else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, &ea_krt_metric))) priority = ea->u.data; if (priority) @@ -1412,15 +1508,15 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) /* Default scope is LINK for device routes, UNIVERSE otherwise */ if (p->af == AF_MPLS) r->r.rtm_scope = RT_SCOPE_UNIVERSE; - else if (ea = ea_find(eattrs, EA_KRT_SCOPE)) + else if (ea = ea_find(eattrs, &ea_krt_scope)) r->r.rtm_scope = ea->u.data; else r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; - if (ea = ea_find(eattrs, EA_KRT_PREFSRC)) + if (ea = ea_find(eattrs, &ea_krt_prefsrc)) nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data); - if (ea = ea_find(eattrs, EA_KRT_REALM)) + if (ea = ea_find(eattrs, &ea_krt_realm)) nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data); @@ -1428,9 +1524,9 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) metrics[0] = 0; struct ea_walk_state ews = { .eattrs = eattrs }; - while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX)) + while (ea = ea_walk(&ews, ea_krt_metrics[0].id, KRT_METRICS_MAX)) { - int id = ea->id - EA_KRT_METRICS; + int id = ea->id - ea_krt_metrics[0].id; metrics[0] |= 1 << id; metrics[id] = ea->u.data; } @@ -1581,21 +1677,15 @@ nl_announce_route(struct nl_parse_state *s) rte *e = rte_get_temp(s->attrs, s->proto->p.main_source); e->net = s->net; - EA_LOCAL_LIST(2) ea0 = { + EA_LOCAL_LIST(2) ea = { .l = { .count = 2, .next = e->attrs->eattrs }, - .a[0] = (eattr) { - .id = EA_KRT_SOURCE, - .type = T_INT, - .u.data = s->krt_proto, - }, - .a[1] = (eattr) { - .id = EA_KRT_METRIC, - .type = T_INT, - .u.data = s->krt_metric, + .a = { + EA_LITERAL_EMBEDDED(&ea_krt_source, 0, s->krt_proto), + EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, s->krt_metric), }, }; - e->attrs->eattrs = &ea0.l; + e->attrs->eattrs = &ea.l; if (s->scan) krt_got_route(s->proto, e, s->krt_src); @@ -1867,20 +1957,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (i->rtm_scope != def_scope) ea_set_attr(&ra->eattrs, - EA_LITERAL_EMBEDDED(EA_KRT_SCOPE, T_INT, 0, i->rtm_scope)); + EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope)); if (a[RTA_PREFSRC]) - { - ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]); + { + ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]); - ea_set_attr(&ra->eattrs, - EA_LITERAL_STORE_ADATA(EA_KRT_PREFSRC, T_IP, 0, &ps, sizeof(ps))); - } + ea_set_attr(&ra->eattrs, + EA_LITERAL_STORE_ADATA(&ea_krt_prefsrc, 0, &ps, sizeof(ps))); + } /* Can be set per-route or per-nexthop */ if (s->rta_flow) ea_set_attr(&ra->eattrs, - EA_LITERAL_EMBEDDED(EA_KRT_REALM, T_INT, 0, s->rta_flow)); + EA_LITERAL_EMBEDDED(&ea_krt_realm, 0, s->rta_flow)); if (a[RTA_METRICS]) { @@ -1891,11 +1981,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) return; } - for (int t = 1; t < KRT_METRICS_MAX; t++) + for (uint t = 1; t < KRT_METRICS_MAX; t++) if (metrics[0] & (1 << t)) ea_set_attr(&ra->eattrs, - EA_LITERAL_EMBEDDED(EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t), - T_INT, 0, metrics[t])); + EA_LITERAL_EMBEDDED(&ea_krt_metrics[t], 0, metrics[t])); } /* @@ -2133,6 +2222,8 @@ krt_sys_io_init(void) { nl_linpool = lp_new_default(krt_pool); HASH_INIT(nl_table_map, krt_pool, 6); + + nl_ea_register(); } int @@ -2186,56 +2277,6 @@ krt_sys_copy_config(struct krt_config *d, struct krt_config *s) d->sys.metric = s->sys.metric; } -static const char *krt_metrics_names[KRT_METRICS_MAX] = { - NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss", - "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack" -}; - -static const char *krt_features_names[KRT_FEATURES_MAX] = { - "ecn", NULL, NULL, "allfrag" -}; - -int -krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED) -{ - switch (a->id) - { - case EA_KRT_PREFSRC: - bsprintf(buf, "prefsrc"); - return GA_NAME; - - case EA_KRT_REALM: - 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); - return GA_FULL; - - case EA_KRT_FEATURES: - buf += bsprintf(buf, "features:"); - ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX); - return GA_FULL; - - default:; - int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET; - if (id > 0 && id < KRT_METRICS_MAX) - { - bsprintf(buf, "%s", krt_metrics_names[id]); - return GA_NAME; - } - - return GA_UNKNOWN; - } -} - - - void kif_sys_start(struct kif_proto *p UNUSED) { diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index 2a3f41de..9300e9c8 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -122,9 +122,6 @@ kif_iface: kif_iface_start iface_patt_list_nopx kif_iface_opt_list; -dynamic_attr: KRT_SOURCE { $$ = f_new_dynamic_attr(T_INT, EA_KRT_SOURCE); } ; -dynamic_attr: KRT_METRIC { $$ = f_new_dynamic_attr(T_INT, EA_KRT_METRIC); } ; - CF_CODE CF_END diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 0ebc4fb3..4da51ce2 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -232,7 +232,6 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src) struct protocol proto_unix_iface = { .name = "Device", .template = "device%d", - .class = PROTOCOL_DEVICE, .proto_size = sizeof(struct kif_proto), .config_size = sizeof(struct kif_config), .preconfig = kif_preconfig, @@ -287,7 +286,7 @@ static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS; static inline u32 krt_metric(rte *a) { - eattr *ea = ea_find(a->attrs->eattrs, EA_KRT_METRIC); + eattr *ea = ea_find(a->attrs->eattrs, &ea_krt_metric); return ea ? ea->u.data : 0; } @@ -1133,24 +1132,15 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src) krt_sys_copy_config(d, s); } -static int -krt_get_attr(const eattr *a, byte *buf, int buflen) -{ - switch (a->id) - { - case EA_KRT_SOURCE: - bsprintf(buf, "source"); - return GA_NAME; - - case EA_KRT_METRIC: - bsprintf(buf, "metric"); - return GA_NAME; - - default: - return krt_sys_get_attr(a, buf, buflen); - } -} +struct ea_class ea_krt_source = { + .name = "krt_source", + .type = T_INT, +}; +struct ea_class ea_krt_metric = { + .name = "krt_metric", + .type = T_INT, +}; #ifdef CONFIG_IP6_SADR_KERNEL #define MAYBE_IP6_SADR NB_IP6_SADR @@ -1167,7 +1157,6 @@ krt_get_attr(const eattr *a, byte *buf, int buflen) struct protocol proto_unix_kernel = { .name = "Kernel", .template = "kernel%d", - .class = PROTOCOL_KERNEL, .preference = DEF_PREF_INHERITED, .channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS, .proto_size = sizeof(struct krt_proto), @@ -1179,7 +1168,6 @@ struct protocol proto_unix_kernel = { .shutdown = krt_shutdown, .reconfigure = krt_reconfigure, .copy_config = krt_copy_config, - .get_attr = krt_get_attr, #ifdef KRT_ALLOW_LEARN .dump = krt_dump, #endif @@ -1189,4 +1177,9 @@ void krt_build(void) { proto_build(&proto_unix_kernel); + + EA_REGISTER_ALL( + &ea_krt_source, + &ea_krt_metric, + ); } diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 20858cd7..04b04162 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -21,8 +21,12 @@ struct kif_proto; #define KRT_DEFAULT_ECMP_LIMIT 16 +#if 0 #define EA_KRT_SOURCE EA_CODE(PROTOCOL_KERNEL, 0) #define EA_KRT_METRIC EA_CODE(PROTOCOL_KERNEL, 1) +#endif + +extern struct ea_class ea_krt_source, ea_krt_metric; #define KRT_REF_SEEN 0x1 /* Seen in table */ #define KRT_REF_BEST 0x2 /* Best in table */ diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 9bb37e5d..8fdad4e6 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -881,8 +881,8 @@ main(int argc, char **argv) resource_init(); timer_init(); olock_init(); - io_init(); rt_init(); + io_init(); if_init(); // roa_init(); config_init(); diff --git a/test/bt-utils.c b/test/bt-utils.c index ce9a49d7..509b5ed4 100644 --- a/test/bt-utils.c +++ b/test/bt-utils.c @@ -62,8 +62,8 @@ bt_bird_init(void) olock_init(); timer_init(); - io_init(); rt_init(); + io_init(); if_init(); config_init(); @@ -72,9 +72,6 @@ bt_bird_init(void) void bt_bird_cleanup(void) { - for (int i = 0; i < PROTOCOL__MAX; i++) - class_to_protocol[i] = NULL; - config = new_config = NULL; } -- cgit v1.2.3 From 337c04c45e1472d6d9b531a3c55f1f2d30ebf308 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 20 Apr 2022 12:24:26 +0200 Subject: Moved route preference to eattrs --- doc/bird.sgml | 3 +-- filter/config.Y | 2 -- filter/data.h | 1 - filter/f-inst.c | 5 ----- lib/route.h | 24 +++++++++++++++++------- nest/rt-attr.c | 11 ++++++++--- nest/rt-dev.c | 3 ++- nest/rt-show.c | 2 +- nest/rt-table.c | 9 ++++++--- nest/rt.h | 1 + proto/babel/babel.c | 12 +++++++----- proto/bgp/attrs.c | 6 +++--- proto/bgp/packets.c | 2 +- proto/ospf/ospf.c | 2 +- proto/ospf/rt.c | 6 ++++-- proto/perf/perf.c | 3 ++- proto/rip/rip.c | 8 ++++---- proto/rpki/rpki.c | 3 ++- proto/static/static.c | 7 ++++--- sysdep/unix/krt.c | 2 +- 20 files changed, 65 insertions(+), 47 deletions(-) (limited to 'filter/data.h') diff --git a/doc/bird.sgml b/doc/bird.sgml index 4df1d94f..a71624aa 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1732,8 +1732,7 @@ Common route attributes are: default value for new routes is