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