]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_vc.c
tools: enable stylechecker to handle new files
[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 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;
34 return jhash_2words(
35 sockunion_hash(&vc->local.nbma),
36 sockunion_hash(&vc->remote.nbma),
37 0);
38 }
39
40 static int nhrp_vc_cmp(const void *cache_data, const void *key_data)
41 {
42 const struct nhrp_vc *a = cache_data;
43 const struct nhrp_vc *b = key_data;
44 return sockunion_same(&a->local.nbma, &b->local.nbma) &&
45 sockunion_same(&a->remote.nbma, &b->remote.nbma);
46 }
47
48 static void *nhrp_vc_alloc(void *data)
49 {
50 struct nhrp_vc *vc, *key = data;
51
52 vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc));
53 if (vc) {
54 *vc = (struct nhrp_vc) {
55 .local.nbma = key->local.nbma,
56 .remote.nbma = key->remote.nbma,
57 .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
58 };
59 }
60
61 return vc;
62 }
63
64 static void nhrp_vc_free(void *data)
65 {
66 XFREE(MTYPE_NHRP_VC, data);
67 }
68
69 struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create)
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
108 list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) {
109 if (lsa->id == child_id) {
110 sa = lsa;
111 break;
112 }
113 }
114
115 if (!sa) {
116 if (!vc) return 0;
117
118 sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa));
119 if (!sa) return 0;
120
121 *sa = (struct child_sa) {
122 .id = child_id,
123 .childlist_entry = LIST_INITIALIZER(sa->childlist_entry),
124 .vc = NULL,
125 };
126 list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]);
127 }
128
129 if (sa->vc == vc)
130 return 0;
131
132 if (vc) {
133 /* Attach first to new VC */
134 vc->ipsec++;
135 nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED);
136 }
137 if (sa->vc && vc) {
138 /* Notify old VC of migration */
139 sa->vc->abort_migration = 0;
140 debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s",
141 sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]),
142 sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]));
143 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA);
144 abort_migration = sa->vc->abort_migration;
145 }
146 if (sa->vc) {
147 /* Deattach old VC */
148 sa->vc->ipsec--;
149 if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc);
150 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED);
151 }
152
153 /* Update */
154 sa->vc = vc;
155 if (!vc) {
156 list_del(&sa->childlist_entry);
157 XFREE(MTYPE_NHRP_VC, sa);
158 }
159
160 return abort_migration;
161 }
162
163 void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action)
164 {
165 notifier_add(n, &vc->notifier_list, action);
166 }
167
168 void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n)
169 {
170 notifier_del(n);
171 nhrp_vc_check_delete(vc);
172 }
173
174
175 struct nhrp_vc_iterator_ctx {
176 void (*cb)(struct nhrp_vc *, void *);
177 void *ctx;
178 };
179
180 static void nhrp_vc_iterator(struct hash_backet *b, void *ctx)
181 {
182 struct nhrp_vc_iterator_ctx *ic = ctx;
183 ic->cb(b->data, ic->ctx);
184 }
185
186 void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx)
187 {
188 struct nhrp_vc_iterator_ctx ic = {
189 .cb = cb,
190 .ctx = ctx,
191 };
192 hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic);
193 }
194
195 void nhrp_vc_init(void)
196 {
197 size_t i;
198
199 nhrp_vc_hash = hash_create(nhrp_vc_key,
200 nhrp_vc_cmp,
201 "NHRP VC hash");
202 for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
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
211 for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) {
212 list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry)
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 }