From 836a87b8acd5da40bde6b89702090c6616e06dfb Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 29 Nov 2021 19:23:42 +0100 Subject: Nest: Attach prefix trie to rtable for faster LPM and interval queries Attach a prefix trie to IP/VPN/ROA tables. Use it for net_route() and net_roa_check(). This leads to 3-5x speedups for IPv4 and 5-10x speedup for IPv6 of these calls. TODO: - Rebuild the trie during rt_prune_table() - Better way to avoid trie_add_prefix() in net_get() for existing tables - Make it configurable (?) --- proto/babel/babel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'proto/babel/babel.c') diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 1e87212c..e43818f5 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -63,7 +63,7 @@ static inline void babel_iface_kick_timer(struct babel_iface *ifa); */ static void -babel_init_entry(void *E) +babel_init_entry(struct fib *f UNUSED, void *E) { struct babel_entry *e = E; -- cgit v1.2.3 From fcb4dd0c831339c4374ace17d8f2ae6ebfeed279 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 27 Feb 2022 03:10:38 +0100 Subject: Babel: Fix bug in iface reconfiguration A recent change in Babel causes ifaces to disappear after reconfiguration. The patch fixes that. Thanks to Johannes Kimmel for an insightful bugreport. --- proto/babel/babel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'proto/babel/babel.c') diff --git a/proto/babel/babel.c b/proto/babel/babel.c index e43818f5..174fc9e2 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -1899,7 +1899,7 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf) struct babel_iface *ifa = babel_find_iface(p, iface); struct babel_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL); - if (ic && iface_is_valid(p, iface)) + if (ic && !iface_is_valid(p, iface)) ic = NULL; if (ifa && ic) -- cgit v1.2.3 From ebd807c0b8eb0b7a3dc3371cd4c87ae886c00885 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Mon, 4 Apr 2022 20:31:14 +0200 Subject: Slab allocator can free the blocks without knowing the parent structure --- lib/resource.h | 2 +- lib/slab.c | 44 ++++++++------ lib/slab_test.c | 158 ++++++++++++++++++++++++-------------------------- nest/neighbor.c | 2 +- nest/rt-attr.c | 6 +- nest/rt-fib.c | 2 +- nest/rt-table.c | 6 +- proto/babel/babel.c | 12 ++-- proto/babel/packets.c | 9 ++- proto/bfd/bfd.c | 2 +- proto/bgp/attrs.c | 2 +- proto/ospf/topology.c | 2 +- proto/rip/rip.c | 4 +- 13 files changed, 127 insertions(+), 124 deletions(-) (limited to 'proto/babel/babel.c') diff --git a/lib/resource.h b/lib/resource.h index ed9e109d..8b180603 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -100,7 +100,7 @@ typedef struct slab slab; slab *sl_new(pool *, unsigned size); void *sl_alloc(slab *); void *sl_allocz(slab *); -void sl_free(slab *, void *); +void sl_free(void *); /* * Low-level memory allocation functions, please don't use diff --git a/lib/slab.c b/lib/slab.c index 9e0f7798..6da602f8 100644 --- a/lib/slab.c +++ b/lib/slab.c @@ -98,7 +98,7 @@ sl_allocz(slab *s) } void -sl_free(slab *s, void *oo) +sl_free(void *oo) { struct sl_obj *o = SKIP_BACK(struct sl_obj, data, oo); @@ -170,6 +170,7 @@ static struct resclass sl_class = { }; struct sl_head { + struct slab *slab; node n; u32 num_full; u32 used_bits[0]; @@ -236,7 +237,7 @@ sl_alloc(slab *s) struct sl_head *h; redo: - h = HEAD(s->partial_heads); + h = SKIP_BACK(struct sl_head, n, HEAD(s->partial_heads)); if (!h->n.next) goto no_partial; okay: @@ -262,7 +263,7 @@ okay: goto redo; no_partial: - h = HEAD(s->empty_heads); + h = SKIP_BACK(struct sl_head, n, HEAD(s->empty_heads)); if (h->n.next) { rem_node(&h->n); @@ -270,12 +271,16 @@ no_partial: s->num_empty_heads--; goto okay; } + h = alloc_page(); + ASSERT_DIE(SL_GET_HEAD(h) == h); + #ifdef POISON memset(h, 0xba, page_size); #endif - ASSERT_DIE(SL_GET_HEAD(h) == h); + memset(h, 0, s->head_size); + h->slab = s; add_head(&s->partial_heads, &h->n); goto okay; } @@ -305,9 +310,10 @@ sl_allocz(slab *s) * and returns it back to the Slab @s. */ void -sl_free(slab *s, void *oo) +sl_free(void *oo) { struct sl_head *h = SL_GET_HEAD(oo); + struct slab *s = h->slab; #ifdef POISON memset(oo, 0xdb, s->data_size); @@ -347,13 +353,14 @@ static void slab_free(resource *r) { slab *s = (slab *) r; - struct sl_head *h, *g; + struct sl_head *h; + node *nn, *nxt; - WALK_LIST_DELSAFE(h, g, s->empty_heads) + WALK_LIST2_DELSAFE(h, nn, nxt, s->empty_heads, n) free_page(h); - WALK_LIST_DELSAFE(h, g, s->partial_heads) + WALK_LIST2_DELSAFE(h, nn, nxt, s->partial_heads, n) free_page(h); - WALK_LIST_DELSAFE(h, g, s->full_heads) + WALK_LIST2_DELSAFE(h, nn, nxt, s->full_heads, n) free_page(h); } @@ -363,12 +370,13 @@ slab_dump(resource *r) slab *s = (slab *) r; int ec=0, pc=0, fc=0; struct sl_head *h; + node *nn; - WALK_LIST(h, s->empty_heads) + WALK_LIST2(h, nn, s->empty_heads, n) ec++; - WALK_LIST(h, s->partial_heads) + WALK_LIST2(h, nn, s->partial_heads, n) pc++; - WALK_LIST(h, s->full_heads) + WALK_LIST2(h, nn, s->full_heads, n) fc++; debug("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size); } @@ -379,19 +387,20 @@ slab_memsize(resource *r) slab *s = (slab *) r; size_t heads = 0; struct sl_head *h; + node *nn; - WALK_LIST(h, s->full_heads) + WALK_LIST2(h, nn, s->full_heads, n) heads++; size_t items = heads * s->objs_per_slab; - WALK_LIST(h, s->partial_heads) + WALK_LIST2(h, nn, s->partial_heads, n) { heads++; items += h->num_full; } - WALK_LIST(h, s->empty_heads) + WALK_LIST2(h, nn, s->empty_heads, n) heads++; size_t eff = items * s->data_size; @@ -407,11 +416,12 @@ slab_lookup(resource *r, unsigned long a) { slab *s = (slab *) r; struct sl_head *h; + node *nn; - WALK_LIST(h, s->partial_heads) + WALK_LIST2(h, nn, s->partial_heads, n) if ((unsigned long) h < a && (unsigned long) h + page_size < a) return r; - WALK_LIST(h, s->full_heads) + WALK_LIST2(h, nn, s->full_heads, n) if ((unsigned long) h < a && (unsigned long) h + page_size < a) return r; return NULL; diff --git a/lib/slab_test.c b/lib/slab_test.c index e3ed0d58..803d0215 100644 --- a/lib/slab_test.c +++ b/lib/slab_test.c @@ -17,6 +17,25 @@ static const int sizes[] = { #define TEST_SIZE 1024 * 128 #define ITEMS(sz) TEST_SIZE / ( (sz) >> u32_log2((sz))/2 ) +struct test_request { + int size; + enum strategy { + TEST_NONE, + TEST_FORWARDS, + TEST_BACKWARDS, + TEST_RANDOM, + TEST_MIXED, + TEST__MAX, + } strategy; +}; + +const char * const strategy_name[TEST__MAX] = { + [TEST_FORWARDS] = "forwards", + [TEST_BACKWARDS] = "backwards", + [TEST_RANDOM] = "random", + [TEST_MIXED] = "mixed", +}; + static inline byte *test_alloc(slab *s, int sz, struct resmem *sliz) { byte *out = sl_alloc(s); @@ -42,7 +61,7 @@ static inline void test_free(slab *s, byte *block, int sz, struct resmem *sliz) block[p]++; } - sl_free(s, block); + sl_free(block); struct resmem ns = rmemsize((resource *) s); @@ -60,118 +79,93 @@ static inline struct resmem get_memsize(slab *s) } static int -t_slab_forwards(const void *data) +t_slab(const void *data) { - int sz = (intptr_t) data; - slab *s = sl_new(&root_pool, sz); - - struct resmem sliz = get_memsize(s); - - int n = ITEMS(sz); - byte **block = mb_alloc(&root_pool, n * sizeof(*block)); - - for (int i = 0; i < n; i++) - block[i] = test_alloc(s, sz, &sliz); - - for (int i = 0; i < n; i++) - test_free(s, block[i], sz, &sliz); + const struct test_request *tr = data; + int sz = tr->size; - mb_free(block); - - return 1; -} - -static int -t_slab_backwards(const void *data) -{ - int sz = (intptr_t) data; slab *s = sl_new(&root_pool, sz); - struct resmem sliz = get_memsize(s); int n = ITEMS(sz); byte **block = mb_alloc(&root_pool, n * sizeof(*block)); - for (int i = 0; i < n; i++) - block[i] = test_alloc(s, sz, &sliz); + switch (tr->strategy) { + case TEST_FORWARDS: + for (int i = 0; i < n; i++) + block[i] = test_alloc(s, sz, &sliz); - for (int i = n - 1; i >= 0; i--) - test_free(s, block[i], sz, &sliz); + for (int i = 0; i < n; i++) + test_free(s, block[i], sz, &sliz); - mb_free(block); + break; - return 1; -} + case TEST_BACKWARDS: + for (int i = 0; i < n; i++) + block[i] = test_alloc(s, sz, &sliz); -static int -t_slab_random(const void *data) -{ - int sz = (intptr_t) data; - slab *s = sl_new(&root_pool, sz); + for (int i = n - 1; i >= 0; i--) + test_free(s, block[i], sz, &sliz); - struct resmem sliz = get_memsize(s); + break; - int n = ITEMS(sz); - byte **block = mb_alloc(&root_pool, n * sizeof(*block)); + case TEST_RANDOM: + for (int i = 0; i < n; i++) + block[i] = test_alloc(s, sz, &sliz); - for (int i = 0; i < n; i++) - block[i] = test_alloc(s, sz, &sliz); + for (int i = 0; i < n; i++) + { + int pos = bt_random() % (n - i); + test_free(s, block[pos], sz, &sliz); + if (pos != n - i - 1) + block[pos] = block[n - i - 1]; + } - for (int i = 0; i < n; i++) - { - int pos = bt_random() % (n - i); - test_free(s, block[pos], sz, &sliz); - if (pos != n - i - 1) - block[pos] = block[n - i - 1]; - } + break; - mb_free(block); + case TEST_MIXED: + { + int cur = 0; + int pending = n; - return 1; -} + while (cur + pending > 0) { + int action = bt_random() % (cur + pending); -static int -t_slab_mixed(const void *data) -{ - int sz = (intptr_t) data; - slab *s = sl_new(&root_pool, sz); - - struct resmem sliz = get_memsize(s); - - int n = ITEMS(sz); - byte **block = mb_alloc(&root_pool, n * sizeof(*block)); + if (action < cur) { + test_free(s, block[action], sz, &sliz); + if (action != --cur) + block[action] = block[cur]; + } else { + block[cur++] = test_alloc(s, sz, &sliz); + pending--; + } + } - int cur = 0; - int pending = n; + break; + } - while (cur + pending > 0) { - int action = bt_random() % (cur + pending); - - if (action < cur) { - test_free(s, block[action], sz, &sliz); - if (action != --cur) - block[action] = block[cur]; - } else { - block[cur++] = test_alloc(s, sz, &sliz); - pending--; - } + default: bug("This shouldn't happen"); } mb_free(block); - return 1; } int main(int argc, char *argv[]) { bt_init(argc, argv); + struct test_request tr; + for (uint i = 0; i < sizeof(sizes) / sizeof(*sizes); i++) - { - bt_test_suite_arg(t_slab_forwards, (void *) (intptr_t) sizes[i], "Slab deallocation from beginning to end, size=%d", sizes[i]); - bt_test_suite_arg(t_slab_backwards, (void *) (intptr_t) sizes[i], "Slab deallocation from end to beginning, size=%d", sizes[i]); - bt_test_suite_arg(t_slab_random, (void *) (intptr_t) sizes[i], "Slab deallocation in random order, size=%d", sizes[i]); - bt_test_suite_arg(t_slab_mixed, (void *) (intptr_t) sizes[i], "Slab deallocation in mixed order, size=%d", sizes[i]); - } + for (uint strategy = TEST_FORWARDS; strategy < TEST__MAX; strategy++) + { + tr = (struct test_request) { + .size = sizes[i], + .strategy = strategy, + }; + bt_test_suite_arg(t_slab, &tr, "Slab allocator test, size=%d, strategy=%s", + tr.size, strategy_name[strategy]); + } return bt_exit_value(); } diff --git a/nest/neighbor.c b/nest/neighbor.c index 1a31fb79..7cf9c85d 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -345,7 +345,7 @@ neigh_free(neighbor *n) { rem_node(&n->n); rem_node(&n->if_n); - sl_free(neigh_slab, n); + sl_free(n); } /** diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 1bece201..863d411b 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -154,7 +154,7 @@ rt_prune_sources(void) { HASH_DO_REMOVE(src_hash, RSH, sp); idm_free(&src_ids, src->global_id); - sl_free(rte_src_slab, src); + sl_free(src); } } HASH_WALK_FILTER_END; @@ -391,7 +391,7 @@ nexthop_free(struct nexthop *o) while (o) { n = o->next; - sl_free(nexthop_slab(o), o); + sl_free(o); o = n; } } @@ -1231,7 +1231,7 @@ rta__free(rta *a) nexthop_free(a->nh.next); ea_free(a->eattrs); a->cached = 0; - sl_free(rta_slab(a), a); + sl_free(a); } rta * diff --git a/nest/rt-fib.c b/nest/rt-fib.c index 1690a8f6..43e3039d 100644 --- a/nest/rt-fib.c +++ b/nest/rt-fib.c @@ -475,7 +475,7 @@ fib_delete(struct fib *f, void *E) } if (f->fib_slab) - sl_free(f->fib_slab, E); + sl_free(E); else mb_free(E); diff --git a/nest/rt-table.c b/nest/rt-table.c index a1e49c21..1885e602 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -631,7 +631,7 @@ rte_free(rte *e) rt_unlock_source(e->src); if (rta_is_cached(e->attrs)) rta_free(e->attrs); - sl_free(rte_slab, e); + sl_free(e); } static inline void @@ -639,7 +639,7 @@ rte_free_quick(rte *e) { rt_unlock_source(e->src); rta_free(e->attrs); - sl_free(rte_slab, e); + sl_free(e); } static int /* Actually better or at least as good as */ @@ -3393,7 +3393,7 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he) rem_node(&he->ln); hc_remove(hc, he); - sl_free(hc->slab, he); + sl_free(he); hc->hash_items--; if (hc->hash_items < hc->hash_min) diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 30809000..b3411fc2 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -119,7 +119,7 @@ babel_get_source(struct babel_proto *p, struct babel_entry *e, u64 router_id) } static void -babel_expire_sources(struct babel_proto *p, struct babel_entry *e) +babel_expire_sources(struct babel_proto *p UNUSED, struct babel_entry *e) { struct babel_source *n, *nx; btime now_ = current_time(); @@ -129,7 +129,7 @@ babel_expire_sources(struct babel_proto *p, struct babel_entry *e) if (n->expires && n->expires <= now_) { rem_node(NODE n); - sl_free(p->source_slab, n); + sl_free(n); } } } @@ -174,7 +174,7 @@ babel_retract_route(struct babel_proto *p, struct babel_route *r) } static void -babel_flush_route(struct babel_proto *p, struct babel_route *r) +babel_flush_route(struct babel_proto *p UNUSED, struct babel_route *r) { DBG("Babel: Flush route %N router_id %lR neigh %I\n", r->e->n.addr, r->router_id, r->neigh->addr); @@ -185,7 +185,7 @@ babel_flush_route(struct babel_proto *p, struct babel_route *r) if (r->e->selected == r) r->e->selected = NULL; - sl_free(p->route_slab, r); + sl_free(r); } static void @@ -336,13 +336,13 @@ found: } static void -babel_remove_seqno_request(struct babel_proto *p, struct babel_seqno_request *sr) +babel_remove_seqno_request(struct babel_proto *p UNUSED, struct babel_seqno_request *sr) { if (sr->nbr) rem_node(&sr->nbr_node); rem_node(NODE sr); - sl_free(p->seqno_slab, sr); + sl_free(sr); } static int diff --git a/proto/babel/packets.c b/proto/babel/packets.c index f13410e2..2a6d443d 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -1318,7 +1318,6 @@ babel_send_to(struct babel_iface *ifa, ip_addr dest) static uint babel_write_queue(struct babel_iface *ifa, list *queue) { - struct babel_proto *p = ifa->proto; struct babel_write_state state = { .next_hop_ip6 = ifa->addr }; if (EMPTY_LIST(*queue)) @@ -1346,7 +1345,7 @@ babel_write_queue(struct babel_iface *ifa, list *queue) pos += len; rem_node(NODE msg); - sl_free(p->msg_slab, msg); + sl_free(msg); } pos += babel_auth_add_tlvs(ifa, (struct babel_tlv *) pos, end - pos); @@ -1507,13 +1506,13 @@ babel_process_packet(struct babel_iface *ifa, else if (res == PARSE_IGNORE) { DBG("Babel: Ignoring TLV of type %d\n", tlv->type); - sl_free(p->msg_slab, msg); + sl_free(msg); } else /* PARSE_ERROR */ { LOG_PKT("Bad TLV from %I via %s type %d pos %d - parse error", saddr, ifa->iface->name, tlv->type, (int) ((byte *)tlv - (byte *)pkt)); - sl_free(p->msg_slab, msg); + sl_free(msg); break; } } @@ -1525,7 +1524,7 @@ babel_process_packet(struct babel_iface *ifa, if (tlv_data[msg->msg.type].handle_tlv) tlv_data[msg->msg.type].handle_tlv(&msg->msg, ifa); rem_node(NODE msg); - sl_free(p->msg_slab, msg); + sl_free(msg); } } diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index dac184c5..277f38bf 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -508,7 +508,7 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s) HASH_REMOVE(p->session_hash_id, HASH_ID, s); HASH_REMOVE(p->session_hash_ip, HASH_IP, s); - sl_free(p->session_slab, s); + sl_free(s); TRACE(D_EVENTS, "Session to %I removed", ip); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 65e87c96..76b99c41 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1664,7 +1664,7 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px) HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px); if (c->prefix_slab) - sl_free(c->prefix_slab, px); + sl_free(px); else mb_free(px); } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 52c2a0ce..9fe68264 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -2135,7 +2135,7 @@ ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e) if (*ee == e) { *ee = e->next; - sl_free(f->hash_slab, e); + sl_free(e); if (f->hash_entries-- < f->hash_entries_min) ospf_top_rehash(f, -HASH_LO_STEP); return; diff --git a/proto/rip/rip.c b/proto/rip/rip.c index a501a784..eb232316 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -108,14 +108,14 @@ rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src) } static inline void -rip_remove_rte(struct rip_proto *p, struct rip_rte **rp) +rip_remove_rte(struct rip_proto *p UNUSED, struct rip_rte **rp) { struct rip_rte *rt = *rp; rip_unlock_neighbor(rt->from); *rp = rt->next; - sl_free(p->rte_slab, rt); + sl_free(rt); } static inline int rip_same_rte(struct rip_rte *a, struct rip_rte *b) -- cgit v1.2.3 From 4a23ede2b056a41456790cc20a0c3d92a7137693 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 18 Mar 2022 22:05:50 +0100 Subject: Protocols have their own explicit init routines --- Makefile.in | 10 ++++++++++ nest/Makefile | 7 ++++++- nest/proto.c | 45 +++++---------------------------------------- nest/protocol.h | 4 ++-- nest/rt-dev.c | 6 ++++++ proto/babel/Makefile | 1 + proto/babel/babel.c | 6 ++++++ proto/bfd/Makefile | 3 ++- proto/bfd/bfd.c | 17 ++++++++--------- proto/bgp/Makefile | 3 ++- proto/bgp/bgp.c | 5 +++++ proto/mrt/Makefile | 3 ++- proto/mrt/mrt.c | 6 ++++++ proto/ospf/Makefile | 3 ++- proto/ospf/ospf.c | 6 ++++++ proto/perf/Makefile | 1 + proto/perf/perf.c | 6 ++++++ proto/pipe/Makefile | 3 ++- proto/pipe/pipe.c | 6 ++++++ proto/radv/Makefile | 3 ++- proto/radv/radv.c | 6 ++++++ proto/rip/Makefile | 3 ++- proto/rip/rip.c | 6 ++++++ proto/rpki/Makefile | 3 ++- proto/rpki/rpki.c | 6 ++++++ proto/static/Makefile | 3 ++- proto/static/static.c | 6 ++++++ sysdep/unix/Makefile | 2 ++ sysdep/unix/krt.c | 13 +++++++++++++ sysdep/unix/main.c | 2 -- test/bt-utils.c | 2 -- 31 files changed, 131 insertions(+), 65 deletions(-) (limited to 'proto/babel/babel.c') diff --git a/Makefile.in b/Makefile.in index e0ff4a1d..0d55807b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -82,6 +82,9 @@ conf-lex-targets := $(addprefix $(objdir)/conf/,cf-lex.o) conf-y-targets := $(addprefix $(objdir)/conf/,cf-parse.y keywords.h commands.h) cf-local = $(conf-y-targets): $(s)config.Y +# nest/Makefile declarations needed for all other modules +proto-build-c := $(addprefix $(objdir)/nest/,proto-build.c) + src-o-files = $(patsubst %.c,$(o)%.o,$(src)) tests-target-files = $(patsubst %.c,$(o)%,$(tests_src)) @@ -95,6 +98,13 @@ else o = $(patsubst $(srcdir)%,$(objdir)%,$(s)) endif +define proto-build_in = +PROTO_BUILD += $(1) +$(proto-build-c): $(lastword $(MAKEFILE_LIST)) +endef + +proto-build = $(eval $(call proto-build_in,$(1))) + define clean_in = clean:: rm -f $(addprefix $(o),$(1)) diff --git a/nest/Makefile b/nest/Makefile index 884d3950..7d451ba4 100644 --- a/nest/Makefile +++ b/nest/Makefile @@ -1,7 +1,12 @@ -src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c +src := a-path.c a-set.c cli.c cmds.c iface.c locks.c neighbor.c password.c proto.c proto-build.c rt-attr.c rt-dev.c rt-fib.c rt-show.c rt-table.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,dev_build) + +$(proto-build-c): $(lastword $(MAKEFILE_LIST)) + $(E)echo GEN $@ + $(Q)echo "$(patsubst %,void %(void); ,$(PROTO_BUILD)) void protos_build_gen(void) { $(patsubst %, %(); ,$(PROTO_BUILD))}" > $@ tests_src := a-set_test.c a-path_test.c tests_targets := $(tests_targets) $(tests-target-files) diff --git a/nest/proto.c b/nest/proto.c index 7cfb1555..7074f73a 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -23,9 +23,9 @@ #include "filter/f-inst.h" pool *proto_pool; -list proto_list; +list STATIC_LIST_INIT(proto_list); -static list protocol_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); }) @@ -1651,6 +1651,8 @@ proto_build(struct protocol *p) /* FIXME: convert this call to some protocol hook */ extern void bfd_init_all(void); +void protos_build_gen(void); + /** * protos_build - build a protocol list * @@ -1663,44 +1665,7 @@ extern void bfd_init_all(void); void protos_build(void) { - init_list(&proto_list); - init_list(&protocol_list); - - proto_build(&proto_device); -#ifdef CONFIG_RADV - proto_build(&proto_radv); -#endif -#ifdef CONFIG_RIP - proto_build(&proto_rip); -#endif -#ifdef CONFIG_STATIC - proto_build(&proto_static); -#endif -#ifdef CONFIG_MRT - proto_build(&proto_mrt); -#endif -#ifdef CONFIG_OSPF - proto_build(&proto_ospf); -#endif -#ifdef CONFIG_PIPE - proto_build(&proto_pipe); -#endif -#ifdef CONFIG_BGP - proto_build(&proto_bgp); -#endif -#ifdef CONFIG_BFD - proto_build(&proto_bfd); - bfd_init_all(); -#endif -#ifdef CONFIG_BABEL - proto_build(&proto_babel); -#endif -#ifdef CONFIG_RPKI - proto_build(&proto_rpki); -#endif -#ifdef CONFIG_PERF - proto_build(&proto_perf); -#endif + protos_build_gen(); proto_pool = rp_new(&root_pool, "Protocols"); proto_shutdown_timer = tm_new(proto_pool); diff --git a/nest/protocol.h b/nest/protocol.h index e05dd7ec..d0810a8f 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -84,8 +84,8 @@ struct protocol { void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ }; -void protos_build(void); -void proto_build(struct protocol *); +void protos_build(void); /* Called from sysdep to initialize protocols */ +void proto_build(struct protocol *); /* Called from protocol to register itself */ void protos_preconfig(struct config *); void protos_commit(struct config *new, struct config *old, int force_restart, int type); struct proto * proto_spawn(struct proto_config *cf, uint disabled); diff --git a/nest/rt-dev.c b/nest/rt-dev.c index e2e65926..05e64fc3 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -195,3 +195,9 @@ struct protocol proto_device = { .reconfigure = dev_reconfigure, .copy_config = dev_copy_config }; + +void +dev_build(void) +{ + proto_build(&proto_device); +} diff --git a/proto/babel/Makefile b/proto/babel/Makefile index 06b58e95..ae6aeaf2 100644 --- a/proto/babel/Makefile +++ b/proto/babel/Makefile @@ -2,5 +2,6 @@ src := babel.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,babel_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/babel/babel.c b/proto/babel/babel.c index b3411fc2..8040345f 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -2494,3 +2494,9 @@ struct protocol proto_babel = { .get_route_info = babel_get_route_info, .get_attr = babel_get_attr }; + +void +babel_build(void) +{ + proto_build(&proto_babel); +} diff --git a/proto/bfd/Makefile b/proto/bfd/Makefile index 402122fc..dbdc0a09 100644 --- a/proto/bfd/Makefile +++ b/proto/bfd/Makefile @@ -2,5 +2,6 @@ src := bfd.c io.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,bfd_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 277f38bf..d1e97cd5 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -113,8 +113,8 @@ #define HASH_IP_EQ(a1,n1,a2,n2) ipa_equal(a1, a2) && n1 == n2 #define HASH_IP_FN(a,n) ipa_hash(a) ^ u32_hash(n) -static list bfd_proto_list; -static list bfd_wait_list; +static list STATIC_LIST_INIT(bfd_proto_list); +static list STATIC_LIST_INIT(bfd_wait_list); const char *bfd_state_names[] = { "AdminDown", "Down", "Init", "Up" }; @@ -998,13 +998,6 @@ bfd_notify_init(struct bfd_proto *p) * BFD protocol glue */ -void -bfd_init_all(void) -{ - init_list(&bfd_proto_list); - init_list(&bfd_wait_list); -} - static struct proto * bfd_init(struct proto_config *c) { @@ -1186,3 +1179,9 @@ struct protocol proto_bfd = { .reconfigure = bfd_reconfigure, .copy_config = bfd_copy_config, }; + +void +bfd_build(void) +{ + proto_build(&proto_bfd); +} diff --git a/proto/bgp/Makefile b/proto/bgp/Makefile index 00aaef5e..2a4cc99c 100644 --- a/proto/bgp/Makefile +++ b/proto/bgp/Makefile @@ -2,5 +2,6 @@ src := attrs.c bgp.c packets.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,bgp_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 52400762..8c97f7b3 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -2592,3 +2592,8 @@ struct protocol proto_bgp = { .get_route_info = bgp_get_route_info, .show_proto_info = bgp_show_proto_info }; + +void bgp_build(void) +{ + proto_build(&proto_bgp); +} diff --git a/proto/mrt/Makefile b/proto/mrt/Makefile index 925fb102..000e1c1c 100644 --- a/proto/mrt/Makefile +++ b/proto/mrt/Makefile @@ -2,5 +2,6 @@ src := mrt.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,mrt_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index e885611a..70b2aeff 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -916,3 +916,9 @@ struct protocol proto_mrt = { .reconfigure = mrt_reconfigure, .copy_config = mrt_copy_config, }; + +void +mrt_build(void) +{ + proto_build(&proto_mrt); +} diff --git a/proto/ospf/Makefile b/proto/ospf/Makefile index 39e74f71..85664543 100644 --- a/proto/ospf/Makefile +++ b/proto/ospf/Makefile @@ -2,5 +2,6 @@ src := dbdes.c hello.c iface.c lsack.c lsalib.c lsreq.c lsupd.c neighbor.c ospf. obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,ospf_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index f9aa6cd1..4ea53942 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -1534,3 +1534,9 @@ struct protocol proto_ospf = { .get_attr = ospf_get_attr, .get_route_info = ospf_get_route_info }; + +void +ospf_build(void) +{ + proto_build(&proto_ospf); +} diff --git a/proto/perf/Makefile b/proto/perf/Makefile index 7877fb19..42051f43 100644 --- a/proto/perf/Makefile +++ b/proto/perf/Makefile @@ -2,5 +2,6 @@ src := perf.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,perf_build) tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/perf/perf.c b/proto/perf/perf.c index 52784c14..5d228045 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -315,3 +315,9 @@ struct protocol proto_perf = { .reconfigure = perf_reconfigure, .copy_config = perf_copy_config, }; + +void +perf_build(void) +{ + proto_build(&proto_perf); +} diff --git a/proto/pipe/Makefile b/proto/pipe/Makefile index 5093da98..ba66027f 100644 --- a/proto/pipe/Makefile +++ b/proto/pipe/Makefile @@ -2,5 +2,6 @@ src := pipe.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,pipe_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 97862780..c3457135 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -303,3 +303,9 @@ struct protocol proto_pipe = { .get_status = pipe_get_status, .show_proto_info = pipe_show_proto_info }; + +void +pipe_build(void) +{ + proto_build(&proto_pipe); +} diff --git a/proto/radv/Makefile b/proto/radv/Makefile index 05317eff..4780bee3 100644 --- a/proto/radv/Makefile +++ b/proto/radv/Makefile @@ -2,5 +2,6 @@ src := packets.c radv.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,radv_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 540ff2a7..7985997a 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -771,3 +771,9 @@ struct protocol proto_radv = { .get_status = radv_get_status, .get_attr = radv_get_attr }; + +void +radv_build(void) +{ + proto_build(&proto_radv); +} diff --git a/proto/rip/Makefile b/proto/rip/Makefile index 7feabcd8..b9ff62d6 100644 --- a/proto/rip/Makefile +++ b/proto/rip/Makefile @@ -2,5 +2,6 @@ src := packets.c rip.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,rip_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index eb232316..9d8b9849 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -1342,3 +1342,9 @@ struct protocol proto_rip = { .get_route_info = rip_get_route_info, .get_attr = rip_get_attr }; + +void +rip_build(void) +{ + proto_build(&proto_rip); +} diff --git a/proto/rpki/Makefile b/proto/rpki/Makefile index eb09b7df..8e3a2761 100644 --- a/proto/rpki/Makefile +++ b/proto/rpki/Makefile @@ -2,5 +2,6 @@ src := rpki.c packets.c tcp_transport.c ssh_transport.c transport.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,rpki_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index be3d19ab..6e111a81 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -949,3 +949,9 @@ struct protocol proto_rpki = { .reconfigure = rpki_reconfigure, .get_status = rpki_get_status, }; + +void +rpki_build(void) +{ + proto_build(&proto_rpki); +} diff --git a/proto/static/Makefile b/proto/static/Makefile index e38f9b74..26aed31f 100644 --- a/proto/static/Makefile +++ b/proto/static/Makefile @@ -2,5 +2,6 @@ src := static.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,static_build) -tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file +tests_objs := $(tests_objs) $(src-o-files) diff --git a/proto/static/static.c b/proto/static/static.c index 6d3871cc..cf2e4585 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -793,3 +793,9 @@ struct protocol proto_static = { .copy_config = static_copy_config, .get_route_info = static_get_route_info, }; + +void +static_build(void) +{ + proto_build(&proto_static); +} diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile index d0d36b5f..51ab98a9 100644 --- a/sysdep/unix/Makefile +++ b/sysdep/unix/Makefile @@ -2,6 +2,8 @@ src := alloc.c io.c krt.c log.c main.c random.c obj := $(src-o-files) $(all-daemon) $(cf-local) +$(call proto-build,kif_build) +$(call proto-build,krt_build) $(conf-y-targets): $(s)krt.Y src := $(filter-out main.c, $(src)) diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 7d7ec7e6..bfd69b73 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -243,6 +243,13 @@ struct protocol proto_unix_iface = { .copy_config = kif_copy_config }; +void +kif_build(void) +{ + proto_build(&proto_unix_iface); +} + + /* * Tracing of routes */ @@ -1177,3 +1184,9 @@ struct protocol proto_unix_kernel = { .dump = krt_dump, #endif }; + +void +krt_build(void) +{ + proto_build(&proto_unix_kernel); +} diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index cdf0a310..71749324 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -906,8 +906,6 @@ main(int argc, char **argv) open_pid_file(); protos_build(); - proto_build(&proto_unix_kernel); - proto_build(&proto_unix_iface); struct config *conf = read_config(); diff --git a/test/bt-utils.c b/test/bt-utils.c index 2a7799c3..8496e185 100644 --- a/test/bt-utils.c +++ b/test/bt-utils.c @@ -68,8 +68,6 @@ bt_bird_init(void) config_init(); protos_build(); - proto_build(&proto_unix_kernel); - proto_build(&proto_unix_iface); } void bt_bird_cleanup(void) -- cgit v1.2.3 From 4aef70136d8bae68e171fa7178889e6ad9fff9b8 Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Fri, 22 Apr 2022 16:41:52 +0200 Subject: Babel: Send out low-interval hello on shutdown When shutting down a Babel instance we send a wildcard retraction to make sure all peers can quickly switch to other route origins. Add another small optimisation borrowed from babeld: sending a Hello message (along with the retraction) with a very low interval. This will cause neighbours to modify their expiry timers for the node's state to quickly time it out, thus conserving resources in the network. --- proto/babel/babel.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'proto/babel/babel.c') diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 174fc9e2..4a7d550f 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -842,14 +842,14 @@ babel_send_ihus(struct babel_iface *ifa) } static void -babel_send_hello(struct babel_iface *ifa) +babel_send_hello(struct babel_iface *ifa, uint interval) { struct babel_proto *p = ifa->proto; union babel_msg msg = {}; msg.type = BABEL_TLV_HELLO; msg.hello.seqno = ifa->hello_seqno++; - msg.hello.interval = ifa->cf->hello_interval; + msg.hello.interval = interval ?: ifa->cf->hello_interval; TRACE(D_PACKETS, "Sending hello on %s with seqno %d interval %t", ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval); @@ -1557,7 +1557,7 @@ babel_iface_timer(timer *t) if (now_ >= ifa->next_hello) { - babel_send_hello(ifa); + babel_send_hello(ifa, 0); ifa->next_hello += hello_period * (1 + (now_ - ifa->next_hello) / hello_period); } @@ -1604,7 +1604,7 @@ babel_iface_start(struct babel_iface *ifa) tm_start(ifa->timer, 100 MS); ifa->up = 1; - babel_send_hello(ifa); + babel_send_hello(ifa, 0); babel_send_wildcard_retraction(ifa); babel_send_wildcard_request(ifa); babel_send_update(ifa, 0); /* Full update */ @@ -2417,6 +2417,11 @@ babel_iface_shutdown(struct babel_iface *ifa) { if (ifa->sk) { + /* + * Retract all our routes and lower the hello interval so peers' neighbour + * state expires quickly + */ + babel_send_hello(ifa, BABEL_MIN_INTERVAL); babel_send_wildcard_retraction(ifa); babel_send_queue(ifa); } -- cgit v1.2.3 From c1194ab7edbb17cb7371ac38e6eab5ae3ae72163 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Sun, 10 Apr 2022 19:31:50 +0200 Subject: Protocols use EA_LITERAL_* to set attributes --- lib/route.h | 11 ++++++++--- proto/babel/babel.c | 36 +++++++++++++----------------------- proto/bgp/attrs.c | 7 +++---- proto/ospf/rt.c | 42 ++++++++++++++++++------------------------ proto/rip/rip.c | 24 ++++++------------------ 5 files changed, 48 insertions(+), 72 deletions(-) (limited to 'proto/babel/babel.c') diff --git a/lib/route.h b/lib/route.h index 49810887..431da4d8 100644 --- a/lib/route.h +++ b/lib/route.h @@ -225,9 +225,14 @@ struct ea_one_attr_list { EA_LITERAL_GENERIC(_id, _type, _flags, .u.i = _val); \ }) -#define EA_LITERAL_ADATA(_id, _type, _flags, _buf, _len) ({ \ +#define EA_LITERAL_STORE_ADATA(_id, _type, _flags, _buf, _len) ({ \ ASSERT_DIE(!(_type & EAF_EMBEDDED)); \ - EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = tmp_store_adata(_buf, _len)); \ + EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = tmp_store_adata((_buf), (_len))); \ + }) + +#define EA_LITERAL_DIRECT_ADATA(_id, _type, _flags, _adata) ({ \ + ASSERT_DIE(!(_type & EAF_EMBEDDED)); \ + EA_LITERAL_GENERIC(_id, _type, _flags, .u.ad = _adata); \ }) #define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \ @@ -261,7 +266,7 @@ ea_set_attr_u32(ea_list **to, uint id, uint flags, uint type, u32 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_ADATA(id, type, flags, data, len)); } +{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(id, type, flags, data, len)); } #define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK) diff --git a/proto/babel/babel.c b/proto/babel/babel.c index a6cc7aa3..db710a0d 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -640,6 +640,18 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) if (r) { + struct { + ea_list l; + eattr a[3]; + } 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), + } + }; + rta a0 = { .source = RTS_BABEL, .scope = SCOPE_UNIVERSE, @@ -648,29 +660,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) .from = r->neigh->addr, .nh.gw = r->next_hop, .nh.iface = r->neigh->ifa->iface, - .eattrs = alloca(sizeof(ea_list) + 3*sizeof(eattr)), - }; - - *a0.eattrs = (ea_list) { .count = 3 }; - a0.eattrs->attrs[0] = (eattr) { - .id = EA_BABEL_METRIC, - .type = T_INT, - .u.data = r->metric, - }; - - struct adata *ad = alloca(sizeof(struct adata) + sizeof(u64)); - ad->length = sizeof(u64); - memcpy(ad->data, &(r->router_id), sizeof(u64)); - a0.eattrs->attrs[1] = (eattr) { - .id = EA_BABEL_ROUTER_ID, - .type = T_OPAQUE, - .u.ptr = ad, - }; - - a0.eattrs->attrs[2] = (eattr) { - .id = EA_BABEL_SEQNO, - .type = T_INT, - .u.data = r->seqno, + .eattrs = &eattrs.l, }; /* diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index a7b6d0cd..4c67b161 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -94,13 +94,12 @@ 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)); - ASSERT_DIE(!(bgp_attr_table[code].type & EAF_EMBEDDED)); - ea_set_attr(to, EA_LITERAL_GENERIC( + ea_set_attr(to, EA_LITERAL_DIRECT_ADATA( EA_CODE(PROTOCOL_BGP, code), bgp_attr_table[code].type, flags & ~BAF_EXT_LEN, - .u.ad = ad + ad )); } @@ -109,7 +108,7 @@ bgp_set_attr_data(ea_list **to, uint code, uint flags, void *data, uint len) { ASSERT(bgp_attr_known(code)); - ea_set_attr(to, EA_LITERAL_ADATA( + ea_set_attr(to, EA_LITERAL_STORE_ADATA( EA_CODE(PROTOCOL_BGP, code), bgp_attr_table[code].type, flags & ~BAF_EXT_LEN, diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 8643f456..5969b7c7 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2062,39 +2062,33 @@ again1: if (reload || ort_changed(nf, &a0)) { - a0.eattrs = alloca(sizeof(ea_list) + 4 * sizeof(eattr)); - memset(a0.eattrs, 0, sizeof(ea_list)); - nf->old_metric1 = nf->n.metric1; nf->old_metric2 = nf->n.metric2; nf->old_tag = nf->n.tag; nf->old_rid = nf->n.rid; - a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { - .id = EA_OSPF_METRIC1, - .type = T_INT, - .u.data = nf->n.metric1, - }; + struct { + ea_list l; + eattr a[4]; + } eattrs; + + eattrs.l = (ea_list) {}; + + eattrs.a[eattrs.l.count++] = + EA_LITERAL_EMBEDDED(EA_OSPF_METRIC1, T_INT, 0, nf->n.metric1); if (nf->n.type == RTS_OSPF_EXT2) - a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { - .id = EA_OSPF_METRIC2, - .type = T_INT, - .u.data = nf->n.metric2, - }; + eattrs.a[eattrs.l.count++] = + EA_LITERAL_EMBEDDED(EA_OSPF_METRIC2, T_INT, 0, 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 = T_INT, - .u.data = nf->n.tag, - }; - - a0.eattrs->attrs[a0.eattrs->count++] = (eattr) { - .id = EA_OSPF_ROUTER_ID, - .type = T_QUAD, - .u.data = nf->n.rid, - }; + eattrs.a[eattrs.l.count++] = + EA_LITERAL_EMBEDDED(EA_OSPF_TAG, T_INT, 0, nf->n.tag); + + eattrs.a[eattrs.l.count++] = + EA_LITERAL_EMBEDDED(EA_OSPF_ROUTER_ID, T_QUAD, 0, nf->n.rid); + + a0.eattrs = &eattrs.l; rta *a = rta_lookup(&a0); rte *e = rte_get_temp(a, p->p.main_source); diff --git a/proto/rip/rip.c b/proto/rip/rip.c index fa5b1289..2b5babcb 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -195,26 +195,14 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) struct { ea_list l; - eattr e[3]; + eattr a[3]; struct rip_iface_adata riad; } ea_block = { - .l = { .count = 3, }, - .e = { - { - .id = EA_RIP_METRIC, - .type = T_INT, - .u.data = rt_metric, - }, - { - .id = EA_RIP_TAG, - .type = T_INT, - .u.data = rt_tag, - }, - { - .id = EA_RIP_FROM, - .type = T_IFACE, - .u.ptr = &ea_block.riad.ad, - } + .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), }, .riad = { .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) }, -- 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 'proto/babel/babel.c') 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 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 'proto/babel/babel.c') 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 8ebac84bc8d51e2404ce6d6dc5e35fb261830596 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 20 Apr 2022 13:56:04 +0200 Subject: Moved advertising router info (FROM attribute) to eattrs --- filter/config.Y | 3 +-- filter/data.h | 3 +-- filter/f-inst.c | 5 ----- lib/route.h | 10 +++++++++- nest/rt-attr.c | 9 ++++++--- nest/rt-show.c | 5 +++-- nest/rt-table.c | 5 ++++- proto/babel/babel.c | 4 ++-- proto/bgp/packets.c | 3 ++- proto/rip/rip.c | 40 ++++++++++++++++++++-------------------- 10 files changed, 48 insertions(+), 39 deletions(-) (limited to 'proto/babel/babel.c') diff --git a/filter/config.Y b/filter/config.Y index dcfae788..e24233aa 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -762,8 +762,7 @@ symbol_value: CF_SYM_KNOWN ; static_attr: - FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); } - | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); } + GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); } | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); } | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); } | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); } diff --git a/filter/data.h b/filter/data.h index 0e25ccd9..a0a164ed 100644 --- a/filter/data.h +++ b/filter/data.h @@ -22,8 +22,7 @@ struct f_val { #define fputip(a) ({ ip_addr *ax = falloc(sizeof(*ax)); *ax = (a); ax; }) enum f_sa_code { - SA_FROM = 1, - SA_GW, + SA_GW = 1, SA_NET, SA_PROTO, SA_SOURCE, diff --git a/filter/f-inst.c b/filter/f-inst.c index 9530d9ad..7158d22e 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -533,7 +533,6 @@ switch (sa.sa_code) { - 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; @@ -563,10 +562,6 @@ switch (sa.sa_code) { - case SA_FROM: - rta->from = v1.val.ip; - break; - case SA_GW: { ip_addr ip = v1.val.ip; diff --git a/lib/route.h b/lib/route.h index be72bb16..e02c63b3 100644 --- a/lib/route.h +++ b/lib/route.h @@ -84,7 +84,6 @@ typedef struct rta { u32 hash_key; /* Hash over important fields */ struct ea_list *eattrs; /* Extended Attribute chain */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ - ip_addr from; /* Advertising router */ u16 cached:1; /* Are attributes cached? */ u16 source:7; /* Route source (RTS_...) */ u16 scope:4; /* Route scope (SCOPE_... -- see ip.h) */ @@ -219,6 +218,13 @@ static inline eattr *ea_find_by_name(ea_list *l, const char *name) (ea ? ea->u.data : (_def)); \ }) +#define ea_get_ip(_l, _ident, _def) ({ \ + struct ea_class *cls = ea_class_find((_ident)); \ + ASSERT_DIE(cls->type == T_IP); \ + const eattr *ea = ea_find((_l), cls->id); \ + (ea ? *((const ip_addr *) ea->u.ptr->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 */ @@ -300,6 +306,8 @@ u32 rt_get_igp_metric(rte *rt); #define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other protocol-specific metric is availabe */ +/* From: Advertising router */ +extern struct ea_class ea_gen_from; /* Next hop structures */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index e5d87b53..87f54b0d 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -70,6 +70,11 @@ struct ea_class ea_gen_preference = { .type = T_INT, }; +struct ea_class ea_gen_from = { + .name = "from", + .type = T_IP, +}; + const char * const rta_src_names[RTS_MAX] = { [RTS_STATIC] = "static", [RTS_INHERIT] = "inherit", @@ -1229,7 +1234,6 @@ rta_hash(rta *a) #define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f)); #define BMIX(f) mem_hash_mix_num(&h, a->f); MIX(hostentry); - MIX(from); BMIX(source); BMIX(scope); BMIX(dest); @@ -1244,7 +1248,6 @@ rta_same(rta *x, rta *y) return (x->source == y->source && x->scope == y->scope && x->dest == y->dest && - ipa_equal(x->from, y->from) && x->hostentry == y->hostentry && nexthop_same(&(x->nh), &(y->nh)) && ea_same(x->eattrs, y->eattrs)); @@ -1398,7 +1401,6 @@ rta_dump(rta *a) rtd[a->dest], a->hash_key); if (!a->cached) debug(" !CACHED"); - debug(" <-%I", a->from); if (a->dest == RTD_UNICAST) for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) { @@ -1475,6 +1477,7 @@ rta_init(void) ea_register_init(&ea_gen_preference); ea_register_init(&ea_gen_igp_metric); + ea_register_init(&ea_gen_from); } /* diff --git a/nest/rt-show.c b/nest/rt-show.c index 1c764d8c..be4c0186 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -48,8 +48,9 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary struct nexthop *nh; tm_format_time(tm, &config->tf_route, e->lastmod); - if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw)) - bsprintf(from, " from %I", a->from); + ip_addr a_from = ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE); + if (ipa_nonzero(a_from) && !ipa_equal(a_from, a->nh.gw)) + bsprintf(from, " from %I", a_from); else from[0] = 0; diff --git a/nest/rt-table.c b/nest/rt-table.c index 919576bd..e8b04e0b 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2596,7 +2596,10 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i 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))) + if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal( + ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE), + ea_get_ip(rb->attrs->eattrs, &ea_gen_from, IPA_NONE) + ))) return 0; diff --git a/proto/babel/babel.c b/proto/babel/babel.c index afd0b1e1..f4503b99 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -645,11 +645,12 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) { struct { ea_list l; - eattr a[4]; + eattr a[5]; } eattrs = { .l.count = ARRAY_SIZE(eattrs.a), .a = { EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, c->preference), + EA_LITERAL_STORE_ADATA(&ea_gen_from, 0, &r->neigh->addr, sizeof(r->neigh->addr)), 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), @@ -660,7 +661,6 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) .source = RTS_BABEL, .scope = SCOPE_UNIVERSE, .dest = RTD_UNICAST, - .from = r->neigh->addr, .nh.gw = r->next_hop, .nh.iface = r->neigh->ifa->iface, .eattrs = &eattrs.l, diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 45a4b1de..9760ebee 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2476,8 +2476,9 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; - a->from = s->proto->remote_ip; a->eattrs = ea; + + ea_set_attr_data(&a->eattrs, &ea_gen_from, 0, &s->proto->remote_ip, sizeof(ip_addr)); ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, c->c.preference); c->desc->decode_next_hop(s, nh, nh_len, a); diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 244bcd0a..7c097a92 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -157,7 +157,18 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .dest = RTD_UNICAST, }; - u8 rt_metric = rt->metric; + struct { + ea_list l; + eattr a[2]; + } ea_block = { + .l.count = ARRAY_SIZE(ea_block.a), + .a = { + EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference), + EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt->metric), + }, + }; + a0.eattrs = &ea_block.l; + u16 rt_tag = rt->tag; if (p->ecmp) @@ -189,30 +200,19 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) else { /* Unipath route */ - a0.from = rt->from->nbr->addr; a0.nh.gw = rt->next_hop; a0.nh.iface = rt->from->ifa->iface; + ea_set_attr_data(&a0.eattrs, &ea_gen_from, 0, &rt->from->nbr->addr, sizeof(ip_addr)); } - struct { - ea_list l; - eattr a[4]; - struct rip_iface_adata riad; - } ea_block = { - .l.count = ARRAY_SIZE(ea_block.a), - .a = { - EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference), - 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) }, - .iface = a0.nh.iface, - }, - }; + ea_set_attr_u32(&a0.eattrs, &ea_rip_tag, 0, rt_tag); - a0.eattrs = &ea_block.l; + struct rip_iface_adata riad = { + .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) }, + .iface = a0.nh.iface, + }; + ea_set_attr(&a0.eattrs, + EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &riad.ad)); rta *a = rta_lookup(&a0); rte *e = rte_get_temp(a, p->p.main_source); -- 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 'proto/babel/babel.c') 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