]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/adjacency.c
ldpd: use red-black trees to store 'adj' elements
[mirror_frr.git] / ldpd / adjacency.c
1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2013, 2015 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <zebra.h>
23
24 #include "ldpd.h"
25 #include "ldpe.h"
26 #include "log.h"
27
28 static __inline int adj_compare(struct adj *, struct adj *);
29 static int adj_itimer(struct thread *);
30 static __inline int tnbr_compare(struct tnbr *, struct tnbr *);
31 static void tnbr_del(struct ldpd_conf *, struct tnbr *);
32 static int tnbr_hello_timer(struct thread *);
33 static void tnbr_start_hello_timer(struct tnbr *);
34 static void tnbr_stop_hello_timer(struct tnbr *);
35
36 RB_GENERATE(global_adj_head, adj, global_entry, adj_compare)
37 RB_GENERATE(nbr_adj_head, adj, nbr_entry, adj_compare)
38 RB_GENERATE(ia_adj_head, adj, ia_entry, adj_compare)
39 RB_GENERATE(tnbr_head, tnbr, entry, tnbr_compare)
40
41 static __inline int
42 adj_compare(struct adj *a, struct adj *b)
43 {
44 if (a->source.type < b->source.type)
45 return (-1);
46 if (a->source.type > b->source.type)
47 return (1);
48
49 switch (a->source.type) {
50 case HELLO_LINK:
51 if (a->source.link.ia->af < b->source.link.ia->af)
52 return (-1);
53 if (a->source.link.ia->af > b->source.link.ia->af)
54 return (1);
55 return (ldp_addrcmp(a->source.link.ia->af,
56 &a->source.link.src_addr, &b->source.link.src_addr));
57 case HELLO_TARGETED:
58 if (a->source.target->af < b->source.target->af)
59 return (-1);
60 if (a->source.target->af > b->source.target->af)
61 return (1);
62 return (ldp_addrcmp(a->source.target->af,
63 &a->source.target->addr, &b->source.target->addr));
64 default:
65 fatalx("adj_get_af: unknown hello type");
66 }
67
68 return (0);
69 }
70
71 struct adj *
72 adj_new(struct in_addr lsr_id, struct hello_source *source,
73 union ldpd_addr *addr)
74 {
75 struct adj *adj;
76
77 log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id),
78 log_hello_src(source));
79
80 if ((adj = calloc(1, sizeof(*adj))) == NULL)
81 fatal(__func__);
82
83 adj->lsr_id = lsr_id;
84 adj->nbr = NULL;
85 adj->source = *source;
86 adj->trans_addr = *addr;
87
88 RB_INSERT(global_adj_head, &global.adj_tree, adj);
89
90 switch (source->type) {
91 case HELLO_LINK:
92 RB_INSERT(ia_adj_head, &source->link.ia->adj_tree, adj);
93 break;
94 case HELLO_TARGETED:
95 source->target->adj = adj;
96 break;
97 }
98
99 return (adj);
100 }
101
102 static void
103 adj_del_single(struct adj *adj)
104 {
105 log_debug("%s: lsr-id %s, %s (%s)", __func__, inet_ntoa(adj->lsr_id),
106 log_hello_src(&adj->source), af_name(adj_get_af(adj)));
107
108 adj_stop_itimer(adj);
109
110 RB_REMOVE(global_adj_head, &global.adj_tree, adj);
111 if (adj->nbr)
112 RB_REMOVE(nbr_adj_head, &adj->nbr->adj_tree, adj);
113 switch (adj->source.type) {
114 case HELLO_LINK:
115 RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj);
116 break;
117 case HELLO_TARGETED:
118 adj->source.target->adj = NULL;
119 break;
120 }
121
122 free(adj);
123 }
124
125 void
126 adj_del(struct adj *adj, uint32_t notif_status)
127 {
128 struct nbr *nbr = adj->nbr;
129 struct adj *atmp;
130
131 adj_del_single(adj);
132
133 /*
134 * If the neighbor still exists but none of its remaining
135 * adjacencies (if any) are from the preferred address-family,
136 * then delete it.
137 */
138 if (nbr && nbr_adj_count(nbr, nbr->af) == 0) {
139 RB_FOREACH_SAFE(adj, nbr_adj_head, &nbr->adj_tree, atmp)
140 adj_del_single(adj);
141 session_shutdown(nbr, notif_status, 0, 0);
142 nbr_del(nbr);
143 }
144 }
145
146 struct adj *
147 adj_find(struct hello_source *source)
148 {
149 struct adj adj;
150 adj.source = *source;
151 return (RB_FIND(global_adj_head, &global.adj_tree, &adj));
152 }
153
154 int
155 adj_get_af(struct adj *adj)
156 {
157 switch (adj->source.type) {
158 case HELLO_LINK:
159 return (adj->source.link.ia->af);
160 case HELLO_TARGETED:
161 return (adj->source.target->af);
162 default:
163 fatalx("adj_get_af: unknown hello type");
164 }
165 }
166
167 /* adjacency timers */
168
169 /* ARGSUSED */
170 static int
171 adj_itimer(struct thread *thread)
172 {
173 struct adj *adj = THREAD_ARG(thread);
174
175 adj->inactivity_timer = NULL;
176
177 log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
178
179 if (adj->source.type == HELLO_TARGETED) {
180 if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
181 adj->source.target->pw_count == 0) {
182 /* remove dynamic targeted neighbor */
183 tnbr_del(leconf, adj->source.target);
184 return (0);
185 }
186 adj->source.target->adj = NULL;
187 }
188
189 adj_del(adj, S_HOLDTIME_EXP);
190
191 return (0);
192 }
193
194 void
195 adj_start_itimer(struct adj *adj)
196 {
197 THREAD_TIMER_OFF(adj->inactivity_timer);
198 adj->inactivity_timer = thread_add_timer(master, adj_itimer, adj,
199 adj->holdtime);
200 }
201
202 void
203 adj_stop_itimer(struct adj *adj)
204 {
205 THREAD_TIMER_OFF(adj->inactivity_timer);
206 }
207
208 /* targeted neighbors */
209
210 static __inline int
211 tnbr_compare(struct tnbr *a, struct tnbr *b)
212 {
213 if (a->af < b->af)
214 return (-1);
215 if (a->af > b->af)
216 return (1);
217
218 return (ldp_addrcmp(a->af, &a->addr, &b->addr));
219 }
220
221 struct tnbr *
222 tnbr_new(int af, union ldpd_addr *addr)
223 {
224 struct tnbr *tnbr;
225
226 if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
227 fatal(__func__);
228
229 tnbr->af = af;
230 tnbr->addr = *addr;
231 tnbr->state = TNBR_STA_DOWN;
232
233 return (tnbr);
234 }
235
236 static void
237 tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr)
238 {
239 tnbr_stop_hello_timer(tnbr);
240 if (tnbr->adj)
241 adj_del(tnbr->adj, S_SHUTDOWN);
242 RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
243 free(tnbr);
244 }
245
246 struct tnbr *
247 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
248 {
249 struct tnbr tnbr;
250 tnbr.af = af;
251 tnbr.addr = *addr;
252 return (RB_FIND(tnbr_head, &xconf->tnbr_tree, &tnbr));
253 }
254
255 struct tnbr *
256 tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
257 {
258 if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
259 tnbr->pw_count == 0) {
260 tnbr_del(xconf, tnbr);
261 return (NULL);
262 }
263
264 return (tnbr);
265 }
266
267 void
268 tnbr_update(struct tnbr *tnbr)
269 {
270 int socket_ok, rtr_id_ok;
271
272 if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
273 socket_ok = 1;
274 else
275 socket_ok = 0;
276
277 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
278 rtr_id_ok = 1;
279 else
280 rtr_id_ok = 0;
281
282 if (tnbr->state == TNBR_STA_DOWN) {
283 if (!socket_ok || !rtr_id_ok)
284 return;
285
286 tnbr->state = TNBR_STA_ACTIVE;
287 send_hello(HELLO_TARGETED, NULL, tnbr);
288
289 tnbr_start_hello_timer(tnbr);
290 } else if (tnbr->state == TNBR_STA_ACTIVE) {
291 if (socket_ok && rtr_id_ok)
292 return;
293
294 tnbr->state = TNBR_STA_DOWN;
295 tnbr_stop_hello_timer(tnbr);
296 }
297 }
298
299 void
300 tnbr_update_all(int af)
301 {
302 struct tnbr *tnbr;
303
304 /* update targeted neighbors */
305 RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree)
306 if (tnbr->af == af || af == AF_UNSPEC)
307 tnbr_update(tnbr);
308 }
309
310 uint16_t
311 tnbr_get_hello_holdtime(struct tnbr *tnbr)
312 {
313 if ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime != 0)
314 return ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime);
315
316 return (leconf->thello_holdtime);
317 }
318
319 uint16_t
320 tnbr_get_hello_interval(struct tnbr *tnbr)
321 {
322 if ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval != 0)
323 return ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval);
324
325 return (leconf->thello_interval);
326 }
327
328 /* target neighbors timers */
329
330 /* ARGSUSED */
331 static int
332 tnbr_hello_timer(struct thread *thread)
333 {
334 struct tnbr *tnbr = THREAD_ARG(thread);
335
336 tnbr->hello_timer = NULL;
337 send_hello(HELLO_TARGETED, NULL, tnbr);
338 tnbr_start_hello_timer(tnbr);
339
340 return (0);
341 }
342
343 static void
344 tnbr_start_hello_timer(struct tnbr *tnbr)
345 {
346 THREAD_TIMER_OFF(tnbr->hello_timer);
347 tnbr->hello_timer = thread_add_timer(master, tnbr_hello_timer, tnbr,
348 tnbr_get_hello_interval(tnbr));
349 }
350
351 static void
352 tnbr_stop_hello_timer(struct tnbr *tnbr)
353 {
354 THREAD_TIMER_OFF(tnbr->hello_timer);
355 }
356
357 struct ctl_adj *
358 adj_to_ctl(struct adj *adj)
359 {
360 static struct ctl_adj actl;
361
362 actl.af = adj_get_af(adj);
363 actl.id = adj->lsr_id;
364 actl.type = adj->source.type;
365 switch (adj->source.type) {
366 case HELLO_LINK:
367 memcpy(actl.ifname, adj->source.link.ia->iface->name,
368 sizeof(actl.ifname));
369 break;
370 case HELLO_TARGETED:
371 actl.src_addr = adj->source.target->addr;
372 break;
373 }
374 actl.holdtime = adj->holdtime;
375 actl.trans_addr = adj->trans_addr;
376
377 return (&actl);
378 }