1*ddc8fec1Syasuoka /* $OpenBSD: adjacency.c,v 1.27 2019/12/12 00:10:29 yasuoka 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 * 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 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 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 * 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 124*ddc8fec1Syasuoka if (adj->lsr_id.s_addr != source->lsr_id.s_addr) 125*ddc8fec1Syasuoka continue; 126*ddc8fec1Syasuoka 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 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 15976e3bd63Sclaudio /* ARGSUSED */ 160c28a25a1Srenato static void 16176e3bd63Sclaudio adj_itimer(int fd, short event, void *arg) 16276e3bd63Sclaudio { 16376e3bd63Sclaudio struct adj *adj = arg; 16476e3bd63Sclaudio 165a8c39dc0Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); 16676e3bd63Sclaudio 167ef2688d9Srenato if (adj->source.type == HELLO_TARGETED) { 1686399cec1Srenato if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && 1696399cec1Srenato adj->source.target->pw_count == 0) { 17099170248Srenato /* remove dynamic targeted neighbor */ 17176e3bd63Sclaudio tnbr_del(adj->source.target); 17299170248Srenato return; 17376e3bd63Sclaudio } 17499170248Srenato adj->source.target->adj = NULL; 17576e3bd63Sclaudio } 17676e3bd63Sclaudio 177e373a269Srenato adj_del(adj, S_HOLDTIME_EXP); 17876e3bd63Sclaudio } 17976e3bd63Sclaudio 18076e3bd63Sclaudio void 18176e3bd63Sclaudio adj_start_itimer(struct adj *adj) 18276e3bd63Sclaudio { 18376e3bd63Sclaudio struct timeval tv; 18476e3bd63Sclaudio 18576e3bd63Sclaudio timerclear(&tv); 18676e3bd63Sclaudio tv.tv_sec = adj->holdtime; 18776e3bd63Sclaudio if (evtimer_add(&adj->inactivity_timer, &tv) == -1) 188b7b4db73Srenato fatal(__func__); 18976e3bd63Sclaudio } 19076e3bd63Sclaudio 19176e3bd63Sclaudio void 19276e3bd63Sclaudio adj_stop_itimer(struct adj *adj) 19376e3bd63Sclaudio { 19476e3bd63Sclaudio if (evtimer_pending(&adj->inactivity_timer, NULL) && 19576e3bd63Sclaudio evtimer_del(&adj->inactivity_timer) == -1) 196b7b4db73Srenato fatal(__func__); 19776e3bd63Sclaudio } 19876e3bd63Sclaudio 19976e3bd63Sclaudio /* targeted neighbors */ 20076e3bd63Sclaudio 20176e3bd63Sclaudio struct tnbr * 202a8c39dc0Srenato tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 20376e3bd63Sclaudio { 20476e3bd63Sclaudio struct tnbr *tnbr; 20576e3bd63Sclaudio 20676e3bd63Sclaudio if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) 207b7b4db73Srenato fatal(__func__); 20876e3bd63Sclaudio 209a8c39dc0Srenato tnbr->af = af; 210a8c39dc0Srenato tnbr->addr = *addr; 211b5921293Srenato tnbr->state = TNBR_STA_DOWN; 212a8c39dc0Srenato tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; 213a8c39dc0Srenato tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval; 21476e3bd63Sclaudio 21576e3bd63Sclaudio return (tnbr); 21676e3bd63Sclaudio } 21776e3bd63Sclaudio 218c28a25a1Srenato static void 21976e3bd63Sclaudio tnbr_del(struct tnbr *tnbr) 22076e3bd63Sclaudio { 22176e3bd63Sclaudio tnbr_stop_hello_timer(tnbr); 22276e3bd63Sclaudio if (tnbr->adj) 223e373a269Srenato adj_del(tnbr->adj, S_SHUTDOWN); 224ef2688d9Srenato LIST_REMOVE(tnbr, entry); 22576e3bd63Sclaudio free(tnbr); 22676e3bd63Sclaudio } 22776e3bd63Sclaudio 22899170248Srenato struct tnbr * 229a8c39dc0Srenato tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 23033f6ccfeSrenato { 23133f6ccfeSrenato struct tnbr *tnbr; 23233f6ccfeSrenato 23333f6ccfeSrenato LIST_FOREACH(tnbr, &xconf->tnbr_list, entry) 234a8c39dc0Srenato if (af == tnbr->af && 235a8c39dc0Srenato ldp_addrcmp(af, addr, &tnbr->addr) == 0) 23633f6ccfeSrenato return (tnbr); 23733f6ccfeSrenato 23833f6ccfeSrenato return (NULL); 23933f6ccfeSrenato } 24033f6ccfeSrenato 24133f6ccfeSrenato struct tnbr * 24299170248Srenato tnbr_check(struct tnbr *tnbr) 24399170248Srenato { 2446399cec1Srenato if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && 2456399cec1Srenato tnbr->pw_count == 0) { 24699170248Srenato tnbr_del(tnbr); 24799170248Srenato return (NULL); 24899170248Srenato } 24999170248Srenato 25099170248Srenato return (tnbr); 25199170248Srenato } 25299170248Srenato 25376e3bd63Sclaudio void 254b5921293Srenato tnbr_update(struct tnbr *tnbr) 25576e3bd63Sclaudio { 25608964f31Srenato int socket_ok, rtr_id_ok; 25776e3bd63Sclaudio 258a8c39dc0Srenato if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1) 259b5921293Srenato socket_ok = 1; 260b5921293Srenato else 261b5921293Srenato socket_ok = 0; 262b5921293Srenato 26308964f31Srenato if (leconf->rtr_id.s_addr != INADDR_ANY) 26408964f31Srenato rtr_id_ok = 1; 26508964f31Srenato else 26608964f31Srenato rtr_id_ok = 0; 26708964f31Srenato 268b5921293Srenato if (tnbr->state == TNBR_STA_DOWN) { 26908964f31Srenato if (!socket_ok || !rtr_id_ok) 270b5921293Srenato return; 271b5921293Srenato 272b5921293Srenato tnbr->state = TNBR_STA_ACTIVE; 2733de94509Srenato send_hello(HELLO_TARGETED, NULL, tnbr); 274b5921293Srenato 275b5921293Srenato evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); 27676e3bd63Sclaudio tnbr_start_hello_timer(tnbr); 277b5921293Srenato } else if (tnbr->state == TNBR_STA_ACTIVE) { 27808964f31Srenato if (socket_ok && rtr_id_ok) 279b5921293Srenato return; 280b5921293Srenato 281b5921293Srenato tnbr->state = TNBR_STA_DOWN; 282b5921293Srenato tnbr_stop_hello_timer(tnbr); 283b5921293Srenato } 284b5921293Srenato } 285b5921293Srenato 286b5921293Srenato void 287a8c39dc0Srenato tnbr_update_all(int af) 288b5921293Srenato { 289b5921293Srenato struct tnbr *tnbr; 290b5921293Srenato 291b5921293Srenato /* update targeted neighbors */ 292b5921293Srenato LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) 293a8c39dc0Srenato if (tnbr->af == af || af == AF_UNSPEC) 294b5921293Srenato tnbr_update(tnbr); 29576e3bd63Sclaudio } 29676e3bd63Sclaudio 29776e3bd63Sclaudio /* target neighbors timers */ 29876e3bd63Sclaudio 29976e3bd63Sclaudio /* ARGSUSED */ 300c28a25a1Srenato static void 30176e3bd63Sclaudio tnbr_hello_timer(int fd, short event, void *arg) 30276e3bd63Sclaudio { 30376e3bd63Sclaudio struct tnbr *tnbr = arg; 30476e3bd63Sclaudio 30576e3bd63Sclaudio send_hello(HELLO_TARGETED, NULL, tnbr); 30622557577Srenato tnbr_start_hello_timer(tnbr); 30776e3bd63Sclaudio } 30876e3bd63Sclaudio 309c28a25a1Srenato static void 31076e3bd63Sclaudio tnbr_start_hello_timer(struct tnbr *tnbr) 31176e3bd63Sclaudio { 31276e3bd63Sclaudio struct timeval tv; 31376e3bd63Sclaudio 31476e3bd63Sclaudio timerclear(&tv); 31576e3bd63Sclaudio tv.tv_sec = tnbr->hello_interval; 31676e3bd63Sclaudio if (evtimer_add(&tnbr->hello_timer, &tv) == -1) 317b7b4db73Srenato fatal(__func__); 31876e3bd63Sclaudio } 31976e3bd63Sclaudio 320c28a25a1Srenato static void 32176e3bd63Sclaudio tnbr_stop_hello_timer(struct tnbr *tnbr) 32276e3bd63Sclaudio { 32376e3bd63Sclaudio if (evtimer_pending(&tnbr->hello_timer, NULL) && 32476e3bd63Sclaudio evtimer_del(&tnbr->hello_timer) == -1) 325b7b4db73Srenato fatal(__func__); 32676e3bd63Sclaudio } 32776e3bd63Sclaudio 32876e3bd63Sclaudio struct ctl_adj * 32976e3bd63Sclaudio adj_to_ctl(struct adj *adj) 33076e3bd63Sclaudio { 33176e3bd63Sclaudio static struct ctl_adj actl; 33276e3bd63Sclaudio 333a8c39dc0Srenato actl.af = adj_get_af(adj); 334a8c39dc0Srenato actl.id = adj->lsr_id; 33576e3bd63Sclaudio actl.type = adj->source.type; 33676e3bd63Sclaudio switch (adj->source.type) { 33776e3bd63Sclaudio case HELLO_LINK: 338a8c39dc0Srenato memcpy(actl.ifname, adj->source.link.ia->iface->name, 33976e3bd63Sclaudio sizeof(actl.ifname)); 34076e3bd63Sclaudio break; 34176e3bd63Sclaudio case HELLO_TARGETED: 3427aa09c5dSrenato actl.src_addr = adj->source.target->addr; 34376e3bd63Sclaudio break; 34476e3bd63Sclaudio } 34576e3bd63Sclaudio actl.holdtime = adj->holdtime; 346a8c39dc0Srenato actl.trans_addr = adj->trans_addr; 34776e3bd63Sclaudio 34876e3bd63Sclaudio return (&actl); 34976e3bd63Sclaudio } 350