xref: /openbsd-src/usr.sbin/ldpd/adjacency.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: adjacency.c,v 1.27 2019/12/12 00:10:29 yasuoka 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 *
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
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
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 *
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
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 /* ARGSUSED */
160 static void
161 adj_itimer(int fd, short event, void *arg)
162 {
163 	struct adj *adj = arg;
164 
165 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
166 
167 	if (adj->source.type == HELLO_TARGETED) {
168 		if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
169 		    adj->source.target->pw_count == 0) {
170 			/* remove dynamic targeted neighbor */
171 			tnbr_del(adj->source.target);
172 			return;
173 		}
174 		adj->source.target->adj = NULL;
175 	}
176 
177 	adj_del(adj, S_HOLDTIME_EXP);
178 }
179 
180 void
181 adj_start_itimer(struct adj *adj)
182 {
183 	struct timeval	tv;
184 
185 	timerclear(&tv);
186 	tv.tv_sec = adj->holdtime;
187 	if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
188 		fatal(__func__);
189 }
190 
191 void
192 adj_stop_itimer(struct adj *adj)
193 {
194 	if (evtimer_pending(&adj->inactivity_timer, NULL) &&
195 	    evtimer_del(&adj->inactivity_timer) == -1)
196 		fatal(__func__);
197 }
198 
199 /* targeted neighbors */
200 
201 struct tnbr *
202 tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
203 {
204 	struct tnbr		*tnbr;
205 
206 	if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
207 		fatal(__func__);
208 
209 	tnbr->af = af;
210 	tnbr->addr = *addr;
211 	tnbr->state = TNBR_STA_DOWN;
212 	tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime;
213 	tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;
214 
215 	return (tnbr);
216 }
217 
218 static void
219 tnbr_del(struct tnbr *tnbr)
220 {
221 	tnbr_stop_hello_timer(tnbr);
222 	if (tnbr->adj)
223 		adj_del(tnbr->adj, S_SHUTDOWN);
224 	LIST_REMOVE(tnbr, entry);
225 	free(tnbr);
226 }
227 
228 struct tnbr *
229 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
230 {
231 	struct tnbr *tnbr;
232 
233 	LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
234 		if (af == tnbr->af &&
235 		    ldp_addrcmp(af, addr, &tnbr->addr) == 0)
236 			return (tnbr);
237 
238 	return (NULL);
239 }
240 
241 struct tnbr *
242 tnbr_check(struct tnbr *tnbr)
243 {
244 	if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
245 	    tnbr->pw_count == 0) {
246 		tnbr_del(tnbr);
247 		return (NULL);
248 	}
249 
250 	return (tnbr);
251 }
252 
253 void
254 tnbr_update(struct tnbr *tnbr)
255 {
256 	int			 socket_ok, rtr_id_ok;
257 
258 	if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
259 		socket_ok = 1;
260 	else
261 		socket_ok = 0;
262 
263 	if (leconf->rtr_id.s_addr != INADDR_ANY)
264 		rtr_id_ok = 1;
265 	else
266 		rtr_id_ok = 0;
267 
268 	if (tnbr->state == TNBR_STA_DOWN) {
269 		if (!socket_ok || !rtr_id_ok)
270 			return;
271 
272 		tnbr->state = TNBR_STA_ACTIVE;
273 		send_hello(HELLO_TARGETED, NULL, tnbr);
274 
275 		evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
276 		tnbr_start_hello_timer(tnbr);
277 	} else if (tnbr->state == TNBR_STA_ACTIVE) {
278 		if (socket_ok && rtr_id_ok)
279 			return;
280 
281 		tnbr->state = TNBR_STA_DOWN;
282 		tnbr_stop_hello_timer(tnbr);
283 	}
284 }
285 
286 void
287 tnbr_update_all(int af)
288 {
289 	struct tnbr		*tnbr;
290 
291 	/* update targeted neighbors */
292 	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
293 		if (tnbr->af == af || af == AF_UNSPEC)
294 			tnbr_update(tnbr);
295 }
296 
297 /* target neighbors timers */
298 
299 /* ARGSUSED */
300 static void
301 tnbr_hello_timer(int fd, short event, void *arg)
302 {
303 	struct tnbr	*tnbr = arg;
304 
305 	send_hello(HELLO_TARGETED, NULL, tnbr);
306 	tnbr_start_hello_timer(tnbr);
307 }
308 
309 static void
310 tnbr_start_hello_timer(struct tnbr *tnbr)
311 {
312 	struct timeval	 tv;
313 
314 	timerclear(&tv);
315 	tv.tv_sec = tnbr->hello_interval;
316 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
317 		fatal(__func__);
318 }
319 
320 static void
321 tnbr_stop_hello_timer(struct tnbr *tnbr)
322 {
323 	if (evtimer_pending(&tnbr->hello_timer, NULL) &&
324 	    evtimer_del(&tnbr->hello_timer) == -1)
325 		fatal(__func__);
326 }
327 
328 struct ctl_adj *
329 adj_to_ctl(struct adj *adj)
330 {
331 	static struct ctl_adj	 actl;
332 
333 	actl.af = adj_get_af(adj);
334 	actl.id = adj->lsr_id;
335 	actl.type = adj->source.type;
336 	switch (adj->source.type) {
337 	case HELLO_LINK:
338 		memcpy(actl.ifname, adj->source.link.ia->iface->name,
339 		    sizeof(actl.ifname));
340 		break;
341 	case HELLO_TARGETED:
342 		actl.src_addr = adj->source.target->addr;
343 		break;
344 	}
345 	actl.holdtime = adj->holdtime;
346 	actl.trans_addr = adj->trans_addr;
347 
348 	return (&actl);
349 }
350