summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-25 11:51:38 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2016-11-25 11:51:38 +0100
commited1a908e535e4333b358d83b472453a2ad6d3f51 (patch)
tree3ee46e6d922c3e363dad23976fcc2de0a7e19429 /proto
parent261816b0d4f3d4549a4402b95541b82fc7f10a4b (diff)
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.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/attrs.c26
-rw-r--r--proto/bgp/bgp.c3
-rw-r--r--proto/bgp/bgp.h2
3 files changed, 31 insertions, 0 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index aa2a3b46..9d23374a 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -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));
}
+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 *
bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id)
{
@@ -1941,6 +1950,23 @@ bgp_init_bucket_table(struct bgp_proto *p)
}
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
bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
{
eattr *p = ea_find(attrs, EA_CODE(EAP_BGP, BA_AS_PATH));
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 8ef4b990..0f1c9446 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -416,6 +416,9 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
BGP_TRACE(D_EVENTS, "BGP session closed");
p->conn = NULL;
+ bgp_free_prefix_table(p);
+ bgp_free_bucket_table(p);
+
if (p->p.proto_state == PS_UP)
bgp_stop(p, 0);
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index b4067f3a..d028bef4 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -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);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
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_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);
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);