Drop unneeded inclusions of ofp-print.h.
[sliver-openvswitch.git] / lib / rconn.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  *
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include <config.h>
35 #include "rconn.h"
36 #include <assert.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include "ofpbuf.h"
42 #include "poll-loop.h"
43 #include "sat-math.h"
44 #include "timeval.h"
45 #include "util.h"
46 #include "vconn.h"
47
48 #define THIS_MODULE VLM_rconn
49 #include "vlog.h"
50
51 #define STATES                                  \
52     STATE(VOID, 1 << 0)                         \
53     STATE(BACKOFF, 1 << 1)                      \
54     STATE(CONNECTING, 1 << 2)                   \
55     STATE(ACTIVE, 1 << 3)                       \
56     STATE(IDLE, 1 << 4)
57 enum state {
58 #define STATE(NAME, VALUE) S_##NAME = VALUE,
59     STATES
60 #undef STATE
61 };
62
63 static const char *
64 state_name(enum state state)
65 {
66     switch (state) {
67 #define STATE(NAME, VALUE) case S_##NAME: return #NAME;
68         STATES
69 #undef STATE
70     }
71     return "***ERROR***";
72 }
73
74 /* A reliable connection to an OpenFlow switch or controller.
75  *
76  * See the large comment in rconn.h for more information. */
77 struct rconn {
78     enum state state;
79     time_t state_entered;
80
81     struct vconn *vconn;
82     char *name;
83     bool reliable;
84
85     struct ofp_queue txq;
86
87     int backoff;
88     int max_backoff;
89     time_t backoff_deadline;
90     time_t last_received;
91     time_t last_connected;
92     unsigned int packets_sent;
93
94     /* These values are simply for statistics reporting, not used directly by
95      * anything internal to the rconn (or the secchan for that matter). */
96     unsigned int packets_received;
97     unsigned int n_attempted_connections, n_successful_connections;
98     time_t creation_time;
99     unsigned long int total_time_connected;
100
101     /* If we can't connect to the peer, it could be for any number of reasons.
102      * Usually, one would assume it is because the peer is not running or
103      * because the network is partitioned.  But it could also be because the
104      * network topology has changed, in which case the upper layer will need to
105      * reassess it (in particular, obtain a new IP address via DHCP and find
106      * the new location of the controller).  We set this flag when we suspect
107      * that this could be the case. */
108     bool questionable_connectivity;
109     time_t last_questioned;
110
111     /* Throughout this file, "probe" is shorthand for "inactivity probe".
112      * When nothing has been received from the peer for a while, we send out
113      * an echo request as an inactivity probe packet.  We should receive back
114      * a response. */
115     int probe_interval;         /* Secs of inactivity before sending probe. */
116 };
117
118 static unsigned int elapsed_in_this_state(const struct rconn *);
119 static unsigned int timeout(const struct rconn *);
120 static bool timed_out(const struct rconn *);
121 static void state_transition(struct rconn *, enum state);
122 static int try_send(struct rconn *);
123 static int reconnect(struct rconn *);
124 static void disconnect(struct rconn *, int error);
125 static void flush_queue(struct rconn *);
126 static void question_connectivity(struct rconn *);
127
128 /* Creates a new rconn, connects it (reliably) to 'name', and returns it. */
129 struct rconn *
130 rconn_new(const char *name, int inactivity_probe_interval, int max_backoff)
131 {
132     struct rconn *rc = rconn_create(inactivity_probe_interval, max_backoff);
133     rconn_connect(rc, name);
134     return rc;
135 }
136
137 /* Creates a new rconn, connects it (unreliably) to 'vconn', and returns it. */
138 struct rconn *
139 rconn_new_from_vconn(const char *name, struct vconn *vconn) 
140 {
141     struct rconn *rc = rconn_create(60, 0);
142     rconn_connect_unreliably(rc, name, vconn);
143     return rc;
144 }
145
146 /* Creates and returns a new rconn.
147  *
148  * 'probe_interval' is a number of seconds.  If the interval passes once
149  * without an OpenFlow message being received from the peer, the rconn sends
150  * out an "echo request" message.  If the interval passes again without a
151  * message being received, the rconn disconnects and re-connects to the peer.
152  * Setting 'probe_interval' to 0 disables this behavior.
153  *
154  * 'max_backoff' is the maximum number of seconds between attempts to connect
155  * to the peer.  The actual interval starts at 1 second and doubles on each
156  * failure until it reaches 'max_backoff'.  If 0 is specified, the default of
157  * 60 seconds is used. */
158 struct rconn *
159 rconn_create(int probe_interval, int max_backoff)
160 {
161     struct rconn *rc = xcalloc(1, sizeof *rc);
162
163     rc->state = S_VOID;
164     rc->state_entered = time_now();
165
166     rc->vconn = NULL;
167     rc->name = xstrdup("void");
168     rc->reliable = false;
169
170     queue_init(&rc->txq);
171
172     rc->backoff = 0;
173     rc->max_backoff = max_backoff ? max_backoff : 60;
174     rc->backoff_deadline = TIME_MIN;
175     rc->last_received = time_now();
176     rc->last_connected = time_now();
177
178     rc->packets_sent = 0;
179
180     rc->packets_received = 0;
181     rc->n_attempted_connections = 0;
182     rc->n_successful_connections = 0;
183     rc->creation_time = time_now();
184     rc->total_time_connected = 0;
185
186     rc->questionable_connectivity = false;
187     rc->last_questioned = time_now();
188
189     rc->probe_interval = probe_interval ? MAX(5, probe_interval) : 0;
190
191     return rc;
192 }
193
194 int
195 rconn_connect(struct rconn *rc, const char *name)
196 {
197     rconn_disconnect(rc);
198     free(rc->name);
199     rc->name = xstrdup(name);
200     rc->reliable = true;
201     return reconnect(rc);
202 }
203
204 void
205 rconn_connect_unreliably(struct rconn *rc,
206                          const char *name, struct vconn *vconn)
207 {
208     assert(vconn != NULL);
209     rconn_disconnect(rc);
210     free(rc->name);
211     rc->name = xstrdup(name);
212     rc->reliable = false;
213     rc->vconn = vconn;
214     rc->last_connected = time_now();
215     state_transition(rc, S_ACTIVE);
216 }
217
218 void
219 rconn_disconnect(struct rconn *rc)
220 {
221     if (rc->vconn) {
222         vconn_close(rc->vconn);
223         rc->vconn = NULL;
224     }
225     free(rc->name);
226     rc->name = xstrdup("void");
227     rc->reliable = false;
228
229     rc->backoff = 0;
230     rc->backoff_deadline = TIME_MIN;
231
232     state_transition(rc, S_VOID);
233 }
234
235 /* Disconnects 'rc' and frees the underlying storage. */
236 void
237 rconn_destroy(struct rconn *rc)
238 {
239     if (rc) {
240         free(rc->name);
241         vconn_close(rc->vconn);
242         flush_queue(rc);
243         queue_destroy(&rc->txq);
244         free(rc);
245     }
246 }
247
248 static unsigned int
249 timeout_VOID(const struct rconn *rc)
250 {
251     return UINT_MAX;
252 }
253
254 static void
255 run_VOID(struct rconn *rc)
256 {
257     /* Nothing to do. */
258 }
259
260 static int
261 reconnect(struct rconn *rc)
262 {
263     int retval;
264
265     VLOG_WARN("%s: connecting...", rc->name);
266     rc->n_attempted_connections++;
267     retval = vconn_open(rc->name, &rc->vconn);
268     if (!retval) {
269         rc->backoff_deadline = time_now() + rc->backoff;
270         state_transition(rc, S_CONNECTING);
271     } else {
272         VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
273         disconnect(rc, 0);
274     }
275     return retval;
276 }
277
278 static unsigned int
279 timeout_BACKOFF(const struct rconn *rc)
280 {
281     return rc->backoff;
282 }
283
284 static void
285 run_BACKOFF(struct rconn *rc)
286 {
287     if (timed_out(rc)) {
288         reconnect(rc);
289     }
290 }
291
292 static unsigned int
293 timeout_CONNECTING(const struct rconn *rc)
294 {
295     return MAX(1, rc->backoff);
296 }
297
298 static void
299 run_CONNECTING(struct rconn *rc)
300 {
301     int retval = vconn_connect(rc->vconn);
302     if (!retval) {
303         VLOG_WARN("%s: connected", rc->name);
304         rc->n_successful_connections++;
305         if (vconn_is_passive(rc->vconn)) {
306             ofp_error(0, "%s: passive vconn not supported", rc->name);
307             state_transition(rc, S_VOID);
308         } else {
309             state_transition(rc, S_ACTIVE);
310             rc->last_connected = rc->state_entered;
311         }
312     } else if (retval != EAGAIN) {
313         VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
314         disconnect(rc, retval);
315     } else if (timed_out(rc)) {
316         VLOG_WARN("%s: connection timed out", rc->name);
317         rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
318         disconnect(rc, 0);
319     }
320 }
321
322 static void
323 do_tx_work(struct rconn *rc)
324 {
325     if (!rc->txq.n) {
326         return;
327     }
328     while (rc->txq.n > 0) {
329         int error = try_send(rc);
330         if (error) {
331             break;
332         }
333     }
334     if (!rc->txq.n) {
335         poll_immediate_wake();
336     }
337 }
338
339 static unsigned int
340 timeout_ACTIVE(const struct rconn *rc)
341 {
342     if (rc->probe_interval) {
343         unsigned int base = MAX(rc->last_received, rc->state_entered);
344         unsigned int arg = base + rc->probe_interval - rc->state_entered;
345         return arg;
346     }
347     return UINT_MAX;
348 }
349
350 static void
351 run_ACTIVE(struct rconn *rc)
352 {
353     if (timed_out(rc)) {
354         unsigned int base = MAX(rc->last_received, rc->state_entered);
355         rconn_send(rc, make_echo_request(), NULL);
356         VLOG_DBG("%s: idle %u seconds, sending inactivity probe",
357                  rc->name, (unsigned int) (time_now() - base));
358         state_transition(rc, S_IDLE);
359         return;
360     }
361
362     do_tx_work(rc);
363 }
364
365 static unsigned int
366 timeout_IDLE(const struct rconn *rc)
367 {
368     return rc->probe_interval;
369 }
370
371 static void
372 run_IDLE(struct rconn *rc)
373 {
374     if (timed_out(rc)) {
375         question_connectivity(rc);
376         VLOG_ERR("%s: no response to inactivity probe after %u "
377                  "seconds, disconnecting",
378                  rc->name, elapsed_in_this_state(rc));
379         disconnect(rc, 0);
380     } else {
381         do_tx_work(rc);
382     }
383 }
384
385 /* Performs whatever activities are necessary to maintain 'rc': if 'rc' is
386  * disconnected, attempts to (re)connect, backing off as necessary; if 'rc' is
387  * connected, attempts to send packets in the send queue, if any. */
388 void
389 rconn_run(struct rconn *rc)
390 {
391     int old_state;
392     do {
393         old_state = rc->state;
394         switch (rc->state) {
395 #define STATE(NAME, VALUE) case S_##NAME: run_##NAME(rc); break;
396             STATES
397 #undef STATE
398         default:
399             NOT_REACHED();
400         }
401     } while (rc->state != old_state);
402 }
403
404 /* Causes the next call to poll_block() to wake up when rconn_run() should be
405  * called on 'rc'. */
406 void
407 rconn_run_wait(struct rconn *rc)
408 {
409     unsigned int timeo = timeout(rc);
410     if (timeo != UINT_MAX) {
411         unsigned int expires = sat_add(rc->state_entered, timeo);
412         unsigned int remaining = sat_sub(expires, time_now());
413         poll_timer_wait(sat_mul(remaining, 1000));
414     }
415
416     if ((rc->state & (S_ACTIVE | S_IDLE)) && rc->txq.n) {
417         vconn_wait(rc->vconn, WAIT_SEND);
418     }
419 }
420
421 /* Attempts to receive a packet from 'rc'.  If successful, returns the packet;
422  * otherwise, returns a null pointer.  The caller is responsible for freeing
423  * the packet (with ofpbuf_delete()). */
424 struct ofpbuf *
425 rconn_recv(struct rconn *rc)
426 {
427     if (rc->state & (S_ACTIVE | S_IDLE)) {
428         struct ofpbuf *buffer;
429         int error = vconn_recv(rc->vconn, &buffer);
430         if (!error) {
431             rc->last_received = time_now();
432             rc->packets_received++;
433             if (rc->state == S_IDLE) {
434                 state_transition(rc, S_ACTIVE);
435             }
436             return buffer;
437         } else if (error != EAGAIN) {
438             disconnect(rc, error);
439         }
440     }
441     return NULL;
442 }
443
444 /* Causes the next call to poll_block() to wake up when a packet may be ready
445  * to be received by vconn_recv() on 'rc'.  */
446 void
447 rconn_recv_wait(struct rconn *rc)
448 {
449     if (rc->vconn) {
450         vconn_wait(rc->vconn, WAIT_RECV);
451     }
452 }
453
454 /* Sends 'b' on 'rc'.  Returns 0 if successful (in which case 'b' is
455  * destroyed), or ENOTCONN if 'rc' is not currently connected (in which case
456  * the caller retains ownership of 'b').
457  *
458  * If 'n_queued' is non-null, then '*n_queued' will be incremented while the
459  * packet is in flight, then decremented when it has been sent (or discarded
460  * due to disconnection).  Because 'b' may be sent (or discarded) before this
461  * function returns, the caller may not be able to observe any change in
462  * '*n_queued'.
463  *
464  * There is no rconn_send_wait() function: an rconn has a send queue that it
465  * takes care of sending if you call rconn_run(), which will have the side
466  * effect of waking up poll_block(). */
467 int
468 rconn_send(struct rconn *rc, struct ofpbuf *b, int *n_queued)
469 {
470     if (rconn_is_connected(rc)) {
471         b->private = n_queued;
472         if (n_queued) {
473             ++*n_queued;
474         }
475         queue_push_tail(&rc->txq, b);
476         if (rc->txq.n == 1) {
477             try_send(rc);
478         }
479         return 0;
480     } else {
481         return ENOTCONN;
482     }
483 }
484
485 /* Sends 'b' on 'rc'.  Increments '*n_queued' while the packet is in flight; it
486  * will be decremented when it has been sent (or discarded due to
487  * disconnection).  Returns 0 if successful, EAGAIN if '*n_queued' is already
488  * at least as large of 'queue_limit', or ENOTCONN if 'rc' is not currently
489  * connected.  Regardless of return value, 'b' is destroyed.
490  *
491  * Because 'b' may be sent (or discarded) before this function returns, the
492  * caller may not be able to observe any change in '*n_queued'.
493  *
494  * There is no rconn_send_wait() function: an rconn has a send queue that it
495  * takes care of sending if you call rconn_run(), which will have the side
496  * effect of waking up poll_block(). */
497 int
498 rconn_send_with_limit(struct rconn *rc, struct ofpbuf *b,
499                       int *n_queued, int queue_limit)
500 {
501     int retval;
502     retval = *n_queued >= queue_limit ? EAGAIN : rconn_send(rc, b, n_queued);
503     if (retval) {
504         ofpbuf_delete(b);
505     }
506     return retval;
507 }
508
509 /* Returns the total number of packets successfully sent on the underlying
510  * vconn.  A packet is not counted as sent while it is still queued in the
511  * rconn, only when it has been successfuly passed to the vconn.  */
512 unsigned int
513 rconn_packets_sent(const struct rconn *rc)
514 {
515     return rc->packets_sent;
516 }
517
518 /* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */
519 const char *
520 rconn_get_name(const struct rconn *rc)
521 {
522     return rc->name;
523 }
524
525 /* Returns true if 'rconn' is connected or in the process of reconnecting,
526  * false if 'rconn' is disconnected and will not reconnect on its own. */
527 bool
528 rconn_is_alive(const struct rconn *rconn)
529 {
530     return rconn->state != S_VOID;
531 }
532
533 /* Returns true if 'rconn' is connected, false otherwise. */
534 bool
535 rconn_is_connected(const struct rconn *rconn)
536 {
537     return rconn->state & (S_ACTIVE | S_IDLE);
538 }
539
540 /* Returns 0 if 'rconn' is connected, otherwise the number of seconds that it
541  * has been disconnected. */
542 int
543 rconn_disconnected_duration(const struct rconn *rconn)
544 {
545     return rconn_is_connected(rconn) ? 0 : time_now() - rconn->last_received;
546 }
547
548 /* Returns the IP address of the peer, or 0 if the peer is not connected over
549  * an IP-based protocol or if its IP address is not known. */
550 uint32_t
551 rconn_get_ip(const struct rconn *rconn) 
552 {
553     return rconn->vconn ? vconn_get_ip(rconn->vconn) : 0;
554 }
555
556 /* If 'rconn' can't connect to the peer, it could be for any number of reasons.
557  * Usually, one would assume it is because the peer is not running or because
558  * the network is partitioned.  But it could also be because the network
559  * topology has changed, in which case the upper layer will need to reassess it
560  * (in particular, obtain a new IP address via DHCP and find the new location
561  * of the controller).  When this appears that this might be the case, this
562  * function returns true.  It also clears the questionability flag and prevents
563  * it from being set again for some time. */
564 bool
565 rconn_is_connectivity_questionable(struct rconn *rconn)
566 {
567     bool questionable = rconn->questionable_connectivity;
568     rconn->questionable_connectivity = false;
569     return questionable;
570 }
571
572 /* Returns the total number of packets successfully received by the underlying
573  * vconn.  */
574 unsigned int
575 rconn_packets_received(const struct rconn *rc)
576 {
577     return rc->packets_received;
578 }
579
580 /* Returns a string representing the internal state of 'rc'.  The caller must
581  * not modify or free the string. */
582 const char *
583 rconn_get_state(const struct rconn *rc)
584 {
585     return state_name(rc->state);
586 }
587
588 /* Returns the number of connection attempts made by 'rc', including any
589  * ongoing attempt that has not yet succeeded or failed. */
590 unsigned int
591 rconn_get_attempted_connections(const struct rconn *rc)
592 {
593     return rc->n_attempted_connections;
594 }
595
596 /* Returns the number of successful connection attempts made by 'rc'. */
597 unsigned int
598 rconn_get_successful_connections(const struct rconn *rc)
599 {
600     return rc->n_successful_connections;
601 }
602
603 /* Returns the time at which the last successful connection was made by
604  * 'rc'. */
605 time_t
606 rconn_get_last_connection(const struct rconn *rc)
607 {
608     return rc->last_connected;
609 }
610
611 /* Returns the time at which 'rc' was created. */
612 time_t
613 rconn_get_creation_time(const struct rconn *rc)
614 {
615     return rc->creation_time;
616 }
617
618 /* Returns the approximate number of seconds that 'rc' has been connected. */
619 unsigned long int
620 rconn_get_total_time_connected(const struct rconn *rc)
621 {
622     return (rc->total_time_connected
623             + (rconn_is_connected(rc) ? elapsed_in_this_state(rc) : 0));
624 }
625
626 /* Returns the current amount of backoff, in seconds.  This is the amount of
627  * time after which the rconn will transition from BACKOFF to CONNECTING. */
628 int
629 rconn_get_backoff(const struct rconn *rc)
630 {
631     return rc->backoff;
632 }
633
634 /* Returns the number of seconds spent in this state so far. */
635 unsigned int
636 rconn_get_state_elapsed(const struct rconn *rc)
637 {
638     return elapsed_in_this_state(rc);
639 }
640 \f
641 /* Tries to send a packet from 'rc''s send buffer.  Returns 0 if successful,
642  * otherwise a positive errno value. */
643 static int
644 try_send(struct rconn *rc)
645 {
646     int retval = 0;
647     struct ofpbuf *next = rc->txq.head->next;
648     int *n_queued = rc->txq.head->private;
649     retval = vconn_send(rc->vconn, rc->txq.head);
650     if (retval) {
651         if (retval != EAGAIN) {
652             disconnect(rc, retval);
653         }
654         return retval;
655     }
656     rc->packets_sent++;
657     if (n_queued) {
658         --*n_queued;
659     }
660     queue_advance_head(&rc->txq, next);
661     return 0;
662 }
663
664 /* Disconnects 'rc'.  'error' is used only for logging purposes.  If it is
665  * nonzero, then it should be EOF to indicate the connection was closed by the
666  * peer in a normal fashion or a positive errno value. */
667 static void
668 disconnect(struct rconn *rc, int error)
669 {
670     if (rc->reliable) {
671         time_t now = time_now();
672
673         if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) {
674             if (error > 0) {
675                 VLOG_WARN("%s: connection dropped (%s)",
676                           rc->name, strerror(error));
677             } else if (error == EOF) {
678                 if (rc->reliable) {
679                     VLOG_WARN("%s: connection closed", rc->name);
680                 }
681             } else {
682                 VLOG_WARN("%s: connection dropped", rc->name);
683             }
684             vconn_close(rc->vconn);
685             rc->vconn = NULL;
686             flush_queue(rc);
687         }
688
689         if (now >= rc->backoff_deadline) {
690             rc->backoff = 1;
691         } else {
692             rc->backoff = MIN(rc->max_backoff, MAX(1, 2 * rc->backoff));
693             VLOG_WARN("%s: waiting %d seconds before reconnect\n",
694                       rc->name, rc->backoff);
695         }
696         rc->backoff_deadline = now + rc->backoff;
697         state_transition(rc, S_BACKOFF);
698         if (now - rc->last_connected > 60) {
699             question_connectivity(rc);
700         }
701     } else {
702         rconn_disconnect(rc);
703     }
704 }
705
706 /* Drops all the packets from 'rc''s send queue and decrements their queue
707  * counts. */
708 static void
709 flush_queue(struct rconn *rc)
710 {
711     if (!rc->txq.n) {
712         return;
713     }
714     while (rc->txq.n > 0) {
715         struct ofpbuf *b = queue_pop_head(&rc->txq);
716         int *n_queued = b->private;
717         if (n_queued) {
718             --*n_queued;
719         }
720         ofpbuf_delete(b);
721     }
722     poll_immediate_wake();
723 }
724
725 static unsigned int
726 elapsed_in_this_state(const struct rconn *rc)
727 {
728     return time_now() - rc->state_entered;
729 }
730
731 static unsigned int
732 timeout(const struct rconn *rc)
733 {
734     switch (rc->state) {
735 #define STATE(NAME, VALUE) case S_##NAME: return timeout_##NAME(rc);
736         STATES
737 #undef STATE
738     default:
739         NOT_REACHED();
740     }
741 }
742
743 static bool
744 timed_out(const struct rconn *rc)
745 {
746     return time_now() >= sat_add(rc->state_entered, timeout(rc));
747 }
748
749 static void
750 state_transition(struct rconn *rc, enum state state)
751 {
752     if (rconn_is_connected(rc)) {
753         rc->total_time_connected += elapsed_in_this_state(rc);
754     }
755     VLOG_DBG("%s: entering %s", rc->name, state_name(state));
756     rc->state = state;
757     rc->state_entered = time_now();
758 }
759
760 static void
761 question_connectivity(struct rconn *rc) 
762 {
763     time_t now = time_now();
764     if (now - rc->last_questioned > 60) {
765         rc->questionable_connectivity = true;
766         rc->last_questioned = now;
767     }
768 }