summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2012-04-12 17:33:44 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2012-04-12 17:33:44 +0000
commita9c25bce4eb2242564115652664a51ad553f790d (patch)
treec5ce584648e315a723054716c5094ac335be73d6 /usr.sbin
parentab8c7358124cfd2734adf977bef218d3288e91ca (diff)
accept pacing ldpd way. Since this daemon has multiple listening fds
we add them all to a accept queue that does the pacing with the accept_pause() and accept_unpause() calls. With and OK deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/ldpd/Makefile4
-rw-r--r--usr.sbin/ldpd/accept.c137
-rw-r--r--usr.sbin/ldpd/control.c26
-rw-r--r--usr.sbin/ldpd/control.h7
-rw-r--r--usr.sbin/ldpd/ldpd.h4
-rw-r--r--usr.sbin/ldpd/ldpe.c8
-rw-r--r--usr.sbin/ldpd/ldpe.h9
-rw-r--r--usr.sbin/ldpd/packet.c16
8 files changed, 180 insertions, 31 deletions
diff --git a/usr.sbin/ldpd/Makefile b/usr.sbin/ldpd/Makefile
index f03dfc97829..792177b68fd 100644
--- a/usr.sbin/ldpd/Makefile
+++ b/usr.sbin/ldpd/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.3 2010/05/26 16:44:32 nicm Exp $
+# $OpenBSD: Makefile,v 1.4 2012/04/12 17:33:43 claudio Exp $
PROG= ldpd
-SRCS= address.c control.c hello.c init.c interface.c \
+SRCS= accept.c address.c control.c hello.c init.c interface.c \
keepalive.c kroute.c labelmapping.c lde.c lde_lib.c ldpd.c ldpe.c \
log.c neighbor.c notification.c packet.c parse.y printconf.c
diff --git a/usr.sbin/ldpd/accept.c b/usr.sbin/ldpd/accept.c
new file mode 100644
index 00000000000..4f1a585f83a
--- /dev/null
+++ b/usr.sbin/ldpd/accept.c
@@ -0,0 +1,137 @@
+/* $OpenBSD: accept.c,v 1.1 2012/04/12 17:33:43 claudio Exp $ */
+
+/*
+ * Copyright (c) 2012 Claudio Jeker <claudio@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/queue.h>
+#include <sys/time.h>
+#include <event.h>
+#include <stdlib.h>
+
+#include "ldpd.h"
+#include "ldpe.h"
+#include "log.h"
+
+struct accept_ev {
+ LIST_ENTRY(accept_ev) entry;
+ struct event ev;
+ void (*accept_cb)(int, short, void *);
+ void *arg;
+ int fd;
+};
+
+struct {
+ LIST_HEAD(, accept_ev) queue;
+ struct event evt;
+} accept_queue;
+
+void accept_arm(void);
+void accept_unarm(void);
+void accept_cb(int, short, void *);
+void accept_timeout(int, short, void *);
+
+void
+accept_init(void)
+{
+ LIST_INIT(&accept_queue.queue);
+ evtimer_set(&accept_queue.evt, accept_timeout, NULL);
+}
+
+int
+accept_add(int fd, void (*cb)(int, short, void *), void *arg)
+{
+ struct accept_ev *av;
+
+ if ((av = calloc(1, sizeof(*av))) == NULL)
+ return -1;
+ av->fd = fd;
+ av->accept_cb = cb;
+ av->arg = arg;
+ LIST_INSERT_HEAD(&accept_queue.queue, av, entry);
+
+ event_set(&av->ev, av->fd, EV_READ, accept_cb, av);
+ event_add(&av->ev, NULL);
+
+ log_debug("accept_add: accepting on fd %d", fd);
+
+ return (0);
+}
+
+void
+accept_del(int fd)
+{
+ struct accept_ev *av;
+
+ LIST_FOREACH(av, &accept_queue.queue, entry)
+ if (av->fd == fd) {
+ log_debug("accept_del: %i removed from queue", fd);
+ event_del(&av->ev);
+ LIST_REMOVE(av, entry);
+ free(av);
+ return;
+ }
+}
+
+void
+accept_pause(void)
+{
+ struct timeval evtpause = { 1, 0 };
+
+ log_debug("accept_pause");
+ accept_unarm();
+ evtimer_add(&accept_queue.evt, &evtpause);
+}
+
+void
+accept_unpause(void)
+{
+ if (evtimer_pending(&accept_queue.evt, NULL)) {
+ log_debug("accept_unpause");
+ evtimer_del(&accept_queue.evt);
+ accept_arm();
+ }
+}
+
+void
+accept_arm(void)
+{
+ struct accept_ev *av;
+ LIST_FOREACH(av, &accept_queue.queue, entry)
+ event_add(&av->ev, NULL);
+}
+
+void
+accept_unarm(void)
+{
+ struct accept_ev *av;
+ LIST_FOREACH(av, &accept_queue.queue, entry)
+ event_del(&av->ev);
+}
+
+void
+accept_cb(int fd, short event, void *arg)
+{
+ struct accept_ev *av = arg;
+ event_add(&av->ev, NULL);
+ av->accept_cb(fd, event, av->arg);
+}
+
+void
+accept_timeout(int fd, short event, void *bula)
+{
+ log_debug("accept_timeout");
+ accept_arm();
+}
diff --git a/usr.sbin/ldpd/control.c b/usr.sbin/ldpd/control.c
index 42908960955..5a14a802977 100644
--- a/usr.sbin/ldpd/control.c
+++ b/usr.sbin/ldpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.9 2010/09/01 13:54:54 claudio Exp $ */
+/* $OpenBSD: control.c,v 1.10 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -38,6 +38,8 @@ struct ctl_conn *control_connbyfd(int);
struct ctl_conn *control_connbypid(pid_t);
void control_close(int);
+int control_fd;
+
int
control_init(void)
{
@@ -78,7 +80,7 @@ control_init(void)
}
session_socket_blockmode(fd, BM_NONBLOCK);
- control_state.fd = fd;
+ control_fd = fd;
return (0);
}
@@ -87,16 +89,12 @@ int
control_listen(void)
{
- if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
+ if (listen(control_fd, CONTROL_BACKLOG) == -1) {
log_warn("control_listen: listen");
return (-1);
}
- event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST,
- control_accept, NULL);
- event_add(&control_state.ev, NULL);
-
- return (0);
+ return (accept_add(control_fd, control_accept, NULL));
}
void
@@ -115,9 +113,14 @@ control_accept(int listenfd, short event, void *bula)
struct ctl_conn *c;
len = sizeof(sun);
- if ((connfd = accept(listenfd,
- (struct sockaddr *)&sun, &len)) == -1) {
- if (errno != EWOULDBLOCK && errno != EINTR)
+ if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) {
+ /*
+ * Pause accept if we are out of file descriptors, or
+ * libevent will haunt us here too.
+ */
+ if (errno == ENFILE || errno == EMFILE)
+ accept_pause();
+ else if (errno != EWOULDBLOCK && errno != EINTR)
log_warn("control_accept: accept");
return;
}
@@ -180,6 +183,7 @@ control_close(int fd)
event_del(&c->iev.ev);
close(c->iev.ibuf.fd);
free(c);
+ accept_unpause();
}
/* ARGSUSED */
diff --git a/usr.sbin/ldpd/control.h b/usr.sbin/ldpd/control.h
index 7468b636500..5bd57c26c00 100644
--- a/usr.sbin/ldpd/control.h
+++ b/usr.sbin/ldpd/control.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.h,v 1.3 2010/04/15 15:04:23 claudio Exp $ */
+/* $OpenBSD: control.h,v 1.4 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -23,11 +23,6 @@
#include <sys/time.h>
#include <event.h>
-struct {
- struct event ev;
- int fd;
-} control_state;
-
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
struct imsgev iev;
diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h
index e6c9ed91895..6633b603291 100644
--- a/usr.sbin/ldpd/ldpd.h
+++ b/usr.sbin/ldpd/ldpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpd.h,v 1.28 2011/01/10 12:28:25 claudio Exp $ */
+/* $OpenBSD: ldpd.h,v 1.29 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -246,7 +246,7 @@ enum blockmodes {
#define MODE_ADV_UNSOLICITED 0x20
struct ldpd_conf {
- struct event disc_ev, sess_ev;
+ struct event disc_ev;
struct in_addr rtr_id;
LIST_HEAD(, iface) iface_list;
diff --git a/usr.sbin/ldpd/ldpe.c b/usr.sbin/ldpd/ldpe.c
index a65d1bef376..f3521502f1f 100644
--- a/usr.sbin/ldpd/ldpe.c
+++ b/usr.sbin/ldpd/ldpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.c,v 1.15 2011/07/04 04:34:14 claudio Exp $ */
+/* $OpenBSD: ldpe.c,v 1.16 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -160,6 +160,7 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
fatal("can't drop privileges");
event_init();
+ accept_init();
/* setup signal handler */
signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL);
@@ -198,10 +199,7 @@ ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2],
EV_READ|EV_PERSIST, disc_recv_packet, leconf);
event_add(&leconf->disc_ev, NULL);
- event_set(&leconf->sess_ev, leconf->ldp_session_socket,
- EV_READ|EV_PERSIST, session_accept, leconf);
- event_add(&leconf->sess_ev, NULL);
-
+ accept_add(leconf->ldp_session_socket, session_accept, leconf);
/* listen on ldpd control socket */
TAILQ_INIT(&ctl_conns);
control_listen();
diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h
index 46fd0496ee2..1a6f2674a64 100644
--- a/usr.sbin/ldpd/ldpe.h
+++ b/usr.sbin/ldpd/ldpe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldpe.h,v 1.15 2011/03/12 01:57:13 claudio Exp $ */
+/* $OpenBSD: ldpe.h,v 1.16 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
@@ -73,6 +73,13 @@ struct nbr {
};
+/* accept.c */
+void accept_init(void);
+int accept_add(int, void (*)(int, short, void *), void *);
+void accept_del(int);
+void accept_pause(void);
+void accept_unpause(void);
+
/* hello.c */
int send_hello(struct iface *);
void recv_hello(struct iface *, struct in_addr, char *, u_int16_t);
diff --git a/usr.sbin/ldpd/packet.c b/usr.sbin/ldpd/packet.c
index b23739c6d90..5a5880d162f 100644
--- a/usr.sbin/ldpd/packet.c
+++ b/usr.sbin/ldpd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.15 2011/03/12 01:52:04 claudio Exp $ */
+/* $OpenBSD: packet.c,v 1.16 2012/04/12 17:33:43 claudio Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -257,13 +257,20 @@ session_accept(int fd, short event, void *bula)
int newfd;
socklen_t len = sizeof(src);
- if (event != EV_READ)
+ if (!(event & EV_READ))
return;
newfd = accept(fd, (struct sockaddr *)&src, &len);
if (newfd == -1) {
- log_debug("sess_recv_packet: accept error: %s",
- strerror(errno));
+ /*
+ * Pause accept if we are out of file descriptors, or
+ * libevent will haunt us here too.
+ */
+ if (errno == ENFILE || errno == EMFILE) {
+ accept_pause();
+ } else if (errno != EWOULDBLOCK && errno != EINTR)
+ log_debug("sess_recv_packet: accept error: %s",
+ strerror(errno));
return;
}
@@ -454,6 +461,7 @@ session_close(struct nbr *nbr)
evtimer_del(&nbr->keepalive_timeout);
close(nbr->fd);
+ accept_unpause();
}
ssize_t