int backoff;
long long int last_received;
long long int last_connected;
+ unsigned int max_tries;
/* These values are simply for statistics reporting, not otherwise used
* directly by anything internal. */
static void reconnect_transition__(struct reconnect *, long long int now,
enum state state);
static long long int reconnect_deadline__(const struct reconnect *);
+static bool reconnect_may_retry(struct reconnect *);
static const char *
reconnect_state_name__(enum state state)
fsm->backoff = 0;
fsm->last_received = now;
fsm->last_connected = now;
+ fsm->max_tries = UINT_MAX;
fsm->creation_time = now;
return fsm;
return fsm->probe_interval;
}
+/* Limits the maximum number of times that 'fsm' will ask the client to try to
+ * reconnect to 'max_tries'. UINT_MAX (the default) means an unlimited number
+ * of tries.
+ *
+ * After the number of tries has expired, the 'fsm' will disable itself
+ * instead of backing off and retrying. */
+void
+reconnect_set_max_tries(struct reconnect *fsm, unsigned int max_tries)
+{
+ fsm->max_tries = max_tries;
+}
+
+/* Returns the current remaining number of connection attempts, UINT_MAX if
+ * the number is unlimited. */
+unsigned int
+reconnect_get_max_tries(struct reconnect *fsm)
+{
+ return fsm->max_tries;
+}
+
/* Configures the backoff parameters for 'fsm'. 'min_backoff' is the minimum
* number of milliseconds, and 'max_backoff' is the maximum, between connection
* attempts.
void
reconnect_enable(struct reconnect *fsm, long long int now)
{
- if (fsm->state == S_VOID) {
+ if (fsm->state == S_VOID && reconnect_may_retry(fsm)) {
reconnect_transition__(fsm, now, S_BACKOFF);
fsm->backoff = 0;
}
void
reconnect_disconnected(struct reconnect *fsm, long long int now, int error)
{
- if (fsm->state != S_BACKOFF) {
+ if (!(fsm->state & (S_BACKOFF | S_VOID))) {
/* Report what happened. */
if (fsm->state & (S_ACTIVE | S_IDLE)) {
if (error > 0) {
VLOG_INFO("%s: waiting %.3g seconds before reconnect\n",
fsm->name, fsm->backoff / 1000.0);
}
- reconnect_transition__(fsm, now, S_BACKOFF);
+
+ reconnect_transition__(fsm, now,
+ reconnect_may_retry(fsm) ? S_BACKOFF : S_VOID);
}
}
stats->state = reconnect_state_name__(fsm->state);
stats->state_elapsed = now - fsm->state_entered;
}
+
+static bool
+reconnect_may_retry(struct reconnect *fsm)
+{
+ bool may_retry = fsm->max_tries > 0;
+ if (may_retry && fsm->max_tries != UINT_MAX) {
+ fsm->max_tries--;
+ }
+ return may_retry;
+}
int reconnect_get_max_backoff(const struct reconnect *);
int reconnect_get_probe_interval(const struct reconnect *);
+void reconnect_set_max_tries(struct reconnect *, unsigned int max_tries);
+unsigned int reconnect_get_max_tries(struct reconnect *);
+
void reconnect_set_backoff(struct reconnect *,
int min_backoff, int max_backoff);
void reconnect_set_probe_interval(struct reconnect *, int probe_interval);
])
AT_CLEANUP
+######################################################################
+AT_SETUP([max-tries of 1 honored])
+AT_KEYWORDS([reconnect])
+AT_DATA([input], [set-max-tries 1
+enable
+
+# Connection succeeds.
+run
+connected
+
+# Send inactivity probe.
+timeout
+run
+
+# Idle timeout kills connection.
+timeout
+run
+disconnected
+])
+OVS_CHECK_LCOV([test-reconnect < input], [0],
+ [### t=1000 ###
+set-max-tries 1
+ 1 tries left
+enable
+ in BACKOFF for 0 ms (0 ms backoff)
+ 0 tries left
+
+# Connection succeeds.
+run
+ should connect
+connected
+ in ACTIVE for 0 ms (0 ms backoff)
+ 1 successful connections out of 1 attempts, seqno 1
+ connected (0 ms), total 0 ms connected
+
+# Send inactivity probe.
+timeout
+ advance 5000 ms
+
+### t=6000 ###
+ in ACTIVE for 5000 ms (0 ms backoff)
+ connected (5000 ms), total 5000 ms connected
+run
+ should send probe
+ in IDLE for 0 ms (0 ms backoff)
+
+# Idle timeout kills connection.
+timeout
+ advance 5000 ms
+
+### t=11000 ###
+ in IDLE for 5000 ms (0 ms backoff)
+ connected (10000 ms), total 10000 ms connected
+run
+ should disconnect
+disconnected
+ in VOID for 0 ms (1000 ms backoff)
+ 1 successful connections out of 1 attempts, seqno 2
+ not connected (0 ms), total 10000 ms connected
+])
+AT_CLEANUP
+
+######################################################################
+AT_SETUP([max-tries of 0 honored])
+AT_KEYWORDS([reconnect])
+AT_DATA([input], [set-max-tries 0
+enable
+run
+timeout
+])
+OVS_CHECK_LCOV([test-reconnect < input], [0],
+ [### t=1000 ###
+set-max-tries 0
+ 0 tries left
+enable
+run
+timeout
+ no timeout
+])
+AT_CLEANUP
main(void)
{
struct reconnect_stats prev;
+ unsigned int old_max_tries;
int old_time;
char line[128];
reconnect_get_stats(reconnect, now, &prev);
printf("### t=%d ###\n", now);
old_time = now;
+ old_max_tries = reconnect_get_max_tries(reconnect);
while (fgets(line, sizeof line, stdin)) {
struct reconnect_stats cur;
struct svec args;
reconnect_get_stats(reconnect, now, &cur);
diff_stats(&prev, &cur);
prev = cur;
+ if (reconnect_get_max_tries(reconnect) != old_max_tries) {
+ old_max_tries = reconnect_get_max_tries(reconnect);
+ printf(" %u tries left\n", old_max_tries);
+ }
}
return 0;
}
}
+static void
+do_set_max_tries(int argc UNUSED, char *argv[])
+{
+ reconnect_set_max_tries(reconnect, atoi(argv[1]));
+}
+
static void
diff_stats(const struct reconnect_stats *old,
const struct reconnect_stats *new)
{ "run", 0, 1, do_run },
{ "advance", 1, 1, do_advance },
{ "timeout", 0, 0, do_timeout },
+ { "set-max-tries", 1, 1, do_set_max_tries },
{ NULL, 0, 0, NULL },
};