summaryrefslogtreecommitdiff
path: root/secchan/fail-open.c
diff options
context:
space:
mode:
Diffstat (limited to 'secchan/fail-open.c')
-rw-r--r--secchan/fail-open.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/secchan/fail-open.c b/secchan/fail-open.c
new file mode 100644
index 000000000..1ef989a02
--- /dev/null
+++ b/secchan/fail-open.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2008, 2009 Nicira Networks.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include "fail-open.h"
+#include <inttypes.h>
+#include <stdlib.h>
+#include "flow.h"
+#include "mac-learning.h"
+#include "odp-util.h"
+#include "ofproto.h"
+#include "rconn.h"
+#include "status.h"
+#include "timeval.h"
+
+#define THIS_MODULE VLM_fail_open
+#include "vlog.h"
+
+struct fail_open {
+ struct ofproto *ofproto;
+ struct rconn *controller;
+ int trigger_duration;
+ int last_disconn_secs;
+ struct status_category *ss_cat;
+};
+
+/* Causes the switch to enter or leave fail-open mode, if appropriate. */
+void
+fail_open_run(struct fail_open *fo)
+{
+ int disconn_secs = rconn_failure_duration(fo->controller);
+ bool open = disconn_secs >= fo->trigger_duration;
+ if (open != (fo->last_disconn_secs != 0)) {
+ if (!open) {
+ flow_t flow;
+
+ VLOG_WARN("No longer in fail-open mode");
+ fo->last_disconn_secs = 0;
+
+ memset(&flow, 0, sizeof flow);
+ ofproto_delete_flow(fo->ofproto, &flow, OFPFW_ALL, 70000);
+ } else {
+ VLOG_WARN("Could not connect to controller for %d seconds, "
+ "failing open", disconn_secs);
+ fo->last_disconn_secs = disconn_secs;
+
+ /* Flush all OpenFlow and datapath flows. We will set up our
+ * fail-open rule from fail_open_flushed() when
+ * ofproto_flush_flows() calls back to us. */
+ ofproto_flush_flows(fo->ofproto);
+ }
+ } else if (open && disconn_secs > fo->last_disconn_secs + 60) {
+ VLOG_INFO("Still in fail-open mode after %d seconds disconnected "
+ "from controller", disconn_secs);
+ fo->last_disconn_secs = disconn_secs;
+ }
+}
+
+void
+fail_open_wait(struct fail_open *fo UNUSED)
+{
+ /* Nothing to do. */
+}
+
+void
+fail_open_flushed(struct fail_open *fo)
+{
+ int disconn_secs = rconn_failure_duration(fo->controller);
+ bool open = disconn_secs >= fo->trigger_duration;
+ if (open) {
+ union ofp_action action;
+ flow_t flow;
+
+ /* Set up a flow that matches every packet and directs them to
+ * OFPP_NORMAL. */
+ memset(&action, 0, sizeof action);
+ action.type = htons(OFPAT_OUTPUT);
+ action.output.len = htons(sizeof action);
+ action.output.port = htons(OFPP_NORMAL);
+ memset(&flow, 0, sizeof flow);
+ ofproto_add_flow(fo->ofproto, &flow, OFPFW_ALL, 70000,
+ &action, 1, 0);
+ }
+}
+
+static void
+fail_open_status_cb(struct status_reply *sr, void *fo_)
+{
+ struct fail_open *fo = fo_;
+ int cur_duration = rconn_failure_duration(fo->controller);
+
+ status_reply_put(sr, "trigger-duration=%d", fo->trigger_duration);
+ status_reply_put(sr, "current-duration=%d", cur_duration);
+ status_reply_put(sr, "triggered=%s",
+ cur_duration >= fo->trigger_duration ? "true" : "false");
+}
+
+struct fail_open *
+fail_open_create(struct ofproto *ofproto,
+ int trigger_duration, struct switch_status *switch_status,
+ struct rconn *controller)
+{
+ struct fail_open *fo = xmalloc(sizeof *fo);
+ fo->ofproto = ofproto;
+ fo->controller = controller;
+ fo->trigger_duration = trigger_duration;
+ fo->last_disconn_secs = 0;
+ fo->ss_cat = switch_status_register(switch_status, "fail-open",
+ fail_open_status_cb, fo);
+ return fo;
+}
+
+void
+fail_open_set_trigger_duration(struct fail_open *fo, int trigger_duration)
+{
+ fo->trigger_duration = trigger_duration;
+}
+
+void
+fail_open_destroy(struct fail_open *fo)
+{
+ if (fo) {
+ /* We don't own fo->controller. */
+ switch_status_unregister(fo->ss_cat);
+ free(fo);
+ }
+}