diff options
author | Esben Norby <norby@cvs.openbsd.org> | 2006-10-18 16:11:59 +0000 |
---|---|---|
committer | Esben Norby <norby@cvs.openbsd.org> | 2006-10-18 16:11:59 +0000 |
commit | 9898323e8078c0a28e2404083e37bbb23637a390 (patch) | |
tree | 2fd1fe72c94b0d594d939719e44a82ce86dd6e10 /usr.sbin/ripd/neighbor.c | |
parent | 489a63b5b7e02bf58b50268110b2421d48373394 (diff) |
Welcome ripd
started by Michele Marchetto some time ago by using the imsg/three process framework
of ospfd. He implemented most of the daemon with a little help and guidance from
Claudio and I.
Currently the daemon is more or less complete, with the exception of key lifetime
and rollover.
Not yet connected to the builds.
OK claudio@
Diffstat (limited to 'usr.sbin/ripd/neighbor.c')
-rw-r--r-- | usr.sbin/ripd/neighbor.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/usr.sbin/ripd/neighbor.c b/usr.sbin/ripd/neighbor.c new file mode 100644 index 00000000000..edd33019bc2 --- /dev/null +++ b/usr.sbin/ripd/neighbor.c @@ -0,0 +1,357 @@ +/* $OpenBSD: neighbor.c,v 1.1 2006/10/18 16:11:58 norby Exp $ */ + +/* + * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> + * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> + * Copyright (c) 2004, 2005, 2006 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/ioctl.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> + +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <event.h> + +#include "ripd.h" +#include "rip.h" +#include "ripe.h" +#include "log.h" +#include "rde.h" + +void nbr_start_timer(struct nbr *); +void nbr_reset_timer(struct nbr *); + +LIST_HEAD(nbr_head, nbr); + +struct nbr_table { + struct nbr_head *hashtbl; + u_int32_t hashmask; +} nbrtable; + +#define NBR_HASH(x) \ + &nbrtable.hashtbl[(x) & nbrtable.hashmask] + +u_int32_t peercnt = NBR_CNTSTART; + +struct { + int state; + enum nbr_event event; + enum nbr_action action; + int new_state; +} nbr_fsm_tbl[] = { + /* current state event that happened action to take resulting state */ + {NBR_STA_DOWN, NBR_EVT_REQUEST_RCVD, NBR_ACT_STRT_TIMER, NBR_STA_ACTIVE}, + {NBR_STA_DOWN, NBR_EVT_RESPONSE_RCVD, NBR_ACT_STRT_TIMER, NBR_STA_ACTIVE}, + {NBR_STA_ACTIVE, NBR_EVT_RESPONSE_RCVD, NBR_ACT_RST_TIMER, NBR_STA_ACTIVE}, + {NBR_STA_ACTIVE, NBR_EVT_REQUEST_RCVD, NBR_ACT_NOTHING, NBR_STA_ACTIVE}, + {NBR_STA_ACTIVE, NBR_EVT_TIMEOUT, NBR_ACT_DEL, NBR_STA_DOWN}, + {NBR_STA_ANY, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN}, + {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0}, +}; + +const char * const nbr_event_names[] = { + "RESPONSE RCVD", + "REQUEST RCVD", + "NBR TIMEOUT", + "NBR KILL", + "NOTHING" +}; + +const char * const nbr_action_names[] = { + "START TIMER", + "RESET TIMER", + "DELETE NBR", + "NOTHING" +}; + +int +nbr_fsm(struct nbr *nbr, enum nbr_event event) +{ + struct timeval now; + int old_state; + int new_state = 0; + int i; + + old_state = nbr->state; + for (i = 0; nbr_fsm_tbl[i].state != -1; i++) + if ((nbr_fsm_tbl[i].state & old_state) && + (nbr_fsm_tbl[i].event == event)) { + new_state = nbr_fsm_tbl[i].new_state; + break; + } + + if (nbr_fsm_tbl[i].state == -1) { + /* event outside of the defined fsm, ignore it. */ + log_warnx("nbr_fsm: neighbor ID %s, " + "event '%s' not expected in state '%s'", + inet_ntoa(nbr->id), nbr_event_name(event), + nbr_state_name(old_state)); + return (0); + } + + switch (nbr_fsm_tbl[i].action) { + case NBR_ACT_RST_TIMER: + nbr_reset_timer(nbr); + break; + case NBR_ACT_STRT_TIMER: + nbr_start_timer(nbr); + break; + case NBR_ACT_DEL: + nbr_act_del(nbr); + break; + case NBR_ACT_NOTHING: + /* do nothing */ + break; + } + + if (new_state != 0) + nbr->state = new_state; + + if (old_state != nbr->state) { + /* neighbor changed from/to ACTIVE */ + gettimeofday(&now, NULL); + nbr->uptime = now.tv_sec; + + log_debug("nbr_fsm: event '%s' resulted in action '%s' and " + "changing state for neighbor ID %s from '%s' to '%s'", + nbr_event_name(event), + nbr_action_name(nbr_fsm_tbl[i].action), + inet_ntoa(nbr->id), nbr_state_name(old_state), + nbr_state_name(nbr->state)); + } + + return (0); +} + +void +nbr_init(u_int32_t hashsize) +{ + u_int32_t hs, i; + + for (hs = 1; hs < hashsize; hs <<= 1) + ; + nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head)); + if (nbrtable.hashtbl == NULL) + fatal("nbr_init"); + + for (i = 0; i < hs; i++) + LIST_INIT(&nbrtable.hashtbl[i]); + + nbrtable.hashmask = hs - 1; +} + +struct nbr * +nbr_new(u_int32_t nbr_id, struct iface *iface, int self) +{ + struct nbr_head *head; + struct nbr *nbr = NULL; + + if ((nbr = calloc(1, sizeof(*nbr))) == NULL) + fatal("nbr_new"); + + nbr->state = NBR_STA_DOWN; + nbr->id.s_addr = nbr_id; + + /* get next unused peerid */ + while (nbr_find_peerid(++peercnt)) + ; + nbr->peerid = peercnt; + head = NBR_HASH(nbr->peerid); + LIST_INSERT_HEAD(head, nbr, hash); + + /* add to peer list */ + nbr->iface = iface; + LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry); + + TAILQ_INIT(&nbr->rp_list); + TAILQ_INIT(&nbr->rq_list); + + /* set event structures */ + evtimer_set(&nbr->timeout_timer, nbr_timeout_timer, nbr); + + log_debug("nbr_new: neighbor ID %s, peerid %lu", + inet_ntoa(nbr->id), nbr->peerid); + + return (nbr); +} + +void +nbr_act_del(struct nbr *nbr) +{ + struct nbr_failed *nbr_failed; + struct iface *iface; + + if (nbr->iface->auth_type == AUTH_CRYPT) { + if ((nbr_failed = calloc(1, sizeof(*nbr_failed))) == NULL) + fatal("nbr_act_del"); + + nbr_failed->addr = nbr->addr; + nbr_failed->auth_seq_num = nbr->auth_seq_num; + iface = nbr->iface; + LIST_INSERT_HEAD(&iface->failed_nbr_list, + nbr_failed, entry); + } + + log_debug("nbr_del: neighbor ID %s, peerid %lu", inet_ntoa(nbr->id), + nbr->peerid); + + /* clear lists */ + //response_list_clr(&nbr->rr_list); + + LIST_REMOVE(nbr, entry); + LIST_REMOVE(nbr, hash); + + free(nbr); +} + +struct nbr * +nbr_find_peerid(u_int32_t peerid) +{ + struct nbr_head *head; + struct nbr *nbr; + + head = NBR_HASH(peerid); + + LIST_FOREACH(nbr, head, hash) { + if (nbr->peerid == peerid) + return (nbr); + } + + return (NULL); +} + +struct nbr * +nbr_find_ip(struct iface *iface, u_int32_t src_ip) +{ + struct nbr *nbr = NULL; + + LIST_FOREACH(nbr, &iface->nbr_list, entry) { + if (nbr->id.s_addr == src_ip) { + return (nbr); + } + } + + return (NULL); +} + +struct nbr_failed * +nbr_failed_find(struct iface *iface, u_int32_t src_ip) +{ + struct nbr_failed *nbr_failed = NULL; + + LIST_FOREACH(nbr_failed, &iface->failed_nbr_list, entry) { + if (nbr_failed->addr.s_addr == src_ip) { + return (nbr_failed); + } + } + + return (NULL); +} + +void +nbr_failed_delete(struct iface *iface, struct nbr_failed *nbr_failed) +{ + LIST_REMOVE(nbr_failed, entry); + + free(nbr_failed); +} + +/* timers */ +/* ARGSUSED */ +void +nbr_timeout_timer(int fd, short event, void *arg) +{ + struct nbr *nbr = arg; + + nbr_fsm(nbr, NBR_EVT_TIMEOUT); +} + +/* actions */ +void +nbr_reset_timer(struct nbr *nbr) +{ + struct timeval tv; + + timerclear(&tv); + tv.tv_sec = NBR_TIMEOUT; + + if (evtimer_add(&nbr->timeout_timer, &tv) == -1) + fatal("nbr_reset_timer"); +} + +void +nbr_start_timer(struct nbr *nbr) +{ + struct timeval tv; + + timerclear(&tv); + tv.tv_sec = NBR_TIMEOUT; + + if (evtimer_add(&nbr->timeout_timer, &tv) == -1) + fatal("nbr_start_timer"); +} + +/* names */ +const char * +nbr_event_name(int event) +{ + return (nbr_event_names[event]); +} + +const char * +nbr_action_name(int action) +{ + return (nbr_action_names[action]); +} + +struct ctl_nbr * +nbr_to_ctl(struct nbr *nbr) +{ + static struct ctl_nbr nctl; + struct timeval tv, now, res; + + memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name)); + memcpy(&nctl.id, &nbr->id, sizeof(nctl.id)); + memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr)); + + nctl.nbr_state = nbr->state; + nctl.iface_state = nbr->iface->state; + + gettimeofday(&now, NULL); + if (evtimer_pending(&nbr->timeout_timer, &tv)) { + timersub(&tv, &now, &res); + if (nbr->state & NBR_STA_DOWN) + nctl.dead_timer = NBR_TIMEOUT - res.tv_sec; + else + nctl.dead_timer = res.tv_sec; + } else + nctl.dead_timer = 0; + + if (nbr->state == NBR_STA_ACTIVE) { + nctl.uptime = now.tv_sec - nbr->uptime; + } else + nctl.uptime = 0; + + return (&nctl); +} |