Skip to content

Commit

Permalink
Welcome eigrpd
Browse files Browse the repository at this point in the history
The eigrpd daemon will support the Enhanced Interior Gateway Routing Protocol.

Built using the imsg/three process framework and heavily based on ospfd(8), ospf6d(8) and ldpd(8).

The current status of eigrpd(8) is as follows:
* Almost full compliance with the specification: DUAL FSM, RTP, CR mode, SIA, etc
* Support for both IPv4 and IPv6
* Support for multiple instances (different ASes/AFs) within the same process
* Support for rdomains (one process per rdomain)
* RIB/FIB synchronization
* Basic redistribution support

Not implemented features (yet):
* Configuration reload support (partially implemented)
* Route summarization
* Advanced route redistribution/filtering
* Carp integration
* Authentication (draft is missing information)
* Stub (not released by Cisco)

Not yet connected to the builds.

ok deraadt@ claudio@
  • Loading branch information
rwestphal committed Oct 2, 2015
0 parents commit a2ef3d6
Show file tree
Hide file tree
Showing 29 changed files with 11,539 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# $OpenBSD$

PROG= eigrpd
SRCS= control.c eigrpd.c eigrpe.c hello.c in_cksum.c interface.c \
kroute.c log.c neighbor.c packet.c parse.y printconf.c query.c \
rde.c rde_dual.c reply.c rtp.c tlv.c update.c util.c

MAN= eigrpd.8 eigrpd.conf.5

CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare
YFLAGS=
LDADD+= -levent -lutil
DPADD+= ${LIBEVENT} ${LIBUTIL}

.include <bsd.prog.mk>
315 changes: 315 additions & 0 deletions control.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
/* $OpenBSD$ */

/*
* Copyright (c) 2003, 2004 Henning Brauer <[email protected]>
*
* 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/stat.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "eigrpd.h"
#include "eigrp.h"
#include "eigrpe.h"
#include "log.h"
#include "control.h"

#define CONTROL_BACKLOG 5

struct ctl_conn *control_connbyfd(int);
struct ctl_conn *control_connbypid(pid_t);
void control_close(int);

int
control_init(char *path)
{
struct sockaddr_un sun;
int fd;
mode_t old_umask;

if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0)) == -1) {
log_warn("%s: socket", __func__);
return (-1);
}

memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strlcpy(sun.sun_path, path, sizeof(sun.sun_path));

if (unlink(path) == -1)
if (errno != ENOENT) {
log_warn("%s: unlink %s", __func__, path);
close(fd);
return (-1);
}

old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
log_warn("%s: bind: %s", __func__, path);
close(fd);
umask(old_umask);
return (-1);
}
umask(old_umask);

if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
log_warn("%s: chmod", __func__);
close(fd);
(void)unlink(path);
return (-1);
}

control_state.fd = fd;

return (0);
}

int
control_listen(void)
{

if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
log_warn("%s: listen", __func__);
return (-1);
}

event_set(&control_state.ev, control_state.fd, EV_READ,
control_accept, NULL);
event_add(&control_state.ev, NULL);
evtimer_set(&control_state.evt, control_accept, NULL);

return (0);
}

void
control_cleanup(char *path)
{
if (path == NULL)
return;
event_del(&control_state.ev);
event_del(&control_state.evt);
unlink(path);
}

/* ARGSUSED */
void
control_accept(int listenfd, short event, void *bula)
{
int connfd;
socklen_t len;
struct sockaddr_un sun;
struct ctl_conn *c;

event_add(&control_state.ev, NULL);
if ((event & EV_TIMEOUT))
return;

len = sizeof(sun);
if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len,
SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) {
/*
* Pause accept if we are out of file descriptors, or
* libevent will haunt us here too.
*/
if (errno == ENFILE || errno == EMFILE) {
struct timeval evtpause = { 1, 0 };

event_del(&control_state.ev);
evtimer_add(&control_state.evt, &evtpause);
} else if (errno != EWOULDBLOCK && errno != EINTR &&
errno != ECONNABORTED)
log_warn("%s: accept4", __func__);
return;
}

