]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/adjacency.c
Merge pull request #714 from opensourcerouting/cli_magic_defpy
[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(const struct adj *, const struct adj *);
29 static int adj_itimer(struct thread *);
30 static __inline int tnbr_compare(const struct tnbr *, const struct tnbr *);
31 static void tnbr_del(struct ldpd_conf *, struct tnbr *);
32 static void tnbr_start(struct tnbr *);
33 static void tnbr_stop(struct tnbr *);
34 static int tnbr_hello_timer(struct thread *);
35 static void tnbr_start_hello_timer(struct tnbr *);
36 static void tnbr_stop_hello_timer(struct tnbr *);
37
38 RB_GENERATE(global_adj_head, adj, global_entry, adj_compare)
39 RB_GENERATE(nbr_adj_head, adj, nbr_entry, adj_compare)
40 RB_GENERATE(ia_adj_head, adj, ia_entry, adj_compare)
41 RB_GENERATE(tnbr_head, tnbr, entry, tnbr_compare)
42
43 static __inline int
44 adj_compare(const struct adj *a, const struct adj *b)
45 {
46 if (adj_get_af(a) < adj_get_af(b))
47 return (-1);
48 if (adj_get_af(a) > adj_get_af(b))
49 return (1);
50
51 if (ntohl(a->lsr_id.s_addr) < ntohl(b->lsr_id.s_addr))
52 return (-1);
53 if (ntohl(a->lsr_id.s_addr) > ntohl(b->lsr_id.s_addr))
54 return (1);
55
56 if (a->source.type < b->source.type)
57 return (-1);
58 if (a->source.type > b->source.type)
59 return (1);
60
61 switch (a->source.type) {
62 case HELLO_LINK:
63 if (strcmp(a->source.link.ia->iface->name,
64 b->source.link.ia->iface->name) < 0)
65 return (-1);
66 if (strcmp(a->source.link.ia->iface->name,
67 b->source.link.ia->iface->name) > 0)
68 return (1);
69 return (ldp_addrcmp(a->source.link.ia->af,
70 &a->source.link.src_addr, &b->source.link.src_addr));
71 case HELLO_TARGETED:
72 return (ldp_addrcmp(a->source.target->af,
73 &a->source.target->addr, &b->source.target->addr));
74 default:
75 fatalx("adj_compare: unknown hello type");
76 }
77
78 return (0);
79 }
80
81 struct adj *
82 adj_new(struct in_addr lsr_id, struct hello_source *source,
83 union ldpd_addr *addr)
84 {
85 struct adj *adj;
86
87 log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id),
88 log_hello_src(source));
89
90 if ((adj = calloc(1, sizeof(*adj))) == NULL)
91 fatal(__func__);
92
93 adj->lsr_id = lsr_id;
94 adj->nbr = NULL;
95 adj->source = *source;
96 adj->trans_addr = *addr;
97
98 RB_INSERT(global_adj_head, &global.adj_tree, adj);
99
100 switch (source->type) {
101 case HELLO_LINK:
102 RB_INSERT(ia_adj_head, &source->link.ia->adj_tree, adj);
103 break;
104 case HELLO_TARGETED:
105 source->target->adj = adj;
106 break;
107 }
108
109 return (adj);
110 }
111
112 static void
113 adj_del_single(struct adj *adj)
114 {
115 log_debug("%s: lsr-id %s, %s (%s)", __func__, inet_ntoa(adj->lsr_id),
116 log_hello_src(&adj->source), af_name(adj_get_af(adj)));
117
118 adj_stop_itimer(adj);
119
120 RB_REMOVE(global_adj_head, &global.adj_tree, adj);
121 if (adj->nbr)
122 RB_REMOVE(nbr_adj_head, &adj->nbr->adj_tree, adj);
123 switch (adj->source.type) {
124 case HELLO_LINK:
125 RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj);
126 break;
127 case HELLO_TARGETED:
128 adj->source.target->adj = NULL;
129 break;
130 }
131
132 free(adj);
133 }
134
135 void
136 adj_del(struct adj *adj, uint32_t notif_status)
137 {
138 struct nbr *nbr = adj->nbr;
139 struct adj *atmp;
140
141 adj_del_single(adj);
142
143 /*
144 * If the neighbor still exists but none of its remaining
145 * adjacencies (if any) are from the preferred address-family,
146 * then delete it.
147 */
148 if (nbr && nbr_adj_count(nbr, nbr->af) == 0) {
149 RB_FOREACH_SAFE(adj, nbr_adj_head, &nbr->adj_tree, atmp)
150 adj_del_single(adj);
151 session_shutdown(nbr, notif_status, 0, 0);
152 nbr_del(nbr);
153 }
154 }
155
156 struct adj *
157 adj_find(struct in_addr lsr_id, struct hello_source *source)
158 {
159 struct adj adj;
160 adj.lsr_id = lsr_id;
161 adj.source = *source;
162 return (RB_FIND(global_adj_head, &global.adj_tree, &adj));
163 }
164
165 int
166 adj_get_af(const struct adj *adj)
167 {
168 switch (adj->source.type) {
169 case HELLO_LINK:
170 return (adj->source.link.ia->af);
171 case HELLO_TARGETED:
172 return (adj->source.target->af);
173 default:
174 fatalx("adj_get_af: unknown hello type");
175 }
176 }
177
178 /* adjacency timers */
179
180 /* ARGSUSED */
181 static int
182 adj_itimer(struct thread *thread)
183 {
184 struct adj *adj = THREAD_ARG(thread);
185
186 adj->inactivity_timer = NULL;
187
188 log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
189
190 if (adj->source.type == HELLO_TARGETED) {
191 if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
192 adj->source.target->pw_count == 0) {
193 /* remove dynamic targeted neighbor */
194 tnbr_del(leconf, adj->source.target);
195 return (0);
196 }
197 adj->source.target->adj = NULL;
198 }
199
200 adj_del(adj, S_HOLDTIME_EXP);
201
202 return (0);
203 }
204
205 void
206 adj_start_itimer(struct adj *adj)
207 {
208 THREAD_TIMER_OFF(adj->inactivity_timer);
209 adj->inactivity_timer = NULL;
210 thread_add_timer(master, adj_itimer, adj, adj->holdtime,
211 &adj->inactivity_timer);
212 }
213
214 void
215 adj_stop_itimer(struct adj *adj)
216 {
217 THREAD_TIMER_OFF(adj->inactivity_timer);
218 }
219
220 /* targeted neighbors */
221
222 static __inline int
223 tnbr_compare(const struct tnbr *a, const struct tnbr *b)
224 {
225 if (a->af < b->af)
226 return (-1);
227 if (a->af > b->af)
228 return (1);
229
230 return (ldp_addrcmp(a->af, &a->addr, &b->addr));
231 }
232
233 struct tnbr *
234 tnbr_new(int af, union ldpd_addr *addr)
235 {
236 struct tnbr *tnbr;
237
238 if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
239 fatal(__func__);
240
241 tnbr->af = af;
242 tnbr->addr = *addr;
243 tnbr->state = TNBR_STA_DOWN;
244
245 return (tnbr);
246 }
247
248 static void
249 tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr)
250 {
251 tnbr_stop(tnbr);
252 RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
253 free(tnbr);
254 }
255
256 struct tnbr *
257 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
258 {
259 struct tnbr tnbr;
260 tnbr.af = af;
261 tnbr.addr = *addr;
262 return (RB_FIND(tnbr_head, &xconf->tnbr_tree, &tnbr));
263 }
264
265 struct tnbr *
266 tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
267 {
268 if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
269 tnbr->pw_count == 0) {
270 tnbr_del(xconf, tnbr);
271 return (NULL);
272 }
273
274 return (tnbr);
275 }
276
277 static void
278 tnbr_start(struct tnbr *tnbr)
279 {
280 send_hello(HELLO_TARGETED, NULL, tnbr);
281 tnbr_start_hello_timer(tnbr);
282 tnbr->state = TNBR_STA_ACTIVE;
283 }
284
285 static void
286 tnbr_stop(struct tnbr *tnbr)
287 {
288 tnbr_stop_hello_timer(tnbr);
289 if (tnbr->adj)
290 adj_del(tnbr->adj, S_SHUTDOWN);
291 tnbr->state = TNBR_STA_DOWN;
292 }
293
294 void
295 tnbr_update(struct tnbr *tnbr)
296 {
297 int socket_ok, rtr_id_ok;
298
299 if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
300 socket_ok = 1;
301 else
302 socket_ok = 0;
303
304 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
305 rtr_id_ok = 1;
306 else
307 rtr_id_ok = 0;
308
309 if (tnbr->state == TNBR_STA_DOWN) {
310 if (!socket_ok || !rtr_id_ok)
311 return;
312
313 tnbr_start(tnbr);
314 } else if (tnbr->state == TNBR_STA_ACTIVE) {
315 if (socket_ok && rtr_id_ok)
316 return;
317
318 tnbr_stop(tnbr);
319 }
320 }
321
322 void
323 tnbr_update_all(int af)
324 {
325 struct tnbr *tnbr;
326
327 /* update targeted neighbors */
328 RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree)
329 if (tnbr->af == af || af == AF_UNSPEC)
330 tnbr_update(tnbr);
331 }
332
333 uint16_t
334 tnbr_get_hello_holdtime(struct tnbr *tnbr)
335 {
336 if ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime != 0)
337 return ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime);
338
339 return (leconf->thello_holdtime);
340 }
341
342 uint16_t
343 tnbr_get_hello_interval(struct tnbr *tnbr)
344 {
345 if ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval != 0)
346 return ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval);
347
348 return (leconf->thello_interval);
349 }
350
351 /* target neighbors timers */
352
353 /* ARGSUSED */
354 static int
355 tnbr_hello_timer(struct thread *thread)
356 {
357 struct tnbr *tnbr = THREAD_ARG(thread);
358
359 tnbr->hello_timer = NULL;
360 send_hello(HELLO_TARGETED, NULL, tnbr);
361 tnbr_start_hello_timer(tnbr);
362
363 return (0);
364 }
365
366 static void
367 tnbr_start_hello_timer(struct tnbr *tnbr)
368 {
369 THREAD_TIMER_OFF(tnbr->hello_timer);
370 tnbr->hello_timer = NULL;
371 thread_add_timer(master, tnbr_hello_timer, tnbr, tnbr_get_hello_interval(tnbr),
372 &tnbr->hello_timer);
373 }
374
375 static void
376 tnbr_stop_hello_timer(struct tnbr *tnbr)
377 {
378 THREAD_TIMER_OFF(tnbr->hello_timer);
379 }
380
381 struct ctl_adj *
382 adj_to_ctl(struct adj *adj)
383 {
384 static struct ctl_adj actl;
385
386 actl.af = adj_get_af(adj);
387 actl.id = adj->lsr_id;
388 actl.type = adj->source.type;
389 switch (adj->source.type) {
390 case HELLO_LINK:
391 memcpy(actl.ifname, adj->source.link.ia->iface->name,
392 sizeof(actl.ifname));
393 actl.src_addr = adj->source.link.src_addr;
394 break;
395 case HELLO_TARGETED:
396 actl.src_addr = adj->source.target->addr;
397 break;
398 }
399 actl.holdtime = adj->holdtime;
400 actl.holdtime_remaining =
401 thread_timer_remain_second(adj->inactivity_timer);
402 actl.trans_addr = adj->trans_addr;
403 actl.ds_tlv = adj->ds_tlv;
404
405 return (&actl);
406 }