summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2013-05-31 14:10:10 +0000
committerclaudio <claudio@openbsd.org>2013-05-31 14:10:10 +0000
commit1f7e7d7716c8800c1a435c679fc7cea21688ec6b (patch)
treed7a1a0e16ddce947e151364a1d1c775505a8e1a7
parentUse %lld for printing time_t (diff)
downloadwireguard-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.c7
-rw-r--r--usr.sbin/ldpd/ldpe.h5
-rw-r--r--usr.sbin/ldpd/neighbor.c58
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);