0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

Route import API redefinition.

Hidden rte_get_temp() into rte_update().
Split rte_update() / rte_withdraw().
This commit is contained in:
Maria Matejka 2020-01-28 11:42:46 +01:00 committed by Maria Matejka
parent 8c7263d20d
commit 86dbe0980c
15 changed files with 176 additions and 194 deletions

View File

@ -624,18 +624,4 @@ void *channel_config_new(const struct channel_class *cc, const char *name, uint
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

View File

@ -286,6 +286,51 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#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, const 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, const net_addr *net, struct rte_src *src);
extern list routing_tables;
struct config;
@ -302,9 +347,6 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
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);
@ -314,6 +356,7 @@ void rt_schedule_prune(rtable *t);
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);
@ -324,7 +367,6 @@ void rt_dump(rtable *);
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);

View File

@ -66,34 +66,27 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
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);
}
}

View File

@ -267,27 +267,6 @@ rte_find(net *net, struct rte_src *src)
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 *e = sl_alloc(rte_slab);
e->attrs = a;
e->id = 0;
e->flags = 0;
e->pref = 0;
return e;
}
rte *
rte_do_cow(rte *r)
{
@ -299,6 +278,18 @@ rte_do_cow(rte *r)
return e;
}
rte *
rte_store(rte *r)
{
rte *e = sl_alloc(rte_slab);
memcpy(e, r, sizeof(rte));
if (e->attrs->aflags & RTAF_CACHED)
e->attrs = rta_clone(r->attrs);
else
e->attrs = rta_lookup(r->attrs);
return e;
}
/**
* rte_cow_rta - get a private writable copy of &rte with writable &rta
* @r: a route entry to be copied
@ -1382,49 +1373,7 @@ rte_unhide_dummy_routes(net *net, rte **dummy)
}
}
/**
* 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;
@ -1528,6 +1477,29 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
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, const net_addr *n, struct rte_src *src)
{
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, const net_addr *n, struct rte *new)
{
ASSERT(new);
ASSERT(new->attrs);
ASSERT(new->attrs->src);
rte *e = sl_alloc(rte_slab);
*e = *new;
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
@ -2415,7 +2387,7 @@ rt_feed_channel_abort(struct channel *c)
* 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;

View File

@ -640,15 +640,18 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.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))
{
@ -660,20 +663,19 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.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, p->p.main_source);
}
}
@ -683,7 +685,7 @@ babel_announce_retraction(struct babel_proto *p, struct babel_entry *e)
{
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, p->p.main_source);
}

View File

@ -1304,7 +1304,7 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
if (!a0)
{
/* Route withdraw */
rte_update3(&s->channel->c, n, NULL, s->last_src);
rte_withdraw(&(s->channel->c), n, s->last_src);
return;
}
@ -1319,13 +1319,12 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
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

View File

@ -2052,27 +2052,29 @@ again1:
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)
@ -2081,7 +2083,7 @@ again1:
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, p->p.main_source);
}
/* Remove unused rt entry, some special entries are persistent */
@ -2097,7 +2099,6 @@ again1:
}
FIB_ITERATE_END;
WALK_LIST(oa, p->area_list)
{
/* Cleanup ASBR hash tables */

View File

@ -160,18 +160,17 @@ perf_loop(void *data)
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), p->p.main_source);
clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);

View File

@ -50,7 +50,7 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
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)
@ -70,7 +70,8 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
a->aflags = 0;
a->hostentry = NULL;
e = rte_get_temp(a);
e->attrs = rta_lookup(a);
e->pflags = 0;
/* Copy protocol specific embedded attributes. */
@ -93,7 +94,10 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
}
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;
}

View File

@ -187,21 +187,20 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
a0.nh.iface = rt->from->ifa->iface;
}
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
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)
};
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_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, p->p.main_source);
}
/**

View File

@ -127,19 +127,16 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
.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, p->p.main_source);
}

View File

@ -99,13 +99,12 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
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)
@ -117,7 +116,7 @@ withdraw:
if (r->state == SRS_DOWN)
return;
rte_update(&p->p, r->net, NULL);
rte_withdraw(p->p.main_channel, r->net, p->p.main_source);
r->state = SRS_DOWN;
}
@ -250,7 +249,7 @@ static void
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);
}

View File

@ -374,7 +374,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
/* p is NULL iff KRT_SHARED_SOCKET and !scan */
int ipv6;
rte *e;
net *net;
sockaddr dst, gate, mask;
ip_addr idst, igate, imask;
@ -495,7 +494,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
net = net_get(p->p.main_channel->table, &ndst);
rta a = {
.src = p->p.main_source,
.source = RTS_INHERIT,
.scope = SCOPE_UNIVERSE,
};
@ -549,14 +547,12 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
}
}
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);

View File

@ -1455,12 +1455,11 @@ nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint
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)
@ -1626,7 +1625,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
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;

View File

@ -298,18 +298,19 @@ krt_uptodate(rte *a, rte *b)
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, p->p.main_source);
}
/* Called when alien route is discovered during scan */
@ -320,7 +321,7 @@ krt_learn_scan(struct krt_proto *p, rte *e)
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))
@ -401,7 +402,7 @@ again:
{
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);
@ -433,7 +434,7 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
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)
@ -499,7 +500,7 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
if (best)
krt_learn_announce_update(p, best);
else
krt_learn_announce_delete(p, n);
krt_learn_announce_delete(p, n->n.addr);
}
}
@ -641,10 +642,7 @@ krt_got_route(struct krt_proto *p, rte *e)
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
@ -700,8 +698,6 @@ delete:
goto done;
done:
rte_free(e);
if (rt_free)
rte_free(rt_free);
@ -779,7 +775,6 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new)
}
#endif
}
rte_free(e);
}
/*