xref: /openbsd/usr.sbin/ldpd/adjacency.c (revision 9aeb55b7)
1*9aeb55b7Srenato /*	$OpenBSD: adjacency.c,v 1.23 2016/06/09 17:26:32 renato Exp $ */
276e3bd63Sclaudio 
376e3bd63Sclaudio /*
45dc9330aSrenato  * Copyright (c) 2013, 2015 Renato Westphal <renato@openbsd.org>
576e3bd63Sclaudio  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
676e3bd63Sclaudio  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
776e3bd63Sclaudio  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
876e3bd63Sclaudio  *
976e3bd63Sclaudio  * Permission to use, copy, modify, and distribute this software for any
1076e3bd63Sclaudio  * purpose with or without fee is hereby granted, provided that the above
1176e3bd63Sclaudio  * copyright notice and this permission notice appear in all copies.
1276e3bd63Sclaudio  *
1376e3bd63Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1476e3bd63Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1576e3bd63Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1676e3bd63Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1776e3bd63Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1876e3bd63Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1976e3bd63Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2076e3bd63Sclaudio  */
2176e3bd63Sclaudio 
2276e3bd63Sclaudio #include <sys/types.h>
2376e3bd63Sclaudio #include <arpa/inet.h>
2476e3bd63Sclaudio #include <stdlib.h>
2576e3bd63Sclaudio #include <string.h>
2676e3bd63Sclaudio 
2776e3bd63Sclaudio #include "ldpd.h"
2876e3bd63Sclaudio #include "ldpe.h"
2976e3bd63Sclaudio #include "log.h"
3076e3bd63Sclaudio 
31c28a25a1Srenato static void	 adj_itimer(int, short, void *);
32c28a25a1Srenato static void	 tnbr_del(struct tnbr *);
33c28a25a1Srenato static void	 tnbr_hello_timer(int, short, void *);
34c28a25a1Srenato static void	 tnbr_start_hello_timer(struct tnbr *);
35c28a25a1Srenato static void	 tnbr_stop_hello_timer(struct tnbr *);
3676e3bd63Sclaudio 
3776e3bd63Sclaudio struct adj *
38a8c39dc0Srenato adj_new(struct in_addr lsr_id, struct hello_source *source,
39a8c39dc0Srenato     union ldpd_addr *addr)
4076e3bd63Sclaudio {
4176e3bd63Sclaudio 	struct adj	*adj;
4276e3bd63Sclaudio 
43a8c39dc0Srenato 	log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id),
4433f6ccfeSrenato 	    log_hello_src(source));
4576e3bd63Sclaudio 
4676e3bd63Sclaudio 	if ((adj = calloc(1, sizeof(*adj))) == NULL)
47b7b4db73Srenato 		fatal(__func__);
4876e3bd63Sclaudio 
49a8c39dc0Srenato 	adj->lsr_id = lsr_id;
50a8c39dc0Srenato 	adj->nbr = NULL;
517aa09c5dSrenato 	adj->source = *source;
52a8c39dc0Srenato 	adj->trans_addr = *addr;
5376e3bd63Sclaudio 
5476e3bd63Sclaudio 	evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
5576e3bd63Sclaudio 
56a8c39dc0Srenato 	LIST_INSERT_HEAD(&global.adj_list, adj, global_entry);
5776e3bd63Sclaudio 
5876e3bd63Sclaudio 	switch (source->type) {
5976e3bd63Sclaudio 	case HELLO_LINK:
60a8c39dc0Srenato 		LIST_INSERT_HEAD(&source->link.ia->adj_list, adj, ia_entry);
6176e3bd63Sclaudio 		break;
6276e3bd63Sclaudio 	case HELLO_TARGETED:
6376e3bd63Sclaudio 		source->target->adj = adj;
6476e3bd63Sclaudio 		break;
6576e3bd63Sclaudio 	}
6676e3bd63Sclaudio 
6776e3bd63Sclaudio 	return (adj);
6876e3bd63Sclaudio }
6976e3bd63Sclaudio 
7076e3bd63Sclaudio void
71*9aeb55b7Srenato adj_del(struct adj *adj, int send_notif, uint32_t notif_status)
7276e3bd63Sclaudio {
73a8c39dc0Srenato 	log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->lsr_id),
7433f6ccfeSrenato 	    log_hello_src(&adj->source));
7576e3bd63Sclaudio 
7676e3bd63Sclaudio 	adj_stop_itimer(adj);
7776e3bd63Sclaudio 
78a8c39dc0Srenato 	LIST_REMOVE(adj, global_entry);
79a8c39dc0Srenato 	if (adj->nbr)
8076e3bd63Sclaudio 		LIST_REMOVE(adj, nbr_entry);
81ef2688d9Srenato 	if (adj->source.type == HELLO_LINK)
82a8c39dc0Srenato 		LIST_REMOVE(adj, ia_entry);
8376e3bd63Sclaudio 
8476e3bd63Sclaudio 	/* last adjacency deleted */
85*9aeb55b7Srenato 	if (adj->nbr && LIST_EMPTY(&adj->nbr->adj_list)) {
86*9aeb55b7Srenato 		if (send_notif)
87*9aeb55b7Srenato 			session_shutdown(adj->nbr, notif_status, 0, 0);
8876e3bd63Sclaudio 		nbr_del(adj->nbr);
89*9aeb55b7Srenato 	}
9076e3bd63Sclaudio 
9176e3bd63Sclaudio 	free(adj);
9276e3bd63Sclaudio }
9376e3bd63Sclaudio 
9476e3bd63Sclaudio struct adj *
95a8c39dc0Srenato adj_find(struct hello_source *source)
9676e3bd63Sclaudio {
9776e3bd63Sclaudio 	struct adj *adj;
9876e3bd63Sclaudio 
99a8c39dc0Srenato 	LIST_FOREACH(adj, &global.adj_list, global_entry) {
10076e3bd63Sclaudio 		if (adj->source.type != source->type)
10176e3bd63Sclaudio 			continue;
10276e3bd63Sclaudio 
10376e3bd63Sclaudio 		switch (source->type) {
10476e3bd63Sclaudio 		case HELLO_LINK:
105a8c39dc0Srenato 			if (ldp_addrcmp(source->link.ia->af,
106a8c39dc0Srenato 			    &adj->source.link.src_addr,
107a8c39dc0Srenato 			    &source->link.src_addr) == 0)
10876e3bd63Sclaudio 				return (adj);
10976e3bd63Sclaudio 			break;
11076e3bd63Sclaudio 		case HELLO_TARGETED:
11176e3bd63Sclaudio 			if (adj->source.target == source->target)
11276e3bd63Sclaudio 				return (adj);
11376e3bd63Sclaudio 			break;
11476e3bd63Sclaudio 		}
11576e3bd63Sclaudio 	}
11676e3bd63Sclaudio 
11776e3bd63Sclaudio 	return (NULL);
11876e3bd63Sclaudio }
11976e3bd63Sclaudio 
120a8c39dc0Srenato int
121a8c39dc0Srenato adj_get_af(struct adj *adj)
122a8c39dc0Srenato {
123a8c39dc0Srenato 	switch (adj->source.type) {
124a8c39dc0Srenato 	case HELLO_LINK:
125a8c39dc0Srenato 		return (adj->source.link.ia->af);
126a8c39dc0Srenato 	case HELLO_TARGETED:
127a8c39dc0Srenato 		return (adj->source.target->af);
128a8c39dc0Srenato 	default:
129a8c39dc0Srenato 		fatalx("adj_get_af: unknown hello type");
130a8c39dc0Srenato 	}
131a8c39dc0Srenato }
132a8c39dc0Srenato 
13376e3bd63Sclaudio /* adjacency timers */
13476e3bd63Sclaudio 
13576e3bd63Sclaudio /* ARGSUSED */
136c28a25a1Srenato static void
13776e3bd63Sclaudio adj_itimer(int fd, short event, void *arg)
13876e3bd63Sclaudio {
13976e3bd63Sclaudio 	struct adj *adj = arg;
14076e3bd63Sclaudio 
141a8c39dc0Srenato 	log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
14276e3bd63Sclaudio 
143ef2688d9Srenato 	if (adj->source.type == HELLO_TARGETED) {
1446399cec1Srenato 		if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
1456399cec1Srenato 		    adj->source.target->pw_count == 0) {
14699170248Srenato 			/* remove dynamic targeted neighbor */
14776e3bd63Sclaudio 			tnbr_del(adj->source.target);
14899170248Srenato 			return;
14976e3bd63Sclaudio 		}
15099170248Srenato 		adj->source.target->adj = NULL;
15176e3bd63Sclaudio 	}
15276e3bd63Sclaudio 
153*9aeb55b7Srenato 	adj_del(adj, 1, S_HOLDTIME_EXP);
15476e3bd63Sclaudio }
15576e3bd63Sclaudio 
15676e3bd63Sclaudio void
15776e3bd63Sclaudio adj_start_itimer(struct adj *adj)
15876e3bd63Sclaudio {
15976e3bd63Sclaudio 	struct timeval	tv;
16076e3bd63Sclaudio 
16176e3bd63Sclaudio 	timerclear(&tv);
16276e3bd63Sclaudio 	tv.tv_sec = adj->holdtime;
16376e3bd63Sclaudio 	if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
164b7b4db73Srenato 		fatal(__func__);
16576e3bd63Sclaudio }
16676e3bd63Sclaudio 
16776e3bd63Sclaudio void
16876e3bd63Sclaudio adj_stop_itimer(struct adj *adj)
16976e3bd63Sclaudio {
17076e3bd63Sclaudio 	if (evtimer_pending(&adj->inactivity_timer, NULL) &&
17176e3bd63Sclaudio 	    evtimer_del(&adj->inactivity_timer) == -1)
172b7b4db73Srenato 		fatal(__func__);
17376e3bd63Sclaudio }
17476e3bd63Sclaudio 
17576e3bd63Sclaudio /* targeted neighbors */
17676e3bd63Sclaudio 
17776e3bd63Sclaudio struct tnbr *
178a8c39dc0Srenato tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
17976e3bd63Sclaudio {
18076e3bd63Sclaudio 	struct tnbr		*tnbr;
18176e3bd63Sclaudio 
18276e3bd63Sclaudio 	if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
183b7b4db73Srenato 		fatal(__func__);
18476e3bd63Sclaudio 
185a8c39dc0Srenato 	tnbr->af = af;
186a8c39dc0Srenato 	tnbr->addr = *addr;
187b5921293Srenato 	tnbr->state = TNBR_STA_DOWN;
188a8c39dc0Srenato 	tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime;
189a8c39dc0Srenato 	tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;
19076e3bd63Sclaudio 
19176e3bd63Sclaudio 	return (tnbr);
19276e3bd63Sclaudio }
19376e3bd63Sclaudio 
194c28a25a1Srenato static void
19576e3bd63Sclaudio tnbr_del(struct tnbr *tnbr)
19676e3bd63Sclaudio {
19776e3bd63Sclaudio 	tnbr_stop_hello_timer(tnbr);
19876e3bd63Sclaudio 	if (tnbr->adj)
199*9aeb55b7Srenato 		adj_del(tnbr->adj, 1, S_SHUTDOWN);
200ef2688d9Srenato 	LIST_REMOVE(tnbr, entry);
20176e3bd63Sclaudio 	free(tnbr);
20276e3bd63Sclaudio }
20376e3bd63Sclaudio 
20499170248Srenato struct tnbr *
205a8c39dc0Srenato tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
20633f6ccfeSrenato {
20733f6ccfeSrenato 	struct tnbr *tnbr;
20833f6ccfeSrenato 
20933f6ccfeSrenato 	LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
210a8c39dc0Srenato 		if (af == tnbr->af &&
211a8c39dc0Srenato 		    ldp_addrcmp(af, addr, &tnbr->addr) == 0)
21233f6ccfeSrenato 			return (tnbr);
21333f6ccfeSrenato 
21433f6ccfeSrenato 	return (NULL);
21533f6ccfeSrenato }
21633f6ccfeSrenato 
21733f6ccfeSrenato struct tnbr *
21899170248Srenato tnbr_check(struct tnbr *tnbr)
21999170248Srenato {
2206399cec1Srenato 	if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
2216399cec1Srenato 	    tnbr->pw_count == 0) {
22299170248Srenato 		tnbr_del(tnbr);
22399170248Srenato 		return (NULL);
22499170248Srenato 	}
22599170248Srenato 
22699170248Srenato 	return (tnbr);
22799170248Srenato }
22899170248Srenato 
22976e3bd63Sclaudio void
230b5921293Srenato tnbr_update(struct tnbr *tnbr)
23176e3bd63Sclaudio {
23208964f31Srenato 	int			 socket_ok, rtr_id_ok;
23376e3bd63Sclaudio 
234a8c39dc0Srenato 	if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
235b5921293Srenato 		socket_ok = 1;
236b5921293Srenato 	else
237b5921293Srenato 		socket_ok = 0;
238b5921293Srenato 
23908964f31Srenato 	if (leconf->rtr_id.s_addr != INADDR_ANY)
24008964f31Srenato 		rtr_id_ok = 1;
24108964f31Srenato 	else
24208964f31Srenato 		rtr_id_ok = 0;
24308964f31Srenato 
244b5921293Srenato 	if (tnbr->state == TNBR_STA_DOWN) {
24508964f31Srenato 		if (!socket_ok || !rtr_id_ok)
246b5921293Srenato 			return;
247b5921293Srenato 
248b5921293Srenato 		tnbr->state = TNBR_STA_ACTIVE;
2493de94509Srenato 		send_hello(HELLO_TARGETED, NULL, tnbr);
250b5921293Srenato 
251b5921293Srenato 		evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
25276e3bd63Sclaudio 		tnbr_start_hello_timer(tnbr);
253b5921293Srenato 	} else if (tnbr->state == TNBR_STA_ACTIVE) {
25408964f31Srenato 		if (socket_ok && rtr_id_ok)
255b5921293Srenato 			return;
256b5921293Srenato 
257b5921293Srenato 		tnbr->state = TNBR_STA_DOWN;
258b5921293Srenato 		tnbr_stop_hello_timer(tnbr);
259b5921293Srenato 	}
260b5921293Srenato }
261b5921293Srenato 
262b5921293Srenato void
263a8c39dc0Srenato tnbr_update_all(int af)
264b5921293Srenato {
265b5921293Srenato 	struct tnbr		*tnbr;
266b5921293Srenato 
267b5921293Srenato 	/* update targeted neighbors */
268b5921293Srenato 	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
269a8c39dc0Srenato 		if (tnbr->af == af || af == AF_UNSPEC)
270b5921293Srenato 			tnbr_update(tnbr);
27176e3bd63Sclaudio }
27276e3bd63Sclaudio 
27376e3bd63Sclaudio /* target neighbors timers */
27476e3bd63Sclaudio 
27576e3bd63Sclaudio /* ARGSUSED */
276c28a25a1Srenato static void
27776e3bd63Sclaudio tnbr_hello_timer(int fd, short event, void *arg)
27876e3bd63Sclaudio {
27976e3bd63Sclaudio 	struct tnbr	*tnbr = arg;
28076e3bd63Sclaudio 
28176e3bd63Sclaudio 	send_hello(HELLO_TARGETED, NULL, tnbr);
28222557577Srenato 	tnbr_start_hello_timer(tnbr);
28376e3bd63Sclaudio }
28476e3bd63Sclaudio 
285c28a25a1Srenato static void
28676e3bd63Sclaudio tnbr_start_hello_timer(struct tnbr *tnbr)
28776e3bd63Sclaudio {
28876e3bd63Sclaudio 	struct timeval	 tv;
28976e3bd63Sclaudio 
29076e3bd63Sclaudio 	timerclear(&tv);
29176e3bd63Sclaudio 	tv.tv_sec = tnbr->hello_interval;
29276e3bd63Sclaudio 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
293b7b4db73Srenato 		fatal(__func__);
29476e3bd63Sclaudio }
29576e3bd63Sclaudio 
296c28a25a1Srenato static void
29776e3bd63Sclaudio tnbr_stop_hello_timer(struct tnbr *tnbr)
29876e3bd63Sclaudio {
29976e3bd63Sclaudio 	if (evtimer_pending(&tnbr->hello_timer, NULL) &&
30076e3bd63Sclaudio 	    evtimer_del(&tnbr->hello_timer) == -1)
301b7b4db73Srenato 		fatal(__func__);
30276e3bd63Sclaudio }
30376e3bd63Sclaudio 
30476e3bd63Sclaudio struct ctl_adj *
30576e3bd63Sclaudio adj_to_ctl(struct adj *adj)
30676e3bd63Sclaudio {
30776e3bd63Sclaudio 	static struct ctl_adj	 actl;
30876e3bd63Sclaudio 
309a8c39dc0Srenato 	actl.af = adj_get_af(adj);
310a8c39dc0Srenato 	actl.id = adj->lsr_id;
31176e3bd63Sclaudio 	actl.type = adj->source.type;
31276e3bd63Sclaudio 	switch (adj->source.type) {
31376e3bd63Sclaudio 	case HELLO_LINK:
314a8c39dc0Srenato 		memcpy(actl.ifname, adj->source.link.ia->iface->name,
31576e3bd63Sclaudio 		    sizeof(actl.ifname));
31676e3bd63Sclaudio 		break;
31776e3bd63Sclaudio 	case HELLO_TARGETED:
3187aa09c5dSrenato 		actl.src_addr = adj->source.target->addr;
31976e3bd63Sclaudio 		break;
32076e3bd63Sclaudio 	}
32176e3bd63Sclaudio 	actl.holdtime = adj->holdtime;
322a8c39dc0Srenato 	actl.trans_addr = adj->trans_addr;
32376e3bd63Sclaudio 
32476e3bd63Sclaudio 	return (&actl);
32576e3bd63Sclaudio }
326