diff options
author | 2013-05-31 14:10:10 +0000 | |
---|---|---|
committer | 2013-05-31 14:10:10 +0000 | |
commit | 1f7e7d7716c8800c1a435c679fc7cea21688ec6b (patch) | |
tree | d7a1a0e16ddce947e151364a1d1c775505a8e1a7 | |
parent | Use %lld for printing time_t (diff) | |
download | wireguard-openbsd-1f7e7d7716c8800c1a435c679fc7cea21688ec6b.tar.xz wireguard-openbsd-1f7e7d7716c8800c1a435c679fc7cea21688ec6b.zip |
When the ldpe process calls connect(), it doesn't regain control until
either the connection is made or an error occurs. The time the process
is blocked can be significantly large to the point of other LDP sessions
being torn down because of their holdtime. Besides that, the ldpctl
program gets unresponsive if the ldpe process is blocked. Fix these
issues by using a non-blocking connect.
Diff from Renato Westphal [renatowestphal at gmail.com]
-rw-r--r-- | usr.sbin/ldpd/hello.c | 7 | ||||
-rw-r--r-- | usr.sbin/ldpd/ldpe.h | 5 | ||||
-rw-r--r-- | usr.sbin/ldpd/neighbor.c | 58 |
3 files changed, 57 insertions, 13 deletions
diff --git a/usr.sbin/ldpd/hello.c b/usr.sbin/ldpd/hello.c index 3bf9be54bd1..137b6e4f9eb 100644 --- a/usr.sbin/ldpd/hello.c +++ b/usr.sbin/ldpd/hello.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hello.c,v 1.13 2013/05/30 16:14:50 claudio Exp $ */ +/* $OpenBSD: hello.c,v 1.14 2013/05/31 14:10:10 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -149,8 +149,9 @@ recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len) nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); if (ntohl(nbr->addr.s_addr) < ntohl(nbr->iface->addr.s_addr) && - nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr)) - nbr_act_session_establish(nbr, 1); + nbr->state == NBR_STA_PRESENT && !nbr_pending_connect(nbr) && + !nbr_pending_idtimer(nbr)) + nbr_establish_connection(nbr); } int diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 1a6f2674a64..5051d5c30c7 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.16 2012/04/12 17:33:43 claudio Exp $ */ +/* $OpenBSD: ldpe.h,v 1.17 2013/05/31 14:10:10 claudio Exp $ */ /* * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> @@ -38,6 +38,7 @@ struct nbr { RB_ENTRY(nbr) id_tree, addr_tree, pid_tree; struct evbuf wbuf; struct event rev; + struct event ev_connect; struct event inactivity_timer; struct event keepalive_timer; struct event keepalive_timeout; @@ -172,7 +173,9 @@ void nbr_idtimer(int, short, void *); void nbr_start_idtimer(struct nbr *); void nbr_stop_idtimer(struct nbr *); int nbr_pending_idtimer(struct nbr *); +int nbr_pending_connect(struct nbr *); +int nbr_establish_connection(struct nbr *); int nbr_act_session_establish(struct nbr *, int); void nbr_mapping_add(struct nbr *, struct mapping_head *, diff --git a/usr.sbin/ldpd/neighbor.c b/usr.sbin/ldpd/neighbor.c index f25e0f22354..04a700852d5 100644 --- a/usr.sbin/ldpd/neighbor.c +++ b/usr.sbin/ldpd/neighbor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: neighbor.c,v 1.25 2013/05/30 16:14:50 claudio Exp $ */ +/* $OpenBSD: neighbor.c,v 1.26 2013/05/31 14:10:10 claudio Exp $ */ /* * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> @@ -28,6 +28,7 @@ #include <ctype.h> #include <err.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,7 +42,6 @@ #include "log.h" #include "lde.h" -int nbr_establish_connection(struct nbr *); void nbr_send_labelmappings(struct nbr *); int nbr_act_session_operational(struct nbr *); @@ -287,6 +287,8 @@ nbr_del(struct nbr *nbr) { session_close(nbr); + if (event_pending(&nbr->ev_connect, EV_WRITE, NULL)) + event_del(&nbr->ev_connect); if (evtimer_pending(&nbr->inactivity_timer, NULL)) evtimer_del(&nbr->inactivity_timer); if (evtimer_pending(&nbr->keepalive_timer, NULL)) @@ -449,7 +451,7 @@ nbr_idtimer(int fd, short event, void *arg) log_debug("nbr_idtimer: neighbor ID %s peerid %lu", inet_ntoa(nbr->id), nbr->peerid); - nbr_act_session_establish(nbr, 1); + nbr_establish_connection(nbr); } void @@ -481,6 +483,40 @@ nbr_pending_idtimer(struct nbr *nbr) } int +nbr_pending_connect(struct nbr *nbr) +{ + if (event_initialized(&nbr->ev_connect) && + event_pending(&nbr->ev_connect, EV_WRITE, NULL)) + return (1); + + return (0); +} + +static void +nbr_connect_cb(int fd, short event, void *arg) +{ + struct nbr *nbr = arg; + int error; + socklen_t len; + + len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + log_warn("nbr_connect_cb getsockopt SOL_SOCKET SO_ERROR"); + return; + } + + if (error) { + close(nbr->fd); + errno = error; + log_debug("nbr_connect_cb: error while " + "connecting to %s", inet_ntoa(nbr->addr)); + return; + } + + nbr_act_session_establish(nbr, 1); +} + +int nbr_establish_connection(struct nbr *nbr) { struct sockaddr_in in; @@ -497,7 +533,15 @@ nbr_establish_connection(struct nbr *nbr) return (-1); } + session_socket_blockmode(nbr->fd, BM_NONBLOCK); + if (connect(nbr->fd, (struct sockaddr *)&in, sizeof(in)) == -1) { + if (errno == EINPROGRESS) { + event_set(&nbr->ev_connect, nbr->fd, EV_WRITE, + nbr_connect_cb, nbr); + event_add(&nbr->ev_connect, NULL); + return (0); + } log_debug("nbr_establish_connection: error while " "connecting to %s", inet_ntoa(nbr->addr)); nbr_start_idtimer(nbr); @@ -505,17 +549,13 @@ nbr_establish_connection(struct nbr *nbr) return (-1); } - return (0); + /* connection completed immediately */ + return (nbr_act_session_establish(nbr, 1)); } int nbr_act_session_establish(struct nbr *nbr, int active) { - if (active) { - if (nbr_establish_connection(nbr) < 0) - return (-1); - } - evbuf_init(&nbr->wbuf, nbr->fd, session_write, nbr); event_set(&nbr->rev, nbr->fd, EV_READ | EV_PERSIST, session_read, nbr); event_add(&nbr->rev, NULL); |