7d3933910a4dfbaff15c780e83d9c61a78c601ae
[cascardo/ovs.git] / tests / test-reconnect.c
1 /*
2  * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #undef NDEBUG
19 #include "reconnect.h"
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "command-line.h"
25 #include "compiler.h"
26 #include "ovstest.h"
27 #include "svec.h"
28 #include "util.h"
29 #include "openvswitch/vlog.h"
30
31 static struct reconnect *reconnect;
32 static int now;
33
34 static void diff_stats(const struct reconnect_stats *old,
35                        const struct reconnect_stats *new,
36                        int delta);
37 static const struct command *get_all_commands(void);
38
39 static void
40 test_reconnect_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
41 {
42     extern struct vlog_module VLM_reconnect;
43     struct reconnect_stats prev;
44     unsigned int old_max_tries;
45     int old_time;
46     char line[128];
47
48     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_OFF);
49
50     now = 1000;
51     reconnect = reconnect_create(now);
52     reconnect_set_name(reconnect, "remote");
53     reconnect_get_stats(reconnect, now, &prev);
54     printf("### t=%d ###\n", now);
55     old_time = now;
56     old_max_tries = reconnect_get_max_tries(reconnect);
57     while (fgets(line, sizeof line, stdin)) {
58         struct reconnect_stats cur;
59         struct svec args;
60
61         fputs(line, stdout);
62         if (line[0] == '#') {
63             continue;
64         }
65
66         svec_init(&args);
67         svec_parse_words(&args, line);
68         svec_terminate(&args);
69         if (!svec_is_empty(&args)) {
70             run_command(args.n, args.names, get_all_commands());
71         }
72         svec_destroy(&args);
73
74         if (old_time != now) {
75             printf("\n### t=%d ###\n", now);
76         }
77
78         reconnect_get_stats(reconnect, now, &cur);
79         diff_stats(&prev, &cur, now - old_time);
80         prev = cur;
81         if (reconnect_get_max_tries(reconnect) != old_max_tries) {
82             old_max_tries = reconnect_get_max_tries(reconnect);
83             printf("  %u tries left\n", old_max_tries);
84         }
85
86         old_time = now;
87     }
88 }
89
90 static void
91 do_enable(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
92 {
93     reconnect_enable(reconnect, now);
94 }
95
96 static void
97 do_disable(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
98 {
99     reconnect_disable(reconnect, now);
100 }
101
102 static void
103 do_force_reconnect(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
104 {
105     reconnect_force_reconnect(reconnect, now);
106 }
107
108 static int
109 error_from_string(const char *s)
110 {
111     if (!s) {
112         return 0;
113     } else if (!strcmp(s, "ECONNREFUSED")) {
114         return ECONNREFUSED;
115     } else if (!strcmp(s, "EOF")) {
116         return EOF;
117     } else {
118         ovs_fatal(0, "unknown error '%s'", s);
119     }
120 }
121
122 static void
123 do_disconnected(int argc OVS_UNUSED, char *argv[])
124 {
125     reconnect_disconnected(reconnect, now, error_from_string(argv[1]));
126 }
127
128 static void
129 do_connecting(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
130 {
131     reconnect_connecting(reconnect, now);
132 }
133
134 static void
135 do_connect_failed(int argc OVS_UNUSED, char *argv[])
136 {
137     reconnect_connect_failed(reconnect, now, error_from_string(argv[1]));
138 }
139
140 static void
141 do_connected(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
142 {
143     reconnect_connected(reconnect, now);
144 }
145
146 static void
147 do_activity(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
148 {
149     reconnect_activity(reconnect, now);
150 }
151
152 static void
153 do_run(int argc, char *argv[])
154 {
155     enum reconnect_action action;
156
157     if (argc > 1) {
158         now += atoi(argv[1]);
159     }
160
161     action = reconnect_run(reconnect, now);
162     switch (action) {
163     default:
164         if (action != 0) {
165             OVS_NOT_REACHED();
166         }
167         break;
168
169     case RECONNECT_CONNECT:
170         printf("  should connect\n");
171         break;
172
173     case RECONNECT_DISCONNECT:
174         printf("  should disconnect\n");
175         break;
176
177     case RECONNECT_PROBE:
178         printf("  should send probe\n");
179         break;
180     }
181 }
182
183 static void
184 do_advance(int argc OVS_UNUSED, char *argv[])
185 {
186     now += atoi(argv[1]);
187 }
188
189 static void
190 do_timeout(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
191 {
192     int timeout = reconnect_timeout(reconnect, now);
193     if (timeout >= 0) {
194         printf("  advance %d ms\n", timeout);
195         now += timeout;
196     } else {
197         printf("  no timeout\n");
198     }
199 }
200
201 static void
202 do_set_max_tries(int argc OVS_UNUSED, char *argv[])
203 {
204     reconnect_set_max_tries(reconnect, atoi(argv[1]));
205 }
206
207 static void
208 diff_stats(const struct reconnect_stats *old,
209            const struct reconnect_stats *new,
210            int delta)
211 {
212     if (old->state != new->state
213         || old->state_elapsed != new->state_elapsed
214         || old->backoff != new->backoff) {
215         printf("  in %s for %u ms (%d ms backoff)\n",
216                new->state, new->state_elapsed, new->backoff);
217     }
218     if (old->creation_time != new->creation_time
219         || old->last_activity != new->last_activity
220         || old->last_connected != new->last_connected) {
221         printf("  created %lld, last activity %lld, last connected %lld\n",
222                new->creation_time, new->last_activity, new->last_connected);
223     }
224     if (old->n_successful_connections != new->n_successful_connections
225         || old->n_attempted_connections != new->n_attempted_connections
226         || old->seqno != new->seqno) {
227         printf("  %u successful connections out of %u attempts, seqno %u\n",
228                new->n_successful_connections, new->n_attempted_connections,
229                new->seqno);
230     }
231     if (old->is_connected != new->is_connected) {
232         printf("  %sconnected\n", new->is_connected ? "" : "dis");
233     }
234     if (old->last_connected != new->last_connected
235         || (old->msec_since_connect != new->msec_since_connect - delta
236             && !(old->msec_since_connect == UINT_MAX
237                  && new->msec_since_connect == UINT_MAX))
238         || (old->total_connected_duration != new->total_connected_duration - delta
239             && !(old->total_connected_duration == 0
240                  && new->total_connected_duration == 0))) {
241         printf("  last connected %u ms ago, connected %u ms total\n",
242                new->msec_since_connect, new->total_connected_duration);
243     }
244     if (old->last_disconnected != new->last_disconnected
245         || (old->msec_since_disconnect != new->msec_since_disconnect - delta
246             && !(old->msec_since_disconnect == UINT_MAX
247                  && new->msec_since_disconnect == UINT_MAX))) {
248         printf("  disconnected at %llu ms (%u ms ago)\n",
249                new->last_disconnected, new->msec_since_disconnect);
250     }
251 }
252
253 static void
254 do_set_passive(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
255 {
256     reconnect_set_passive(reconnect, true, now);
257 }
258
259 static void
260 do_listening(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
261 {
262     reconnect_listening(reconnect, now);
263 }
264
265 static void
266 do_listen_error(int argc OVS_UNUSED, char *argv[])
267 {
268     reconnect_listen_error(reconnect, now, atoi(argv[1]));
269 }
270
271 static const struct command all_commands[] = {
272     { "enable", NULL, 0, 0, do_enable },
273     { "disable", NULL, 0, 0, do_disable },
274     { "force-reconnect", NULL, 0, 0, do_force_reconnect },
275     { "disconnected", NULL, 0, 1, do_disconnected },
276     { "connecting", NULL, 0, 0, do_connecting },
277     { "connect-failed", NULL, 0, 1, do_connect_failed },
278     { "connected", NULL, 0, 0, do_connected },
279     { "activity", NULL, 0, 0, do_activity },
280     { "run", NULL, 0, 1, do_run },
281     { "advance", NULL, 1, 1, do_advance },
282     { "timeout", NULL, 0, 0, do_timeout },
283     { "set-max-tries", NULL, 1, 1, do_set_max_tries },
284     { "passive", NULL, 0, 0, do_set_passive },
285     { "listening", NULL, 0, 0, do_listening },
286     { "listen-error", NULL, 1, 1, do_listen_error },
287     { NULL, NULL, 0, 0, NULL },
288 };
289
290 static const struct command *
291 get_all_commands(void)
292 {
293     return all_commands;
294 }
295
296 OVSTEST_REGISTER("test-reconnect", test_reconnect_main);