void
bmap_grow(struct bmap *b, uint need)
{
+ ASSERT_DIE(b->size);
+
uint size = b->size * 2;
while (size < need)
size *= 2;
static void channel_feed_end(struct channel *c);
static void channel_stop_export(struct channel *c);
static void channel_export_stopped(struct rt_export_request *req);
+static void channel_refeed_stopped(struct rt_export_request *req);
static void channel_check_stopped(struct channel *c);
static inline int proto_is_done(struct proto *p)
{
case TES_FEEDING:
if (c->proto->feed_begin)
- c->proto->feed_begin(c, !c->refeeding);
+ c->proto->feed_begin(c);
break;
case TES_READY:
channel_feed_end(c);
}
}
+void
+channel_refeed_log_state_change(struct rt_export_request *req, u8 state)
+{
+ struct channel *c = SKIP_BACK(struct channel, refeed_req, req);
+ CD(c, "Channel export state changed to %s", rt_export_state_name(state));
+
+ switch (state)
+ {
+ case TES_FEEDING:
+ if (c->proto->feed_begin)
+ c->proto->feed_begin(c);
+ break;
+ case TES_READY:
+ rt_stop_export(req, channel_refeed_stopped);
+ break;
+ }
+}
+
+
static void
channel_dump_import_req(struct rt_import_request *req)
{
debug(" Channel %s.%s export request %p\n", c->proto->name, c->name, req);
}
+static void
+channel_dump_refeed_req(struct rt_export_request *req)
+{
+ struct channel *c = SKIP_BACK(struct channel, refeed_req, req);
+ debug(" Channel %s.%s refeed request %p\n", c->proto->name, c->name, req);
+}
+
+
+static void
+channel_rpe_mark_seen_export(struct rt_export_request *req, struct rt_pending_export *rpe)
+{
+ channel_rpe_mark_seen(SKIP_BACK(struct channel, out_req, req), rpe);
+}
+
+static void
+channel_rpe_mark_seen_refeed(struct rt_export_request *req, struct rt_pending_export *rpe)
+{
+ channel_rpe_mark_seen(SKIP_BACK(struct channel, refeed_req, req), rpe);
+}
+
+
+struct channel *
+channel_from_export_request(struct rt_export_request *req)
+{
+ if (req->dump_req == channel_dump_export_req)
+ return SKIP_BACK(struct channel, out_req, req);
+
+ if (req->dump_req == channel_dump_refeed_req)
+ return SKIP_BACK(struct channel, refeed_req, req);
+
+ bug("Garbled channel export request");
+}
+
+
static void
proto_log_state_change(struct proto *p)
{
struct settle settle;
struct channel *c;
struct rt_export_request req;
+ struct channel_feeding_request cfr[2];
};
static void
CD(c, "Feeding triggered by RPKI change");
- c->refeed_pending = 1;
- channel_stop_export(c);
+ /* Refeed already pending */
+ if ((s->cfr[0].state == CFRS_PENDING) || (s->cfr[1].state == CFRS_PENDING))
+ return;
+
+ /* First refeed inactive */
+ if (s->cfr[0].state == CFRS_INACTIVE)
+ {
+ s->cfr[0].type = CFRT_AUXILIARY;
+ channel_request_feeding(c, &s->cfr[0]);
+ }
+ else
+ {
+ /* Second refeed MUST be inactive */
+ ASSERT_DIE(s->cfr[1].state == CFRS_INACTIVE);
+ s->cfr[1].type = CFRT_AUXILIARY;
+ channel_request_feeding(c, &s->cfr[1]);
+ }
}
static void
.trace_routes = c->debug | c->proto->debug,
.dump_req = channel_dump_export_req,
.log_state_change = channel_export_log_state_change,
- .mark_seen = channel_rpe_mark_seen,
+ .mark_seen = channel_rpe_mark_seen_export,
};
bmap_init(&c->export_map, c->proto->pool, 16);
bug("Unknown route announcement mode");
}
+ c->refeed_req = c->out_req;
+ c->refeed_req.name = mb_sprintf(c->proto->pool, "%s.%s.refeed", c->proto->name, c->name);
+ c->refeed_req.dump_req = channel_dump_refeed_req;
+ c->refeed_req.log_state_change = channel_refeed_log_state_change;
+ c->refeed_req.mark_seen = channel_rpe_mark_seen_refeed;
+
DBG("%s.%s: Channel start export req=%p\n", c->proto->name, c->name, &c->out_req);
rt_request_export(c->table, &c->out_req);
}
switch (c->channel_state)
{
case CS_STOP:
- if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->in_req.hook || c->reload_req.hook)
+ if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->refeed_req.hook || c->in_req.hook || c->reload_req.hook)
return;
channel_set_state(c, CS_DOWN);
break;
case CS_PAUSE:
- if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->reload_req.hook)
+ if (!EMPTY_LIST(c->roa_subscriptions) || c->out_req.hook || c->refeed_req.hook || c->reload_req.hook)
return;
channel_set_state(c, CS_START);
if (c->refeed_pending)
{
- c->refeeding = 1;
- c->refeed_pending = 0;
+ ASSERT_DIE(!c->refeeding);
+ c->refeeding = c->refeed_pending;
+ c->refeed_pending = NULL;
channel_reset_limit(c, &c->out_limit, PLD_OUT);
channel_check_stopped(c);
}
+static void
+channel_refeed_stopped(struct rt_export_request *req)
+{
+ struct channel *c = SKIP_BACK(struct channel, refeed_req, req);
+
+ req->hook = NULL;
+
+ channel_feed_end(c);
+}
+
+static void
+channel_init_feeding(struct channel *c)
+{
+ for (struct channel_feeding_request *cfrp = c->refeed_pending; cfrp; cfrp = cfrp->next)
+ if (cfrp->type == CFRT_DIRECT)
+ {
+ /* Direct feeding requested? Restart the export by force. */
+ channel_stop_export(c);
+ return;
+ }
+
+ /* No direct feeding, running auxiliary refeed. */
+ c->refeeding = c->refeed_pending;
+ c->refeed_pending = NULL;
+ c->refeed_trie = f_new_trie(lp_new(c->proto->pool), 0);
+ rt_request_export(c->table, &c->refeed_req);
+}
+
static void
channel_feed_end(struct channel *c)
{
struct limit *l = &c->out_limit;
if (c->refeeding &&
(c->limit_active & (1 << PLD_OUT)) &&
- (c->refeed_count <= l->max) &&
(l->count <= l->max))
{
log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, l->max);
- channel_reset_limit(c, &c->out_limit, PLD_OUT);
+ c->limit_active &= ~(1 << PLD_OUT);
- c->refeed_pending = 1;
- channel_stop_export(c);
- return;
+ /* Queue the same refeed batch back into pending */
+ struct channel_feeding_request **ptr = &c->refeed_pending;
+ while (*ptr)
+ ptr = &((*ptr)->next);
+
+ *ptr = c->refeeding;
+
+ /* Mark the requests to be redone */
+ for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next)
+ cfr->state = CFRS_PENDING;
+
+ c->refeeding = NULL;
}
- if (c->proto->feed_end)
- c->proto->feed_end(c);
+ /* Inform the protocol about the feed ending */
+ CALL(c->proto->feed_end, c);
+
+ /* Free the dynamic feeding requests */
+ for (struct channel_feeding_request *cfr = c->refeeding, *next = cfr ? cfr->next : NULL;
+ cfr;
+ (cfr = next), (next = next ? next->next : NULL))
+ if (cfr->flags & CFRF_DYNAMIC)
+ mb_free(cfr);
+
+ /* Drop the refeed batch */
+ c->refeeding = NULL;
+ if (c->refeed_trie)
+ {
+ rfree(c->refeed_trie->lp);
+ c->refeed_trie = NULL;
+ }
+ /* Run the pending batch */
if (c->refeed_pending)
- channel_stop_export(c);
- else
- c->refeeding = 0;
+ channel_init_feeding(c);
}
/* Called by protocol for reload from in_table */
* even when feeding is already running, in that case it is restarted.
*/
void
-channel_request_feeding(struct channel *c)
+channel_request_feeding(struct channel *c, struct channel_feeding_request *cfr)
{
ASSERT(c->out_req.hook);
- if (c->refeed_pending)
- return;
+ /* Enqueue the request */
+ cfr->next = c->refeed_pending;
+ c->refeed_pending = cfr;
- c->refeed_pending = 1;
- channel_stop_export(c);
+ /* Initialize refeeds unless already refeeding */
+ if (!c->refeeding)
+ channel_init_feeding(c);
+}
+
+void
+channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type type)
+{
+ struct channel_feeding_request *req = mb_allocz(c->proto->pool, sizeof *req);
+ req->type = type;
+ req->flags |= CFRF_DYNAMIC;
+ channel_request_feeding(c, req);
}
static void
channel_stop_export(struct channel *c)
{
- if (!c->out_req.hook || (c->out_req.hook->export_state == TES_STOP))
- return;
+ if (c->refeed_req.hook && (c->refeed_req.hook->export_state != TES_STOP))
+ rt_stop_export(&c->refeed_req, channel_refeed_stopped);
- rt_stop_export(&c->out_req, channel_export_stopped);
+ if (c->out_req.hook && (c->out_req.hook->export_state != TES_STOP))
+ rt_stop_export(&c->out_req, channel_export_stopped);
}
static void
channel_request_reload(c);
if (export_changed)
- channel_request_feeding(c);
+ channel_request_feeding_dynamic(c, CFRT_AUXILIARY);
done:
CD(c, "Reconfigured");
if (dir != CMD_RELOAD_IN)
WALK_LIST(c, p->channels)
if (c->channel_state == CS_UP)
- channel_request_feeding(c);
+ channel_request_feeding_dynamic(c, CFRT_AUXILIARY);
cli_msg(-15, "%s: reloading", p->name);
}
#include "nest/rt.h"
#include "nest/limit.h"
#include "conf/conf.h"
+#include "filter/data.h"
struct iface;
struct ifa;
void (*rt_notify)(struct proto *, struct channel *, const net_addr *net, struct rte *new, const struct rte *old);
int (*preexport)(struct channel *, struct rte *rt);
void (*reload_routes)(struct channel *);
- void (*feed_begin)(struct channel *, int initial);
+ void (*feed_begin)(struct channel *);
void (*feed_end)(struct channel *);
/*
struct rt_import_request in_req; /* Table import connection */
struct rt_export_request out_req; /* Table export connection */
- u32 refeed_count; /* Number of routes exported during refeed regardless of out_limit */
+ struct rt_export_request refeed_req; /* Auxiliary refeed request */
+ struct f_trie *refeed_trie; /* Auxiliary refeed trie */
+ struct channel_feeding_request *refeeding; /* Refeeding the channel */
+ struct channel_feeding_request *refeed_pending; /* Scheduled refeeds */
uint feed_block_size; /* How many routes to feed at once */
u8 stale; /* Used in reconfiguration */
u8 channel_state;
- u8 refeeding; /* Refeeding the channel. */
u8 reloadable; /* Hook reload_routes() is allowed on the channel */
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
struct rt_export_request reload_req; /* Feeder for import reload */
u8 reload_pending; /* Reloading and another reload is scheduled */
- u8 refeed_pending; /* Refeeding and another refeed is scheduled */
u8 rpki_reload; /* RPKI changes trigger channel reload */
struct rt_exporter *out_table; /* Internal table for exported routes */
static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_STOP); }
-void channel_request_feeding(struct channel *c);
+struct channel_feeding_request {
+ struct channel_feeding_request *next;
+ PACKED enum channel_feeding_request_type {
+ CFRT_DIRECT = 1,
+ CFRT_AUXILIARY,
+ } type;
+ PACKED enum {
+ CFRS_INACTIVE = 0,
+ CFRS_PENDING,
+ CFRS_RUNNING,
+ } state;
+ PACKED enum {
+ CFRF_DYNAMIC = 1,
+ } flags;
+};
+
+struct channel *channel_from_export_request(struct rt_export_request *req);
+void channel_request_feeding(struct channel *c, struct channel_feeding_request *);
+void channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type);
+
+static inline int channel_net_is_refeeding(struct channel *c, const net_addr *n)
+{ return (c->refeeding && c->refeed_trie && !trie_match_net(c->refeed_trie, n)); }
+static inline void channel_net_mark_refed(struct channel *c, const net_addr *n)
+{
+ ASSERT_DIE(c->refeeding && c->refeed_trie);
+ trie_add_prefix(c->refeed_trie, n, n->pxlen, n->pxlen);
+}
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);
{
/* Special case for merged export */
pass = 1;
- rte *em = rt_export_merged(ec, feed, count, tmp_linpool, 1);
+ rte *em = rt_export_merged(ec, n, feed, count, tmp_linpool, 1);
if (em)
e = *em;
struct proto *p = c->proto;
struct channel_export_stats *stats = &c->export_stats;
- if (c->refeeding && new)
- c->refeed_count++;
-
if (!old && new)
if (CHANNEL_LIMIT_PUSH(c, OUT))
{
}
static void
-rt_notify_basic(struct channel *c, const net_addr *net, rte *new, const rte *old)
+rt_notify_basic(struct channel *c, const net_addr *net, rte *new, const rte *old, int force)
{
- if (new && old && rte_same(new, old))
+ if (new && old && rte_same(new, old) && !force)
{
channel_rte_trace_out(D_ROUTES, c, new, "already exported");
return;
}
+ /* Refeeding and old is new */
+ if (force && !old && bmap_test(&c->export_map, new->id))
+ old = new;
+
if (new)
new = export_filter(c, new, 0);
}
void
-channel_rpe_mark_seen(struct rt_export_request *req, struct rt_pending_export *rpe)
+channel_rpe_mark_seen(struct channel *c, struct rt_pending_export *rpe)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
-
channel_trace(c, D_ROUTES, "Marking seen %p (%lu)", rpe, rpe->seq);
- rpe_mark_seen(req->hook, rpe);
+ ASSERT_DIE(c->out_req.hook);
+ rpe_mark_seen(c->out_req.hook, rpe);
+
+ if (c->refeed_req.hook && (c->refeed_req.hook->export_state == TES_FEEDING))
+ rpe_mark_seen(c->refeed_req.hook, rpe);
+
if (rpe->old)
bmap_clear(&c->export_reject_map, rpe->old->rte.id);
}
struct rt_pending_export *first, struct rt_pending_export *last,
const rte **feed, uint count)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
+ struct channel *c = channel_from_export_request(req);
+ int refeeding = channel_net_is_refeeding(c, n);
rte nb0, *new_best = NULL;
const rte *old_best = NULL;
continue;
/* Has been already rejected, won't bother with it */
- if (!c->refeeding && bmap_test(&c->export_reject_map, feed[i]->id))
+ if (!refeeding && bmap_test(&c->export_reject_map, feed[i]->id))
continue;
/* Previously exported */
if (!old_best && bmap_test(&c->export_map, feed[i]->id))
{
- /* is still best */
- if (!new_best)
+ if (new_best)
+ {
+ /* is superseded */
+ old_best = feed[i];
+ break;
+ }
+ else if (refeeding)
+ /* is superseeded but maybe by a new version of itself */
+ old_best = feed[i];
+ else
{
+ /* is still best */
DBG("rt_notify_accepted: idempotent\n");
goto done;
}
-
- /* is superseded */
- old_best = feed[i];
- break;
}
/* Have no new best route yet */
/* Check obsolete routes for previously exported */
RPE_WALK(first, rpe, NULL)
{
- channel_rpe_mark_seen(req, rpe);
+ channel_rpe_mark_seen(c, rpe);
if (rpe->old)
{
if (bmap_test(&c->export_map, rpe->old->rte.id))
do_rt_notify(c, n, new_best, old_best);
else
DBG("rt_notify_accepted: nothing to export\n");
+
+ if (refeeding)
+ channel_net_mark_refed(c, n);
}
rte *
-rt_export_merged(struct channel *c, const rte **feed, uint count, linpool *pool, int silent)
+rt_export_merged(struct channel *c, const net_addr *n, const rte **feed, uint count, linpool *pool, int silent)
{
_Thread_local static rte rloc;
+ int refeeding = !silent && channel_net_is_refeeding(c, n);
+
+ if (refeeding)
+ channel_net_mark_refed(c, n);
+
// struct proto *p = c->proto;
struct nexthop_adata *nhs = NULL;
const rte *best0 = feed[0];
return NULL;
/* Already rejected, no need to re-run the filter */
- if (!c->refeeding && bmap_test(&c->export_reject_map, best0->id))
+ if (!refeeding && bmap_test(&c->export_reject_map, best0->id))
return NULL;
rloc = *best0;
continue;
rte tmp0 = *feed[i];
- rte *tmp = export_filter(c, &tmp0, 1);
+ rte *tmp = export_filter(c, &tmp0, !refeeding);
if (!tmp || !rte_is_reachable(tmp))
continue;
struct rt_pending_export *first, struct rt_pending_export *last,
const rte **feed, uint count)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
+ struct channel *c = channel_from_export_request(req);
// struct proto *p = c->proto;
/* Check obsolete routes for previously exported */
RPE_WALK(first, rpe, NULL)
{
- channel_rpe_mark_seen(req, rpe);
+ channel_rpe_mark_seen(c, rpe);
if (rpe->old)
{
if (bmap_test(&c->export_map, rpe->old->rte.id))
}
/* Prepare new merged route */
- rte *new_merged = count ? rt_export_merged(c, feed, count, tmp_linpool, 0) : NULL;
+ rte *new_merged = count ? rt_export_merged(c, n, feed, count, tmp_linpool, 0) : NULL;
if (new_merged || old_best)
do_rt_notify(c, n, new_merged, old_best);
void
rt_notify_optimal(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
+ struct channel *c = channel_from_export_request(req);
const rte *o = RTE_VALID_OR_NULL(first->old_best);
struct rte_storage *new_best = first->new_best;
+ int refeeding = channel_net_is_refeeding(c, net);
+
RPE_WALK(first, rpe, NULL)
{
- channel_rpe_mark_seen(req, rpe);
+ channel_rpe_mark_seen(c, rpe);
new_best = rpe->new_best;
}
rte n0 = RTE_COPY_VALID(new_best);
if (n0.src || o)
- rt_notify_basic(c, net, n0.src ? &n0 : NULL, o);
+ rt_notify_basic(c, net, n0.src ? &n0 : NULL, o, refeeding);
+
+ if (refeeding)
+ channel_net_mark_refed(c, net);
}
void
rt_notify_any(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
+ struct channel *c = channel_from_export_request(req);
const rte *n = RTE_VALID_OR_NULL(first->new);
const rte *o = RTE_VALID_OR_NULL(first->old);
"Notifying any, net %N, first %p (%lu), new %p, old %p",
net, first, first->seq, n, o);
- if (!n && !o)
+ if (!n && !o || channel_net_is_refeeding(c, net))
{
- channel_rpe_mark_seen(req, first);
+ /* We want to skip this notification because:
+ * - there is nothing to notify, or
+ * - this net is going to get a full refeed soon
+ */
+ channel_rpe_mark_seen(c, first);
return;
}
RPE_WALK(first, rpe, src)
{
- channel_rpe_mark_seen(req, rpe);
+ channel_rpe_mark_seen(c, rpe);
new_latest = rpe->new;
}
rte n0 = RTE_COPY_VALID(new_latest);
if (n0.src || o)
- rt_notify_basic(c, net, n0.src ? &n0 : NULL, o);
+ rt_notify_basic(c, net, n0.src ? &n0 : NULL, o, 0);
channel_trace(c, D_ROUTES, "Notified net %N", net);
}
struct rt_pending_export *first, struct rt_pending_export *last,
const rte **feed, uint count)
{
- struct channel *c = SKIP_BACK(struct channel, out_req, req);
+ struct channel *c = channel_from_export_request(req);
+ int refeeding = channel_net_is_refeeding(c, net);
channel_trace(c, D_ROUTES, "Feeding any, net %N, first %p (%lu), %p (%lu), count %u",
net, first, first ? first->seq : 0, last ? last->seq : 0, count);
if (rte_is_valid(feed[i]))
{
rte n0 = *feed[i];
- rt_notify_basic(c, net, &n0, NULL);
+ rt_notify_basic(c, net, &n0, NULL, refeeding);
}
RPE_WALK(first, rpe, NULL)
{
- channel_rpe_mark_seen(req, rpe);
+ channel_rpe_mark_seen(c, rpe);
if (rpe == last)
break;
}
channel_trace(c, D_ROUTES, "Fed %N", net);
+ if (refeeding)
+ channel_net_mark_refed(c, net);
}
void
void rt_notify_accepted(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first, struct rt_pending_export *last, const rte **feed, uint count);
void rt_notify_merged(struct rt_export_request *req, const net_addr *net, struct rt_pending_export *first, struct rt_pending_export *last, const rte **feed, uint count);
-void channel_rpe_mark_seen(struct rt_export_request *req, struct rt_pending_export *rpe);
+void channel_rpe_mark_seen(struct channel *c, struct rt_pending_export *rpe);
/* Types of route announcement, also used as flags */
#define RA_UNDEF 0 /* Undefined RA type */
static inline net *net_get(struct rtable_private *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
net *net_route(struct rtable_private *tab, const net_addr *n);
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
-rte *rt_export_merged(struct channel *c, const rte ** feed, uint count, linpool *pool, int silent);
+rte *rt_export_merged(struct channel *c, const net_addr *n, const rte ** feed, uint count, linpool *pool, int silent);
void rt_refresh_begin(struct rt_import_request *);
void rt_refresh_end(struct rt_import_request *);
void rt_modify_stale(rtable *t, struct rt_import_request *);
}
static void
-babel_feed_begin(struct channel *C, int initial)
+babel_feed_begin(struct channel *C)
{
- if (initial)
+ if (!C->refeeding || C->refeed_req.hook)
return;
struct babel_proto *p = (struct babel_proto *) C->proto;
static void
babel_feed_end(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct babel_proto *p = (struct babel_proto *) C->proto;
struct fib *rtable = (C->net_type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable;
int changed = 0;
}
static void
-bgp_feed_begin(struct channel *C, int initial)
+bgp_feed_begin(struct channel *C)
{
struct bgp_proto *p = (void *) C->proto;
struct bgp_channel *c = (void *) C;
if (!p->conn)
return;
- if (initial && p->cf->gr_mode)
- c->feed_state = BFS_LOADING;
-
- if (!initial && C->out_table)
+ if (!C->refeeding)
{
- c->feed_out_table = 1;
+ if (p->cf->gr_mode)
+ c->feed_state = BFS_LOADING;
return;
}
- /* It is refeed and both sides support enhanced route refresh */
- if (!initial && p->enhanced_refresh)
+ if (!C->refeed_req.hook)
{
- /* BoRR must not be sent before End-of-RIB */
- if (c->feed_state == BFS_LOADING || c->feed_state == BFS_LOADED)
+ /* Direct refeed */
+ if (C->out_table)
+ {
+ /* FIXME: THIS IS BROKEN, IT DOESN'T PRUNE THE OUT TABLE */
+ c->feed_out_table = 1;
return;
+ }
+
+ ASSERT_DIE(p->enhanced_refresh);
+
+ /* It is refeed and both sides support enhanced route refresh */
+ /* BoRR must not be sent before End-of-RIB */
+ ASSERT_DIE((c->feed_state != BFS_LOADING) && (c->feed_state != BFS_LOADED));
c->feed_state = BFS_REFRESHING;
bgp_schedule_packet(p->conn, c, PKT_BEGIN_REFRESH);
{
case BGP_RR_REQUEST:
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
- channel_request_feeding(&c->c);
+ if (c->c.out_table)
+ {
+ /* FIXME: REQUEST REFRESH FROM OUT TABLE */
+ }
+ else
+ channel_request_feeding_dynamic(&c->c, p->enhanced_refresh ? CFRT_DIRECT : CFRT_AUXILIARY);
break;
case BGP_RR_BEGIN:
}
void
-ospf_feed_begin(struct channel *C, int initial UNUSED)
+ospf_feed_begin(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct ospf_proto *p = (struct ospf_proto *) C->proto;
struct top_hash_entry *en;
void
ospf_feed_end(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct ospf_proto *p = (struct ospf_proto *) C->proto;
struct top_hash_entry *en;
void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en);
void ospf_update_lsadb(struct ospf_proto *p);
-void ospf_feed_begin(struct channel *C, int initial);
+void ospf_feed_begin(struct channel *C);
void ospf_feed_end(struct channel *C);
static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry **en)
}
static void
-perf_feed_begin(struct channel *c, int initial UNUSED)
+perf_feed_begin(struct channel *c)
{
struct perf_proto *p = (struct perf_proto *) c->proto;
perf_feed_end(struct channel *c)
{
struct perf_proto *p = (struct perf_proto *) c->proto;
+
struct timespec ts_end;
clock_gettime(CLOCK_MONOTONIC, &ts_end);
p->feed_begin = NULL;
if (p->run < p->repeat)
- channel_request_feeding(c);
+ channel_request_feeding_dynamic(c, CFRT_DIRECT);
else
PLOG("feed done");
}
struct pipe_proto *p = (void *) C->proto;
/* Route reload on one channel is just refeed on the other */
- channel_request_feeding((C == p->pri) ? p->sec : p->pri);
+ channel_request_feeding_dynamic((C == p->pri) ? p->sec : p->pri, CFRT_DIRECT);
}
static void
-pipe_feed_begin(struct channel *C, int initial UNUSED)
+pipe_feed_begin(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct pipe_proto *p = (void *) C->proto;
uint *flags = (C == p->pri) ? &p->sec_flags : &p->pri_flags;
static void
pipe_feed_end(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct pipe_proto *p = (void *) C->proto;
struct channel *dst = (C == p->pri) ? p->sec : p->pri;
uint *flags = (C == p->pri) ? &p->sec_flags : &p->pri_flags;
/* We started to accept routes so we need to refeed them */
if (!old->propagate_routes && new->propagate_routes)
- channel_request_feeding(p->p.main_channel);
+ channel_request_feeding_dynamic(p->p.main_channel, CFRT_DIRECT);
IFACE_WALK(iface)
{
}
void
-rip_feed_begin(struct channel *C, int initial)
+rip_feed_begin(struct channel *C)
{
- if (initial)
+ if (!C->refeeding || C->refeed_req.hook)
return;
struct rip_proto *p = (struct rip_proto *) C->proto;
void
rip_feed_end(struct channel *C)
{
+ if (!C->refeeding || C->refeed_req.hook)
+ return;
+
struct rip_proto *p = (struct rip_proto *) C->proto;
int changed = 0;
const rte **feed = alloca(count * sizeof(rte *));
rte_feed_obtain_valid(net, feed, count);
- return rt_export_merged(c, feed, count, krt_filter_lp, 1);
+ return rt_export_merged(c, net->n.addr, feed, count, krt_filter_lp, 1);
}
static _Thread_local rte rt;
{
struct krt_proto *p = (void *) C->proto;
+ if (C->refeeding && C->refeed_req.hook)
+ return;
+
if (p->flush_routes)
{
p->flush_routes = 2;
if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
{
p->flush_routes = 1;
- channel_request_feeding(p->p.main_channel);
+ channel_request_feeding_dynamic(p->p.main_channel, CFRT_AUXILIARY);
return PS_UP;
}
else