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