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