BGP: Fix memory leak in graceful restart code

Prefix and bucket tables are initialized when entering established state
but not explicitly freed when leaving it (that is handled by protocol
restart). With graceful restart, BGP may enter and leave established
state multiple times without hard protocol restart causing memory leak.
This commit is contained in:
Ondrej Zajicek (work) 2016-11-25 11:51:38 +01:00
parent 261816b0d4
commit ed1a908e53
4 changed files with 37 additions and 0 deletions

View file

@ -25,6 +25,12 @@
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \ (v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
}) })
#define HASH_FREE(v) \
({ \
mb_free((v).data); \
(v) = (typeof(v)){ }; \
})
#define HASH_FIND(v,id,key...) \ #define HASH_FIND(v,id,key...) \
({ \ ({ \
u32 _h = HASH_FN(v, id, key); \ u32 _h = HASH_FN(v, id, key); \

View file

@ -934,6 +934,15 @@ bgp_init_prefix_table(struct bgp_proto *p, u32 order)
p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix)); p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix));
} }
void
bgp_free_prefix_table(struct bgp_proto *p)
{
HASH_FREE(p->prefix_hash);
rfree(p->prefix_slab);
p->prefix_slab = NULL;
}
static struct bgp_prefix * static struct bgp_prefix *
bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id) bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id)
{ {
@ -1940,6 +1949,23 @@ bgp_init_bucket_table(struct bgp_proto *p)
// fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix); // fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
} }
void
bgp_free_bucket_table(struct bgp_proto *p)
{
mb_free(p->bucket_hash);
p->bucket_hash = NULL;
struct bgp_bucket *b;
WALK_LIST_FIRST(b, p->bucket_queue)
{
rem_node(&b->send_node);
mb_free(b);
}
mb_free(p->withdraw_bucket);
p->withdraw_bucket = NULL;
}
void void
bgp_get_route_info(rte *e, byte *buf, ea_list *attrs) bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
{ {

View file

@ -416,6 +416,9 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
BGP_TRACE(D_EVENTS, "BGP session closed"); BGP_TRACE(D_EVENTS, "BGP session closed");
p->conn = NULL; p->conn = NULL;
bgp_free_prefix_table(p);
bgp_free_bucket_table(p);
if (p->p.proto_state == PS_UP) if (p->p.proto_state == PS_UP)
bgp_stop(p, 0); bgp_stop(p, 0);
} }

View file

@ -253,8 +253,10 @@ int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_be
void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs); void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
void bgp_init_bucket_table(struct bgp_proto *); void bgp_init_bucket_table(struct bgp_proto *);
void bgp_free_bucket_table(struct bgp_proto *p);
void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck); void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
void bgp_init_prefix_table(struct bgp_proto *p, u32 order); void bgp_init_prefix_table(struct bgp_proto *p, u32 order);
void bgp_free_prefix_table(struct bgp_proto *p);
void bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp); void bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp);
uint bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains); uint bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);
void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs); void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs);