]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/adjacency.c
Merge pull request #12780 from opensourcerouting/spdx-license-id
[mirror_frr.git] / ldpd / adjacency.c
1 // SPDX-License-Identifier: ISC
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>
9 */
10
11 #include <zebra.h>
12
13 #include "ldpd.h"
14 #include "ldpe.h"
15 #include "log.h"
16
17 static __inline int adj_compare(const struct adj *, const struct adj *);
18 static void adj_itimer(struct thread *);
19 static __inline int tnbr_compare(const struct tnbr *, const struct tnbr *);
20 static void tnbr_del(struct ldpd_conf *, struct tnbr *);
21 static void tnbr_start(struct tnbr *);
22 static void tnbr_stop(struct tnbr *);
23 static void tnbr_hello_timer(struct thread *);
24 static void tnbr_start_hello_timer(struct tnbr *);
25 static void tnbr_stop_hello_timer(struct tnbr *);
26
27 RB_GENERATE(global_adj_head, adj, global_entry, adj_compare)
28 RB_GENERATE(nbr_adj_head, adj, nbr_entry, adj_compare)
29 RB_GENERATE(ia_adj_head, adj, ia_entry, adj_compare)
30 RB_GENERATE(tnbr_head, tnbr, entry, tnbr_compare)
31
32 static __inline int
33 adj_compare(const struct adj *a, const struct adj *b)
34 {
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
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:
52 if (if_cmp_name_func(a->source.link.ia->iface->name,
53 b->source.link.ia->iface->name) < 0)
54 return (-1);
55 if (if_cmp_name_func(a->source.link.ia->iface->name,
56 b->source.link.ia->iface->name) > 0)
57 return (1);
58 return (ldp_addrcmp(a->source.link.ia->af,
59 &a->source.link.src_addr, &b->source.link.src_addr));
60 case HELLO_TARGETED:
61 return (ldp_addrcmp(a->source.target->af,
62 &a->source.target->addr, &b->source.target->addr));
63 default:
64 fatalx("adj_compare: unknown hello type");
65 }
66
67 return (0);
68 }
69
70 struct adj *
71 adj_new(struct in_addr lsr_id, struct hello_source *source,
72 union ldpd_addr *addr)
73 {
74 struct adj *adj;
75
76 log_debug("%s: lsr-id %pI4, %s", __func__, &lsr_id,
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
87 RB_INSERT(global_adj_head, &global.adj_tree, adj);
88
89 switch (source->type) {
90 case HELLO_LINK:
91 RB_INSERT(ia_adj_head, &source->link.ia->adj_tree, adj);
92 break;
93 case HELLO_TARGETED:
94 source->target->adj = adj;
95 break;
96 }
97
98 return (adj);
99 }
100
101 void
102 adj_del(struct adj *adj, uint32_t notif_status)
103 {
104 struct nbr *nbr = adj->nbr;
105
106 log_debug("%s: lsr-id %pI4, %s (%s)", __func__, &adj->lsr_id,
107 log_hello_src(&adj->source), af_name(adj_get_af(adj)));
108
109 adj_stop_itimer(adj);
110
111 RB_REMOVE(global_adj_head, &global.adj_tree, adj);
112 if (nbr)
113 RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj);
114 switch (adj->source.type) {
115 case HELLO_LINK:
116 RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj);
117
118 if (nbr)
119 ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_DEL);
120 break;
121 case HELLO_TARGETED:
122 adj->source.target->adj = NULL;
123 break;
124 }
125
126 free(adj);
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) {
134 session_shutdown(nbr, notif_status, 0, 0);
135 nbr_del(nbr);
136 }
137 }
138
139 struct adj *
140 adj_find(struct in_addr lsr_id, struct hello_source *source)
141 {
142 struct adj adj;
143 adj.lsr_id = lsr_id;
144 adj.source = *source;
145 return (RB_FIND(global_adj_head, &global.adj_tree, &adj));
146 }
147
148 int
149 adj_get_af(const struct adj *adj)
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 */
164 static void adj_itimer(struct thread *thread)
165 {
166 struct adj *adj = THREAD_ARG(thread);
167
168 adj->inactivity_timer = NULL;
169
170 log_debug("%s: lsr-id %pI4", __func__, &adj->lsr_id);
171
172 if (adj->source.type == HELLO_TARGETED) {
173 if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
174 adj->source.target->pw_count == 0 &&
175 adj->source.target->rlfa_count == 0) {
176 /* remove dynamic targeted neighbor */
177 tnbr_del(leconf, adj->source.target);
178 return;
179 }
180 }
181
182 adj_del(adj, S_HOLDTIME_EXP);
183 }
184
185 void
186 adj_start_itimer(struct adj *adj)
187 {
188 THREAD_OFF(adj->inactivity_timer);
189 adj->inactivity_timer = NULL;
190 thread_add_timer(master, adj_itimer, adj, adj->holdtime,
191 &adj->inactivity_timer);
192 }
193
194 void
195 adj_stop_itimer(struct adj *adj)
196 {
197 THREAD_OFF(adj->inactivity_timer);
198 }
199
200 /* targeted neighbors */
201
202 static __inline int
203 tnbr_compare(const struct tnbr *a, const struct tnbr *b)
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
213 struct tnbr *
214 tnbr_new(int af, union ldpd_addr *addr)
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;
224
225 return (tnbr);
226 }
227
228 static void
229 tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr)
230 {
231 tnbr_stop(tnbr);
232 RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
233 free(tnbr);
234 }
235
236 struct tnbr *
237 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
238 {
239 struct tnbr tnbr;
240 tnbr.af = af;
241 tnbr.addr = *addr;
242 return (RB_FIND(tnbr_head, &xconf->tnbr_tree, &tnbr));
243 }
244
245 struct tnbr *
246 tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
247 {
248 if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
249 tnbr->pw_count == 0 && tnbr->rlfa_count == 0) {
250 tnbr_del(xconf, tnbr);
251 return (NULL);
252 }
253
254 return (tnbr);
255 }
256
257 static void
258 tnbr_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
265 static void
266 tnbr_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
274 void
275 tnbr_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
284 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
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
293 tnbr_start(tnbr);
294 } else if (tnbr->state == TNBR_STA_ACTIVE) {
295 if (socket_ok && rtr_id_ok)
296 return;
297
298 tnbr_stop(tnbr);
299 }
300 }
301
302 void
303 tnbr_update_all(int af)
304 {
305 struct tnbr *tnbr;
306
307 /* update targeted neighbors */
308 RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree)
309 if (tnbr->af == af || af == AF_UNSPEC)
310 tnbr_update(tnbr);
311 }
312
313 uint16_t
314 tnbr_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
322 uint16_t
323 tnbr_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
331 /* target neighbors timers */
332
333 /* ARGSUSED */
334 static void tnbr_hello_timer(struct thread *thread)
335 {
336 struct tnbr *tnbr = THREAD_ARG(thread);
337
338 tnbr->hello_timer = NULL;
339 send_hello(HELLO_TARGETED, NULL, tnbr);
340 tnbr_start_hello_timer(tnbr);
341 }
342
343 static void
344 tnbr_start_hello_timer(struct tnbr *tnbr)
345 {
346 THREAD_OFF(tnbr->hello_timer);
347 tnbr->hello_timer = NULL;
348 thread_add_timer(master, tnbr_hello_timer, tnbr, tnbr_get_hello_interval(tnbr),
349 &tnbr->hello_timer);
350 }
351
352 static void
353 tnbr_stop_hello_timer(struct tnbr *tnbr)
354 {
355 THREAD_OFF(tnbr->hello_timer);
356 }
357
358 struct ctl_adj *
359 adj_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));
370 actl.src_addr = adj->source.link.src_addr;
371 break;
372 case HELLO_TARGETED:
373 actl.src_addr = adj->source.target->addr;
374 break;
375 }
376 actl.holdtime = adj->holdtime;
377 actl.holdtime_remaining =
378 thread_timer_remain_second(adj->inactivity_timer);
379 actl.trans_addr = adj->trans_addr;
380 actl.ds_tlv = adj->ds_tlv;
381
382 return (&actl);
383 }