mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +00:00
rt-table: Fix kernel protocol export filter memory bug
Kernel protocol calls rt_export_merged(), which used @rte_update_pool for temporary allocations, supposing it is called from other functions from rt-table.c that handles locking and flushing of the linpool. Therefore, linpool was not flushed properly and memory leaked. Add linpool argument to rt_export_merged() and use @krt_filter_lp when called from kernel protocol. Thanks to Justin Cattle and Alexander Frolkin for the bugreport. (Commit squashed and updated by Ondrej Zajicek)
This commit is contained in:
parent
bc00f05815
commit
a290da25a1
@ -276,7 +276,7 @@ void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *s
|
|||||||
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
|
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
|
||||||
void rte_discard(rtable *tab, rte *old);
|
void rte_discard(rtable *tab, rte *old);
|
||||||
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
|
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
|
||||||
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, int silent);
|
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent);
|
||||||
void rt_refresh_begin(rtable *t, struct announce_hook *ah);
|
void rt_refresh_begin(rtable *t, struct announce_hook *ah);
|
||||||
void rt_refresh_end(rtable *t, struct announce_hook *ah);
|
void rt_refresh_end(rtable *t, struct announce_hook *ah);
|
||||||
void rte_dump(rte *);
|
void rte_dump(rte *);
|
||||||
|
@ -245,7 +245,7 @@ rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static rte *
|
static rte *
|
||||||
export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
|
export_filter_(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
|
||||||
{
|
{
|
||||||
struct proto *p = ah->proto;
|
struct proto *p = ah->proto;
|
||||||
struct filter *filter = ah->out_filter;
|
struct filter *filter = ah->out_filter;
|
||||||
@ -260,9 +260,9 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
|
|||||||
if (!tmpa)
|
if (!tmpa)
|
||||||
tmpa = &tmpb;
|
tmpa = &tmpb;
|
||||||
|
|
||||||
*tmpa = make_tmp_attrs(rt, rte_update_pool);
|
*tmpa = make_tmp_attrs(rt, pool);
|
||||||
|
|
||||||
v = p->import_control ? p->import_control(p, &rt, tmpa, rte_update_pool) : 0;
|
v = p->import_control ? p->import_control(p, &rt, tmpa, pool) : 0;
|
||||||
if (v < 0)
|
if (v < 0)
|
||||||
{
|
{
|
||||||
if (silent)
|
if (silent)
|
||||||
@ -281,7 +281,7 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
v = filter && ((filter == FILTER_REJECT) ||
|
v = filter && ((filter == FILTER_REJECT) ||
|
||||||
(f_run(filter, &rt, tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT));
|
(f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT));
|
||||||
if (v)
|
if (v)
|
||||||
{
|
{
|
||||||
if (silent)
|
if (silent)
|
||||||
@ -304,6 +304,12 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline rte *
|
||||||
|
export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
|
||||||
|
{
|
||||||
|
return export_filter_(ah, rt0, rt_free, tmpa, rte_update_pool, silent);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
|
do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
|
||||||
{
|
{
|
||||||
@ -586,7 +592,7 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol
|
|||||||
|
|
||||||
|
|
||||||
static struct mpnh *
|
static struct mpnh *
|
||||||
mpnh_merge_rta(struct mpnh *nhs, rta *a, int max)
|
mpnh_merge_rta(struct mpnh *nhs, rta *a, linpool *pool, int max)
|
||||||
{
|
{
|
||||||
struct mpnh nh = { .gw = a->gw, .iface = a->iface };
|
struct mpnh nh = { .gw = a->gw, .iface = a->iface };
|
||||||
struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh;
|
struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh;
|
||||||
@ -594,7 +600,7 @@ mpnh_merge_rta(struct mpnh *nhs, rta *a, int max)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rte *
|
rte *
|
||||||
rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, int silent)
|
rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
|
||||||
{
|
{
|
||||||
// struct proto *p = ah->proto;
|
// struct proto *p = ah->proto;
|
||||||
struct mpnh *nhs = NULL;
|
struct mpnh *nhs = NULL;
|
||||||
@ -606,7 +612,7 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
|
|||||||
if (!rte_is_valid(best0))
|
if (!rte_is_valid(best0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
best = export_filter(ah, best0, rt_free, tmpa, silent);
|
best = export_filter_(ah, best0, rt_free, tmpa, pool, silent);
|
||||||
|
|
||||||
if (!best || !rte_is_reachable(best))
|
if (!best || !rte_is_reachable(best))
|
||||||
return best;
|
return best;
|
||||||
@ -616,13 +622,13 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
|
|||||||
if (!rte_mergable(best0, rt0))
|
if (!rte_mergable(best0, rt0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rt = export_filter(ah, rt0, &tmp, NULL, 1);
|
rt = export_filter_(ah, rt0, &tmp, NULL, pool, 1);
|
||||||
|
|
||||||
if (!rt)
|
if (!rt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rte_is_reachable(rt))
|
if (rte_is_reachable(rt))
|
||||||
nhs = mpnh_merge_rta(nhs, rt->attrs, ah->proto->merge_limit);
|
nhs = mpnh_merge_rta(nhs, rt->attrs, pool, ah->proto->merge_limit);
|
||||||
|
|
||||||
if (tmp)
|
if (tmp)
|
||||||
rte_free(tmp);
|
rte_free(tmp);
|
||||||
@ -630,11 +636,11 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
|
|||||||
|
|
||||||
if (nhs)
|
if (nhs)
|
||||||
{
|
{
|
||||||
nhs = mpnh_merge_rta(nhs, best->attrs, ah->proto->merge_limit);
|
nhs = mpnh_merge_rta(nhs, best->attrs, pool, ah->proto->merge_limit);
|
||||||
|
|
||||||
if (nhs->next)
|
if (nhs->next)
|
||||||
{
|
{
|
||||||
best = rte_cow_rta(best, rte_update_pool);
|
best = rte_cow_rta(best, pool);
|
||||||
best->attrs->dest = RTD_MULTIPATH;
|
best->attrs->dest = RTD_MULTIPATH;
|
||||||
best->attrs->nexthops = nhs;
|
best->attrs->nexthops = nhs;
|
||||||
}
|
}
|
||||||
@ -685,7 +691,7 @@ rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_
|
|||||||
|
|
||||||
/* Prepare new merged route */
|
/* Prepare new merged route */
|
||||||
if (new_best)
|
if (new_best)
|
||||||
new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, 0);
|
new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, rte_update_pool, 0);
|
||||||
|
|
||||||
/* Prepare old merged route (without proper merged next hops) */
|
/* Prepare old merged route (without proper merged next hops) */
|
||||||
/* There are some issues with running filter on old route - see rt_notify_basic() */
|
/* There are some issues with running filter on old route - see rt_notify_basic() */
|
||||||
@ -2470,7 +2476,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
|||||||
if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
|
if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
|
||||||
{
|
{
|
||||||
rte *rt_free;
|
rte *rt_free;
|
||||||
e = rt_export_merged(a, n, &rt_free, &tmpa, 1);
|
e = rt_export_merged(a, n, &rt_free, &tmpa, rte_update_pool, 1);
|
||||||
pass = 1;
|
pass = 1;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
|
@ -613,7 +613,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
|
|||||||
rte *rt;
|
rte *rt;
|
||||||
|
|
||||||
if (p->p.accept_ra_types == RA_MERGED)
|
if (p->p.accept_ra_types == RA_MERGED)
|
||||||
return rt_export_merged(ah, net, rt_free, tmpa, 1);
|
return rt_export_merged(ah, net, rt_free, tmpa, krt_filter_lp, 1);
|
||||||
|
|
||||||
rt = net->routes;
|
rt = net->routes;
|
||||||
*rt_free = NULL;
|
*rt_free = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user