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