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