From d2a8b1912a8dcc654f0b2e2b51e67494f772aa94 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 5 Feb 2020 23:59:54 +0100 Subject: [PATCH] BGP: Handle export table internally Handle export table internally in BGP protocol instead of in channel and put there exported route after full BGP processing. --- nest/protocol.h | 1 + nest/rt-table.c | 3 ++- proto/bgp/attrs.c | 38 ++++++++++++++++++++++++++++++++++++++ proto/bgp/bgp.c | 3 +++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/nest/protocol.h b/nest/protocol.h index 4d8584f2..85aeec99 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -521,6 +521,7 @@ struct channel { struct fib_iterator reload_fit; /* Iterator in in_table used during reloading */ u8 reload_active; /* Iterator reload_fit is linked */ + u8 out_table_int; /* Update of out_table is handled internally by protocol */ struct rtable *out_table; /* Internal table for exported routes */ }; diff --git a/nest/rt-table.c b/nest/rt-table.c index fe402cba..5983bd4c 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -612,7 +612,8 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, ea_list *tmpa, int } } - if (c->out_table && !rte_update_out(c, net->n.addr, new, old, &old_free, refeed)) + if (c->out_table && !c->out_table_int && + !rte_update_out(c, net->n.addr, new, old, &old_free, refeed)) return; /* Use route from export_table as old */ diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 8132a2c9..be3c9d20 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1553,6 +1553,33 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old, ea { attrs = bgp_update_attrs(p, c, new, attrs, bgp_linpool2); + if (c->c.out_table && c->c.out_table_int) + { + rte *old_free = NULL; + rte *new1 = NULL; + + /* Prepare new1 as final route after bgp_update_attrs() attribute changes */ + if (attrs) + { + new1 = rte_cow_rta(new, bgp_linpool2); + new1->attrs->eattrs = attrs; + } + + /* Update out_table, we use 'new' as 'old' to ensure it is non-NULL */ + int drop = !rte_update_out(C, n->n.addr, new1, new, &old_free, new == old); + + if (new1 != new) + rte_free(new1); + if (old_free) + rte_free(old_free); + + if (drop) + { + lp_flush(bgp_linpool2); + return; + } + } + /* If attributes are invalid, we fail back to withdraw */ buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c); path = new->attrs->src->global_id; @@ -1561,6 +1588,17 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old, ea } else { + if (c->c.out_table && c->c.out_table_int) + { + rte *old_free = NULL; + + if (!rte_update_out(C, n->n.addr, new, old, &old_free, 0)) + return; + + if (old_free) + rte_free(old_free); + } + buck = bgp_get_withdraw_bucket(c); path = old->attrs->src->global_id; } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index c3ae2ab1..2b511af0 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1543,7 +1543,10 @@ bgp_channel_start(struct channel *C) channel_setup_in_table(C); if (c->cf->export_table) + { channel_setup_out_table(C); + C->out_table_int = 1; + } c->next_hop_addr = c->cf->next_hop_addr; c->link_addr = IPA_NONE;