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