{
struct bgp_conn *conn = t->data;
- DBG("BGP: Hold timeout, closing connection\n");
- bgp_error(conn, 4, 0, NULL, 0);
+ DBG("BGP: Hold timeout\n");
+
+ /* If there is something in input queue, we are probably congested
+ and perhaps just not processed BGP packets in time. */
+
+ if (sk_rx_ready(conn->sk) > 0)
+ bgp_start_timer(conn->hold_timer, 10);
+ else
+ bgp_error(conn, 4, 0, NULL, 0);
}
static void
#include "lib/unix.h"
#include "lib/sysio.h"
-/* Maximum number of calls of rx/tx handler for one socket in one
+/* Maximum number of calls of tx handler for one socket in one
* select iteration. Should be small enough to not monopolize CPU by
* one protocol instance.
*/
#define MAX_STEPS 4
+/* Maximum number of calls of rx handler for all sockets in one select
+ iteration. RX callbacks are often much more costly so we limit
+ this to gen small latencies */
+#define MAX_RX_STEPS 4
+
/*
* Tracked Files
*/
static list sock_list;
static struct birdsock *current_sock;
+static struct birdsock *stored_sock;
static int sock_recalc_fdsets_p;
static inline sock *
close(s->fd);
if (s == current_sock)
current_sock = sk_next(s);
+ if (s == stored_sock)
+ stored_sock = sk_next(s);
rem_node(&s->n);
sock_recalc_fdsets_p = 1;
}
}
}
+int
+sk_rx_ready(sock *s)
+{
+ fd_set rd, wr;
+ struct timeval timo;
+ int rv;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_SET(s->fd, &rd);
+
+ timo.tv_sec = 0;
+ timo.tv_usec = 0;
+
+ redo:
+ rv = select(s->fd+1, &rd, &wr, NULL, &timo);
+
+ if ((rv < 0) && (errno == EINTR || errno == EAGAIN))
+ goto redo;
+
+ return rv;
+}
+
/**
* sk_send - send data to a socket
* @s: socket
srandom((int) now_real);
}
+static int short_loops = 0;
+#define SHORT_LOOP_MAX 10
+
void
io_loop(void)
{
}
/* And finally enter select() to find active sockets */
-
hi = select(hi+1, &rd, &wr, NULL, &timo);
+
if (hi < 0)
{
if (errno == EINTR || errno == EAGAIN)
}
if (hi)
{
- current_sock = SKIP_BACK(sock, n, HEAD(sock_list)); /* guaranteed to be non-empty */
+ /* guaranteed to be non-empty */
+ current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
+
while (current_sock)
{
sock *s = current_sock;
int e;
- int steps = MAX_STEPS;
- if (FD_ISSET(s->fd, &rd) && s->rx_hook)
+ int steps;
+
+ steps = MAX_STEPS;
+ if ((s->type >= SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
do
{
steps--;
current_sock = sk_next(s);
next: ;
}
+
+ short_loops++;
+ if (events && (short_loops < SHORT_LOOP_MAX))
+ continue;
+ short_loops = 0;
+
+ int count = 0;
+ current_sock = stored_sock;
+ if (current_sock == NULL)
+ current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
+
+ while (current_sock && count < MAX_RX_STEPS)
+ {
+ sock *s = current_sock;
+ int e;
+ int steps;
+
+ if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
+ {
+ count++;
+ e = sk_read(s);
+ if (s != current_sock)
+ goto next2;
+ }
+ current_sock = sk_next(s);
+ next2: ;
+ }
+
+ stored_sock = current_sock;
}
}
}