[ovs-dev] [PATCH 2/4] reconnect: Add connection attempt limiting feature.
Ben Pfaff
blp at nicira.com
Fri Dec 18 21:47:49 UTC 2009
Sometimes it is useful to limit the number of connection attempts, either
from policy or because it is not possible to reconnect at all (e.g. because
a connection was accepted from a listening socket instead of made with
connect()). This commit adds that feature.
---
lib/reconnect.c | 41 +++++++++++++++++++++++--
lib/reconnect.h | 3 ++
tests/reconnect.at | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/test-reconnect.c | 13 ++++++++
4 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/lib/reconnect.c b/lib/reconnect.c
index fadeeb8..2ae65c6 100644
--- a/lib/reconnect.c
+++ b/lib/reconnect.c
@@ -57,6 +57,7 @@ struct reconnect {
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. */
@@ -69,6 +70,7 @@ struct reconnect {
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)
@@ -99,6 +101,7 @@ reconnect_create(long long int now)
fsm->backoff = 0;
fsm->last_received = now;
fsm->last_connected = now;
+ fsm->max_tries = UINT_MAX;
fsm->creation_time = now;
return fsm;
@@ -160,6 +163,26 @@ reconnect_get_probe_interval(const struct reconnect *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.
@@ -213,7 +236,7 @@ reconnect_is_enabled(const struct reconnect *fsm)
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;
}
@@ -250,7 +273,7 @@ reconnect_force_reconnect(struct reconnect *fsm, long long int now)
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) {
@@ -285,7 +308,9 @@ reconnect_disconnected(struct reconnect *fsm, long long int now, int error)
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);
}
}
@@ -521,3 +546,13 @@ reconnect_get_stats(const struct reconnect *fsm, long long int now,
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;
+}
diff --git a/lib/reconnect.h b/lib/reconnect.h
index 3442c07..76c7f78 100644
--- a/lib/reconnect.h
+++ b/lib/reconnect.h
@@ -42,6 +42,9 @@ int reconnect_get_min_backoff(const struct reconnect *);
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);
diff --git a/tests/reconnect.at b/tests/reconnect.at
index 33e4b95..225da0d 100644
--- a/tests/reconnect.at
+++ b/tests/reconnect.at
@@ -1037,3 +1037,83 @@ timeout
])
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
diff --git a/tests/test-reconnect.c b/tests/test-reconnect.c
index a8784fc..8441fad 100644
--- a/tests/test-reconnect.c
+++ b/tests/test-reconnect.c
@@ -40,6 +40,7 @@ int
main(void)
{
struct reconnect_stats prev;
+ unsigned int old_max_tries;
int old_time;
char line[128];
@@ -49,6 +50,7 @@ main(void)
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;
@@ -74,6 +76,10 @@ main(void)
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;
@@ -191,6 +197,12 @@ do_timeout(int argc UNUSED, char *argv[] UNUSED)
}
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)
{
@@ -235,6 +247,7 @@ static const struct command commands[] = {
{ "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 },
};
--
1.6.3.3
More information about the dev
mailing list