Merge citrix into master.
[sliver-openvswitch.git] / ofproto / fail-open.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
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 #include "fail-open.h"
19 #include <inttypes.h>
20 #include <stdlib.h>
21 #include "flow.h"
22 #include "mac-learning.h"
23 #include "odp-util.h"
24 #include "ofproto.h"
25 #include "rconn.h"
26 #include "status.h"
27 #include "timeval.h"
28
29 #define THIS_MODULE VLM_fail_open
30 #include "vlog.h"
31
32 struct fail_open {
33     struct ofproto *ofproto;
34     struct rconn *controller;
35     int trigger_duration;
36     int last_disconn_secs;
37     struct status_category *ss_cat;
38 };
39
40 /* Causes the switch to enter or leave fail-open mode, if appropriate. */
41 void
42 fail_open_run(struct fail_open *fo)
43 {
44     int disconn_secs = rconn_failure_duration(fo->controller);
45     bool open = disconn_secs >= fo->trigger_duration;
46     if (open != (fo->last_disconn_secs != 0)) {
47         if (!open) {
48             flow_t flow;
49
50             VLOG_WARN("No longer in fail-open mode");
51             fo->last_disconn_secs = 0;
52
53             memset(&flow, 0, sizeof flow);
54             ofproto_delete_flow(fo->ofproto, &flow, OFPFW_ALL, 70000);
55         } else {
56             VLOG_WARN("Could not connect to controller (or switch failed "
57                       "controller's post-connection admission control "
58                       "policy) for %d seconds, failing open", disconn_secs);
59             fo->last_disconn_secs = disconn_secs;
60
61             /* Flush all OpenFlow and datapath flows.  We will set up our
62              * fail-open rule from fail_open_flushed() when
63              * ofproto_flush_flows() calls back to us. */
64             ofproto_flush_flows(fo->ofproto);
65         }
66     } else if (open && disconn_secs > fo->last_disconn_secs + 60) {
67         VLOG_INFO("Still in fail-open mode after %d seconds disconnected "
68                   "from controller", disconn_secs);
69         fo->last_disconn_secs = disconn_secs;
70     }
71 }
72
73 void
74 fail_open_wait(struct fail_open *fo UNUSED)
75 {
76     /* Nothing to do. */
77 }
78
79 void
80 fail_open_flushed(struct fail_open *fo)
81 {
82     int disconn_secs = rconn_failure_duration(fo->controller);
83     bool open = disconn_secs >= fo->trigger_duration;
84     if (open) {
85         union ofp_action action;
86         flow_t flow;
87
88         /* Set up a flow that matches every packet and directs them to
89          * OFPP_NORMAL. */
90         memset(&action, 0, sizeof action);
91         action.type = htons(OFPAT_OUTPUT);
92         action.output.len = htons(sizeof action);
93         action.output.port = htons(OFPP_NORMAL);
94         memset(&flow, 0, sizeof flow);
95         ofproto_add_flow(fo->ofproto, &flow, OFPFW_ALL, 70000,
96                          &action, 1, 0);
97     }
98 }
99
100 static void
101 fail_open_status_cb(struct status_reply *sr, void *fo_)
102 {
103     struct fail_open *fo = fo_;
104     int cur_duration = rconn_failure_duration(fo->controller);
105
106     status_reply_put(sr, "trigger-duration=%d", fo->trigger_duration);
107     status_reply_put(sr, "current-duration=%d", cur_duration);
108     status_reply_put(sr, "triggered=%s",
109                      cur_duration >= fo->trigger_duration ? "true" : "false");
110 }
111
112 struct fail_open *
113 fail_open_create(struct ofproto *ofproto,
114                  int trigger_duration, struct switch_status *switch_status,
115                  struct rconn *controller)
116 {
117     struct fail_open *fo = xmalloc(sizeof *fo);
118     fo->ofproto = ofproto;
119     fo->controller = controller;
120     fo->trigger_duration = trigger_duration;
121     fo->last_disconn_secs = 0;
122     fo->ss_cat = switch_status_register(switch_status, "fail-open",
123                                         fail_open_status_cb, fo);
124     return fo;
125 }
126
127 void
128 fail_open_set_trigger_duration(struct fail_open *fo, int trigger_duration)
129 {
130     fo->trigger_duration = trigger_duration;
131 }
132
133 void
134 fail_open_destroy(struct fail_open *fo)
135 {
136     if (fo) {
137         /* We don't own fo->controller. */
138         switch_status_unregister(fo->ss_cat);
139         free(fo);
140     }
141 }