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