/*
- * Copyright (c) 2008, 2009, 2010, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "reconnect.h"
-#include <assert.h>
#include <stdlib.h>
-#include "poll-loop.h"
-#include "vlog.h"
+#include "openvswitch/poll-loop.h"
+#include "util.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(reconnect);
long long int last_connected;
long long int last_disconnected;
unsigned int max_tries;
+ unsigned int backoff_free_tries;
/* These values are simply for statistics reporting, not otherwise used
* directly by anything internal. */
return fsm->max_tries;
}
+/* Sets the number of connection attempts that will be made without backoff to
+ * 'backoff_free_tries'. Values 0 and 1 both represent a single attempt. */
+void
+reconnect_set_backoff_free_tries(struct reconnect *fsm,
+ unsigned int backoff_free_tries)
+{
+ fsm->backoff_free_tries = backoff_free_tries;
+}
+
/* Configures the backoff parameters for 'fsm'. 'min_backoff' is the minimum
* number of milliseconds, and 'max_backoff' is the maximum, between connection
- * attempts.
+ * attempts. The current backoff is also the duration that 'fsm' is willing to
+ * wait for a given connection to succeed or fail.
*
* 'min_backoff' must be at least 1000, and 'max_backoff' must be greater than
* or equal to 'min_backoff'.
if (fsm->state & (S_ACTIVE | S_IDLE)) {
if (error > 0) {
VLOG_WARN("%s: connection dropped (%s)",
- fsm->name, strerror(error));
+ fsm->name, ovs_strerror(error));
} else if (error == EOF) {
VLOG(fsm->info, "%s: connection closed by peer", fsm->name);
} else {
} else if (fsm->state == S_LISTENING) {
if (error > 0) {
VLOG_WARN("%s: error listening for connections (%s)",
- fsm->name, strerror(error));
+ fsm->name, ovs_strerror(error));
} else {
VLOG(fsm->info, "%s: error listening for connections",
fsm->name);
}
- } else {
+ } else if (fsm->backoff < fsm->max_backoff) {
const char *type = fsm->passive ? "listen" : "connection";
if (error > 0) {
- VLOG_WARN("%s: %s attempt failed (%s)",
- fsm->name, type, strerror(error));
+ VLOG_INFO("%s: %s attempt failed (%s)",
+ fsm->name, type, ovs_strerror(error));
} else {
VLOG(fsm->info, "%s: %s attempt timed out", fsm->name, type);
}
+ } else {
+ /* We have reached the maximum backoff, so suppress logging to
+ * avoid wastefully filling the log. (Previously we logged that we
+ * were suppressing further logging, see below.) */
}
if (fsm->state & (S_ACTIVE | S_IDLE)) {
fsm->last_disconnected = now;
}
+
+ if (!reconnect_may_retry(fsm)) {
+ reconnect_transition__(fsm, now, S_VOID);
+ return;
+ }
+
/* Back off. */
- if (fsm->state & (S_ACTIVE | S_IDLE)
- && (fsm->last_activity - fsm->last_connected >= fsm->backoff
- || fsm->passive)) {
+ if (fsm->backoff_free_tries > 1) {
+ fsm->backoff_free_tries--;
+ fsm->backoff = 0;
+ } else if (fsm->state & (S_ACTIVE | S_IDLE)
+ && (fsm->last_activity - fsm->last_connected >= fsm->backoff
+ || fsm->passive)) {
fsm->backoff = fsm->passive ? 0 : fsm->min_backoff;
} else {
if (fsm->backoff < fsm->min_backoff) {
fsm->backoff = fsm->min_backoff;
- } else if (fsm->backoff >= fsm->max_backoff / 2) {
- fsm->backoff = fsm->max_backoff;
- } else {
+ } else if (fsm->backoff < fsm->max_backoff / 2) {
fsm->backoff *= 2;
- }
- if (fsm->passive) {
- VLOG(fsm->info, "%s: waiting %.3g seconds before trying to "
- "listen again", fsm->name, fsm->backoff / 1000.0);
+ VLOG(fsm->info, "%s: waiting %.3g seconds before %s",
+ fsm->name, fsm->backoff / 1000.0,
+ fsm->passive ? "trying to listen again" : "reconnect");
} else {
- VLOG(fsm->info, "%s: waiting %.3g seconds before reconnect",
- fsm->name, fsm->backoff / 1000.0);
+ if (fsm->backoff < fsm->max_backoff) {
+ VLOG_INFO("%s: continuing to %s in the background but "
+ "suppressing further logging", fsm->name,
+ fsm->passive ? "try to listen" : "reconnect");
+ }
+ fsm->backoff = fsm->max_backoff;
}
}
-
- reconnect_transition__(fsm, now,
- reconnect_may_retry(fsm) ? S_BACKOFF : S_VOID);
+ reconnect_transition__(fsm, now, S_BACKOFF);
}
}
if (fsm->state != S_CONNECTING) {
if (fsm->passive) {
VLOG(fsm->info, "%s: listening...", fsm->name);
- } else {
+ } else if (fsm->backoff < fsm->max_backoff) {
VLOG(fsm->info, "%s: connecting...", fsm->name);
}
reconnect_transition__(fsm, now, S_CONNECTING);
void
reconnect_activity(struct reconnect *fsm, long long int now)
{
- if (fsm->state != S_ACTIVE) {
+ if (fsm->state == S_IDLE) {
reconnect_transition__(fsm, now, S_ACTIVE);
}
fsm->last_activity = now;
static long long int
reconnect_deadline__(const struct reconnect *fsm)
{
- assert(fsm->state_entered != LLONG_MIN);
+ ovs_assert(fsm->state_entered != LLONG_MIN);
switch (fsm->state) {
case S_VOID:
case S_LISTENING:
return fsm->state_entered;
}
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
/* Assesses whether any action should be taken on 'fsm'. The return value is
return 0;
}
- NOT_REACHED();
+ OVS_NOT_REACHED();
} else {
return 0;
}