1*5b133f3fSguenther /* $OpenBSD: adjacency.c,v 1.28 2023/03/08 04:43:13 guenther 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
31e373a269Srenato static void adj_del_single(struct adj *);
32c28a25a1Srenato static void adj_itimer(int, short, void *);
33c28a25a1Srenato static void tnbr_del(struct tnbr *);
34c28a25a1Srenato static void tnbr_hello_timer(int, short, void *);
35c28a25a1Srenato static void tnbr_start_hello_timer(struct tnbr *);
36c28a25a1Srenato static void tnbr_stop_hello_timer(struct tnbr *);
3776e3bd63Sclaudio
3876e3bd63Sclaudio struct adj *
adj_new(struct in_addr lsr_id,struct hello_source * source,union ldpd_addr * addr)39a8c39dc0Srenato adj_new(struct in_addr lsr_id, struct hello_source *source,
40a8c39dc0Srenato union ldpd_addr *addr)
4176e3bd63Sclaudio {
4276e3bd63Sclaudio struct adj *adj;
4376e3bd63Sclaudio
44a8c39dc0Srenato log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(lsr_id),
4533f6ccfeSrenato log_hello_src(source));
4676e3bd63Sclaudio
4776e3bd63Sclaudio if ((adj = calloc(1, sizeof(*adj))) == NULL)
48b7b4db73Srenato fatal(__func__);
4976e3bd63Sclaudio
50a8c39dc0Srenato adj->lsr_id = lsr_id;
51a8c39dc0Srenato adj->nbr = NULL;
527aa09c5dSrenato adj->source = *source;
53a8c39dc0Srenato adj->trans_addr = *addr;
5476e3bd63Sclaudio
5576e3bd63Sclaudio evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
5676e3bd63Sclaudio
57a8c39dc0Srenato LIST_INSERT_HEAD(&global.adj_list, adj, global_entry);
5876e3bd63Sclaudio
5976e3bd63Sclaudio switch (source->type) {
6076e3bd63Sclaudio case HELLO_LINK:
61a8c39dc0Srenato LIST_INSERT_HEAD(&source->link.ia->adj_list, adj, ia_entry);
6276e3bd63Sclaudio break;
6376e3bd63Sclaudio case HELLO_TARGETED:
6476e3bd63Sclaudio source->target->adj = adj;
6576e3bd63Sclaudio break;
6676e3bd63Sclaudio }
6776e3bd63Sclaudio
6876e3bd63Sclaudio return (adj);
6976e3bd63Sclaudio }
7076e3bd63Sclaudio
71e373a269Srenato static void
adj_del_single(struct adj * adj)72e373a269Srenato adj_del_single(struct adj *adj)
7376e3bd63Sclaudio {
74e373a269Srenato log_debug("%s: lsr-id %s, %s (%s)", __func__, inet_ntoa(adj->lsr_id),
75e373a269Srenato log_hello_src(&adj->source), af_name(adj_get_af(adj)));
7676e3bd63Sclaudio
7776e3bd63Sclaudio adj_stop_itimer(adj);
7876e3bd63Sclaudio
79a8c39dc0Srenato LIST_REMOVE(adj, global_entry);
80a8c39dc0Srenato if (adj->nbr)
8176e3bd63Sclaudio LIST_REMOVE(adj, nbr_entry);
82b86d2571Srenato switch (adj->source.type) {
83b86d2571Srenato case HELLO_LINK:
84a8c39dc0Srenato LIST_REMOVE(adj, ia_entry);
85b86d2571Srenato break;
86b86d2571Srenato case HELLO_TARGETED:
87b86d2571Srenato adj->source.target->adj = NULL;
88b86d2571Srenato break;
89b86d2571Srenato }
90b86d2571Srenato
9120eeeb6fSrenato free(adj);
929aeb55b7Srenato }
9376e3bd63Sclaudio
94e373a269Srenato void
adj_del(struct adj * adj,uint32_t notif_status)95e373a269Srenato adj_del(struct adj *adj, uint32_t notif_status)
96e373a269Srenato {
97e373a269Srenato struct nbr *nbr = adj->nbr;
98e373a269Srenato struct adj *atmp;
99e373a269Srenato
100e373a269Srenato adj_del_single(adj);
101e373a269Srenato
10220eeeb6fSrenato /*
103e373a269Srenato * If the neighbor still exists but none of its remaining
104e373a269Srenato * adjacencies (if any) are from the preferred address-family,
105e373a269Srenato * then delete it.
10620eeeb6fSrenato */
10720eeeb6fSrenato if (nbr && nbr_adj_count(nbr, nbr->af) == 0) {
10820eeeb6fSrenato LIST_FOREACH_SAFE(adj, &nbr->adj_list, nbr_entry, atmp)
109e373a269Srenato adj_del_single(adj);
110e373a269Srenato session_shutdown(nbr, notif_status, 0, 0);
111e373a269Srenato nbr_del(nbr);
11220eeeb6fSrenato }
11376e3bd63Sclaudio }
11476e3bd63Sclaudio
11576e3bd63Sclaudio struct adj *
adj_find(struct hello_source * source)116a8c39dc0Srenato adj_find(struct hello_source *source)
11776e3bd63Sclaudio {
11876e3bd63Sclaudio struct adj *adj;
11976e3bd63Sclaudio
120a8c39dc0Srenato LIST_FOREACH(adj, &global.adj_list, global_entry) {
12176e3bd63Sclaudio if (adj->source.type != source->type)
12276e3bd63Sclaudio continue;
12376e3bd63Sclaudio
124ddc8fec1Syasuoka if (adj->lsr_id.s_addr != source->lsr_id.s_addr)
125ddc8fec1Syasuoka continue;
126ddc8fec1Syasuoka
12776e3bd63Sclaudio switch (source->type) {
12876e3bd63Sclaudio case HELLO_LINK:
129a8c39dc0Srenato if (ldp_addrcmp(source->link.ia->af,
130a8c39dc0Srenato &adj->source.link.src_addr,
131a8c39dc0Srenato &source->link.src_addr) == 0)
13276e3bd63Sclaudio return (adj);
13376e3bd63Sclaudio break;
13476e3bd63Sclaudio case HELLO_TARGETED:
13576e3bd63Sclaudio if (adj->source.target == source->target)
13676e3bd63Sclaudio return (adj);
13776e3bd63Sclaudio break;
13876e3bd63Sclaudio }
13976e3bd63Sclaudio }
14076e3bd63Sclaudio
14176e3bd63Sclaudio return (NULL);
14276e3bd63Sclaudio }
14376e3bd63Sclaudio
144a8c39dc0Srenato int
adj_get_af(struct adj * adj)145a8c39dc0Srenato adj_get_af(struct adj *adj)
146a8c39dc0Srenato {
147a8c39dc0Srenato switch (adj->source.type) {
148a8c39dc0Srenato case HELLO_LINK:
149a8c39dc0Srenato return (adj->source.link.ia->af);
150a8c39dc0Srenato case HELLO_TARGETED:
151a8c39dc0Srenato return (adj->source.target->af);
152a8c39dc0Srenato default:
153a8c39dc0Srenato fatalx("adj_get_af: unknown hello type");
154a8c39dc0Srenato }
155a8c39dc0Srenato }
156a8c39dc0Srenato
15776e3bd63Sclaudio /* adjacency timers */
15876e3bd63Sclaudio
159c28a25a1Srenato static void
adj_itimer(int fd,short event,void * arg)16076e3bd63Sclaudio adj_itimer(int fd, short event, void *arg)
16176e3bd63Sclaudio {
16276e3bd63Sclaudio struct adj *adj = arg;
16376e3bd63Sclaudio
164a8c39dc0Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
16576e3bd63Sclaudio
166ef2688d9Srenato if (adj->source.type == HELLO_TARGETED) {
1676399cec1Srenato if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
1686399cec1Srenato adj->source.target->pw_count == 0) {
16999170248Srenato /* remove dynamic targeted neighbor */
17076e3bd63Sclaudio tnbr_del(adj->source.target);
17199170248Srenato return;
17276e3bd63Sclaudio }
17399170248Srenato adj->source.target->adj = NULL;
17476e3bd63Sclaudio }
17576e3bd63Sclaudio
176e373a269Srenato adj_del(adj, S_HOLDTIME_EXP);
17776e3bd63Sclaudio }
17876e3bd63Sclaudio
17976e3bd63Sclaudio void
adj_start_itimer(struct adj * adj)18076e3bd63Sclaudio adj_start_itimer(struct adj *adj)
18176e3bd63Sclaudio {
18276e3bd63Sclaudio struct timeval tv;
18376e3bd63Sclaudio
18476e3bd63Sclaudio timerclear(&tv);
18576e3bd63Sclaudio tv.tv_sec = adj->holdtime;
18676e3bd63Sclaudio if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
187b7b4db73Srenato fatal(__func__);
18876e3bd63Sclaudio }
18976e3bd63Sclaudio
19076e3bd63Sclaudio void
adj_stop_itimer(struct adj * adj)19176e3bd63Sclaudio adj_stop_itimer(struct adj *adj)
19276e3bd63Sclaudio {
19376e3bd63Sclaudio if (evtimer_pending(&adj->inactivity_timer, NULL) &&
19476e3bd63Sclaudio evtimer_del(&adj->inactivity_timer) == -1)
195b7b4db73Srenato fatal(__func__);
19676e3bd63Sclaudio }
19776e3bd63Sclaudio
19876e3bd63Sclaudio /* targeted neighbors */
19976e3bd63Sclaudio
20076e3bd63Sclaudio struct tnbr *
tnbr_new(struct ldpd_conf * xconf,int af,union ldpd_addr * addr)201a8c39dc0Srenato tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
20276e3bd63Sclaudio {
20376e3bd63Sclaudio struct tnbr *tnbr;
20476e3bd63Sclaudio
20576e3bd63Sclaudio if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL)
206b7b4db73Srenato fatal(__func__);
20776e3bd63Sclaudio
208a8c39dc0Srenato tnbr->af = af;
209a8c39dc0Srenato tnbr->addr = *addr;
210b5921293Srenato tnbr->state = TNBR_STA_DOWN;
211a8c39dc0Srenato tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime;
212a8c39dc0Srenato tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;
21376e3bd63Sclaudio
21476e3bd63Sclaudio return (tnbr);
21576e3bd63Sclaudio }
21676e3bd63Sclaudio
217c28a25a1Srenato static void
tnbr_del(struct tnbr * tnbr)21876e3bd63Sclaudio tnbr_del(struct tnbr *tnbr)
21976e3bd63Sclaudio {
22076e3bd63Sclaudio tnbr_stop_hello_timer(tnbr);
22176e3bd63Sclaudio if (tnbr->adj)
222e373a269Srenato adj_del(tnbr->adj, S_SHUTDOWN);
223ef2688d9Srenato LIST_REMOVE(tnbr, entry);
22476e3bd63Sclaudio free(tnbr);
22576e3bd63Sclaudio }
22676e3bd63Sclaudio
22799170248Srenato struct tnbr *
tnbr_find(struct ldpd_conf * xconf,int af,union ldpd_addr * addr)228a8c39dc0Srenato tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
22933f6ccfeSrenato {
23033f6ccfeSrenato struct tnbr *tnbr;
23133f6ccfeSrenato
23233f6ccfeSrenato LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
233a8c39dc0Srenato if (af == tnbr->af &&
234a8c39dc0Srenato ldp_addrcmp(af, addr, &tnbr->addr) == 0)
23533f6ccfeSrenato return (tnbr);
23633f6ccfeSrenato
23733f6ccfeSrenato return (NULL);
23833f6ccfeSrenato }
23933f6ccfeSrenato
24033f6ccfeSrenato struct tnbr *
tnbr_check(struct tnbr * tnbr)24199170248Srenato tnbr_check(struct tnbr *tnbr)
24299170248Srenato {
2436399cec1Srenato if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
2446399cec1Srenato tnbr->pw_count == 0) {
24599170248Srenato tnbr_del(tnbr);
24699170248Srenato return (NULL);
24799170248Srenato }
24899170248Srenato
24999170248Srenato return (tnbr);
25099170248Srenato }
25199170248Srenato
25276e3bd63Sclaudio void
tnbr_update(struct tnbr * tnbr)253b5921293Srenato tnbr_update(struct tnbr *tnbr)
25476e3bd63Sclaudio {
25508964f31Srenato int socket_ok, rtr_id_ok;
25676e3bd63Sclaudio
257a8c39dc0Srenato if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1)
258b5921293Srenato socket_ok = 1;
259b5921293Srenato else
260b5921293Srenato socket_ok = 0;
261b5921293Srenato
26208964f31Srenato if (leconf->rtr_id.s_addr != INADDR_ANY)
26308964f31Srenato rtr_id_ok = 1;
26408964f31Srenato else
26508964f31Srenato rtr_id_ok = 0;
26608964f31Srenato
267b5921293Srenato if (tnbr->state == TNBR_STA_DOWN) {
26808964f31Srenato if (!socket_ok || !rtr_id_ok)
269b5921293Srenato return;
270b5921293Srenato
271b5921293Srenato tnbr->state = TNBR_STA_ACTIVE;
2723de94509Srenato send_hello(HELLO_TARGETED, NULL, tnbr);
273b5921293Srenato
274b5921293Srenato evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
27576e3bd63Sclaudio tnbr_start_hello_timer(tnbr);
276b5921293Srenato } else if (tnbr->state == TNBR_STA_ACTIVE) {
27708964f31Srenato if (socket_ok && rtr_id_ok)
278b5921293Srenato return;
279b5921293Srenato
280b5921293Srenato tnbr->state = TNBR_STA_DOWN;
281b5921293Srenato tnbr_stop_hello_timer(tnbr);
282b5921293Srenato }
283b5921293Srenato }
284b5921293Srenato
285b5921293Srenato void
tnbr_update_all(int af)286a8c39dc0Srenato tnbr_update_all(int af)
287b5921293Srenato {
288b5921293Srenato struct tnbr *tnbr;
289b5921293Srenato
290b5921293Srenato /* update targeted neighbors */
291b5921293Srenato LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
292a8c39dc0Srenato if (tnbr->af == af || af == AF_UNSPEC)
293b5921293Srenato tnbr_update(tnbr);
29476e3bd63Sclaudio }
29576e3bd63Sclaudio
29676e3bd63Sclaudio /* target neighbors timers */
29776e3bd63Sclaudio
298c28a25a1Srenato static void
tnbr_hello_timer(int fd,short event,void * arg)29976e3bd63Sclaudio tnbr_hello_timer(int fd, short event, void *arg)
30076e3bd63Sclaudio {
30176e3bd63Sclaudio struct tnbr *tnbr = arg;
30276e3bd63Sclaudio
30376e3bd63Sclaudio send_hello(HELLO_TARGETED, NULL, tnbr);
30422557577Srenato tnbr_start_hello_timer(tnbr);
30576e3bd63Sclaudio }
30676e3bd63Sclaudio
307c28a25a1Srenato static void
tnbr_start_hello_timer(struct tnbr * tnbr)30876e3bd63Sclaudio tnbr_start_hello_timer(struct tnbr *tnbr)
30976e3bd63Sclaudio {
31076e3bd63Sclaudio struct timeval tv;
31176e3bd63Sclaudio
31276e3bd63Sclaudio timerclear(&tv);
31376e3bd63Sclaudio tv.tv_sec = tnbr->hello_interval;
31476e3bd63Sclaudio if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
315b7b4db73Srenato fatal(__func__);
31676e3bd63Sclaudio }
31776e3bd63Sclaudio
318c28a25a1Srenato static void
tnbr_stop_hello_timer(struct tnbr * tnbr)31976e3bd63Sclaudio tnbr_stop_hello_timer(struct tnbr *tnbr)
32076e3bd63Sclaudio {
32176e3bd63Sclaudio if (evtimer_pending(&tnbr->hello_timer, NULL) &&
32276e3bd63Sclaudio evtimer_del(&tnbr->hello_timer) == -1)
323b7b4db73Srenato fatal(__func__);
32476e3bd63Sclaudio }
32576e3bd63Sclaudio
32676e3bd63Sclaudio struct ctl_adj *
adj_to_ctl(struct adj * adj)32776e3bd63Sclaudio adj_to_ctl(struct adj *adj)
32876e3bd63Sclaudio {
32976e3bd63Sclaudio static struct ctl_adj actl;
33076e3bd63Sclaudio
331a8c39dc0Srenato actl.af = adj_get_af(adj);
332a8c39dc0Srenato actl.id = adj->lsr_id;
33376e3bd63Sclaudio actl.type = adj->source.type;
33476e3bd63Sclaudio switch (adj->source.type) {
33576e3bd63Sclaudio case HELLO_LINK:
336a8c39dc0Srenato memcpy(actl.ifname, adj->source.link.ia->iface->name,
33776e3bd63Sclaudio sizeof(actl.ifname));
33876e3bd63Sclaudio break;
33976e3bd63Sclaudio case HELLO_TARGETED:
3407aa09c5dSrenato actl.src_addr = adj->source.target->addr;
34176e3bd63Sclaudio break;
34276e3bd63Sclaudio }
34376e3bd63Sclaudio actl.holdtime = adj->holdtime;
344a8c39dc0Srenato actl.trans_addr = adj->trans_addr;
34576e3bd63Sclaudio
34676e3bd63Sclaudio return (&actl);
34776e3bd63Sclaudio }
348