]>
Commit | Line | Data |
---|---|---|
2fb975da TT |
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 | ||
bf8d3d6a | 20 | DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection"); |
819dc8bb | 21 | |
2fb975da TT |
22 | struct child_sa { |
23 | uint32_t id; | |
24 | struct nhrp_vc *vc; | |
25 | struct list_head childlist_entry; | |
26 | }; | |
27 | ||
28 | static struct hash *nhrp_vc_hash; | |
29 | static struct list_head childlist_head[512]; | |
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 | ||
996c9314 LB |
107 | list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) |
108 | { | |
2fb975da TT |
109 | if (lsa->id == child_id) { |
110 | sa = lsa; | |
111 | break; | |
112 | } | |
113 | } | |
114 | ||
115 | if (!sa) { | |
996c9314 LB |
116 | if (!vc) |
117 | return 0; | |
2fb975da TT |
118 | |
119 | sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa)); | |
2fb975da | 120 | |
996c9314 | 121 | *sa = (struct child_sa){ |
2fb975da | 122 | .id = child_id, |
996c9314 LB |
123 | .childlist_entry = |
124 | LIST_INITIALIZER(sa->childlist_entry), | |
2fb975da TT |
125 | .vc = NULL, |
126 | }; | |
996c9314 LB |
127 | list_add_tail(&sa->childlist_entry, |
128 | &childlist_head[child_hash]); | |
2fb975da TT |
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; | |
b6c48481 DS |
142 | debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %pSU to %pSU", |
143 | &sa->vc->remote.nbma, &vc->remote.nbma); | |
2fb975da TT |
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--; | |
996c9314 LB |
150 | if (!sa->vc->ipsec) |
151 | nhrp_vc_ipsec_reset(sa->vc); | |
2fb975da TT |
152 | nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); |
153 | } | |
154 | ||
155 | /* Update */ | |
156 | sa->vc = vc; | |
157 | if (!vc) { | |
158 | list_del(&sa->childlist_entry); | |
159 | XFREE(MTYPE_NHRP_VC, sa); | |
160 | } | |
161 | ||
162 | return abort_migration; | |
163 | } | |
164 | ||
996c9314 LB |
165 | void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, |
166 | notifier_fn_t action) | |
2fb975da TT |
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); | |
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 | ||
e3b78da8 | 183 | static void nhrp_vc_iterator(struct hash_bucket *b, void *ctx) |
2fb975da TT |
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 = { | |
996c9314 | 192 | .cb = cb, .ctx = ctx, |
2fb975da TT |
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 | ||
996c9314 | 201 | nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash"); |
7e3a1ec7 | 202 | for (i = 0; i < array_size(childlist_head); i++) |
2fb975da TT |
203 | list_init(&childlist_head[i]); |
204 | } | |
205 | ||
206 | void nhrp_vc_reset(void) | |
207 | { | |
208 | struct child_sa *sa, *n; | |
209 | size_t i; | |
210 | ||
7e3a1ec7 | 211 | for (i = 0; i < array_size(childlist_head); i++) { |
996c9314 LB |
212 | list_for_each_entry_safe(sa, n, &childlist_head[i], |
213 | childlist_entry) | |
2fb975da TT |
214 | nhrp_vc_ipsec_updown(sa->id, 0); |
215 | } | |
216 | } | |
217 | ||
218 | void nhrp_vc_terminate(void) | |
219 | { | |
220 | nhrp_vc_reset(); | |
221 | hash_clean(nhrp_vc_hash, nhrp_vc_free); | |
222 | } |