+static void fail_open_recover(struct fail_open *);
+
+/* Returns the number of seconds of disconnection after which fail-open mode
+ * should activate. */
+static int
+trigger_duration(const struct fail_open *fo)
+{
+ if (!fo->n_controllers) {
+ /* Shouldn't ever arrive here, but if we do, never fail open. */
+ return INT_MAX;
+ } else {
+ /* Otherwise, every controller must have a chance to send an
+ * inactivity probe and reconnect before we fail open, so take the
+ * maximum probe interval and multiply by 3:
+ *
+ * - The first interval is the idle time before sending an inactivity
+ * probe.
+ *
+ * - The second interval is the time allowed for a response to the
+ * inactivity probe.
+ *
+ * - The third interval is the time allowed to reconnect after no
+ * response is received.
+ */
+ int max_probe_interval;
+ size_t i;
+
+ max_probe_interval = 0;
+ for (i = 0; i < fo->n_controllers; i++) {
+ int probe_interval = rconn_get_probe_interval(fo->controllers[i]);
+ max_probe_interval = MAX(max_probe_interval, probe_interval);
+ }
+ return max_probe_interval * 3;
+ }
+}
+
+/* Returns the number of seconds for which all controllers have been
+ * disconnected. */
+static int
+failure_duration(const struct fail_open *fo)
+{
+ int min_failure_duration;
+ size_t i;
+
+ if (!fo->n_controllers) {
+ return 0;
+ }
+
+ min_failure_duration = INT_MAX;
+ for (i = 0; i < fo->n_controllers; i++) {
+ int failure_duration = rconn_failure_duration(fo->controllers[i]);
+ min_failure_duration = MIN(min_failure_duration, failure_duration);
+ }
+ return min_failure_duration;
+}
+
+/* Returns true if 'fo' is currently in fail-open mode, otherwise false. */
+bool
+fail_open_is_active(const struct fail_open *fo)
+{
+ return fo->last_disconn_secs != 0;
+}
+
+/* Returns true if at least one controller is connected (regardless of whether
+ * those controllers are believed to have authenticated and accepted this
+ * switch), false if none of them are connected. */
+static bool
+any_controller_is_connected(const struct fail_open *fo)
+{
+ size_t i;
+
+ for (i = 0; i < fo->n_controllers; i++) {
+ if (rconn_is_connected(fo->controllers[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Returns true if at least one controller is believed to have authenticated
+ * and accepted this switch, false otherwise. */
+static bool
+any_controller_is_admitted(const struct fail_open *fo)
+{
+ size_t i;
+
+ for (i = 0; i < fo->n_controllers; i++) {
+ if (rconn_is_admitted(fo->controllers[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void
+send_bogus_packet_in(struct fail_open *fo, struct rconn *rconn)
+{
+ uint8_t mac[ETH_ADDR_LEN];
+ struct ofpbuf *opi;
+ struct ofpbuf b;
+
+ /* Compose ofp_packet_in. */
+ ofpbuf_init(&b, 128);
+ eth_addr_nicira_random(mac);
+ compose_benign_packet(&b, "Open vSwitch Controller Probe", 0xa033, mac);
+ opi = make_packet_in(pktbuf_get_null(), OFPP_LOCAL, OFPR_NO_MATCH, &b, 64);
+ ofpbuf_uninit(&b);
+
+ /* Send. */
+ rconn_send_with_limit(rconn, opi, fo->bogus_packet_counter, 1);
+}
+
+static void
+send_bogus_packet_ins(struct fail_open *fo)
+{
+ size_t i;
+
+ for (i = 0; i < fo->n_controllers; i++) {
+ if (rconn_is_connected(fo->controllers[i])) {
+ send_bogus_packet_in(fo, fo->controllers[i]);
+ }
+ }
+}
+
+/* Enter fail-open mode if we should be in it. */