vswitch: Don't pass null pointer to stat().
[sliver-openvswitch.git] / secchan / 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 for %d seconds, "
57                       "failing open", disconn_secs);
58             fo->last_disconn_secs = disconn_secs;
59
60             /* Flush all OpenFlow and datapath flows.  We will set up our
61              * fail-open rule from fail_open_flushed() when
62              * ofproto_flush_flows() calls back to us. */
63             ofproto_flush_flows(fo->ofproto);
64         }
65     } else if (open && disconn_secs > fo->last_disconn_secs + 60) {
66         VLOG_INFO("Still in fail-open mode after %d seconds disconnected "
67                   "from controller", disconn_secs);
68         fo->last_disconn_secs = disconn_secs;
69     }
70 }
71
72 void
73 fail_open_wait(struct fail_open *fo UNUSED)
74 {
75     /* Nothing to do. */
76 }
77
78 void
79 fail_open_flushed(struct fail_open *fo)
80 {
81     int disconn_secs = rconn_failure_duration(fo->controller);
82     bool open = disconn_secs >= fo->trigger_duration;
83     if (open) {
84         union ofp_action action;
85         flow_t flow;
86
87         /* Set up a flow that matches every packet and directs them to
88          * OFPP_NORMAL. */
89         memset(&action, 0, sizeof action);
90         action.type = htons(OFPAT_OUTPUT);
91         action.output.len = htons(sizeof action);
92         action.output.port = htons(OFPP_NORMAL);
93         memset(&flow, 0, sizeof flow);
94         ofproto_add_flow(fo->ofproto, &flow, OFPFW_ALL, 70000,
95                          &action, 1, 0);
96     }
97 }
98
99 static void
100 fail_open_status_cb(struct status_reply *sr, void *fo_)
101 {
102     struct fail_open *fo = fo_;
103     int cur_duration = rconn_failure_duration(fo->controller);
104
105     status_reply_put(sr, "trigger-duration=%d", fo->trigger_duration);
106     status_reply_put(sr, "current-duration=%d", cur_duration);
107     status_reply_put(sr, "triggered=%s",
108                      cur_duration >= fo->trigger_duration ? "true" : "false");
109 }
110
111 struct fail_open *
112 fail_open_create(struct ofproto *ofproto,
113                  int trigger_duration, struct switch_status *switch_status,
114                  struct rconn *controller)
115 {
116     struct fail_open *fo = xmalloc(sizeof *fo);
117     fo->ofproto = ofproto;
118     fo->controller = controller;
119     fo->trigger_duration = trigger_duration;
120     fo->last_disconn_secs = 0;
121     fo->ss_cat = switch_status_register(switch_status, "fail-open",
122                                         fail_open_status_cb, fo);
123     return fo;
124 }
125
126 void
127 fail_open_set_trigger_duration(struct fail_open *fo, int trigger_duration)
128 {
129     fo->trigger_duration = trigger_duration;
130 }
131
132 void
133 fail_open_destroy(struct fail_open *fo)
134 {
135     if (fo) {
136         /* We don't own fo->controller. */
137         switch_status_unregister(fo->ss_cat);
138         free(fo);
139     }
140 }