diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2005-01-28 14:05:41 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2005-01-28 14:05:41 +0000 |
commit | ccc5f735cc0a287cd117c41e690e7bab855d35df (patch) | |
tree | 73ce6ba377048b4358b66dcd68c700d22eea33eb /usr.sbin/ospfd/lsreq.c | |
parent | 0dcb4b3a6285e3cc2e96ba56db5f830a086696f7 (diff) |
Welcome ospfd
started by Esben Norby some time ago by using the imsg/three process framework
of bgpd. He implemented the basic concept plus the ospf finite state machines.
Later I joined and helped him cleanup, debug and extend his work.
Right now it is not particularly useful, major parts are still missing but is
imported to allow more people to work on it.
status:
The basic protocol works for broadcast networks and the LS database is
synchronized and updated. It is not possible to be DR or BDR on a network
and other interface types like point-to-point are not yet supported.
The shortest path tree is not calculated and so no routing information is
exchanged with the kernel FIB.
Not yet connected to the builds.
OK henning@
Diffstat (limited to 'usr.sbin/ospfd/lsreq.c')
-rw-r--r-- | usr.sbin/ospfd/lsreq.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/usr.sbin/ospfd/lsreq.c b/usr.sbin/ospfd/lsreq.c new file mode 100644 index 00000000000..8018c240ad5 --- /dev/null +++ b/usr.sbin/ospfd/lsreq.c @@ -0,0 +1,259 @@ +/* $OpenBSD: lsreq.c,v 1.1 2005/01/28 14:05:40 claudio Exp $ */ + +/* + * Copyright (c) 2004, 2005 Esben Norby <esben.norby@ericsson.com> + * + * 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 <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> + +#include "ospfd.h" +#include "ospf.h" +#include "log.h" +#include "ospfe.h" + +extern struct imsgbuf *ibuf_rde; + +/* link state request packet handling */ +int +send_ls_req(struct nbr *nbr) +{ + struct sockaddr_in dst; + struct ls_req_hdr *ls_req_hdr; + struct lsa_entry *le, *nle; + char *buf = NULL; + char *ptr; + int ret = 0; + + log_debug("send_ls_req: neighbor ID %s", inet_ntoa(nbr->id)); + + if (nbr->iface->passive) + return (0); + + /* XXX use buffer API instead for better decoupling */ + if ((ptr = buf = calloc(1, READ_BUF_SIZE)) == NULL) + fatal("send_ls_req"); + + /* set destination */ + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + + switch (nbr->iface->type) { + case IF_TYPE_POINTOPOINT: + inet_aton(AllSPFRouters, &dst.sin_addr); + break; + case IF_TYPE_BROADCAST: + case IF_TYPE_NBMA: + case IF_TYPE_POINTOMULTIPOINT: + case IF_TYPE_VIRTUALLINK: + dst.sin_addr.s_addr = nbr->addr.s_addr; + break; + default: + fatalx("send_ls_req: unknown interface type"); + } + + /* OSPF header */ + gen_ospf_hdr(ptr, nbr->iface, PACKET_TYPE_LS_REQUEST); + ptr += sizeof(struct ospf_hdr); + + /* LSA header(s) */ + for (le = TAILQ_FIRST(&nbr->ls_req_list); le != NULL && + (ptr - buf) < nbr->iface->mtu - PACKET_HDR; le = nle) { + nbr->ls_req = nle = TAILQ_NEXT(le, entry); + ls_req_hdr = (struct ls_req_hdr *)ptr; + ls_req_hdr->type = htonl(le->le_lsa->type); + ls_req_hdr->ls_id = le->le_lsa->ls_id; + ls_req_hdr->adv_rtr = le->le_lsa->adv_rtr; + ptr += sizeof(*ls_req_hdr); + } + + /* update authentication and calculate checksum */ + auth_gen(buf, ptr - buf, nbr->iface); + + if ((ret = send_packet(nbr->iface, buf, (ptr - buf), &dst)) == -1) + log_warnx("send_ls_req: error sending packet on " + "interface %s", nbr->iface->name); + free(buf); + return (ret); +} + +void +recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len) +{ + log_debug("recv_ls_req: neighbor ID %s", inet_ntoa(nbr->id)); + + switch (nbr->state) { + case NBR_STA_DOWN: + case NBR_STA_ATTEMPT: + case NBR_STA_INIT: + case NBR_STA_2_WAY: + case NBR_STA_XSTRT: + case NBR_STA_SNAP: + log_debug("recv_ls_req: packet ignored in state %s, " + "neighbor ID %s", nbr_state_name(nbr->state), + inet_ntoa(nbr->id)); + nbr_fsm(nbr, NBR_EVT_ADJ_OK); + break; + case NBR_STA_XCHNG: + case NBR_STA_LOAD: + case NBR_STA_FULL: + imsg_compose(ibuf_rde, IMSG_LS_REQ, nbr->peerid, 0, -1, + buf, len); + break; + default: + fatalx("recv_ls_req: unknown neighbor state"); + } +} + +/* link state request list */ +void +ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa) +{ + struct lsa_entry *le; + + if (lsa == NULL) + fatalx("ls_req_list_add: no LSA header"); + + if ((le = calloc(1, sizeof(*le))) == NULL) + fatal("ls_req_list_add"); + + TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry); + le->le_lsa = lsa; + nbr->ls_req_cnt++; +} + +struct lsa_entry * +ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr) +{ + struct lsa_entry *le; + + TAILQ_FOREACH(le, &nbr->ls_req_list, entry) { + if ((lsa_hdr->type == le->le_lsa->type) && + (lsa_hdr->ls_id == le->le_lsa->ls_id) && + (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr)) + return (le); + } + return (NULL); +} + +void +ls_req_list_free(struct nbr *nbr, struct lsa_entry *le) +{ + if (nbr->ls_req == le) { + nbr->ls_req = TAILQ_NEXT(le, entry); + } + + TAILQ_REMOVE(&nbr->ls_req_list, le, entry); + free(le->le_lsa); + free(le); + nbr->ls_req_cnt--; + + /* received all requested LSA(s), send a new LS req */ + if (nbr->ls_req != NULL && + nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) { + start_ls_req_tx_timer(nbr); + } + + if (ls_req_list_empty(nbr)) + nbr_fsm(nbr, NBR_EVT_LOAD_DONE); +} + +void +ls_req_list_clr(struct nbr *nbr) +{ + struct lsa_entry *le; + + while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) { + TAILQ_REMOVE(&nbr->ls_req_list, le, entry); + free(le->le_lsa); + free(le); + } + + nbr->ls_req_cnt = 0; + nbr->ls_req = NULL; +} + +bool +ls_req_list_empty(struct nbr *nbr) +{ + return (TAILQ_EMPTY(&nbr->ls_req_list)); +} + +/* timers */ +void +ls_req_tx_timer(int fd, short event, void *arg) +{ + struct nbr *nbr = arg; + struct timeval tv; + + log_debug("ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id)); + + switch (nbr->state) { + case NBR_STA_DOWN: + case NBR_STA_ATTEMPT: + case NBR_STA_INIT: + case NBR_STA_2_WAY: + case NBR_STA_SNAP: + case NBR_STA_XSTRT: + case NBR_STA_XCHNG: + return; + case NBR_STA_LOAD: + send_ls_req(nbr); + break; + case NBR_STA_FULL: + return; + default: + log_debug("ls_req_tx_timer: unknown neighbor state, " + "neighbor ID %s", inet_ntoa(nbr->id)); + break; + } + + /* reschedule lsreq_tx_timer */ + if (nbr->state == NBR_STA_LOAD) { + timerclear(&tv); + tv.tv_sec = nbr->iface->rxmt_interval; + log_debug("ls_req_tx_timer: reschedule neighbor ID %s", + inet_ntoa(nbr->id)); + evtimer_add(&nbr->lsreq_tx_timer, &tv); + } +} + +int +start_ls_req_tx_timer(struct nbr *nbr) +{ + struct timeval tv; + + if (nbr == nbr->iface->self) + return (0); + + log_debug("start_ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id)); + timerclear(&tv); + + return (evtimer_add(&nbr->lsreq_tx_timer, &tv)); +} + +int +stop_ls_req_tx_timer(struct nbr *nbr) +{ + if (nbr == nbr->iface->self) + return (0); + + log_debug("stop_ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id)); + + return (evtimer_del(&nbr->lsreq_tx_timer)); +} |