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