]>
Commit | Line | Data |
---|---|---|
3ed497fc | 1 | /* |
922fed06 | 2 | * Copyright (c) 2009, 2010, 2011, 2012, 2014, 2016 Nicira, Inc. |
3ed497fc BP |
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> | |
3f636c7e | 18 | #undef NDEBUG |
3ed497fc | 19 | #include "reconnect.h" |
3ed497fc BP |
20 | #include <errno.h> |
21 | #include <stdio.h> | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
3ed497fc BP |
24 | #include "command-line.h" |
25 | #include "compiler.h" | |
3f636c7e | 26 | #include "ovstest.h" |
3ed497fc BP |
27 | #include "svec.h" |
28 | #include "util.h" | |
e6211adc | 29 | #include "openvswitch/vlog.h" |
3ed497fc BP |
30 | |
31 | static struct reconnect *reconnect; | |
32 | static int now; | |
33 | ||
3ed497fc | 34 | static void diff_stats(const struct reconnect_stats *old, |
5eda645e AE |
35 | const struct reconnect_stats *new, |
36 | int delta); | |
5f383751 | 37 | static const struct ovs_cmdl_command *get_all_commands(void); |
3ed497fc | 38 | |
eadd1644 AZ |
39 | static void |
40 | test_reconnect_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) | |
3ed497fc BP |
41 | { |
42 | struct reconnect_stats prev; | |
a85c0bbc | 43 | unsigned int old_max_tries; |
3ed497fc BP |
44 | int old_time; |
45 | char line[128]; | |
46 | ||
45863ce5 | 47 | vlog_set_levels_from_string_assert("reconnect:off"); |
1e8cf0f7 | 48 | |
3ed497fc BP |
49 | now = 1000; |
50 | reconnect = reconnect_create(now); | |
51 | reconnect_set_name(reconnect, "remote"); | |
52 | reconnect_get_stats(reconnect, now, &prev); | |
53 | printf("### t=%d ###\n", now); | |
54 | old_time = now; | |
a85c0bbc | 55 | old_max_tries = reconnect_get_max_tries(reconnect); |
3ed497fc BP |
56 | while (fgets(line, sizeof line, stdin)) { |
57 | struct reconnect_stats cur; | |
58 | struct svec args; | |
59 | ||
60 | fputs(line, stdout); | |
61 | if (line[0] == '#') { | |
62 | continue; | |
63 | } | |
64 | ||
65 | svec_init(&args); | |
66 | svec_parse_words(&args, line); | |
67 | svec_terminate(&args); | |
68 | if (!svec_is_empty(&args)) { | |
1636c761 RB |
69 | struct ovs_cmdl_context ctx = { |
70 | .argc = args.n, | |
71 | .argv = args.names, | |
72 | }; | |
73 | ovs_cmdl_run_command(&ctx, get_all_commands()); | |
3ed497fc BP |
74 | } |
75 | svec_destroy(&args); | |
76 | ||
77 | if (old_time != now) { | |
78 | printf("\n### t=%d ###\n", now); | |
3ed497fc BP |
79 | } |
80 | ||
81 | reconnect_get_stats(reconnect, now, &cur); | |
5eda645e | 82 | diff_stats(&prev, &cur, now - old_time); |
3ed497fc | 83 | prev = cur; |
a85c0bbc BP |
84 | if (reconnect_get_max_tries(reconnect) != old_max_tries) { |
85 | old_max_tries = reconnect_get_max_tries(reconnect); | |
86 | printf(" %u tries left\n", old_max_tries); | |
87 | } | |
5eda645e AE |
88 | |
89 | old_time = now; | |
3ed497fc | 90 | } |
3ed497fc BP |
91 | } |
92 | ||
93 | static void | |
1636c761 | 94 | do_enable(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
95 | { |
96 | reconnect_enable(reconnect, now); | |
97 | } | |
98 | ||
99 | static void | |
1636c761 | 100 | do_disable(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
101 | { |
102 | reconnect_disable(reconnect, now); | |
103 | } | |
104 | ||
105 | static void | |
1636c761 | 106 | do_force_reconnect(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
107 | { |
108 | reconnect_force_reconnect(reconnect, now); | |
109 | } | |
110 | ||
111 | static int | |
112 | error_from_string(const char *s) | |
113 | { | |
114 | if (!s) { | |
115 | return 0; | |
116 | } else if (!strcmp(s, "ECONNREFUSED")) { | |
117 | return ECONNREFUSED; | |
118 | } else if (!strcmp(s, "EOF")) { | |
119 | return EOF; | |
120 | } else { | |
121 | ovs_fatal(0, "unknown error '%s'", s); | |
122 | } | |
123 | } | |
124 | ||
125 | static void | |
1636c761 | 126 | do_disconnected(struct ovs_cmdl_context *ctx) |
3ed497fc | 127 | { |
1636c761 | 128 | reconnect_disconnected(reconnect, now, error_from_string(ctx->argv[1])); |
3ed497fc BP |
129 | } |
130 | ||
131 | static void | |
1636c761 | 132 | do_connecting(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
133 | { |
134 | reconnect_connecting(reconnect, now); | |
135 | } | |
136 | ||
137 | static void | |
1636c761 | 138 | do_connect_failed(struct ovs_cmdl_context *ctx) |
3ed497fc | 139 | { |
1636c761 | 140 | reconnect_connect_failed(reconnect, now, error_from_string(ctx->argv[1])); |
3ed497fc BP |
141 | } |
142 | ||
143 | static void | |
1636c761 | 144 | do_connected(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
145 | { |
146 | reconnect_connected(reconnect, now); | |
147 | } | |
148 | ||
149 | static void | |
1636c761 | 150 | do_activity(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc | 151 | { |
a6f639f8 | 152 | reconnect_activity(reconnect, now); |
3ed497fc BP |
153 | } |
154 | ||
155 | static void | |
1636c761 | 156 | do_run(struct ovs_cmdl_context *ctx) |
3ed497fc BP |
157 | { |
158 | enum reconnect_action action; | |
159 | ||
1636c761 RB |
160 | if (ctx->argc > 1) { |
161 | now += atoi(ctx->argv[1]); | |
3ed497fc BP |
162 | } |
163 | ||
164 | action = reconnect_run(reconnect, now); | |
165 | switch (action) { | |
166 | default: | |
167 | if (action != 0) { | |
428b2edd | 168 | OVS_NOT_REACHED(); |
3ed497fc BP |
169 | } |
170 | break; | |
171 | ||
172 | case RECONNECT_CONNECT: | |
173 | printf(" should connect\n"); | |
174 | break; | |
175 | ||
176 | case RECONNECT_DISCONNECT: | |
177 | printf(" should disconnect\n"); | |
178 | break; | |
179 | ||
180 | case RECONNECT_PROBE: | |
181 | printf(" should send probe\n"); | |
182 | break; | |
183 | } | |
184 | } | |
185 | ||
186 | static void | |
1636c761 | 187 | do_advance(struct ovs_cmdl_context *ctx) |
3ed497fc | 188 | { |
1636c761 | 189 | now += atoi(ctx->argv[1]); |
3ed497fc BP |
190 | } |
191 | ||
192 | static void | |
1636c761 | 193 | do_timeout(struct ovs_cmdl_context *ctx OVS_UNUSED) |
3ed497fc BP |
194 | { |
195 | int timeout = reconnect_timeout(reconnect, now); | |
196 | if (timeout >= 0) { | |
197 | printf(" advance %d ms\n", timeout); | |
198 | now += timeout; | |
199 | } else { | |
200 | printf(" no timeout\n"); | |
201 | } | |
202 | } | |
203 | ||
a85c0bbc | 204 | static void |
1636c761 | 205 | do_set_max_tries(struct ovs_cmdl_context *ctx) |
a85c0bbc | 206 | { |
1636c761 | 207 | reconnect_set_max_tries(reconnect, atoi(ctx->argv[1])); |
a85c0bbc BP |
208 | } |
209 | ||
3ed497fc BP |
210 | static void |
211 | diff_stats(const struct reconnect_stats *old, | |
5eda645e AE |
212 | const struct reconnect_stats *new, |
213 | int delta) | |
3ed497fc BP |
214 | { |
215 | if (old->state != new->state | |
216 | || old->state_elapsed != new->state_elapsed | |
217 | || old->backoff != new->backoff) { | |
218 | printf(" in %s for %u ms (%d ms backoff)\n", | |
219 | new->state, new->state_elapsed, new->backoff); | |
220 | } | |
221 | if (old->creation_time != new->creation_time | |
a6f639f8 | 222 | || old->last_activity != new->last_activity |
3ed497fc | 223 | || old->last_connected != new->last_connected) { |
a6f639f8 BP |
224 | printf(" created %lld, last activity %lld, last connected %lld\n", |
225 | new->creation_time, new->last_activity, new->last_connected); | |
3ed497fc BP |
226 | } |
227 | if (old->n_successful_connections != new->n_successful_connections | |
228 | || old->n_attempted_connections != new->n_attempted_connections | |
229 | || old->seqno != new->seqno) { | |
230 | printf(" %u successful connections out of %u attempts, seqno %u\n", | |
231 | new->n_successful_connections, new->n_attempted_connections, | |
232 | new->seqno); | |
233 | } | |
5eda645e AE |
234 | if (old->is_connected != new->is_connected) { |
235 | printf(" %sconnected\n", new->is_connected ? "" : "dis"); | |
3ed497fc | 236 | } |
5eda645e AE |
237 | if (old->last_connected != new->last_connected |
238 | || (old->msec_since_connect != new->msec_since_connect - delta | |
239 | && !(old->msec_since_connect == UINT_MAX | |
240 | && new->msec_since_connect == UINT_MAX)) | |
241 | || (old->total_connected_duration != new->total_connected_duration - delta | |
242 | && !(old->total_connected_duration == 0 | |
243 | && new->total_connected_duration == 0))) { | |
244 | printf(" last connected %u ms ago, connected %u ms total\n", | |
245 | new->msec_since_connect, new->total_connected_duration); | |
eba18f00 | 246 | } |
5eda645e AE |
247 | if (old->last_disconnected != new->last_disconnected |
248 | || (old->msec_since_disconnect != new->msec_since_disconnect - delta | |
249 | && !(old->msec_since_disconnect == UINT_MAX | |
250 | && new->msec_since_disconnect == UINT_MAX))) { | |
251 | printf(" disconnected at %llu ms (%u ms ago)\n", | |
252 | new->last_disconnected, new->msec_since_disconnect); | |
eba18f00 | 253 | } |
3ed497fc BP |
254 | } |
255 | ||
19df7f51 | 256 | static void |
1636c761 | 257 | do_set_passive(struct ovs_cmdl_context *ctx OVS_UNUSED) |
19df7f51 BP |
258 | { |
259 | reconnect_set_passive(reconnect, true, now); | |
260 | } | |
261 | ||
262 | static void | |
1636c761 | 263 | do_listening(struct ovs_cmdl_context *ctx OVS_UNUSED) |
19df7f51 BP |
264 | { |
265 | reconnect_listening(reconnect, now); | |
266 | } | |
267 | ||
268 | static void | |
1636c761 | 269 | do_listen_error(struct ovs_cmdl_context *ctx) |
19df7f51 | 270 | { |
1636c761 | 271 | reconnect_listen_error(reconnect, now, atoi(ctx->argv[1])); |
19df7f51 BP |
272 | } |
273 | ||
5f383751 | 274 | static const struct ovs_cmdl_command all_commands[] = { |
1f4a7252 RM |
275 | { "enable", NULL, 0, 0, do_enable, OVS_RO }, |
276 | { "disable", NULL, 0, 0, do_disable, OVS_RO }, | |
277 | { "force-reconnect", NULL, 0, 0, do_force_reconnect, OVS_RO }, | |
278 | { "disconnected", NULL, 0, 1, do_disconnected, OVS_RO }, | |
279 | { "connecting", NULL, 0, 0, do_connecting, OVS_RO }, | |
280 | { "connect-failed", NULL, 0, 1, do_connect_failed, OVS_RO }, | |
281 | { "connected", NULL, 0, 0, do_connected, OVS_RO }, | |
282 | { "activity", NULL, 0, 0, do_activity, OVS_RO }, | |
283 | { "run", NULL, 0, 1, do_run, OVS_RO }, | |
284 | { "advance", NULL, 1, 1, do_advance, OVS_RO }, | |
285 | { "timeout", NULL, 0, 0, do_timeout, OVS_RO }, | |
286 | { "set-max-tries", NULL, 1, 1, do_set_max_tries, OVS_RO }, | |
287 | { "passive", NULL, 0, 0, do_set_passive, OVS_RO }, | |
288 | { "listening", NULL, 0, 0, do_listening, OVS_RO }, | |
289 | { "listen-error", NULL, 1, 1, do_listen_error, OVS_RO }, | |
290 | { NULL, NULL, 0, 0, NULL, OVS_RO }, | |
3ed497fc | 291 | }; |
eadd1644 | 292 | |
5f383751 | 293 | static const struct ovs_cmdl_command * |
d2586fce GS |
294 | get_all_commands(void) |
295 | { | |
296 | return all_commands; | |
297 | } | |
298 | ||
eadd1644 | 299 | OVSTEST_REGISTER("test-reconnect", test_reconnect_main); |