You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
6.9 KiB

  1. From ee72f0a0eb93038ef6dfd01fed9f32e24c5de2a1 Mon Sep 17 00:00:00 2001
  2. From: Reuben Dowle <reuben.dowle@4rf.com>
  3. Date: Mon, 7 Dec 2020 16:35:13 +1300
  4. Subject: [PATCH] nhrpd: Cleanup resources when interface is deleted
  5. Currently when an interface is deleted from configuration, associated
  6. resources are not freed. This causes memory leaks and crashes.
  7. To reproduce this issue:
  8. * Connect to a DMVPN hub
  9. * Outside of frr, delete the underlying GRE interface
  10. * Use 'no interface xxx' to delete the interface containing nhrp configurations
  11. Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com>
  12. ---
  13. nhrpd/nhrp_cache.c | 42 ++++++++++++++++++++++++++++++++++++++++--
  14. nhrpd/nhrp_interface.c | 15 +++++++++++++++
  15. nhrpd/nhrp_nhs.c | 18 ++++++++++++++++++
  16. nhrpd/nhrp_peer.c | 27 +++++++++++++++++++++++++++
  17. nhrpd/nhrpd.h | 3 +++
  18. 5 files changed, 103 insertions(+), 2 deletions(-)
  19. mode change 100644 => 100755 nhrpd/nhrp_cache.c
  20. mode change 100644 => 100755 nhrpd/nhrp_interface.c
  21. mode change 100644 => 100755 nhrpd/nhrpd.h
  22. --- a/nhrpd/nhrp_cache.c
  23. +++ b/nhrpd/nhrp_cache.c
  24. @@ -69,12 +69,13 @@ static void nhrp_cache_free(struct nhrp_
  25. {
  26. struct nhrp_interface *nifp = c->ifp->info;
  27. - zassert(c->cur.type == NHRP_CACHE_INVALID && c->cur.peer == NULL);
  28. - zassert(c->new.type == NHRP_CACHE_INVALID && c->new.peer == NULL);
  29. + debugf(NHRP_DEBUG_COMMON, "Deleting cache entry");
  30. nhrp_cache_counts[c->cur.type]--;
  31. notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE);
  32. zassert(!notifier_active(&c->notifier_list));
  33. hash_release(nifp->cache_hash, c);
  34. + THREAD_OFF(c->t_timeout);
  35. + THREAD_OFF(c->t_auth);
  36. XFREE(MTYPE_NHRP_CACHE, c);
  37. }
  38. @@ -140,6 +141,41 @@ struct nhrp_cache_config *nhrp_cache_con
  39. create ? nhrp_cache_config_alloc : NULL);
  40. }
  41. +static void do_nhrp_cache_free(struct hash_bucket *hb,
  42. + void *arg __attribute__((__unused__)))
  43. +{
  44. + struct nhrp_cache *c = hb->data;
  45. +
  46. + nhrp_cache_free(c);
  47. +}
  48. +
  49. +static void do_nhrp_cache_config_free(struct hash_bucket *hb,
  50. + void *arg __attribute__((__unused__)))
  51. +{
  52. + struct nhrp_cache_config *cc = hb->data;
  53. +
  54. + nhrp_cache_config_free(cc);
  55. +}
  56. +
  57. +void nhrp_cache_interface_del(struct interface *ifp)
  58. +{
  59. + struct nhrp_interface *nifp = ifp->info;
  60. +
  61. + debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted cache entries (%lu)",
  62. + nifp->cache_hash ? nifp->cache_hash->count : 0);
  63. +
  64. + if (nifp->cache_hash) {
  65. + hash_iterate(nifp->cache_hash, do_nhrp_cache_free, NULL);
  66. + hash_free(nifp->cache_hash);
  67. + }
  68. +
  69. + if (nifp->cache_config_hash) {
  70. + hash_iterate(nifp->cache_config_hash, do_nhrp_cache_config_free,
  71. + NULL);
  72. + hash_free(nifp->cache_config_hash);
  73. + }
  74. +}
  75. +
  76. struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
  77. union sockunion *remote_addr, int create)
  78. {
  79. @@ -164,6 +200,7 @@ struct nhrp_cache *nhrp_cache_get(struct
  80. static int nhrp_cache_do_free(struct thread *t)
  81. {
  82. struct nhrp_cache *c = THREAD_ARG(t);
  83. +
  84. c->t_timeout = NULL;
  85. nhrp_cache_free(c);
  86. return 0;
  87. @@ -172,6 +209,7 @@ static int nhrp_cache_do_free(struct thr
  88. static int nhrp_cache_do_timeout(struct thread *t)
  89. {
  90. struct nhrp_cache *c = THREAD_ARG(t);
  91. +
  92. c->t_timeout = NULL;
  93. if (c->cur.type != NHRP_CACHE_INVALID)
  94. nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL);
  95. --- a/nhrpd/nhrp_interface.c
  96. +++ b/nhrpd/nhrp_interface.c
  97. @@ -49,6 +49,21 @@ static int nhrp_if_new_hook(struct inter
  98. static int nhrp_if_delete_hook(struct interface *ifp)
  99. {
  100. + struct nhrp_interface *nifp = ifp->info;
  101. +
  102. + debugf(NHRP_DEBUG_IF, "Deleted interface (%s)", ifp->name);
  103. +
  104. + nhrp_cache_interface_del(ifp);
  105. + nhrp_nhs_interface_del(ifp);
  106. + nhrp_peer_interface_del(ifp);
  107. +
  108. + if (nifp->ipsec_profile)
  109. + free(nifp->ipsec_profile);
  110. + if (nifp->ipsec_fallback_profile)
  111. + free(nifp->ipsec_fallback_profile);
  112. + if (nifp->source)
  113. + free(nifp->source);
  114. +
  115. XFREE(MTYPE_NHRP_IF, ifp->info);
  116. return 0;
  117. }
  118. --- a/nhrpd/nhrp_nhs.c
  119. +++ b/nhrpd/nhrp_nhs.c
  120. @@ -378,6 +378,24 @@ int nhrp_nhs_free(struct nhrp_nhs *nhs)
  121. return 0;
  122. }
  123. +void nhrp_nhs_interface_del(struct interface *ifp)
  124. +{
  125. + struct nhrp_interface *nifp = ifp->info;
  126. + struct nhrp_nhs *nhs, *tmp;
  127. + afi_t afi;
  128. +
  129. + for (afi = 0; afi < AFI_MAX; afi++) {
  130. + debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)",
  131. + !list_empty(&nifp->afi[afi].nhslist_head));
  132. +
  133. + list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head,
  134. + nhslist_entry)
  135. + {
  136. + nhrp_nhs_free(nhs);
  137. + }
  138. + }
  139. +}
  140. +
  141. void nhrp_nhs_terminate(void)
  142. {
  143. struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
  144. --- a/nhrpd/nhrp_peer.c
  145. +++ b/nhrpd/nhrp_peer.c
  146. @@ -38,11 +38,17 @@ static void nhrp_packet_debug(struct zbu
  147. static void nhrp_peer_check_delete(struct nhrp_peer *p)
  148. {
  149. + char buf[2][256];
  150. struct nhrp_interface *nifp = p->ifp->info;
  151. if (p->ref || notifier_active(&p->notifier_list))
  152. return;
  153. + debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%s local:%s",
  154. + p->ref,
  155. + sockunion2str(&p->vc->remote.nbma, buf[0], sizeof(buf[0])),
  156. + sockunion2str(&p->vc->local.nbma, buf[1], sizeof(buf[1])));
  157. +
  158. THREAD_OFF(p->t_fallback);
  159. hash_release(nifp->peer_hash, p);
  160. nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
  161. @@ -185,6 +191,27 @@ static void *nhrp_peer_create(void *data
  162. return p;
  163. }
  164. +static void do_peer_hash_free(struct hash_bucket *hb,
  165. + void *arg __attribute__((__unused__)))
  166. +{
  167. + struct nhrp_peer *p = hb->data;
  168. + nhrp_peer_check_delete(p);
  169. +}
  170. +
  171. +void nhrp_peer_interface_del(struct interface *ifp)
  172. +{
  173. + struct nhrp_interface *nifp = ifp->info;
  174. +
  175. + debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted peer entries (%lu)",
  176. + nifp->peer_hash ? nifp->peer_hash->count : 0);
  177. +
  178. + if (nifp->peer_hash) {
  179. + hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL);
  180. + assert(nifp->peer_hash->count == 0);
  181. + hash_free(nifp->peer_hash);
  182. + }
  183. +}
  184. +
  185. struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
  186. const union sockunion *remote_nbma)
  187. {
  188. --- a/nhrpd/nhrpd.h
  189. +++ b/nhrpd/nhrpd.h
  190. @@ -343,6 +343,7 @@ void nhrp_nhs_foreach(struct interface *
  191. void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
  192. void *),
  193. void *ctx);
  194. +void nhrp_nhs_interface_del(struct interface *ifp);
  195. void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp);
  196. void nhrp_route_announce(int add, enum nhrp_cache_type type,
  197. @@ -366,6 +367,7 @@ void nhrp_shortcut_foreach(afi_t afi,
  198. void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force);
  199. void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted);
  200. +void nhrp_cache_interface_del(struct interface *ifp);
  201. void nhrp_cache_config_free(struct nhrp_cache_config *c);
  202. struct nhrp_cache_config *nhrp_cache_config_get(struct interface *ifp,
  203. union sockunion *remote_addr,
  204. @@ -446,6 +448,7 @@ struct nhrp_reqid *nhrp_reqid_lookup(str
  205. int nhrp_packet_init(void);
  206. +void nhrp_peer_interface_del(struct interface *ifp);
  207. struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
  208. const union sockunion *remote_nbma);
  209. struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p);