2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-25 15:07:05 +00:00

reconnect: Add connection attempt limiting feature.

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.
This commit is contained in:
Ben Pfaff
2009-12-17 13:46:16 -08:00
parent b8781ff08d
commit a85c0bbcfd
4 changed files with 134 additions and 3 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
@@ -190,6 +196,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 },
};