nhrp_vc.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* NHRP virtual connection
  2. * Copyright (c) 2014-2015 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include "zebra.h"
  10. #include "memory.h"
  11. #include "stream.h"
  12. #include "hash.h"
  13. #include "thread.h"
  14. #include "jhash.h"
  15. #include "nhrpd.h"
  16. #include "os.h"
  17. struct child_sa {
  18. uint32_t id;
  19. struct nhrp_vc *vc;
  20. struct list_head childlist_entry;
  21. };
  22. static struct hash *nhrp_vc_hash;
  23. static struct list_head childlist_head[512];
  24. static unsigned int nhrp_vc_key(void *peer_data)
  25. {
  26. struct nhrp_vc *vc = peer_data;
  27. return jhash_2words(
  28. sockunion_hash(&vc->local.nbma),
  29. sockunion_hash(&vc->remote.nbma),
  30. 0);
  31. }
  32. static int nhrp_vc_cmp(const void *cache_data, const void *key_data)
  33. {
  34. const struct nhrp_vc *a = cache_data;
  35. const struct nhrp_vc *b = key_data;
  36. return sockunion_same(&a->local.nbma, &b->local.nbma) &&
  37. sockunion_same(&a->remote.nbma, &b->remote.nbma);
  38. }
  39. static void *nhrp_vc_alloc(void *data)
  40. {
  41. struct nhrp_vc *vc, *key = data;
  42. vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc));
  43. if (vc) {
  44. *vc = (struct nhrp_vc) {
  45. .local.nbma = key->local.nbma,
  46. .remote.nbma = key->remote.nbma,
  47. .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
  48. };
  49. }
  50. return vc;
  51. }
  52. static void nhrp_vc_free(void *data)
  53. {
  54. XFREE(MTYPE_NHRP_VC, data);
  55. }
  56. struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create)
  57. {
  58. struct nhrp_vc key;
  59. key.local.nbma = *src;
  60. key.remote.nbma = *dst;
  61. return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0);
  62. }
  63. static void nhrp_vc_check_delete(struct nhrp_vc *vc)
  64. {
  65. if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list))
  66. return;
  67. hash_release(nhrp_vc_hash, vc);
  68. nhrp_vc_free(vc);
  69. }
  70. static void nhrp_vc_update(struct nhrp_vc *vc, long cmd)
  71. {
  72. vc->updating = 1;
  73. notifier_call(&vc->notifier_list, cmd);
  74. vc->updating = 0;
  75. nhrp_vc_check_delete(vc);
  76. }
  77. static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc)
  78. {
  79. vc->local.id[0] = 0;
  80. vc->local.certlen = 0;
  81. vc->remote.id[0] = 0;
  82. vc->remote.certlen = 0;
  83. }
  84. int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
  85. {
  86. char buf[2][SU_ADDRSTRLEN];
  87. struct child_sa *sa = NULL, *lsa;
  88. uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head);
  89. int abort_migration = 0;
  90. list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) {
  91. if (lsa->id == child_id) {
  92. sa = lsa;
  93. break;
  94. }
  95. }
  96. if (!sa) {
  97. if (!vc) return 0;
  98. sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa));
  99. if (!sa) return 0;
  100. *sa = (struct child_sa) {
  101. .id = child_id,
  102. .childlist_entry = LIST_INITIALIZER(sa->childlist_entry),
  103. .vc = NULL,
  104. };
  105. list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]);
  106. }
  107. if (sa->vc == vc)
  108. return 0;
  109. if (vc) {
  110. /* Attach first to new VC */
  111. vc->ipsec++;
  112. nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED);
  113. }
  114. if (sa->vc && vc) {
  115. /* Notify old VC of migration */
  116. sa->vc->abort_migration = 0;
  117. debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s",
  118. sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]),
  119. sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]));
  120. nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA);
  121. abort_migration = sa->vc->abort_migration;
  122. }
  123. if (sa->vc) {
  124. /* Deattach old VC */
  125. sa->vc->ipsec--;
  126. if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc);
  127. nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED);
  128. }
  129. /* Update */
  130. sa->vc = vc;
  131. if (!vc) {
  132. list_del(&sa->childlist_entry);
  133. XFREE(MTYPE_NHRP_VC, sa);
  134. }
  135. return abort_migration;
  136. }
  137. void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action)
  138. {
  139. notifier_add(n, &vc->notifier_list, action);
  140. }
  141. void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n)
  142. {
  143. notifier_del(n);
  144. nhrp_vc_check_delete(vc);
  145. }
  146. struct nhrp_vc_iterator_ctx {
  147. void (*cb)(struct nhrp_vc *, void *);
  148. void *ctx;
  149. };
  150. static void nhrp_vc_iterator(struct hash_backet *b, void *ctx)
  151. {
  152. struct nhrp_vc_iterator_ctx *ic = ctx;
  153. ic->cb(b->data, ic->ctx);
  154. }
  155. void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx)
  156. {
  157. struct nhrp_vc_iterator_ctx ic = {
  158. .cb = cb,
  159. .ctx = ctx,
  160. };
  161. hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic);
  162. }
  163. void nhrp_vc_init(void)
  164. {
  165. size_t i;
  166. nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp);
  167. for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
  168. list_init(&childlist_head[i]);
  169. }
  170. void nhrp_vc_reset(void)
  171. {
  172. struct child_sa *sa, *n;
  173. size_t i;
  174. for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) {
  175. list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry)
  176. nhrp_vc_ipsec_updown(sa->id, 0);
  177. }
  178. }
  179. void nhrp_vc_terminate(void)
  180. {
  181. nhrp_vc_reset();
  182. hash_clean(nhrp_vc_hash, nhrp_vc_free);
  183. }