1*b86d2571Srenato /* $OpenBSD: adjacency.c,v 1.25 2016/06/18 17:11:37 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 719aeb55b7Srenato adj_del(struct adj *adj, int send_notif, uint32_t notif_status) 7276e3bd63Sclaudio { 7320eeeb6fSrenato struct nbr *nbr = adj->nbr; 7420eeeb6fSrenato struct adj *atmp; 7520eeeb6fSrenato 76a8c39dc0Srenato log_debug("%s: lsr-id %s, %s", __func__, inet_ntoa(adj->lsr_id), 7733f6ccfeSrenato log_hello_src(&adj->source)); 7876e3bd63Sclaudio 7976e3bd63Sclaudio adj_stop_itimer(adj); 8076e3bd63Sclaudio 81a8c39dc0Srenato LIST_REMOVE(adj, global_entry); 82a8c39dc0Srenato if (adj->nbr) 8376e3bd63Sclaudio LIST_REMOVE(adj, nbr_entry); 84*b86d2571Srenato switch (adj->source.type) { 85*b86d2571Srenato case HELLO_LINK: 86a8c39dc0Srenato LIST_REMOVE(adj, ia_entry); 87*b86d2571Srenato break; 88*b86d2571Srenato case HELLO_TARGETED: 89*b86d2571Srenato adj->source.target->adj = NULL; 90*b86d2571Srenato break; 91*b86d2571Srenato } 92*b86d2571Srenato 9320eeeb6fSrenato free(adj); 9476e3bd63Sclaudio 9576e3bd63Sclaudio /* last adjacency deleted */ 9620eeeb6fSrenato if (nbr && LIST_EMPTY(&nbr->adj_list)) { 979aeb55b7Srenato if (send_notif) 9820eeeb6fSrenato session_shutdown(nbr, notif_status, 0, 0); 9920eeeb6fSrenato nbr_del(nbr); 10020eeeb6fSrenato nbr = NULL; 1019aeb55b7Srenato } 10276e3bd63Sclaudio 10320eeeb6fSrenato /* 10420eeeb6fSrenato * If the neighbor still exists but none of its remaining adjacencies 10520eeeb6fSrenato * are from the preferred address-family, 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) 10920eeeb6fSrenato adj_del(adj, 0, 0); 11020eeeb6fSrenato } 11176e3bd63Sclaudio } 11276e3bd63Sclaudio 11376e3bd63Sclaudio struct adj * 114a8c39dc0Srenato adj_find(struct hello_source *source) 11576e3bd63Sclaudio { 11676e3bd63Sclaudio struct adj *adj; 11776e3bd63Sclaudio 118a8c39dc0Srenato LIST_FOREACH(adj, &global.adj_list, global_entry) { 11976e3bd63Sclaudio if (adj->source.type != source->type) 12076e3bd63Sclaudio continue; 12176e3bd63Sclaudio 12276e3bd63Sclaudio switch (source->type) { 12376e3bd63Sclaudio case HELLO_LINK: 124a8c39dc0Srenato if (ldp_addrcmp(source->link.ia->af, 125a8c39dc0Srenato &adj->source.link.src_addr, 126a8c39dc0Srenato &source->link.src_addr) == 0) 12776e3bd63Sclaudio return (adj); 12876e3bd63Sclaudio break; 12976e3bd63Sclaudio case HELLO_TARGETED: 13076e3bd63Sclaudio if (adj->source.target == source->target) 13176e3bd63Sclaudio return (adj); 13276e3bd63Sclaudio break; 13376e3bd63Sclaudio } 13476e3bd63Sclaudio } 13576e3bd63Sclaudio 13676e3bd63Sclaudio return (NULL); 13776e3bd63Sclaudio } 13876e3bd63Sclaudio 139a8c39dc0Srenato int 140a8c39dc0Srenato adj_get_af(struct adj *adj) 141a8c39dc0Srenato { 142a8c39dc0Srenato switch (adj->source.type) { 143a8c39dc0Srenato case HELLO_LINK: 144a8c39dc0Srenato return (adj->source.link.ia->af); 145a8c39dc0Srenato case HELLO_TARGETED: 146a8c39dc0Srenato return (adj->source.target->af); 147a8c39dc0Srenato default: 148a8c39dc0Srenato fatalx("adj_get_af: unknown hello type"); 149a8c39dc0Srenato } 150a8c39dc0Srenato } 151a8c39dc0Srenato 15276e3bd63Sclaudio /* adjacency timers */ 15376e3bd63Sclaudio 15476e3bd63Sclaudio /* ARGSUSED */ 155c28a25a1Srenato static void 15676e3bd63Sclaudio adj_itimer(int fd, short event, void *arg) 15776e3bd63Sclaudio { 15876e3bd63Sclaudio struct adj *adj = arg; 15976e3bd63Sclaudio 160a8c39dc0Srenato log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); 16176e3bd63Sclaudio 162ef2688d9Srenato if (adj->source.type == HELLO_TARGETED) { 1636399cec1Srenato if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && 1646399cec1Srenato adj->source.target->pw_count == 0) { 16599170248Srenato /* remove dynamic targeted neighbor */ 16676e3bd63Sclaudio tnbr_del(adj->source.target); 16799170248Srenato return; 16876e3bd63Sclaudio } 16999170248Srenato adj->source.target->adj = NULL; 17076e3bd63Sclaudio } 17176e3bd63Sclaudio 1729aeb55b7Srenato adj_del(adj, 1, S_HOLDTIME_EXP); 17376e3bd63Sclaudio } 17476e3bd63Sclaudio 17576e3bd63Sclaudio void 17676e3bd63Sclaudio adj_start_itimer(struct adj *adj) 17776e3bd63Sclaudio { 17876e3bd63Sclaudio struct timeval tv; 17976e3bd63Sclaudio 18076e3bd63Sclaudio timerclear(&tv); 18176e3bd63Sclaudio tv.tv_sec = adj->holdtime; 18276e3bd63Sclaudio if (evtimer_add(&adj->inactivity_timer, &tv) == -1) 183b7b4db73Srenato fatal(__func__); 18476e3bd63Sclaudio } 18576e3bd63Sclaudio 18676e3bd63Sclaudio void 18776e3bd63Sclaudio adj_stop_itimer(struct adj *adj) 18876e3bd63Sclaudio { 18976e3bd63Sclaudio if (evtimer_pending(&adj->inactivity_timer, NULL) && 19076e3bd63Sclaudio evtimer_del(&adj->inactivity_timer) == -1) 191b7b4db73Srenato fatal(__func__); 19276e3bd63Sclaudio } 19376e3bd63Sclaudio 19476e3bd63Sclaudio /* targeted neighbors */ 19576e3bd63Sclaudio 19676e3bd63Sclaudio struct tnbr * 197a8c39dc0Srenato tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 19876e3bd63Sclaudio { 19976e3bd63Sclaudio struct tnbr *tnbr; 20076e3bd63Sclaudio 20176e3bd63Sclaudio if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) 202b7b4db73Srenato fatal(__func__); 20376e3bd63Sclaudio 204a8c39dc0Srenato tnbr->af = af; 205a8c39dc0Srenato tnbr->addr = *addr; 206b5921293Srenato tnbr->state = TNBR_STA_DOWN; 207a8c39dc0Srenato tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; 208a8c39dc0Srenato tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval; 20976e3bd63Sclaudio 21076e3bd63Sclaudio return (tnbr); 21176e3bd63Sclaudio } 21276e3bd63Sclaudio 213c28a25a1Srenato static void 21476e3bd63Sclaudio tnbr_del(struct tnbr *tnbr) 21576e3bd63Sclaudio { 21676e3bd63Sclaudio tnbr_stop_hello_timer(tnbr); 21776e3bd63Sclaudio if (tnbr->adj) 2189aeb55b7Srenato adj_del(tnbr->adj, 1, S_SHUTDOWN); 219ef2688d9Srenato LIST_REMOVE(tnbr, entry); 22076e3bd63Sclaudio free(tnbr); 22176e3bd63Sclaudio } 22276e3bd63Sclaudio 22399170248Srenato struct tnbr * 224a8c39dc0Srenato tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) 22533f6ccfeSrenato { 22633f6ccfeSrenato struct tnbr *tnbr; 22733f6ccfeSrenato 22833f6ccfeSrenato LIST_FOREACH(tnbr, &xconf->tnbr_list, entry) 229a8c39dc0Srenato if (af == tnbr->af && 230a8c39dc0Srenato ldp_addrcmp(af, addr, &tnbr->addr) == 0) 23133f6ccfeSrenato return (tnbr); 23233f6ccfeSrenato 23333f6ccfeSrenato return (NULL); 23433f6ccfeSrenato } 23533f6ccfeSrenato 23633f6ccfeSrenato struct tnbr * 23799170248Srenato tnbr_check(struct tnbr *tnbr) 23899170248Srenato { 2396399cec1Srenato if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && 2406399cec1Srenato tnbr->pw_count == 0) { 24199170248Srenato tnbr_del(tnbr); 24299170248Srenato return (NULL); 24399170248Srenato } 24499170248Srenato 24599170248Srenato return (tnbr); 24699170248Srenato } 24799170248Srenato 24876e3bd63Sclaudio void 249b5921293Srenato tnbr_update(struct tnbr *tnbr) 25076e3bd63Sclaudio { 25108964f31Srenato int socket_ok, rtr_id_ok; 25276e3bd63Sclaudio 253a8c39dc0Srenato if ((ldp_af_global_get(&global, tnbr->af))->ldp_edisc_socket != -1) 254b5921293Srenato socket_ok = 1; 255b5921293Srenato else 256b5921293Srenato socket_ok = 0; 257b5921293Srenato 25808964f31Srenato if (leconf->rtr_id.s_addr != INADDR_ANY) 25908964f31Srenato rtr_id_ok = 1; 26008964f31Srenato else 26108964f31Srenato rtr_id_ok = 0; 26208964f31Srenato 263b5921293Srenato if (tnbr->state == TNBR_STA_DOWN) { 26408964f31Srenato if (!socket_ok || !rtr_id_ok) 265b5921293Srenato return; 266b5921293Srenato 267b5921293Srenato tnbr->state = TNBR_STA_ACTIVE; 2683de94509Srenato send_hello(HELLO_TARGETED, NULL, tnbr); 269b5921293Srenato 270b5921293Srenato evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); 27176e3bd63Sclaudio tnbr_start_hello_timer(tnbr); 272b5921293Srenato } else if (tnbr->state == TNBR_STA_ACTIVE) { 27308964f31Srenato if (socket_ok && rtr_id_ok) 274b5921293Srenato return; 275b5921293Srenato 276b5921293Srenato tnbr->state = TNBR_STA_DOWN; 277b5921293Srenato tnbr_stop_hello_timer(tnbr); 278b5921293Srenato } 279b5921293Srenato } 280b5921293Srenato 281b5921293Srenato void 282a8c39dc0Srenato tnbr_update_all(int af) 283b5921293Srenato { 284b5921293Srenato struct tnbr *tnbr; 285b5921293Srenato 286b5921293Srenato /* update targeted neighbors */ 287b5921293Srenato LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) 288a8c39dc0Srenato if (tnbr->af == af || af == AF_UNSPEC) 289b5921293Srenato tnbr_update(tnbr); 29076e3bd63Sclaudio } 29176e3bd63Sclaudio 29276e3bd63Sclaudio /* target neighbors timers */ 29376e3bd63Sclaudio 29476e3bd63Sclaudio /* ARGSUSED */ 295c28a25a1Srenato static void 29676e3bd63Sclaudio tnbr_hello_timer(int fd, short event, void *arg) 29776e3bd63Sclaudio { 29876e3bd63Sclaudio struct tnbr *tnbr = arg; 29976e3bd63Sclaudio 30076e3bd63Sclaudio send_hello(HELLO_TARGETED, NULL, tnbr); 30122557577Srenato tnbr_start_hello_timer(tnbr); 30276e3bd63Sclaudio } 30376e3bd63Sclaudio 304c28a25a1Srenato static void 30576e3bd63Sclaudio tnbr_start_hello_timer(struct tnbr *tnbr) 30676e3bd63Sclaudio { 30776e3bd63Sclaudio struct timeval tv; 30876e3bd63Sclaudio 30976e3bd63Sclaudio timerclear(&tv); 31076e3bd63Sclaudio tv.tv_sec = tnbr->hello_interval; 31176e3bd63Sclaudio if (evtimer_add(&tnbr->hello_timer, &tv) == -1) 312b7b4db73Srenato fatal(__func__); 31376e3bd63Sclaudio } 31476e3bd63Sclaudio 315c28a25a1Srenato static void 31676e3bd63Sclaudio tnbr_stop_hello_timer(struct tnbr *tnbr) 31776e3bd63Sclaudio { 31876e3bd63Sclaudio if (evtimer_pending(&tnbr->hello_timer, NULL) && 31976e3bd63Sclaudio evtimer_del(&tnbr->hello_timer) == -1) 320b7b4db73Srenato fatal(__func__); 32176e3bd63Sclaudio } 32276e3bd63Sclaudio 32376e3bd63Sclaudio struct ctl_adj * 32476e3bd63Sclaudio adj_to_ctl(struct adj *adj) 32576e3bd63Sclaudio { 32676e3bd63Sclaudio static struct ctl_adj actl; 32776e3bd63Sclaudio 328a8c39dc0Srenato actl.af = adj_get_af(adj); 329a8c39dc0Srenato actl.id = adj->lsr_id; 33076e3bd63Sclaudio actl.type = adj->source.type; 33176e3bd63Sclaudio switch (adj->source.type) { 33276e3bd63Sclaudio case HELLO_LINK: 333a8c39dc0Srenato memcpy(actl.ifname, adj->source.link.ia->iface->name, 33476e3bd63Sclaudio sizeof(actl.ifname)); 33576e3bd63Sclaudio break; 33676e3bd63Sclaudio case HELLO_TARGETED: 3377aa09c5dSrenato actl.src_addr = adj->source.target->addr; 33876e3bd63Sclaudio break; 33976e3bd63Sclaudio } 34076e3bd63Sclaudio actl.holdtime = adj->holdtime; 341a8c39dc0Srenato actl.trans_addr = adj->trans_addr; 34276e3bd63Sclaudio 34376e3bd63Sclaudio return (&actl); 34476e3bd63Sclaudio } 345