xref: /openbsd/usr.sbin/ldpd/adjacency.c (revision 6399cec1)
1*6399cec1Srenato /*	$OpenBSD: adjacency.c,v 1.7 2015/07/21 04:52:29 renato Exp $ */
276e3bd63Sclaudio 
376e3bd63Sclaudio /*
476e3bd63Sclaudio  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
576e3bd63Sclaudio  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
676e3bd63Sclaudio  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
776e3bd63Sclaudio  *
876e3bd63Sclaudio  * Permission to use, copy, modify, and distribute this software for any
976e3bd63Sclaudio  * purpose with or without fee is hereby granted, provided that the above
1076e3bd63Sclaudio  * copyright notice and this permission notice appear in all copies.
1176e3bd63Sclaudio  *
1276e3bd63Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1376e3bd63Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1476e3bd63Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1576e3bd63Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1676e3bd63Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1776e3bd63Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1876e3bd63Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1976e3bd63Sclaudio  */
2076e3bd63Sclaudio 
2176e3bd63Sclaudio #include <sys/types.h>
2276e3bd63Sclaudio #include <sys/socket.h>
2376e3bd63Sclaudio #include <arpa/inet.h>
2476e3bd63Sclaudio 
2576e3bd63Sclaudio #include <stdio.h>
2676e3bd63Sclaudio #include <stdlib.h>
2776e3bd63Sclaudio #include <string.h>
2876e3bd63Sclaudio 
2976e3bd63Sclaudio #include "ldpd.h"
3076e3bd63Sclaudio #include "ldpe.h"
3176e3bd63Sclaudio #include "control.h"
3276e3bd63Sclaudio #include "log.h"
3376e3bd63Sclaudio 
3476e3bd63Sclaudio extern struct ldpd_conf        *leconf;
3576e3bd63Sclaudio 
3676e3bd63Sclaudio void	 adj_itimer(int, short, void *);
3776e3bd63Sclaudio char	*print_hello_src(struct hello_source *);
3876e3bd63Sclaudio 
3976e3bd63Sclaudio void	 tnbr_hello_timer(int, short, void *);
4076e3bd63Sclaudio void	 tnbr_start_hello_timer(struct tnbr *);
4176e3bd63Sclaudio void	 tnbr_stop_hello_timer(struct tnbr *);
4276e3bd63Sclaudio 
4376e3bd63Sclaudio struct adj *
449f1af4beSrenato adj_new(struct nbr *nbr, struct hello_source *source, struct in_addr addr)
4576e3bd63Sclaudio {
4676e3bd63Sclaudio 	struct adj	*adj;
4776e3bd63Sclaudio 
4876e3bd63Sclaudio 	log_debug("adj_new: LSR ID %s, %s", inet_ntoa(nbr->id),
4976e3bd63Sclaudio 	    print_hello_src(source));
5076e3bd63Sclaudio 
5176e3bd63Sclaudio 	if ((adj = calloc(1, sizeof(*adj))) == NULL)
5276e3bd63Sclaudio 		fatal("adj_new");
5376e3bd63Sclaudio 
5476e3bd63Sclaudio 	adj->nbr = nbr;
5576e3bd63Sclaudio 	memcpy(&adj->source, source, sizeof(*source));
5676e3bd63Sclaudio 	adj->addr = addr;
5776e3bd63Sclaudio 
5876e3bd63Sclaudio 	evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
5976e3bd63Sclaudio 
6076e3bd63Sclaudio 	LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
6176e3bd63Sclaudio 
6276e3bd63Sclaudio 	switch (source->type) {
6376e3bd63Sclaudio 	case HELLO_LINK:
6476e3bd63Sclaudio 		LIST_INSERT_HEAD(&source->link.iface->adj_list, adj,
6576e3bd63Sclaudio 		    iface_entry);
6676e3bd63Sclaudio 		break;
6776e3bd63Sclaudio 	case HELLO_TARGETED:
6876e3bd63Sclaudio 		source->target->adj = adj;
6976e3bd63Sclaudio 		break;
7076e3bd63Sclaudio 	}
7176e3bd63Sclaudio 
7276e3bd63Sclaudio 	return (adj);
7376e3bd63Sclaudio }
7476e3bd63Sclaudio 
7576e3bd63Sclaudio void
7676e3bd63Sclaudio adj_del(struct adj *adj)
7776e3bd63Sclaudio {
7876e3bd63Sclaudio 	log_debug("adj_del: LSR ID %s, %s", inet_ntoa(adj->nbr->id),
7976e3bd63Sclaudio 	    print_hello_src(&adj->source));
8076e3bd63Sclaudio 
8176e3bd63Sclaudio 	adj_stop_itimer(adj);
8276e3bd63Sclaudio 
8376e3bd63Sclaudio 	LIST_REMOVE(adj, nbr_entry);
8476e3bd63Sclaudio 
8576e3bd63Sclaudio 	/* last adjacency deleted */
8676e3bd63Sclaudio 	if (LIST_EMPTY(&adj->nbr->adj_list))
8776e3bd63Sclaudio 		nbr_del(adj->nbr);
8876e3bd63Sclaudio 
8976e3bd63Sclaudio 	free(adj);
9076e3bd63Sclaudio }
9176e3bd63Sclaudio 
9276e3bd63Sclaudio struct adj *
9376e3bd63Sclaudio adj_find(struct nbr *nbr, struct hello_source *source)
9476e3bd63Sclaudio {
9576e3bd63Sclaudio 	struct adj *adj;
9676e3bd63Sclaudio 
9776e3bd63Sclaudio 	LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
9876e3bd63Sclaudio 		if (adj->source.type != source->type)
9976e3bd63Sclaudio 			continue;
10076e3bd63Sclaudio 
10176e3bd63Sclaudio 		switch (source->type) {
10276e3bd63Sclaudio 		case HELLO_LINK:
10376e3bd63Sclaudio 			if (adj->source.link.src_addr.s_addr ==
10476e3bd63Sclaudio 			    source->link.src_addr.s_addr)
10576e3bd63Sclaudio 				return (adj);
10676e3bd63Sclaudio 			break;
10776e3bd63Sclaudio 		case HELLO_TARGETED:
10876e3bd63Sclaudio 			if (adj->source.target == source->target)
10976e3bd63Sclaudio 				return (adj);
11076e3bd63Sclaudio 			break;
11176e3bd63Sclaudio 		}
11276e3bd63Sclaudio 	}
11376e3bd63Sclaudio 
11476e3bd63Sclaudio 	return (NULL);
11576e3bd63Sclaudio }
11676e3bd63Sclaudio 
11776e3bd63Sclaudio char *
11876e3bd63Sclaudio print_hello_src(struct hello_source *src)
11976e3bd63Sclaudio {
12076e3bd63Sclaudio 	static char buffer[64];
12176e3bd63Sclaudio 
12271256830Srenato 	switch (src->type) {
12371256830Srenato 	case HELLO_LINK:
12476e3bd63Sclaudio 		snprintf(buffer, sizeof(buffer), "iface %s",
12576e3bd63Sclaudio 		    src->link.iface->name);
12671256830Srenato 		break;
12771256830Srenato 	case HELLO_TARGETED:
12876e3bd63Sclaudio 		snprintf(buffer, sizeof(buffer), "source %s",
12976e3bd63Sclaudio 		    inet_ntoa(src->target->addr));
13071256830Srenato 		break;
13171256830Srenato 	}
13276e3bd63Sclaudio 
13371256830Srenato 	return (buffer);
13476e3bd63Sclaudio }
13576e3bd63Sclaudio 
13676e3bd63Sclaudio /* adjacency timers */
13776e3bd63Sclaudio 
13876e3bd63Sclaudio /* ARGSUSED */
13976e3bd63Sclaudio void
14076e3bd63Sclaudio adj_itimer(int fd, short event, void *arg)
14176e3bd63Sclaudio {
14276e3bd63Sclaudio 	struct adj *adj = arg;
14376e3bd63Sclaudio 
14476e3bd63Sclaudio 	log_debug("adj_itimer: LDP ID %s", inet_ntoa(adj->nbr->id));
14576e3bd63Sclaudio 
14676e3bd63Sclaudio 	switch (adj->source.type) {
14776e3bd63Sclaudio 	case HELLO_LINK:
14876e3bd63Sclaudio 		LIST_REMOVE(adj, iface_entry);
14976e3bd63Sclaudio 		break;
15076e3bd63Sclaudio 	case HELLO_TARGETED:
151*6399cec1Srenato 		if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
152*6399cec1Srenato 		    adj->source.target->pw_count == 0) {
15399170248Srenato 			/* remove dynamic targeted neighbor */
15476e3bd63Sclaudio 			LIST_REMOVE(adj->source.target, entry);
15576e3bd63Sclaudio 			tnbr_del(adj->source.target);
15699170248Srenato 			return;
15776e3bd63Sclaudio 		}
15899170248Srenato 		adj->source.target->adj = NULL;
15976e3bd63Sclaudio 		break;
16076e3bd63Sclaudio 	}
16176e3bd63Sclaudio 
16276e3bd63Sclaudio 	adj_del(adj);
16376e3bd63Sclaudio }
16476e3bd63Sclaudio 
16576e3bd63Sclaudio void
16676e3bd63Sclaudio adj_start_itimer(struct adj *adj)
16776e3bd63Sclaudio {
16876e3bd63Sclaudio 	struct timeval	tv;
16976e3bd63Sclaudio 
17076e3bd63Sclaudio 	timerclear(&tv);
17176e3bd63Sclaudio 	tv.tv_sec = adj->holdtime;
17276e3bd63Sclaudio 
17376e3bd63Sclaudio 	if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
17476e3bd63Sclaudio 		fatal("adj_start_itimer");
17576e3bd63Sclaudio }
17676e3bd63Sclaudio 
17776e3bd63Sclaudio void
17876e3bd63Sclaudio adj_stop_itimer(struct adj *adj)
17976e3bd63Sclaudio {
18076e3bd63Sclaudio 	if (evtimer_pending(&adj->inactivity_timer, NULL) &&
18176e3bd63Sclaudio 	    evtimer_del(&adj->inactivity_timer) == -1)
18276e3bd63Sclaudio 		fatal("adj_stop_itimer");
18376e3bd63Sclaudio }
18476e3bd63Sclaudio 
18576e3bd63Sclaudio /* targeted neighbors */
18676e3bd63Sclaudio 
18776e3bd63Sclaudio struct tnbr *
18899170248Srenato tnbr_new(struct ldpd_conf *xconf, struct in_addr addr)
18976e3bd63Sclaudio {
19076e3bd63Sclaudio 	struct tnbr		*tnbr;
19176e3bd63Sclaudio 
19276e3bd63Sclaudio 	if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
19376e3bd63Sclaudio 		fatal("tnbr_new");
19476e3bd63Sclaudio 
19576e3bd63Sclaudio 	tnbr->addr.s_addr = addr.s_addr;
1968989c09eSrenato 	tnbr->hello_holdtime = xconf->thello_holdtime;
1978989c09eSrenato 	tnbr->hello_interval = xconf->thello_interval;
19876e3bd63Sclaudio 
19976e3bd63Sclaudio 	return (tnbr);
20076e3bd63Sclaudio }
20176e3bd63Sclaudio 
20276e3bd63Sclaudio void
20376e3bd63Sclaudio tnbr_del(struct tnbr *tnbr)
20476e3bd63Sclaudio {
20576e3bd63Sclaudio 	tnbr_stop_hello_timer(tnbr);
20676e3bd63Sclaudio 	if (tnbr->adj)
20776e3bd63Sclaudio 		adj_del(tnbr->adj);
20876e3bd63Sclaudio 	free(tnbr);
20976e3bd63Sclaudio }
21076e3bd63Sclaudio 
21199170248Srenato struct tnbr *
21299170248Srenato tnbr_check(struct tnbr *tnbr)
21399170248Srenato {
214*6399cec1Srenato 	if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
215*6399cec1Srenato 	    tnbr->pw_count == 0) {
21699170248Srenato 		LIST_REMOVE(tnbr, entry);
21799170248Srenato 		tnbr_del(tnbr);
21899170248Srenato 		return (NULL);
21999170248Srenato 	}
22099170248Srenato 
22199170248Srenato 	return (tnbr);
22299170248Srenato }
22399170248Srenato 
22476e3bd63Sclaudio void
22576e3bd63Sclaudio tnbr_init(struct ldpd_conf *xconf, struct tnbr *tnbr)
22676e3bd63Sclaudio {
22776e3bd63Sclaudio 	/* set event handlers for targeted neighbor */
22876e3bd63Sclaudio 	evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
22976e3bd63Sclaudio 
23076e3bd63Sclaudio 	tnbr->discovery_fd = xconf->ldp_ediscovery_socket;
23176e3bd63Sclaudio 	tnbr_start_hello_timer(tnbr);
23276e3bd63Sclaudio }
23376e3bd63Sclaudio 
23476e3bd63Sclaudio struct tnbr *
235be87e4d3Srenato tnbr_find(struct ldpd_conf *xconf, struct in_addr addr)
23676e3bd63Sclaudio {
23776e3bd63Sclaudio 	struct tnbr *tnbr;
23876e3bd63Sclaudio 
239be87e4d3Srenato 	LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
24076e3bd63Sclaudio 		if (addr.s_addr == tnbr->addr.s_addr)
24176e3bd63Sclaudio 			return (tnbr);
24276e3bd63Sclaudio 
24376e3bd63Sclaudio 	return (NULL);
24476e3bd63Sclaudio }
24576e3bd63Sclaudio 
24676e3bd63Sclaudio /* target neighbors timers */
24776e3bd63Sclaudio 
24876e3bd63Sclaudio /* ARGSUSED */
24976e3bd63Sclaudio void
25076e3bd63Sclaudio tnbr_hello_timer(int fd, short event, void *arg)
25176e3bd63Sclaudio {
25276e3bd63Sclaudio 	struct tnbr *tnbr = arg;
25376e3bd63Sclaudio 	struct timeval tv;
25476e3bd63Sclaudio 
25576e3bd63Sclaudio 	send_hello(HELLO_TARGETED, NULL, tnbr);
25676e3bd63Sclaudio 
25776e3bd63Sclaudio 	/* reschedule hello_timer */
25876e3bd63Sclaudio 	timerclear(&tv);
25976e3bd63Sclaudio 	tv.tv_sec = tnbr->hello_interval;
26076e3bd63Sclaudio 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
26176e3bd63Sclaudio 		fatal("tnbr_hello_timer");
26276e3bd63Sclaudio }
26376e3bd63Sclaudio 
26476e3bd63Sclaudio void
26576e3bd63Sclaudio tnbr_start_hello_timer(struct tnbr *tnbr)
26676e3bd63Sclaudio {
26776e3bd63Sclaudio 	struct timeval tv;
26876e3bd63Sclaudio 
26976e3bd63Sclaudio 	send_hello(HELLO_TARGETED, NULL, tnbr);
27076e3bd63Sclaudio 
27176e3bd63Sclaudio 	timerclear(&tv);
27276e3bd63Sclaudio 	tv.tv_sec = tnbr->hello_interval;
27376e3bd63Sclaudio 	if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
27476e3bd63Sclaudio 		fatal("tnbr_start_hello_timer");
27576e3bd63Sclaudio }
27676e3bd63Sclaudio 
27776e3bd63Sclaudio void
27876e3bd63Sclaudio tnbr_stop_hello_timer(struct tnbr *tnbr)
27976e3bd63Sclaudio {
28076e3bd63Sclaudio 	if (evtimer_pending(&tnbr->hello_timer, NULL) &&
28176e3bd63Sclaudio 	    evtimer_del(&tnbr->hello_timer) == -1)
28276e3bd63Sclaudio 		fatal("tnbr_stop_hello_timer");
28376e3bd63Sclaudio }
28476e3bd63Sclaudio 
28576e3bd63Sclaudio struct ctl_adj *
28676e3bd63Sclaudio adj_to_ctl(struct adj *adj)
28776e3bd63Sclaudio {
28876e3bd63Sclaudio 	static struct ctl_adj	 actl;
28976e3bd63Sclaudio 
29076e3bd63Sclaudio 	actl.id.s_addr = adj->nbr->id.s_addr;
29176e3bd63Sclaudio 	actl.type = adj->source.type;
29276e3bd63Sclaudio 	switch (adj->source.type) {
29376e3bd63Sclaudio 	case HELLO_LINK:
29476e3bd63Sclaudio 		memcpy(actl.ifname, adj->source.link.iface->name,
29576e3bd63Sclaudio 		    sizeof(actl.ifname));
29676e3bd63Sclaudio 		break;
29776e3bd63Sclaudio 	case HELLO_TARGETED:
29876e3bd63Sclaudio 		actl.src_addr.s_addr = adj->source.target->addr.s_addr;
29976e3bd63Sclaudio 		break;
30076e3bd63Sclaudio 	}
30176e3bd63Sclaudio 	actl.holdtime = adj->holdtime;
30276e3bd63Sclaudio 
30376e3bd63Sclaudio 	return (&actl);
30476e3bd63Sclaudio }
30576e3bd63Sclaudio 
30676e3bd63Sclaudio void
30776e3bd63Sclaudio ldpe_adj_ctl(struct ctl_conn *c)
30876e3bd63Sclaudio {
30976e3bd63Sclaudio 	struct adj	*adj;
31076e3bd63Sclaudio 	struct iface	*iface;
31176e3bd63Sclaudio 	struct tnbr	*tnbr;
31276e3bd63Sclaudio 	struct ctl_adj	*actl;
31376e3bd63Sclaudio 
31476e3bd63Sclaudio 	/* basic discovery mechanism */
31576e3bd63Sclaudio 	LIST_FOREACH(iface, &leconf->iface_list, entry)
31676e3bd63Sclaudio 		LIST_FOREACH(adj, &iface->adj_list, iface_entry) {
31776e3bd63Sclaudio 			actl = adj_to_ctl(adj);
31876e3bd63Sclaudio 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
31976e3bd63Sclaudio 			    0, 0, -1, actl, sizeof(struct ctl_adj));
32076e3bd63Sclaudio 		}
32176e3bd63Sclaudio 
32276e3bd63Sclaudio 	/* extended discovery mechanism */
32376e3bd63Sclaudio 	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
32476e3bd63Sclaudio 		if (tnbr->adj) {
32576e3bd63Sclaudio 			actl = adj_to_ctl(tnbr->adj);
32676e3bd63Sclaudio 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
32776e3bd63Sclaudio 			    0, 0, -1, actl, sizeof(struct ctl_adj));
32876e3bd63Sclaudio 		}
32976e3bd63Sclaudio 
33076e3bd63Sclaudio 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
33176e3bd63Sclaudio }
332