summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2015-07-22 21:35:38 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2015-07-22 21:35:38 +0200
commit28066f4bccdd5449908e97af4465b73202d7256f (patch)
treef0f42c48c912b41b1c4615e07354bf454d981334
parentmultipath is broken if deterministic-med is enabled (diff)
downloadfrr-28066f4bccdd5449908e97af4465b73202d7256f.tar.xz
frr-28066f4bccdd5449908e97af4465b73202d7256f.zip
Fixup of peer memory leaks in bgp
When deleting a set of peers, the peer->group pointer was being set to NULL and then passed into peer_delete. peer_delete has functionality to safely remove the peer->group structure if it non-null and to remove the peer->group if it's refcnt reaches zero. This is a day one bug in the quagga source tree.
-rw-r--r--bgpd/bgpd.c28
-rw-r--r--bgpd/bgpd.h13
2 files changed, 22 insertions, 19 deletions
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index dec6b7d68..5ef07f0c4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -963,9 +963,13 @@ peer_free (struct peer *peer)
/* increase reference count on a struct peer */
struct peer *
-peer_lock (struct peer *peer)
+peer_lock_with_caller (const char *name, struct peer *peer)
{
assert (peer && (peer->lock >= 0));
+
+#if 0
+ zlog_debug("%s peer_lock %p %d", name, peer, peer->lock);
+#endif
peer->lock++;
@@ -976,30 +980,22 @@ peer_lock (struct peer *peer)
* struct peer is freed and NULL returned if last reference
*/
struct peer *
-peer_unlock (struct peer *peer)
+peer_unlock_with_caller (const char *name, struct peer *peer)
{
assert (peer && (peer->lock > 0));
+
+#if 0
+ zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock);
+#endif
peer->lock--;
if (peer->lock == 0)
{
-#if 0
- zlog_debug ("unlocked and freeing");
- zlog_backtrace (LOG_DEBUG);
-#endif
peer_free (peer);
return NULL;
}
-#if 0
- if (peer->lock == 1)
- {
- zlog_debug ("unlocked to 1");
- zlog_backtrace (LOG_DEBUG);
- }
-#endif
-
return peer;
}
@@ -1277,7 +1273,7 @@ peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
+
peer = peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
@@ -2222,7 +2218,6 @@ peer_group_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
other = peer->doppelganger;
- peer->group = NULL;
peer_delete (peer);
if (other && other->status != Deleted)
{
@@ -2271,7 +2266,6 @@ peer_group_remote_as_delete (struct peer_group *group)
{
other = peer->doppelganger;
- peer->group = NULL;
peer_delete (peer);
if (other && other->status != Deleted)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 050731c94..5c9457fea 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1129,8 +1129,17 @@ extern struct peer_group *peer_group_lookup_dynamic_neighbor (struct bgp *,
extern struct peer *peer_lookup_dynamic_neighbor (struct bgp *,
union sockunion *);
extern void peer_drop_dynamic_neighbor (struct peer *);
-extern struct peer *peer_lock (struct peer *);
-extern struct peer *peer_unlock (struct peer *);
+
+/*
+ * Peers are incredibly easy to memory leak
+ * due to the various ways that they are actually used
+ * Provide some functionality to debug locks and unlocks
+ */
+extern struct peer *peer_lock_with_caller(const char *, struct peer *);
+extern struct peer *peer_unlock_with_caller(const char *, struct peer *);
+#define peer_unlock(A) peer_unlock_with_caller(__FUNCTION__, (A))
+#define peer_lock(B) peer_lock_with_caller(__FUNCTION__, (B))
+
extern bgp_peer_sort_t peer_sort (struct peer *peer);
extern int peer_active (struct peer *);
extern int peer_active_nego (struct peer *);