diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2013-06-04 13:16:22 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2013-06-04 13:16:22 +0000 |
commit | 9840c0205f8b6b93252ce251f31c31ceafcce496 (patch) | |
tree | e385a9305469dac5bb1e4ddf9611b043d4102fac /usr.sbin/ldpd/adjacency.c | |
parent | 271a7f452333d488de68b19ec6cdffddc326fac2 (diff) |
I screwed up and forgot to commit this new file :(
Diffstat (limited to 'usr.sbin/ldpd/adjacency.c')
-rw-r--r-- | usr.sbin/ldpd/adjacency.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/usr.sbin/ldpd/adjacency.c b/usr.sbin/ldpd/adjacency.c new file mode 100644 index 00000000000..efe202fc79d --- /dev/null +++ b/usr.sbin/ldpd/adjacency.c @@ -0,0 +1,316 @@ +/* $OpenBSD: adjacency.c,v 1.1 2013/06/04 13:16:21 claudio Exp $ */ + +/* + * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> + * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> + * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ldpd.h" +#include "ldpe.h" +#include "control.h" +#include "log.h" + +extern struct ldpd_conf *leconf; + +void adj_itimer(int, short, void *); +char *print_hello_src(struct hello_source *); + +void tnbr_hello_timer(int, short, void *); +void tnbr_start_hello_timer(struct tnbr *); +void tnbr_stop_hello_timer(struct tnbr *); + +struct adj * +adj_new(struct nbr *nbr, struct hello_source *source, u_int16_t holdtime, + struct in_addr addr) +{ + struct adj *adj; + + log_debug("adj_new: LSR ID %s, %s", inet_ntoa(nbr->id), + print_hello_src(source)); + + if ((adj = calloc(1, sizeof(*adj))) == NULL) + fatal("adj_new"); + + adj->nbr = nbr; + memcpy(&adj->source, source, sizeof(*source)); + adj->addr = addr; + + evtimer_set(&adj->inactivity_timer, adj_itimer, adj); + + LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry); + + switch (source->type) { + case HELLO_LINK: + LIST_INSERT_HEAD(&source->link.iface->adj_list, adj, + iface_entry); + break; + case HELLO_TARGETED: + source->target->adj = adj; + break; + } + + return (adj); +} + +void +adj_del(struct adj *adj) +{ + log_debug("adj_del: LSR ID %s, %s", inet_ntoa(adj->nbr->id), + print_hello_src(&adj->source)); + + adj_stop_itimer(adj); + + LIST_REMOVE(adj, nbr_entry); + + /* last adjacency deleted */ + if (LIST_EMPTY(&adj->nbr->adj_list)) + nbr_del(adj->nbr); + + free(adj); +} + +struct adj * +adj_find(struct nbr *nbr, struct hello_source *source) +{ + struct adj *adj; + + LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { + if (adj->source.type != source->type) + continue; + + switch (source->type) { + case HELLO_LINK: + if (adj->source.link.src_addr.s_addr == + source->link.src_addr.s_addr) + return (adj); + break; + case HELLO_TARGETED: + if (adj->source.target == source->target) + return (adj); + break; + } + } + + return (NULL); +} + +char * +print_hello_src(struct hello_source *src) +{ + static char buffer[64]; + + if (src->type == HELLO_LINK) + snprintf(buffer, sizeof(buffer), "iface %s", + src->link.iface->name); + else + snprintf(buffer, sizeof(buffer), "source %s", + inet_ntoa(src->target->addr)); + + return buffer; +} + +/* adjacency timers */ + +/* ARGSUSED */ +void +adj_itimer(int fd, short event, void *arg) +{ + struct adj *adj = arg; + + log_debug("adj_itimer: LDP ID %s", inet_ntoa(adj->nbr->id)); + + switch (adj->source.type) { + case HELLO_LINK: + LIST_REMOVE(adj, iface_entry); + break; + case HELLO_TARGETED: + adj->source.target->adj = NULL; + if (!(adj->source.target->flags & F_TNBR_CONFIGURED)) { + LIST_REMOVE(adj->source.target, entry); + tnbr_del(adj->source.target); + } + break; + } + + adj_del(adj); +} + +void +adj_start_itimer(struct adj *adj) +{ + struct timeval tv; + + timerclear(&tv); + tv.tv_sec = adj->holdtime; + + if (evtimer_add(&adj->inactivity_timer, &tv) == -1) + fatal("adj_start_itimer"); +} + +void +adj_stop_itimer(struct adj *adj) +{ + if (evtimer_pending(&adj->inactivity_timer, NULL) && + evtimer_del(&adj->inactivity_timer) == -1) + fatal("adj_stop_itimer"); +} + +/* targeted neighbors */ + +struct tnbr * +tnbr_new(struct in_addr addr, int configured) +{ + struct tnbr *tnbr; + + if ((tnbr = calloc(1, sizeof(*tnbr))) == NULL) + fatal("tnbr_new"); + + tnbr->addr.s_addr = addr.s_addr; + if (configured) + tnbr->flags |= F_TNBR_CONFIGURED; + else { + tnbr->hello_holdtime = leconf->thello_holdtime; + tnbr->hello_interval = leconf->thello_interval; + } + + return (tnbr); +} + +void +tnbr_del(struct tnbr *tnbr) +{ + tnbr_stop_hello_timer(tnbr); + if (tnbr->adj) + adj_del(tnbr->adj); + free(tnbr); +} + +void +tnbr_init(struct ldpd_conf *xconf, struct tnbr *tnbr) +{ + /* set event handlers for targeted neighbor */ + evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); + + tnbr->discovery_fd = xconf->ldp_ediscovery_socket; + tnbr_start_hello_timer(tnbr); +} + +struct tnbr * +tnbr_find(struct in_addr addr) +{ + struct tnbr *tnbr; + + LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) + if (addr.s_addr == tnbr->addr.s_addr) + return (tnbr); + + return (NULL); +} + +/* target neighbors timers */ + +/* ARGSUSED */ +void +tnbr_hello_timer(int fd, short event, void *arg) +{ + struct tnbr *tnbr = arg; + struct timeval tv; + + send_hello(HELLO_TARGETED, NULL, tnbr); + + /* reschedule hello_timer */ + timerclear(&tv); + tv.tv_sec = tnbr->hello_interval; + if (evtimer_add(&tnbr->hello_timer, &tv) == -1) + fatal("tnbr_hello_timer"); +} + +void +tnbr_start_hello_timer(struct tnbr *tnbr) +{ + struct timeval tv; + + send_hello(HELLO_TARGETED, NULL, tnbr); + + timerclear(&tv); + tv.tv_sec = tnbr->hello_interval; + if (evtimer_add(&tnbr->hello_timer, &tv) == -1) + fatal("tnbr_start_hello_timer"); +} + +void +tnbr_stop_hello_timer(struct tnbr *tnbr) +{ + if (evtimer_pending(&tnbr->hello_timer, NULL) && + evtimer_del(&tnbr->hello_timer) == -1) + fatal("tnbr_stop_hello_timer"); +} + +struct ctl_adj * +adj_to_ctl(struct adj *adj) +{ + static struct ctl_adj actl; + + actl.id.s_addr = adj->nbr->id.s_addr; + actl.type = adj->source.type; + switch (adj->source.type) { + case HELLO_LINK: + memcpy(actl.ifname, adj->source.link.iface->name, + sizeof(actl.ifname)); + break; + case HELLO_TARGETED: + actl.src_addr.s_addr = adj->source.target->addr.s_addr; + break; + } + actl.holdtime = adj->holdtime; + + return (&actl); +} + +void +ldpe_adj_ctl(struct ctl_conn *c) +{ + struct adj *adj; + struct iface *iface; + struct tnbr *tnbr; + struct ctl_adj *actl; + + /* basic discovery mechanism */ + LIST_FOREACH(iface, &leconf->iface_list, entry) + LIST_FOREACH(adj, &iface->adj_list, iface_entry) { + actl = adj_to_ctl(adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, + 0, 0, -1, actl, sizeof(struct ctl_adj)); + } + + /* extended discovery mechanism */ + LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) + if (tnbr->adj) { + actl = adj_to_ctl(tnbr->adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, + 0, 0, -1, actl, sizeof(struct ctl_adj)); + } + + imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); +} |