c->reloadable = 1;
init_list(&c->roa_subscriptions);
+ init_list(&c->net_feed);
CALL(c->channel->init, c, cf);
/* Restart feeding */
if (c->refeed_pending)
- channel_request_feeding(c);
+ channel_request_feeding(c, NULL);
}
+static void
+channel_feed_net(void *data)
+{
+ struct channel_net_feed *nf = data;
+
+ rt_feed_channel_net(nf->c, nf->addr);
+ rem_node(&nf->n);
+ mb_free(nf);
+}
+
+static void
+channel_schedule_feed_net(struct channel *c, net_addr *n)
+{
+ struct channel_net_feed *nf = mb_alloc(c->proto->pool, sizeof(struct channel_net_feed) + n->length);
+ nf->n = (node) {};
+ nf->e = (event) { .hook = channel_feed_net, .data = nf };
+ nf->c = c;
+ net_copy(nf->addr, n);
+ add_tail(&c->net_feed, &nf->n);
+ ev_schedule(&nf->e);
+}
static void
channel_roa_in_changed(struct rt_subscription *s)
CD(c, "Feeding triggered by RPKI change%s", active ? " - already active" : "");
if (!active)
- channel_request_feeding(c);
+ channel_request_feeding(c, NULL);
else
c->refeed_pending = 1;
}
if (c->export_state == ES_FEEDING)
rt_feed_channel_abort(c);
+ /* Abort also all scheduled net feeds */
+ struct channel_net_feed *n;
+ node *nxt;
+ WALK_LIST_DELSAFE(n, nxt, c->net_feed)
+ {
+ ev_postpone(&n->e);
+ rem_node(&n->n);
+ mb_free(n);
+ }
+
c->export_state = ES_DOWN;
c->stats.exp_routes = 0;
bmap_reset(&c->export_map, 1024);
* 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, net_addr *n)
{
ASSERT(c->channel_state == CS_UP);
if (!c->feed_active)
return;
+ /* Unless only single net is requested */
+ if (n)
+ return channel_schedule_feed_net(c, n);
+
rt_feed_channel_abort(c);
}
+ /* Single net refeed isn't counted */
+ if (n)
+ return channel_schedule_feed_net(c, n);
+
/* Track number of exported routes during refeed */
c->refeed_count = 0;
channel_request_reload(c);
if (export_changed)
- channel_request_feeding(c);
+ channel_request_feeding(c, NULL);
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(c, NULL);
cli_msg(-15, "%s: reloading", p->name);
}
struct fib_iterator reload_fit; /* FIB iterator in in_table used during reloading */
struct rte *reload_next_rte; /* Route iterator in in_table used during reloading */
u8 reload_active; /* Iterator reload_fit is linked */
-
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 */
+ list net_feed; /* Active net feeders (struct channel_net_feed) */
+
struct rtable *out_table; /* Internal table for exported routes */
list roa_subscriptions; /* List of active ROA table subscriptions based on filters roa_check() */
};
+struct channel_net_feed {
+ node n;
+ struct event e;
+ struct channel *c;
+ net_addr addr[0];
+};
+
/*
* Channel states
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_FLUSHING); }
-void channel_request_feeding(struct channel *c);
+void channel_request_feeding(struct channel *c, net_addr *n);
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);
/* Route export structure. Protocols get this structure as an information about
* new routes on the channel. */
+
struct rte_export {
- net *net; /* Network information */
- struct rte_src *new_src; /* New route src (NULL for withdraw) */
+ net_addr *net; /* Network information */
rte *new; /* New route (NULL for withdraw) */
+ struct rte_src *new_src; /* New route src (kept if route is rejected by preexport or filter) */
+ rte *old; /* Old route (only if export table is on) */
struct rte_src *old_src; /* Old route src */
- rte *old; /* Old route */
};
#define REF_COW 1 /* Copy this rte on write */
void *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
rte *rte_find(net *net, struct rte_src *src);
-int rt_examine(struct channel *c, net_addr *a);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
void rt_dump(rtable *);
void rt_dump_all(void);
int rt_feed_channel(struct channel *c);
+void rt_feed_channel_net(struct channel *c, net_addr *n);
void rt_feed_channel_abort(struct channel *c);
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
}
struct rte_export_internal {
- struct rte_export pub;
- rte *new_best;
- rte *old_best;
+ net *net;
+ rte *new, *old, *new_best, *old_best;
rte *rt_free;
- uint refeed:1;
+ struct rte_export pub;
+ _Bool refeed;
};
static int /* Actually better or at least as good as */
const struct filter *filter = c->out_filter;
struct proto_stats *stats = &c->stats;
rte *rt;
+ int v;
rt = rt0;
*rt_free = NULL;
if (silent && bmap_test(&c->export_reject_map, rt0->id))
return NULL;
- int pv = p->preexport ? p->preexport(p, &rt, pool) : 0;
- if (pv < 0)
+ v = p->preexport ? p->preexport(p, &rt, pool) : 0;
+ if (v < 0)
{
if (silent)
goto reject;
stats->exp_updates_rejected++;
- if (pv == RIC_REJECT)
+ if (v == RIC_REJECT)
rte_trace_out(D_FILTERS, c, rt, "rejected by protocol");
goto reject;
}
- if (pv > 0)
+ if (v > 0)
{
if (!silent)
rte_trace_out(D_FILTERS, c, rt, "forced accept by protocol");
goto accept;
}
- int fv = filter && ((filter == FILTER_REJECT) ||
+ v = filter && ((filter == FILTER_REJECT) ||
(f_run(filter, &rt, pool,
(silent ? FF_SILENT : 0)) > F_ACCEPT));
- if (fv)
+ if (v)
{
if (silent)
goto reject;
return rt;
reject:
- /* We have rejected the route by filter */
- if (pv == 0)
- bmap_set(&c->export_reject_map, rt0->id);
+ /* We have rejected the route */
+ bmap_set(&c->export_reject_map, rt0->id);
/* Discard temporary rte */
if (rt != rt0)
}
static void
-do_rt_notify(struct channel *c, struct rte_export_internal *e)
+do_rt_notify(struct channel *c, struct rte_export *ep, _Bool refeed)
{
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
- struct rte_export *ep = &(e->pub);
- if (e->refeed && ep->new)
+ if (refeed && ep->new)
c->refeed_count++;
/* Apply export limit */
rte *old_exported = NULL;
if (c->out_table)
{
- if (!rte_update_out(c, ep->net->n.addr, ep->old_src, ep->new, &(old_exported), e->refeed))
+ if (!rte_update_out(c, ep->net, ep->old_src, ep->new, &(old_exported), refeed))
return;
}
else if (c->out_filter == FILTER_ACCEPT)
USE_RESULT static _Bool
rt_notify_basic(struct channel *c, struct rte_export_internal *e)
{
- if (e->pub.new)
+ struct rte_export *ep = &e->pub;
+
+ if (e->new)
c->stats.exp_updates_received++;
else
c->stats.exp_withdraws_received++;
- if (e->pub.new)
- e->pub.new = export_filter(c, e->pub.new, &e->rt_free, 0);
-
- if (e->pub.old && !bmap_test(&c->export_map, e->pub.old->id))
- e->pub.old = NULL;
+ if (e->new)
+ {
+ ep->new = export_filter(c, e->new, &e->rt_free, 0);
+ ep->new_src = e->new->attrs->src;
+ }
- if (!e->pub.new && !e->pub.old)
- return 0;
+ if (e->old && bmap_test(&c->export_map, e->old->id))
+ {
+ ep->old = e->old;
+ ep->old_src = e->old->attrs->src;
+ }
- return 1;
+ return (ep->new || ep->old);
}
USE_RESULT static _Bool
// struct proto *p = c->proto;
rte *new_best = NULL;
rte *old_best = NULL;
+ rte *new_filtered = NULL;
int new_first = 0;
/*
* old_best is after new_changed -> try new_changed, otherwise old_best
*/
- if (e->pub.net->routes)
+ if (e->net->routes)
c->stats.exp_updates_received++;
else
c->stats.exp_withdraws_received++;
/* Find old_best - either old_changed, or route for net->routes */
- if (e->pub.old && bmap_test(&c->export_map, e->pub.old->id))
- old_best = e->pub.old;
+ if (e->old && bmap_test(&c->export_map, e->old->id))
+ old_best = e->old;
else
{
- for (rte *r = e->pub.net->routes; rte_is_valid(r); r = r->next)
+ for (rte *r = e->net->routes; rte_is_valid(r); r = r->next)
{
if (bmap_test(&c->export_map, r->id))
{
}
/* Note if new_changed found before old_best */
- if (r == e->pub.new)
+ if (r == e->new)
new_first = 1;
}
}
/* Find new_best */
- if ((e->pub.new == e->pub.old) || (old_best == e->pub.old))
+ if ((e->new == e->old) || (old_best == e->old))
{
/* Feed or old_best changed -> find first accepted by filters */
- for (rte *r = e->pub.net->routes; rte_is_valid(r); r = r->next)
+ for (rte *r = e->net->routes; rte_is_valid(r); r = r->next)
if (new_best = export_filter(c, r, &e->rt_free, 0))
break;
}
else
{
/* Other cases -> either new_changed, or old_best (and nothing changed) */
- if (new_first && (e->pub.new = export_filter(c, e->pub.new, &e->rt_free, 0)))
- new_best = e->pub.new;
+ if (new_first && (new_filtered = export_filter(c, e->new, &e->rt_free, 0)))
+ new_best = new_filtered;
else
return 0;
}
if (!new_best && !old_best)
return 0;
- e->pub.new = new_best;
- e->pub.new_src = new_best ? new_best->attrs->src : NULL;
- e->pub.old = old_best;
- e->pub.old_src = old_best ? old_best->attrs->src : NULL;
+ e->pub = (struct rte_export) {
+ .new = new_best,
+ .new_src = new_best ? new_best->attrs->src : NULL,
+ .old = old_best,
+ .old_src = old_best ? old_best->attrs->src : NULL,
+ };
return 1;
}
/* Check whether the change is relevant to the merged route */
if ((e->new_best == e->old_best) &&
- (e->pub.new != e->pub.old) &&
- !rte_mergable(e->new_best, e->pub.new) &&
- !rte_mergable(e->old_best, e->pub.old))
+ (e->new != e->old) &&
+ !rte_mergable(e->new_best, e->new) &&
+ !rte_mergable(e->old_best, e->old))
return 0;
if (e->new_best)
else
c->stats.exp_withdraws_received++;
+ struct rte_export *ep = &e->pub;
+
/* Prepare new merged route */
if (e->new_best)
- e->pub.new = rt_export_merged(c, e->pub.net, &(e->rt_free), rte_update_pool, 0);
+ {
+ ep->new = rt_export_merged(c, e->net, &(e->rt_free), rte_update_pool, 0);
+ ep->new_src = e->net->routes->attrs->src;
+ }
/* Check old merged route */
- if (e->old_best && !bmap_test(&c->export_map, e->old_best->id))
- e->pub.old = NULL;
+ if (e->old_best)
+ ep->old = bmap_test(&c->export_map, e->old_best->id) ? e->old_best : NULL;
- if (!e->pub.new && !e->pub.old)
+ if (!ep->new && !ep->old)
return 0;
- e->pub.new_src = e->pub.new ? e->pub.new->attrs->src : NULL;
- e->pub.old_src = e->pub.old ? e->pub.old->attrs->src : NULL;
-
+ ep->old_src = ep->old ? ep->old->attrs->src : NULL;
return 1;
}
+static void
+rte_export(struct channel *c, struct rte_export_internal *e)
+{
+ uint ra_mode = c->ra_mode;
+ _Bool accepted = 0;
+
+ switch (ra_mode)
+ {
+ case RA_OPTIMAL:
+ if (e->new_best == e->old_best)
+ break;
+
+ e->new = e->new_best;
+ e->old = e->old_best;
+ /* fall through */
+ case RA_ANY:
+ accepted = rt_notify_basic(c, e);
+ break;
+
+ case RA_ACCEPTED:
+ accepted = rt_notify_accepted(c, e);
+ break;
+
+ case RA_MERGED:
+ accepted = rt_notify_merged(c, e);
+ break;
+
+ default:
+ bug("Strange channel route announcement mode");
+ }
+
+ if (accepted)
+ {
+ e->pub.net = e->net->n.addr;
+ do_rt_notify(c, &e->pub, e->refeed);
+ }
+
+ if (e->rt_free)
+ rte_free(e->rt_free);
+
+ if (e->old && (!e->new || (e->new->id != e->old->id)))
+ bmap_clear(&c->export_reject_map, e->old->id);
+}
+
/**
* rte_announce - announce a routing table change
continue;
}
- struct rte_export_internal e = {
- .pub = {
- .net = net,
- .new_src = new ? new->attrs->src : NULL,
- .new = new,
- .old_src = old ? old->attrs->src : NULL,
- .old = old,
- },
- .new_best = new_best,
- .old_best = old_best,
+ struct rte_export_internal rei = {
+ .net = net,
+ .new = new, .old = old,
+ .new_best = new_best, .old_best = old_best,
};
-
- switch (c->ra_mode)
- {
- case RA_OPTIMAL:
- if (new_best != old_best)
- {
- e.pub.new = new_best;
- e.pub.new_src = new_best ? new_best->attrs->src : NULL;
- e.pub.old = old_best;
- e.pub.old_src = old_best ? old_best->attrs->src : NULL;
- if (!rt_notify_basic(c, &e))
- goto next_channel;
- }
- break;
-
- case RA_ANY:
- if (new != old)
- if (!rt_notify_basic(c, &e))
- goto next_channel;
- break;
-
- case RA_ACCEPTED:
- if (!rt_notify_accepted(c, &e))
- goto next_channel;
- break;
-
- case RA_MERGED:
- if (!rt_notify_merged(c, &e))
- goto next_channel;
- break;
- }
-
- do_rt_notify(c, &e);
-
-next_channel:
- /* Discard temporary rte */
- if (e.rt_free)
- rte_free(e.rt_free);
-
- /* Drop the old stored rejection if applicable.
- * new->id == old->id happens when updating hostentries. */
- if (old && (!new || (new->id != old->id)))
- bmap_clear(&c->export_reject_map, old->id);
+
+ rte_export(c, &rei);
}
}
rte_update_unlock();
}
-/* Check channel for best route to given net whether it would be exported */
-int
-rt_examine(struct channel *c, net_addr *a)
-{
- net *n = net_find(c->table, a);
- rte *rt = n ? n->routes : NULL;
-
- if (!rte_is_valid(rt))
- return 0;
-
- if (bmap_test(&c->export_reject_map, rt->id))
- return 0;
-
- rte_update_lock();
-
- struct proto *p = c->proto;
- /* Rest is stripped down export_filter() */
- int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0;
- if (v == RIC_PROCESS)
- v = (f_run(c->out_filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT);
-
- /* Discard temporary rte */
- if (rt != n->routes)
- rte_free(rt);
-
- rte_update_unlock();
-
- return v > 0;
-}
-
-
/**
* rt_refresh_begin - start a refresh cycle
* @t: related routing table
DBG("\tdone\n");
}
+static uint
+rt_feed_channel_net_internal(struct channel *c, net *nn)
+{
+ struct rte_export_internal rei = {
+ .net = nn,
+ .new_best = nn->routes,
+ .new = nn->routes,
+ .refeed = 1,
+ };
+
+ rte_update_lock();
+ if (c->ra_mode == RA_ANY)
+ {
+ uint cnt = 0;
+ for (rei.new = nn->routes; rei.new; rei.new = rei.new->next)
+ if (rte_is_valid(rei.new))
+ rte_export(c, &rei), cnt++;
+ return cnt;
+ }
+ else
+ {
+ rte_export(c, &rei);
+ return 1;
+ }
+ rte_update_unlock();
+}
+
+void
+rt_feed_channel_net(struct channel *c, net_addr *n)
+{
+ net *nn = net_find(c->table, n);
+ if (!nn)
+ return;
+
+ rt_feed_channel_net_internal(c, nn);
+}
+
/**
* rt_feed_channel - advertise all routes to a channel
* @c: channel to be fed
return 0;
}
- for (rte *e = n->routes; e; e = e->next)
- {
- if (c->export_state != ES_FEEDING)
- goto done;
-
- if (rte_is_valid(e))
- {
- max_feed--;
-
- struct rte_export_internal ee = {
- .pub = {
- .net = n,
- },
- .new_best = n->routes,
- .old_best = n->routes,
- .refeed = c->refeeding,
- };
-
- switch (c->ra_mode) {
- case RA_OPTIMAL:
- case RA_ANY:
- ee.pub.new = e;
- ee.pub.new_src = e->attrs->src;
- ee.pub.old = e;
- ee.pub.old_src = e->attrs->src;
- if (!rt_notify_basic(c, &ee))
- goto next_rte;
- break;
- case RA_ACCEPTED:
- if (!rt_notify_accepted(c, &ee))
- goto next_rte;
- break;
- case RA_MERGED:
- if (!rt_notify_merged(c, &ee))
- goto next_rte;
- break;
- default:
- ASSERT(0);
- }
-
- do_rt_notify(c, &ee);
-
- /* Discard temporary rte */
-next_rte:
- if (ee.rt_free)
- rte_free(ee.rt_free);
- }
-
- if (c->ra_mode != RA_ANY)
- break;
- }
+ max_feed -= rt_feed_channel_net_internal(c, n);
}
FIB_ITERATE_END;
-done:
c->feed_active = 0;
return 1;
}
if (rt_metric > BABEL_INFINITY)
{
log(L_WARN "%s: Invalid babel_metric value %u for route %N",
- p->p.name, rt_metric, export->net->n.addr);
+ p->p.name, rt_metric, export->net);
rt_metric = BABEL_INFINITY;
}
- e = babel_get_entry(p, export->net->n.addr);
+ e = babel_get_entry(p, export->net);
/* Activate triggered updates */
if ((e->valid != BABEL_ENTRY_VALID) ||
else
{
/* Withdraw */
- e = babel_find_entry(p, export->net->n.addr);
+ e = babel_find_entry(p, export->net);
if (!e || e->valid != BABEL_ENTRY_VALID)
return;
path = e->old_src->global_id;
}
- px = bgp_get_prefix(c, e->net->n.addr, c->add_path_tx ? path : 0);
+ px = bgp_get_prefix(c, e->net, c->add_path_tx ? path : 0);
add_tail(&buck->prefixes, &px->buck_node);
bgp_schedule_packet(p->conn, c, PKT_UPDATE);
{
case BGP_RR_REQUEST:
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
- channel_request_feeding(&c->c);
+ channel_request_feeding(&c->c, NULL);
break;
case BGP_RR_BEGIN:
if (!e->new)
{
- nf = fib_find(&p->rtf, e->net->n.addr);
+ nf = fib_find(&p->rtf, e->net);
if (!nf || !nf->external_rte)
return;
if (m1 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N",
- p->p.name, m1, e->net->n.addr);
+ p->p.name, m1, e->net);
m1 = LSINFINITY;
}
if (m2 > LSINFINITY)
{
log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N",
- p->p.name, m2, e->net->n.addr);
+ p->p.name, m2, e->net);
m2 = LSINFINITY;
}
if (ipa_zero(fwd))
{
log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N",
- p->p.name, e->net->n.addr);
+ p->p.name, e->net);
return;
}
}
- nf = fib_get(&p->rtf, e->net->n.addr);
+ nf = fib_get(&p->rtf, e->net);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
nf->external_rte = 1;
}
p->feed_begin = NULL;
if (p->run < p->repeat)
- channel_request_feeding(c);
+ channel_request_feeding(c, NULL);
else
PLOG("feed done");
}
if (dst->table->pipe_busy)
{
log(L_ERR "Pipe loop detected when sending %N to table %s",
- export->net->n.addr, dst->table->name);
+ export->net, dst->table->name);
return;
}
};
src_ch->table->pipe_busy = 1;
- rte_update(dst, export->net->n.addr, &e0);
+ rte_update(dst, export->net, &e0);
src_ch->table->pipe_busy = 0;
}
else
{
src_ch->table->pipe_busy = 1;
- rte_withdraw(dst, export->net->n.addr, export->old_src);
+ rte_withdraw(dst, export->net, export->old_src);
src_ch->table->pipe_busy = 0;
}
}
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((C == p->pri) ? p->sec : p->pri, NULL);
}
* The RAdv protocol could receive routes (through radv_preexport() and
* radv_rt_notify()), but only the configured trigger route is tracked (in
* &active var). When a radv protocol is reconfigured, the connected routing
- * table is examined (in radv_check_active()) to have proper &active value in
+ * table is examined to have proper &active value in
* case of the specified trigger prefix was changed.
*
* Supported standards:
}
static inline int
-radv_net_match_trigger(struct radv_config *cf, net *n)
+radv_net_match_trigger(struct radv_config *cf, net_addr *n)
{
- return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
+ return radv_trigger_valid(cf) && net_equal(n, &cf->trigger);
}
int
// struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (P->cf);
- if (radv_net_match_trigger(cf, (*new)->net))
+ if (radv_net_match_trigger(cf, (*new)->net->n.addr))
return RIC_PROCESS;
if (cf->propagate_routes)
(preference != RA_PREF_HIGH))
{
log(L_WARN "%s: Invalid ra_preference value %u on route %N",
- p->p.name, preference, e->net->n.addr);
+ p->p.name, preference, e->net);
preference = RA_PREF_MEDIUM;
preference_set = 1;
lifetime = 0;
lifetime_set = 1;
}
- rt = fib_get(&p->routes, e->net->n.addr);
+ rt = fib_get(&p->routes, e->net);
/* Ignore update if nothing changed */
if (rt->valid &&
else
{
/* Withdraw */
- rt = fib_find(&p->routes, e->net->n.addr);
+ rt = fib_find(&p->routes, e->net);
if (!rt || !rt->valid)
return;
p->prune_time = next;
}
-static int
-radv_check_active(struct radv_proto *p)
-{
- struct radv_config *cf = (struct radv_config *) (p->p.cf);
-
- if (!radv_trigger_valid(cf))
- return 1;
-
- struct channel *c = p->p.main_channel;
- return rt_examine(c, &cf->trigger);
-}
-
static void
radv_postconfig(struct proto_config *CF)
{
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
return 0;
- P->cf = CF; /* radv_check_active() requires proper P->cf */
- p->active = radv_check_active(p);
+ P->cf = CF;
/* Allocate or free FIB */
radv_set_fib(p, new->propagate_routes);
/* 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(p->p.main_channel, NULL);
+ else if (!net_equal(&old->trigger, &new->trigger))
+ {
+ /* On trigger change, refeed the routes for which the preexport may have changed */
+ channel_request_feeding(p->p.main_channel, &old->trigger);
+ channel_request_feeding(p->p.main_channel, &new->trigger);
+ }
+
struct iface *iface;
WALK_LIST(iface, iface_list)
if (rt_metric > p->infinity)
{
log(L_WARN "%s: Invalid rip_metric value %u for route %N",
- p->p.name, rt_metric, e->net->n.addr);
+ p->p.name, rt_metric, e->net);
rt_metric = p->infinity;
}
if (rt_tag > 0xffff)
{
log(L_WARN "%s: Invalid rip_tag value %u for route %N",
- p->p.name, rt_tag, e->net->n.addr);
+ p->p.name, rt_tag, e->net);
rt_metric = p->infinity;
rt_tag = 0;
}
* collection.
*/
- en = fib_get(&p->rtable, e->net->n.addr);
+ en = fib_get(&p->rtable, e->net);
old_metric = en->valid ? en->metric : -1;
else
{
/* Withdraw */
- en = fib_find(&p->rtable, e->net->n.addr);
+ en = fib_find(&p->rtable, e->net);
if (!en || en->valid != RIP_ENTRY_VALID)
return;
}
void
-krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
+krt_replace_rte(struct krt_proto *p, rte *new, rte *old)
{
int err = 0;
void
-krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
+krt_replace_rte(struct krt_proto *p, rte *new, rte *old)
{
int err = 0;
if (krt_is_installed(p, n))
{
/* FIXME: this does not work if gw is changed in export filter */
- krt_replace_rte(p, n, NULL, n->routes);
+ krt_replace_rte(p, NULL, n->routes);
}
}
FIB_WALK_END;
update:
krt_trace_in(p, new, "updating");
- krt_replace_rte(p, n, new, e);
+ krt_replace_rte(p, new, e);
goto done;
delete:
krt_trace_in(p, e, "deleting");
- krt_replace_rte(p, n, NULL, e);
+ krt_replace_rte(p, NULL, e);
goto done;
done:
if (new)
{
krt_trace_in(p, new, "installing");
- krt_replace_rte(p, n, new, NULL);
+ krt_replace_rte(p, new, NULL);
}
if (rt_free)
void
krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
{
- net *net = e->net;
-
switch (src)
{
case KRT_SRC_BIRD:
if (new)
{
krt_trace_in(p, e, "[redirect] deleting");
- krt_replace_rte(p, net, NULL, e);
+ krt_replace_rte(p, NULL, e);
}
/* If !new, it is probably echo of our deletion */
break;
* but if we processed the update as usual, we would send withdraw to the
* kernel, which would remove the new imported route instead.
*/
- rte *best = e->net->routes;
- if (!e->new && best && (best->attrs->src->proto == ch->proto))
+ if (!e->new && (e->new_src->proto == ch->proto))
return;
#endif
if (p->initialized) /* Before first scan we don't touch the routes */
- krt_replace_rte(p, e->net, e->new, e->old);
+ krt_replace_rte(p, e->new, e->old);
}
static void
int krt_capable(rte *e);
void krt_do_scan(struct krt_proto *);
-void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old);
+void krt_replace_rte(struct krt_proto *p, rte *new, rte *old);
int krt_sys_get_attr(const eattr *a, byte *buf, int buflen);