diff --git a/nest/route.h b/nest/route.h index 329eefa6..74f2d84a 100644 --- a/nest/route.h +++ b/nest/route.h @@ -225,7 +225,7 @@ struct rt_exporter { netindex_hash *netindex; /* Table for net <-> id conversion */ void (*stopped)(struct rt_exporter *); /* Callback when exporter can stop */ void (*cleanup_done)(struct rt_exporter *, u64 end); /* Callback when cleanup has been done */ - struct rt_export_feed *(*feed_net)(struct rt_exporter *, struct rcu_unwinder *, u32, const struct rt_export_item *first); + struct rt_export_feed *(*feed_net)(struct rt_exporter *, struct rcu_unwinder *, u32, _Bool (*)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *, const struct rt_export_item *first); void (*feed_cleanup)(struct rt_exporter *, struct rt_export_feeder *); }; @@ -313,6 +313,12 @@ static inline int rt_prefilter_net(const struct rt_prefilter *p, const net_addr static inline _Bool rt_net_is_feeding_feeder(struct rt_export_feeder *ref, const net_addr *n) { + if (!rt_prefilter_net(&ref->prefilter, n)) + return 0; + + if (!ref->feeding) + return 1; + for (struct rt_feeding_request *rfr = ref->feeding; rfr; rfr = rfr->next) if (rt_prefilter_net(&rfr->prefilter, n)) return 1; diff --git a/nest/rt-export.c b/nest/rt-export.c index f421a63b..1dd536a5 100644 --- a/nest/rt-export.c +++ b/nest/rt-export.c @@ -149,13 +149,13 @@ rt_export_get(struct rt_export_request *r) if (r->feeder.domain.rtable) { LOCK_DOMAIN(rtable, r->feeder.domain); - feed = e->feed_net(e, NULL, ni->index, update); + feed = e->feed_net(e, NULL, ni->index, NULL, NULL, update); UNLOCK_DOMAIN(rtable, r->feeder.domain); } else { RCU_ANCHOR(u); - feed = e->feed_net(e, u, ni->index, update); + feed = e->feed_net(e, u, ni->index, NULL, NULL, update); } bmap_set(&r->feed_map, ni->index); @@ -263,7 +263,8 @@ rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u) return NULL; } - struct rt_export_feed *feed = e->feed_net(e, u, f->feed_index, NULL); + struct rt_export_feed *feed = e->feed_net(e, u, f->feed_index, + rt_net_is_feeding_feeder, f, NULL); if (feed == &rt_feed_index_out_of_range) { rtex_trace(f, D_ROUTES, "Nothing more to feed", f->feed_index); @@ -280,13 +281,6 @@ rt_export_get_next_feed(struct rt_export_feeder *f, struct rcu_unwinder *u) if (!feed) NOT_THIS_FEED("Nothing found for index %u", f->feed_index); - struct netindex *ni = feed->ni; - if (!rt_prefilter_net(&f->prefilter, ni->addr)) - NOT_THIS_FEED("Not feeding %N due to prefilter", ni->addr); - - if (f->feeding && !rt_net_is_feeding_feeder(f, ni->addr)) - NOT_THIS_FEED("Not feeding %N, not requested", ni->addr); - f->feed_index++; return feed; } diff --git a/nest/rt-table.c b/nest/rt-table.c index cc211163..c14692d5 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2209,7 +2209,7 @@ rt_net_feed_validate_first( } static struct rt_export_feed * -rt_net_feed_index(struct rtable_reading *tr, net *n, const struct rt_pending_export *first) +rt_net_feed_index(struct rtable_reading *tr, net *n, _Bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first) { /* Get the feed itself. It may change under our hands tho. */ struct rt_pending_export *first_in_net, *last_in_net; @@ -2230,10 +2230,19 @@ rt_net_feed_index(struct rtable_reading *tr, net *n, const struct rt_pending_exp ocnt++; } + if (ecnt) { + const net_addr *a = (first->it.new ?: first->it.old)->net; + if (prefilter && !prefilter(f, a)) + return NULL; + } + struct rt_export_feed *feed = NULL; if (rcnt || ocnt || ecnt) { + if (!ecnt && prefilter && !prefilter(f, NET_READ_BEST_ROUTE(tr, n)->rte.net)) + return NULL; + feed = rt_alloc_feed(rcnt+ocnt, ecnt); if (rcnt) @@ -2276,13 +2285,13 @@ rt_net_feed_index(struct rtable_reading *tr, net *n, const struct rt_pending_exp } static struct rt_export_feed * -rt_net_feed_internal(struct rtable_reading *tr, u32 index, const struct rt_pending_export *first) +rt_net_feed_internal(struct rtable_reading *tr, u32 index, _Bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_pending_export *first) { net *n = rt_net_feed_get_net(tr, index); if (!n) return &rt_feed_index_out_of_range; - return rt_net_feed_index(tr, n, first); + return rt_net_feed_index(tr, n, prefilter, f, first); } struct rt_export_feed * @@ -2290,14 +2299,14 @@ rt_net_feed(rtable *t, const net_addr *a, const struct rt_pending_export *first) { RT_READ(t, tr); const struct netindex *ni = net_find_index(tr->t->netindex, a); - return ni ? rt_net_feed_internal(tr, ni->index, first) : NULL; + return ni ? rt_net_feed_internal(tr, ni->index, NULL, NULL, first) : NULL; } static struct rt_export_feed * -rt_feed_net_all(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, const struct rt_export_item *_first) +rt_feed_net_all(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, _Bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first) { RT_READ_ANCHORED(SKIP_BACK(rtable, export_all, e), tr, u); - return rt_net_feed_internal(tr, index, SKIP_BACK(const struct rt_pending_export, it, _first)); + return rt_net_feed_internal(tr, index, prefilter, f, SKIP_BACK(const struct rt_pending_export, it, _first)); } rte @@ -2322,7 +2331,7 @@ rt_net_best(rtable *t, const net_addr *a) } static struct rt_export_feed * -rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, const struct rt_export_item *_first) +rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, _Bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first) { SKIP_BACK_DECLARE(rtable, t, export_best, e); SKIP_BACK_DECLARE(const struct rt_pending_export, first, it, _first); @@ -2344,8 +2353,15 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, const rpe = atomic_load_explicit(&rpe->next, memory_order_acquire)) ecnt++; + if (ecnt) { + const net_addr *a = (first->it.new ?: first->it.old)->net; + if (prefilter && !prefilter(f, a)) + return NULL; + } + struct rte_storage *best = NET_READ_BEST_ROUTE(tr, n); - if (!ecnt && !best) + + if (!ecnt && (!best || prefilter && !prefilter(f, best->rte.net))) return NULL; struct rt_export_feed *feed = rt_alloc_feed(!!best, ecnt); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 5ea97ac5..2450f657 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1879,17 +1879,22 @@ bgp_out_item_done(struct lfjour *j, struct lfjour_item *i) {} static struct rt_export_feed * -bgp_out_feed_net(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, const struct rt_export_item *_first) +bgp_out_feed_net(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, _Bool (*prefilter)(struct rt_export_feeder *, const net_addr *), struct rt_export_feeder *f, const struct rt_export_item *_first) { ASSERT_DIE(u == NULL); SKIP_BACK_DECLARE(struct bgp_ptx_private, c, exporter, e); ASSERT_DIE(DOMAIN_IS_LOCKED(rtable, c->lock)); + struct netindex *ni = net_resolve_index(c->c->c.table->netindex, index); if (ni == &net_index_out_of_range) return &rt_feed_index_out_of_range; + if (ni == NULL) return NULL; + if (prefilter && !prefilter(f, ni->addr)) + return NULL; + struct rt_export_feed *feed = NULL; uint count = 0;