if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
log_warn("%s: calloc", __func__);
close(connfd);
return;
}

imsg_init(&c->iev.ibuf, connfd);
c->iev.handler = control_dispatch_imsg;
c->iev.events = EV_READ;
event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
c->iev.handler, &c->iev);
event_add(&c->iev.ev, NULL);

TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
}

struct ctl_conn *
control_connbyfd(int fd)
{
struct ctl_conn *c;

for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
c = TAILQ_NEXT(c, entry))
; /* nothing */

return (c);
}

struct ctl_conn *
control_connbypid(pid_t pid)
{
struct ctl_conn *c;

for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
c = TAILQ_NEXT(c, entry))
; /* nothing */

return (c);
}

void
control_close(int fd)
{
struct ctl_conn *c;

if ((c = control_connbyfd(fd)) == NULL) {
log_warnx("%s: fd %d: not found", __func__, fd);
return;
}

msgbuf_clear(&c->iev.ibuf.w);
TAILQ_REMOVE(&ctl_conns, c, entry);

event_del(&c->iev.ev);
close(c->iev.ibuf.fd);

/* Some file descriptors are available again. */
if (evtimer_pending(&control_state.evt, NULL)) {
evtimer_del(&control_state.evt);
event_add(&control_state.ev, NULL);
}

free(c);
}

/* ARGSUSED */
void
control_dispatch_imsg(int fd, short event, void *bula)
{
struct ctl_conn *c;
struct imsg imsg;
ssize_t n;
unsigned int ifidx;
int verbose;

if ((c = control_connbyfd(fd)) == NULL) {
log_warnx("%s: fd %d: not found", __func__, fd);
return;
}

if (event & EV_READ) {
if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
control_close(fd);
return;
}
}
if (event & EV_WRITE) {
if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
control_close(fd);
return;
}
}

for (;;) {
if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
control_close(fd);
return;
}

if (n == 0)
break;

switch (imsg.hdr.type) {
case IMSG_CTL_FIB_COUPLE:
case IMSG_CTL_FIB_DECOUPLE:
case IMSG_CTL_RELOAD:
c->iev.ibuf.pid = imsg.hdr.pid;
eigrpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_IFINFO:
c->iev.ibuf.pid = imsg.hdr.pid;
eigrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
break;
case IMSG_CTL_SHOW_INTERFACE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(ifidx))
break;

memcpy(&ifidx, imsg.data, sizeof(ifidx));
eigrpe_iface_ctl(c, ifidx);
imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
0, -1, NULL, 0);
break;
case IMSG_CTL_SHOW_TOPOLOGY:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct ctl_show_topology_req))
break;

c->iev.ibuf.pid = imsg.hdr.pid;
eigrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
break;
case IMSG_CTL_SHOW_NBR:
eigrpe_nbr_ctl(c);
break;
case IMSG_CTL_LOG_VERBOSE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(verbose))
break;

/* forward to other processes */
eigrpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
eigrpe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);

memcpy(&verbose, imsg.data, sizeof(verbose));
log_verbose(verbose);
break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
break;
}
imsg_free(&imsg);
}

imsg_event_add(&c->iev);
}

int
control_imsg_relay(struct imsg *imsg)
{
struct ctl_conn *c;

if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
return (0);

return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
-1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
}
44 changes: 44 additions & 0 deletions control.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* $OpenBSD$ */

/*
* Copyright (c) 2003, 2004 Henning Brauer <[email protected]>
*
* 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.
*/

#ifndef _CONTROL_H_
#define _CONTROL_H_

#include <sys/queue.h>
#include <sys/time.h>
#include <event.h>

struct {
struct event ev;
struct event evt;
int fd;
} control_state;

struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
struct imsgev iev;
};

int control_init(char *);
int control_listen(void);
void control_accept(int, short, void *);
void control_dispatch_imsg(int, short, void *);
int control_imsg_relay(struct imsg *);
void control_cleanup(char *);

#endif /* _CONTROL_H_ */
Loading

0 comments on commit a2ef3d6

Please sign in to comment.