]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_vc.c
Merge pull request #10770 from chiragshah6/evpn_dev3
[mirror_frr.git] / nhrpd / nhrp_vc.c
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
10 #include "zebra.h"
11 #include "memory.h"
12 #include "stream.h"
13 #include "hash.h"
14 #include "thread.h"
15 #include "jhash.h"
16
17 #include "nhrpd.h"
18 #include "os.h"
19
20 DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection");
21
22 PREDECL_DLIST(childlist);
23
24 struct child_sa {
25 uint32_t id;
26 struct nhrp_vc *vc;
27 struct childlist_item childlist_entry;
28 };
29
30 DECLARE_DLIST(childlist, struct child_sa, childlist_entry);
31
32 static struct hash *nhrp_vc_hash;
33 static struct childlist_head childlist_head[512];
34
35 static unsigned int nhrp_vc_key(const void *peer_data)
36 {
37 const struct nhrp_vc *vc = peer_data;
38 return jhash_2words(sockunion_hash(&vc->local.nbma),
39 sockunion_hash(&vc->remote.nbma), 0);
40 }
41
42 static bool nhrp_vc_cmp(const void *cache_data, const void *key_data)
43 {
44 const struct nhrp_vc *a = cache_data;
45 const struct nhrp_vc *b = key_data;
46
47 return sockunion_same(&a->local.nbma, &b->local.nbma)
48 && sockunion_same(&a->remote.nbma, &b->remote.nbma);
49 }
50
51 static void *nhrp_vc_alloc(void *data)
52 {
53 struct nhrp_vc *vc, *key = data;
54
55 vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc));
56
57 *vc = (struct nhrp_vc){
58 .local.nbma = key->local.nbma,
59 .remote.nbma = key->remote.nbma,
60 .notifier_list =
61 NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
62 };
63
64 return vc;
65 }
66
67 static void nhrp_vc_free(void *data)
68 {
69 XFREE(MTYPE_NHRP_VC, data);
70 }
71
72 struct nhrp_vc *nhrp_vc_get(const union sockunion *src,
73 const union sockunion *dst, int create)
74 {
75 struct nhrp_vc key;
76 key.local.nbma = *src;
77 key.remote.nbma = *dst;
78 return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0);
79 }
80
81 static void nhrp_vc_check_delete(struct nhrp_vc *vc)
82 {
83 if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list))
84 return;
85 hash_release(nhrp_vc_hash, vc);
86 nhrp_vc_free(vc);
87 }
88
89 static void nhrp_vc_update(struct nhrp_vc *vc, long cmd)
90 {
91 vc->updating = 1;
92 notifier_call(&vc->notifier_list, cmd);
93 vc->updating = 0;
94 nhrp_vc_check_delete(vc);
95 }
96
97 static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc)
98 {
99 vc->local.id[0] = 0;
100 vc->local.certlen = 0;
101 vc->remote.id[0] = 0;
102 vc->remote.certlen = 0;
103 }
104
105 int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
106 {
107 struct child_sa *sa = NULL, *lsa;
108 uint32_t child_hash = child_id % array_size(childlist_head);
109 int abort_migration = 0;
110
111 frr_each (childlist, &childlist_head[child_hash], lsa) {
112 if (lsa->id == child_id) {
113 sa = lsa;
114 break;
115 }
116 }
117
118 if (!sa) {
119 if (!vc)
120 return 0;
121
122 sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa));
123
124 *sa = (struct child_sa){
125 .id = child_id,
126 .vc = NULL,
127 };
128 childlist_add_tail(&childlist_head[child_hash], sa);
129 }
130
131 if (sa->vc == vc)
132 return 0;
133
134 if (vc) {
135 /* Attach first to new VC */
136 vc->ipsec++;
137 nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED);
138 }
139 if (sa->vc && vc) {
140 /* Notify old VC of migration */
141 sa->vc->abort_migration = 0;
142 debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %pSU to %pSU",
143 &sa->vc->remote.nbma, &vc->remote.nbma);
144 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA);
145 abort_migration = sa->vc->abort_migration;
146 }
147 if (sa->vc) {
148 /* Deattach old VC */
149 sa->vc->ipsec--;
150 if (!sa->vc->ipsec)
151 nhrp_vc_ipsec_reset(sa->vc);
152 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED);
153 }
154
155 /* Update */
156 sa->vc = vc;
157 if (!vc) {
158 childlist_del(&childlist_head[child_hash], sa);
159 XFREE(MTYPE_NHRP_VC, sa);
160 }
161
162 return abort_migration;
163 }
164
165 void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n,
166 notifier_fn_t action)
167 {
168 notifier_add(n, &vc->notifier_list, action);
169 }
170
171 void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n)
172 {
173 notifier_del(n, &vc->notifier_list);
174 nhrp_vc_check_delete(vc);
175 }
176
177
178 struct nhrp_vc_iterator_ctx {
179 void (*cb)(struct nhrp_vc *, void *);
180 void *ctx;
181 };
182
183 static void nhrp_vc_iterator(struct hash_bucket *b, void *ctx)
184 {
185 struct nhrp_vc_iterator_ctx *ic = ctx;
186 ic->cb(b->data, ic->ctx);
187 }
188
189 void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx)
190 {
191 struct nhrp_vc_iterator_ctx ic = {
192 .cb = cb, .ctx = ctx,
193 };
194 hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic);
195 }
196
197 void nhrp_vc_init(void)
198 {
199 size_t i;
200
201 nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash");
202 for (i = 0; i < array_size(childlist_head); i++)
203 childlist_init(&childlist_head[i]);
204 }
205
206 void nhrp_vc_reset(void)
207 {
208 struct child_sa *sa;
209 size_t i;
210
211 for (i = 0; i < array_size(childlist_head); i++) {
212 frr_each_safe (childlist, &childlist_head[i], sa)
213 nhrp_vc_ipsec_updown(sa->id, 0);
214 }
215 }
216
217 void nhrp_vc_terminate(void)
218 {
219 nhrp_vc_reset();
220 hash_clean(nhrp_vc_hash, nhrp_vc_free);
221 }