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