]>
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)); | |
0ce1ca80 DS |
51 | |
52 | *vc = (struct nhrp_vc){ | |
53 | .local.nbma = key->local.nbma, | |
54 | .remote.nbma = key->remote.nbma, | |
55 | .notifier_list = | |
56 | NOTIFIER_LIST_INITIALIZER(&vc->notifier_list), | |
57 | }; | |
2fb975da TT |
58 | |
59 | return vc; | |
60 | } | |
61 | ||
62 | static void nhrp_vc_free(void *data) | |
63 | { | |
64 | XFREE(MTYPE_NHRP_VC, data); | |
65 | } | |
66 | ||
996c9314 LB |
67 | struct nhrp_vc *nhrp_vc_get(const union sockunion *src, |
68 | const union sockunion *dst, int create) | |
2fb975da TT |
69 | { |
70 | struct nhrp_vc key; | |
71 | key.local.nbma = *src; | |
72 | key.remote.nbma = *dst; | |
73 | return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0); | |
74 | } | |
75 | ||
76 | static void nhrp_vc_check_delete(struct nhrp_vc *vc) | |
77 | { | |
78 | if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list)) | |
79 | return; | |
80 | hash_release(nhrp_vc_hash, vc); | |
81 | nhrp_vc_free(vc); | |
82 | } | |
83 | ||
84 | static void nhrp_vc_update(struct nhrp_vc *vc, long cmd) | |
85 | { | |
86 | vc->updating = 1; | |
87 | notifier_call(&vc->notifier_list, cmd); | |
88 | vc->updating = 0; | |
89 | nhrp_vc_check_delete(vc); | |
90 | } | |
91 | ||
92 | static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc) | |
93 | { | |
94 | vc->local.id[0] = 0; | |
95 | vc->local.certlen = 0; | |
96 | vc->remote.id[0] = 0; | |
97 | vc->remote.certlen = 0; | |
98 | } | |
99 | ||
100 | int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) | |
101 | { | |
102 | char buf[2][SU_ADDRSTRLEN]; | |
103 | struct child_sa *sa = NULL, *lsa; | |
104 | uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head); | |
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; | |
142 | debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", | |
996c9314 LB |
143 | sockunion2str(&sa->vc->remote.nbma, buf[0], |
144 | sizeof buf[0]), | |
145 | sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1])); | |
2fb975da TT |
146 | nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); |
147 | abort_migration = sa->vc->abort_migration; | |
148 | } | |
149 | if (sa->vc) { | |
150 | /* Deattach old VC */ | |
151 | sa->vc->ipsec--; | |
996c9314 LB |
152 | if (!sa->vc->ipsec) |
153 | nhrp_vc_ipsec_reset(sa->vc); | |
2fb975da TT |
154 | nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); |
155 | } | |
156 | ||
157 | /* Update */ | |
158 | sa->vc = vc; | |
159 | if (!vc) { | |
160 | list_del(&sa->childlist_entry); | |
161 | XFREE(MTYPE_NHRP_VC, sa); | |
162 | } | |
163 | ||
164 | return abort_migration; | |
165 | } | |
166 | ||
996c9314 LB |
167 | void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, |
168 | notifier_fn_t action) | |
2fb975da TT |
169 | { |
170 | notifier_add(n, &vc->notifier_list, action); | |
171 | } | |
172 | ||
173 | void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) | |
174 | { | |
175 | notifier_del(n); | |
176 | nhrp_vc_check_delete(vc); | |
177 | } | |
178 | ||
179 | ||
180 | struct nhrp_vc_iterator_ctx { | |
181 | void (*cb)(struct nhrp_vc *, void *); | |
182 | void *ctx; | |
183 | }; | |
184 | ||
185 | static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) | |
186 | { | |
187 | struct nhrp_vc_iterator_ctx *ic = ctx; | |
188 | ic->cb(b->data, ic->ctx); | |
189 | } | |
190 | ||
191 | void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx) | |
192 | { | |
193 | struct nhrp_vc_iterator_ctx ic = { | |
996c9314 | 194 | .cb = cb, .ctx = ctx, |
2fb975da TT |
195 | }; |
196 | hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic); | |
197 | } | |
198 | ||
199 | void nhrp_vc_init(void) | |
200 | { | |
201 | size_t i; | |
202 | ||
996c9314 | 203 | nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash"); |
2fb975da TT |
204 | for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) |
205 | list_init(&childlist_head[i]); | |
206 | } | |
207 | ||
208 | void nhrp_vc_reset(void) | |
209 | { | |
210 | struct child_sa *sa, *n; | |
211 | size_t i; | |
212 | ||
213 | for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) { | |
996c9314 LB |
214 | list_for_each_entry_safe(sa, n, &childlist_head[i], |
215 | childlist_entry) | |
2fb975da TT |
216 | nhrp_vc_ipsec_updown(sa->id, 0); |
217 | } | |
218 | } | |
219 | ||
220 | void nhrp_vc_terminate(void) | |
221 | { | |
222 | nhrp_vc_reset(); | |
223 | hash_clean(nhrp_vc_hash, nhrp_vc_free); | |
224 | } |