]>
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 | ||
819dc8bb DL |
20 | DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection") |
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 | ||
31 | static unsigned int nhrp_vc_key(void *peer_data) | |
32 | { | |
33 | 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 | ||
38 | static int nhrp_vc_cmp(const void *cache_data, const void *key_data) | |
39 | { | |
40 | const struct nhrp_vc *a = cache_data; | |
41 | const struct nhrp_vc *b = key_data; | |
996c9314 LB |
42 | return sockunion_same(&a->local.nbma, &b->local.nbma) |
43 | && sockunion_same(&a->remote.nbma, &b->remote.nbma); | |
2fb975da TT |
44 | } |
45 | ||
46 | static void *nhrp_vc_alloc(void *data) | |
47 | { | |
48 | struct nhrp_vc *vc, *key = data; | |
49 | ||
50 | vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc)); | |
51 | if (vc) { | |
996c9314 | 52 | *vc = (struct nhrp_vc){ |
2fb975da TT |
53 | .local.nbma = key->local.nbma, |
54 | .remote.nbma = key->remote.nbma, | |
996c9314 LB |
55 | .notifier_list = |
56 | NOTIFIER_LIST_INITIALIZER(&vc->notifier_list), | |
2fb975da TT |
57 | }; |
58 | } | |
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 | { | |
103 | char buf[2][SU_ADDRSTRLEN]; | |
104 | struct child_sa *sa = NULL, *lsa; | |
105 | uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head); | |
106 | int abort_migration = 0; | |
107 | ||
996c9314 LB |
108 | list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) |
109 | { | |
2fb975da TT |
110 | if (lsa->id == child_id) { |
111 | sa = lsa; | |
112 | break; | |
113 | } | |
114 | } | |
115 | ||
116 | if (!sa) { | |
996c9314 LB |
117 | if (!vc) |
118 | return 0; | |
2fb975da TT |
119 | |
120 | sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa)); | |
996c9314 LB |
121 | if (!sa) |
122 | return 0; | |
2fb975da | 123 | |
996c9314 | 124 | *sa = (struct child_sa){ |
2fb975da | 125 | .id = child_id, |
996c9314 LB |
126 | .childlist_entry = |
127 | LIST_INITIALIZER(sa->childlist_entry), | |
2fb975da TT |
128 | .vc = NULL, |
129 | }; | |
996c9314 LB |
130 | list_add_tail(&sa->childlist_entry, |
131 | &childlist_head[child_hash]); | |
2fb975da TT |
132 | } |
133 | ||
134 | if (sa->vc == vc) | |
135 | return 0; | |
136 | ||
137 | if (vc) { | |
138 | /* Attach first to new VC */ | |
139 | vc->ipsec++; | |
140 | nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED); | |
141 | } | |
142 | if (sa->vc && vc) { | |
143 | /* Notify old VC of migration */ | |
144 | sa->vc->abort_migration = 0; | |
145 | debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", | |
996c9314 LB |
146 | sockunion2str(&sa->vc->remote.nbma, buf[0], |
147 | sizeof buf[0]), | |
148 | sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1])); | |
2fb975da TT |
149 | nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); |
150 | abort_migration = sa->vc->abort_migration; | |
151 | } | |
152 | if (sa->vc) { | |
153 | /* Deattach old VC */ | |
154 | sa->vc->ipsec--; | |
996c9314 LB |
155 | if (!sa->vc->ipsec) |
156 | nhrp_vc_ipsec_reset(sa->vc); | |
2fb975da TT |
157 | nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); |
158 | } | |
159 | ||
160 | /* Update */ | |
161 | sa->vc = vc; | |
162 | if (!vc) { | |
163 | list_del(&sa->childlist_entry); | |
164 | XFREE(MTYPE_NHRP_VC, sa); | |
165 | } | |
166 | ||
167 | return abort_migration; | |
168 | } | |
169 | ||
996c9314 LB |
170 | void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, |
171 | notifier_fn_t action) | |
2fb975da TT |
172 | { |
173 | notifier_add(n, &vc->notifier_list, action); | |
174 | } | |
175 | ||
176 | void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) | |
177 | { | |
178 | notifier_del(n); | |
179 | nhrp_vc_check_delete(vc); | |
180 | } | |
181 | ||
182 | ||
183 | struct nhrp_vc_iterator_ctx { | |
184 | void (*cb)(struct nhrp_vc *, void *); | |
185 | void *ctx; | |
186 | }; | |
187 | ||
188 | static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) | |
189 | { | |
190 | struct nhrp_vc_iterator_ctx *ic = ctx; | |
191 | ic->cb(b->data, ic->ctx); | |
192 | } | |
193 | ||
194 | void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx) | |
195 | { | |
196 | struct nhrp_vc_iterator_ctx ic = { | |
996c9314 | 197 | .cb = cb, .ctx = ctx, |
2fb975da TT |
198 | }; |
199 | hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic); | |
200 | } | |
201 | ||
202 | void nhrp_vc_init(void) | |
203 | { | |
204 | size_t i; | |
205 | ||
996c9314 | 206 | nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash"); |
2fb975da TT |
207 | for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) |
208 | list_init(&childlist_head[i]); | |
209 | } | |
210 | ||
211 | void nhrp_vc_reset(void) | |
212 | { | |
213 | struct child_sa *sa, *n; | |
214 | size_t i; | |
215 | ||
216 | for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) { | |
996c9314 LB |
217 | list_for_each_entry_safe(sa, n, &childlist_head[i], |
218 | childlist_entry) | |
2fb975da TT |
219 | nhrp_vc_ipsec_updown(sa->id, 0); |
220 | } | |
221 | } | |
222 | ||
223 | void nhrp_vc_terminate(void) | |
224 | { | |
225 | nhrp_vc_reset(); | |
226 | hash_clean(nhrp_vc_hash, nhrp_vc_free); | |
227 | } |