diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2012-04-12 17:33:44 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2012-04-12 17:33:44 +0000 |
commit | a9c25bce4eb2242564115652664a51ad553f790d (patch) | |
tree | c5ce584648e315a723054716c5094ac335be73d6 /usr.sbin | |
parent | ab8c7358124cfd2734adf977bef218d3288e91ca (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/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/ldpd/accept.c | 137 | ||||
-rw-r--r-- | usr.sbin/ldpd/control.c | 26 | ||||
-rw-r--r-- | usr.sbin/ldpd/control.h | 7 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.c | 8 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 9 | ||||
-rw-r--r-- | usr.sbin/ldpd/packet.c | 16 |
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 |