Hidden rte_get_temp() into rte_update().
Split rte_update() / rte_withdraw().
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);
-
-/* Moved from route.h to avoid dependency conflicts */
-static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }
-
-static inline void
-rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
-{
- if (c->in_table && !rte_update_in(c, n, new, src))
- return;
-
- rte_update2(c, n, new, src);
-}
-
-
#endif
#define RIC_REJECT -1 /* Rejected by protocol */
#define RIC_DROP -2 /* Silently dropped by protocol */
+/**
+ * rte_update - enter a new update to a routing table
+ * @c: channel doing the update
+ * @net: network address
+ * @rte: a &rte representing the new route
+ *
+ * This function imports a new route to the appropriate table (via the channel).
+ * Table keys are @net (obligatory) and @rte->attrs->src.
+ * Both the @net and @rte pointers can be local.
+ *
+ * The route attributes (@rte->attrs) are obligatory. They can be also allocated
+ * locally. Anyway, if you use an already-cached attribute object, you shall
+ * call rta_clone() on that object yourself. (This semantics may change in future.)
+ *
+ * If the route attributes are local, you may set @rte->attrs->src to NULL, then
+ * the protocol's default route source will be supplied.
+ *
+ * When rte_update() gets a route, it automatically validates it. This includes
+ * checking for validity of the given network and next hop addresses and also
+ * checking for host-scope or link-scope routes. Then the import filters are
+ * processed and if accepted, the route is passed to route table recalculation.
+ *
+ * The accepted routes are then inserted into the table, replacing the old route
+ * (key is the @net together with @rte->attrs->src). Then the route is announced
+ * to all the channels connected to the table using the standard export mechanism.
+ *
+ * All memory used for temporary allocations is taken from a special linpool
+ * @rte_update_pool and freed when rte_update() finishes.
+ */
+void rte_update(struct channel *c, net_addr *net, struct rte *rte);
+
+/**
+ * rte_withdraw - withdraw a route from a routing table
+ * @c: channel doing the withdraw
+ * @net: network address
+ * @src: the route source identifier
+ *
+ * This function withdraws a previously announced route from the table.
+ * No import filter is called. This function is idempotent. If no route
+ * is found under the given key, it does nothing.
+ *
+ * If @src is NULL, the protocol's default route source is used.
+ */
+void rte_withdraw(struct channel *c, net_addr *net, struct rte_src *src);
+
extern list routing_tables;
struct config;
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);
-rte *rte_get_temp(struct rta *);
-void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
-/* rte_update() moved to protocol.h to avoid dependency conflicts */
int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
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 rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
+rte *rte_store(rte *);
static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
rte *rte_cow_rta(rte *r, linpool *lp);
void rte_init_tmp_attrs(struct rte *r, linpool *lp, uint max);
void rt_dump_all(void);
int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
-int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);
DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip);
/* Use iface ID as local source ID */
- struct rte_src *src = rt_get_source(P, ad->iface->index);
- rte_update2(c, net, NULL, src);
+ rte_withdraw(c, net, rt_get_source(P, ad->iface->index));
}
else if (flags & IF_CHANGE_UP)
{
- rta *a;
- rte *e;
-
DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
if (cf->check_link && !(ad->iface->flags & IF_LINK_UP))
return;
- /* Use iface ID as local source ID */
- struct rte_src *src = rt_get_source(P, ad->iface->index);
-
rta a0 = {
- .src = src,
+ /* Use iface ID as local source ID */
+ .src = rt_get_source(P, ad->iface->index),
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh.iface = ad->iface,
};
-
- a = rta_lookup(&a0);
- e = rte_get_temp(a);
- e->pflags = 0;
- rte_update2(c, net, e, src);
+ rte e0 = {
+ .attrs = rta_lookup(&a0),
+ };
+ rte_update(c, net, &e0);
}
}
return e;
}
-/**
- * rte_get_temp - get a temporary &rte
- * @a: attributes to assign to the new route (a &rta; in case it's
- * un-cached, rte_update() will create a cached copy automatically)
- *
- * Create a temporary &rte and bind it with the attributes @a.
- * Also set route preference to the default preference set for
- * the protocol.
- */
rte *
-rte_get_temp(rta *a)
+rte_do_cow(rte *r)
{
rte *e = sl_alloc(rte_slab);
- e->attrs = a;
- e->id = 0;
+ memcpy(e, r, sizeof(rte));
+ e->attrs = rta_clone(r->attrs);
e->flags = 0;
- e->pref = 0;
return e;
}
rte *
-rte_do_cow(rte *r)
+rte_store(rte *r)
{
rte *e = sl_alloc(rte_slab);
-
memcpy(e, r, sizeof(rte));
- e->attrs = rta_clone(r->attrs);
- e->flags = 0;
+ if (e->attrs->aflags & RTAF_CACHED)
+ e->attrs = rta_clone(r->attrs);
+ else
+ e->attrs = rta_lookup(r->attrs);
return e;
}
}
}
-/**
- * rte_update - enter a new update to a routing table
- * @table: table to be updated
- * @c: channel doing the update
- * @net: network node
- * @p: protocol submitting the update
- * @src: protocol originating the update
- * @new: a &rte representing the new route or %NULL for route removal.
- *
- * This function is called by the routing protocols whenever they discover
- * a new route or wish to update/remove an existing route. The right announcement
- * sequence is to build route attributes first (either un-cached with @aflags set
- * to zero or a cached one using rta_lookup(); in this case please note that
- * you need to increase the use count of the attributes yourself by calling
- * rta_clone()), call rte_get_temp() to obtain a temporary &rte, fill in all
- * the appropriate data and finally submit the new &rte by calling rte_update().
- *
- * @src specifies the protocol that originally created the route and the meaning
- * of protocol-dependent data of @new. If @new is not %NULL, @src have to be the
- * same value as @new->attrs->proto. @p specifies the protocol that called
- * rte_update(). In most cases it is the same protocol as @src. rte_update()
- * stores @p in @new->sender;
- *
- * When rte_update() gets any route, it automatically validates it (checks,
- * whether the network and next hop address are valid IP addresses and also
- * whether a normal routing protocol doesn't try to smuggle a host or link
- * scope route to the table), converts all protocol dependent attributes stored
- * in the &rte to temporary extended attributes, consults import filters of the
- * protocol to see if the route should be accepted and/or its attributes modified,
- * stores the temporary attributes back to the &rte.
- *
- * Now, having a "public" version of the route, we
- * automatically find any old route defined by the protocol @src
- * for network @n, replace it by the new one (or removing it if @new is %NULL),
- * recalculate the optimal route for this destination and finally broadcast
- * the change (if any) to all routing protocols by calling rte_announce().
- *
- * All memory used for attribute lists and other temporary allocations is taken
- * from a special linear pool @rte_update_pool and freed when rte_update()
- * finishes.
- */
-
-void
+static void
rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
struct proto *p = c->proto;
rte_update_unlock();
}
+static int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
+
+void
+rte_withdraw(struct channel *c, net_addr *n, struct rte_src *src)
+{
+ if (!src)
+ src = c->proto->main_source;
+
+ if (!c->in_table || rte_update_in(c, n, NULL, src))
+ rte_update2(c, n, NULL, src ?: c->proto->main_source);
+}
+
+void
+rte_update(struct channel *c, net_addr *n, struct rte *new)
+{
+ ASSERT(new);
+ ASSERT(new->attrs);
+
+ rte *e = sl_alloc(rte_slab);
+ *e = *new;
+
+ if (!e->attrs->src)
+ {
+ ASSERT(!rta_is_cached(e->attrs));
+ e->attrs->src = c->proto->main_source;
+ }
+
+ if (!c->in_table || rte_update_in(c, n, e, e->attrs->src))
+ rte_update2(c, n, e, e->attrs->src);
+}
+
/* Independent call to rte_announce(), used from next hop
recalculation, outside of rte_update(). new must be non-NULL */
static inline void
* Import table
*/
-int
+static int
rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
struct rtable *tab = c->in_table;
.nh.iface = r->neigh->ifa->iface,
};
- rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a);
- rte->u.babel.seqno = r->seqno;
- rte->u.babel.metric = r->metric;
- rte->u.babel.router_id = r->router_id;
- rte->pflags = EA_ID_FLAG(EA_BABEL_METRIC) | EA_ID_FLAG(EA_BABEL_ROUTER_ID);
+ rte e0 = {
+ .attrs = rta_lookup(&a0),
+ .u.babel = {
+ .seqno = r->seqno,
+ .metric = r->metric,
+ .router_id = r->router_id,
+ },
+ .pflags = EA_ID_FLAG(EA_BABEL_METRIC) | EA_ID_FLAG(EA_BABEL_ROUTER_ID),
+ };
e->unreachable = 0;
- rte_update2(c, e->n.addr, rte, p->p.main_source);
+ rte_update(c, e->n.addr, &e0);
}
else if (e->valid && (e->router_id != p->router_id))
{
.dest = RTD_UNREACHABLE,
};
- rta *a = rta_lookup(&a0);
- rte *rte = rte_get_temp(a);
- memset(&rte->u.babel, 0, sizeof(rte->u.babel));
- rte->pflags = 0;
- rte->pref = 1;
+ rte e0 = {
+ .attrs = &a0,
+ .pref = 1,
+ };
e->unreachable = 1;
- rte_update2(c, e->n.addr, rte, p->p.main_source);
+ rte_update(c, e->n.addr, &e0);
}
else
{
/* Retraction */
e->unreachable = 0;
- rte_update2(c, e->n.addr, NULL, p->p.main_source);
+ rte_withdraw(c, e->n.addr, NULL);
}
}
{
struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
e->unreachable = 0;
- rte_update2(c, e->n.addr, NULL, p->p.main_source);
+ rte_withdraw(c, e->n.addr, NULL);
}
if (!a0)
{
/* Route withdraw */
- rte_update3(&s->channel->c, n, NULL, s->last_src);
+ rte_withdraw(&(s->channel->c), n, s->last_src);
return;
}
a0->eattrs = ea;
}
- rta *a = rta_clone(s->cached_rta);
- rte *e = rte_get_temp(a);
+ rte e0 = {
+ .attrs = rta_clone(s->cached_rta),
+ .u.bgp.stale = -1,
+ };
- e->pflags = 0;
- e->u.bgp.suppressed = 0;
- e->u.bgp.stale = -1;
- rte_update3(&s->channel->c, n, e, s->last_src);
+ rte_update(&(s->channel->c), n, &e0);
}
static void
if (reload || ort_changed(nf, &a0))
{
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
+ rte e0 = {
+ .attrs = rta_lookup(&a0),
+ .u.ospf.metric1 = nf->old_metric1 = nf->n.metric1,
+ .u.ospf.metric2 = nf->old_metric2 = nf->n.metric2,
+ .u.ospf.tag = nf->old_tag = nf->n.tag,
+ .u.ospf.router_id = nf->old_rid = nf->n.rid,
+ .pflags = EA_ID_FLAG(EA_OSPF_METRIC1) | EA_ID_FLAG(EA_OSPF_ROUTER_ID),
+ };
rta_free(nf->old_rta);
- nf->old_rta = rta_clone(a);
- e->u.ospf.metric1 = nf->old_metric1 = nf->n.metric1;
- e->u.ospf.metric2 = nf->old_metric2 = nf->n.metric2;
- e->u.ospf.tag = nf->old_tag = nf->n.tag;
- e->u.ospf.router_id = nf->old_rid = nf->n.rid;
- e->pflags = EA_ID_FLAG(EA_OSPF_METRIC1) | EA_ID_FLAG(EA_OSPF_ROUTER_ID);
+ nf->old_rta = rta_clone(e0.attrs);
if (nf->n.type == RTS_OSPF_EXT2)
- e->pflags |= EA_ID_FLAG(EA_OSPF_METRIC2);
+ e0.pflags |= EA_ID_FLAG(EA_OSPF_METRIC2);
/* Perhaps onfly if tag is non-zero? */
if ((nf->n.type == RTS_OSPF_EXT1) || (nf->n.type == RTS_OSPF_EXT2))
- e->pflags |= EA_ID_FLAG(EA_OSPF_TAG);
+ e0.pflags |= EA_ID_FLAG(EA_OSPF_TAG);
DBG("Mod rte type %d - %N via %I on iface %s, met %d\n",
a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1);
- rte_update(&p->p, nf->fn.addr, e);
+
+ rte_update(p->p.main_channel, nf->fn.addr, &e0);
}
}
else if (nf->old_rta)
rta_free(nf->old_rta);
nf->old_rta = NULL;
- rte_update(&p->p, nf->fn.addr, NULL);
+ rte_withdraw(p->p.main_channel, nf->fn.addr, NULL);
}
/* Remove unused rt entry, some special entries are persistent */
}
FIB_ITERATE_END;
-
WALK_LIST(oa, p->area_list)
{
/* Cleanup ASBR hash tables */
clock_gettime(CLOCK_MONOTONIC, &ts_generated);
- for (uint i=0; i<N; i++) {
- rte *e = rte_get_temp(p->data[i].a);
- e->pflags = 0;
-
- rte_update(P, &(p->data[i].net), e);
+ for (uint i=0; i<N; i++)
+ {
+ rte e0 = { .attrs = p->data[i].a, };
+ rte_update(P->main_channel, &(p->data[i].net), &e0);
}
clock_gettime(CLOCK_MONOTONIC, &ts_update);
if (!p->keep)
for (uint i=0; i<N; i++)
- rte_update(P, &(p->data[i].net), NULL);
+ rte_withdraw(P->main_channel, &(p->data[i].net), NULL);
clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri;
struct rte_src *src;
- rte *e;
+ rte e0 = {}, *e = &e0;
rta *a;
if (!new && !old)
a->aflags = 0;
a->hostentry = NULL;
- e = rte_get_temp(a);
+
+ e->attrs = rta_lookup(a);
e->pflags = 0;
/* Copy protocol specific embedded attributes. */
}
src_ch->table->pipe_busy = 1;
- rte_update2(dst, n->n.addr, e, src);
+ if (e)
+ rte_update(dst, n->n.addr, e);
+ else
+ rte_withdraw(dst, n->n.addr, src);
src_ch->table->pipe_busy = 0;
}
a0.nh.iface = rt->from->nbr->iface;
}
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
-
- e->u.rip.from = a0.nh.iface;
- e->u.rip.metric = rt_metric;
- e->u.rip.tag = rt_tag;
- e->pflags = EA_ID_FLAG(EA_RIP_METRIC) | EA_ID_FLAG(EA_RIP_TAG);
+ rte e0 = {
+ .attrs = rta_lookup(&a0),
+ .u.rip = {
+ .from = a0.nh.iface,
+ .metric = rt_metric,
+ .tag = rt_tag,
+ },
+ .pflags = EA_ID_FLAG(EA_RIP_METRIC) | EA_ID_FLAG(EA_RIP_TAG)
+ };
- rte_update(&p->p, en->n.addr, e);
+ rte_update(p->p.main_channel, en->n.addr, &e0);
}
else
- {
- /* Withdraw */
- rte_update(&p->p, en->n.addr, NULL);
- }
+ rte_withdraw(p->p.main_channel, en->n.addr, NULL);
}
/**
.dest = RTD_NONE,
};
- rta *a = rta_lookup(&a0);
- rte *e = rte_get_temp(a);
+ rte e0 = { .attrs = rta_lookup(&a0) };
- e->pflags = 0;
-
- rte_update2(channel, &pfxr->n, e, a0.src);
+ rte_update(channel, &pfxr->n, &e0);
}
void
rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr)
{
struct rpki_proto *p = cache->p;
- rte_update2(channel, &pfxr->n, NULL, p->p.main_source);
+ rte_withdraw(channel, &pfxr->n, NULL);
}
return;
/* We skip rta_lookup() here */
- rte *e = rte_get_temp(a);
- e->pflags = 0;
+ rte e0 = { .attrs = a }, *e = &e0;
if (r->cmds)
f_eval_rte(r->cmds, &e, static_lp);
- rte_update(&p->p, r->net, e);
+ rte_update(p->p.main_channel, r->net, e);
r->state = SRS_CLEAN;
if (r->cmds)
if (r->state == SRS_DOWN)
return;
- rte_update(&p->p, r->net, NULL);
+ rte_withdraw(p->p.main_channel, r->net, NULL);
r->state = SRS_DOWN;
}
static_remove_rte(struct static_proto *p, struct static_route *r)
{
if (r->state)
- rte_update(&p->p, r->net, NULL);
+ rte_withdraw(p->p.main_channel, r->net, NULL);
static_reset_rte(p, r);
}
/* p is NULL iff KRT_SHARED_SOCKET and !scan */
int ipv6;
- rte *e;
net *net;
sockaddr dst, gate, mask;
ip_addr idst, igate, imask;
net = net_get(p->p.main_channel->table, &ndst);
rta a = {
- .src = p->p.main_source,
.source = RTS_INHERIT,
.scope = SCOPE_UNIVERSE,
};
}
}
- done:
- e = rte_get_temp(&a);
+ done:;
+ rte e0 = {}, *e = &e0;
+ e->attrs = &a;
e->net = net;
e->u.krt.src = src;
e->u.krt.proto = src2;
- e->u.krt.seen = 0;
- e->u.krt.best = 0;
- e->u.krt.metric = 0;
if (scan)
krt_got_route(p, e);
static void
nl_announce_route(struct nl_parse_state *s)
{
- rte *e = rte_get_temp(s->attrs);
+ rte e0 = {}, *e = &e0;
+ e->attrs = 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)
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;
static void
krt_learn_announce_update(struct krt_proto *p, rte *e)
{
- net *n = e->net;
- rta *aa = rta_clone(e->attrs);
- rte *ee = rte_get_temp(aa);
- ee->pflags = EA_ID_FLAG(EA_KRT_SOURCE) | EA_ID_FLAG(EA_KRT_METRIC);
- ee->u.krt = e->u.krt;
- rte_update(&p->p, n->n.addr, ee);
+ rte e0 = {
+ .attrs = rta_clone(e->attrs),
+ .pflags = EA_ID_FLAG(EA_KRT_SOURCE) | EA_ID_FLAG(EA_KRT_METRIC),
+ .u.krt = e->u.krt,
+ };
+
+ rte_update(p->p.main_channel, e->net->n.addr, &e0);
}
static void
-krt_learn_announce_delete(struct krt_proto *p, net *n)
+krt_learn_announce_delete(struct krt_proto *p, net_addr *n)
{
- rte_update(&p->p, n->n.addr, NULL);
+ rte_withdraw(p->p.main_channel, n, NULL);
}
/* Called when alien route is discovered during scan */
net *n = net_get(&p->krt_table, n0->n.addr);
rte *m, **mm;
- e->attrs = rta_lookup(e->attrs);
+ e = rte_store(e);
for(mm=&n->routes; m = *mm; mm=&m->next)
if (krt_same_key(m, e))
{
DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
if (old_best)
- krt_learn_announce_delete(p, n);
+ krt_learn_announce_delete(p, n->n.addr);
FIB_ITERATE_PUT(&fit);
fib_delete(fib, n);
net *n = net_get(&p->krt_table, n0->n.addr);
rte *g, **gg, *best, **bestp, *old_best;
- e->attrs = rta_lookup(e->attrs);
+ e = rte_store(e);
old_best = n->routes;
for(gg=&n->routes; g = *gg; gg = &g->next)
if (best)
krt_learn_announce_update(p, best);
else
- krt_learn_announce_delete(p, n);
+ krt_learn_announce_delete(p, n->n.addr);
}
}
if (KRT_CF->learn)
krt_learn_scan(p, e);
else
- {
- krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
- rte_free(e);
- }
+ krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
return;
}
#endif
goto done;
done:
- rte_free(e);
-
if (rt_free)
rte_free(rt_free);
}
#endif
}
- rte_free(e);
}
/*