]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
15aaf599 | 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include "fail-open.h" | |
19 | #include <inttypes.h> | |
20 | #include <stdlib.h> | |
cf3fad8a | 21 | #include "classifier.h" |
19a87e36 | 22 | #include "connmgr.h" |
064af421 BP |
23 | #include "flow.h" |
24 | #include "mac-learning.h" | |
25 | #include "odp-util.h" | |
f25d0cf3 | 26 | #include "ofp-actions.h" |
fa37b408 | 27 | #include "ofp-util.h" |
7778bd15 | 28 | #include "ofpbuf.h" |
064af421 | 29 | #include "ofproto.h" |
5bee6e26 | 30 | #include "ofproto-provider.h" |
7778bd15 BP |
31 | #include "pktbuf.h" |
32 | #include "poll-loop.h" | |
064af421 | 33 | #include "rconn.h" |
064af421 | 34 | #include "timeval.h" |
7778bd15 | 35 | #include "vconn.h" |
064af421 BP |
36 | #include "vlog.h" |
37 | ||
d98e6007 | 38 | VLOG_DEFINE_THIS_MODULE(fail_open); |
5136ce49 | 39 | |
7778bd15 BP |
40 | /* |
41 | * Fail-open mode. | |
42 | * | |
43 | * In fail-open mode, the switch detects when the controller cannot be | |
44 | * contacted or when the controller is dropping switch connections because the | |
45 | * switch does not pass its admission control policy. In those situations the | |
46 | * switch sets up flows itself using the "normal" action. | |
47 | * | |
48 | * There is a little subtlety to implementation, to properly handle the case | |
49 | * where the controller allows switch connections but drops them a few seconds | |
50 | * later for admission control reasons. Because of this case, we don't want to | |
51 | * just stop setting up flows when we connect to the controller: if we did, | |
52 | * then new flow setup and existing flows would stop during the duration of | |
53 | * connection to the controller, and thus the whole network would go down for | |
54 | * that period of time. | |
55 | * | |
4a2026dd BP |
56 | * So, instead, we add some special cases when we are connected to a |
57 | * controller, but not yet sure that it has admitted us: | |
7778bd15 BP |
58 | * |
59 | * - We set up flows immediately ourselves, but simultaneously send out an | |
60 | * OFPT_PACKET_IN to the controller. We put a special bogus buffer-id in | |
61 | * these OFPT_PACKET_IN messages so that duplicate packets don't get sent | |
62 | * out to the network when the controller replies. | |
63 | * | |
64 | * - We also send out OFPT_PACKET_IN messages for totally bogus packets | |
65 | * every so often, in case no real new flows are arriving in the network. | |
66 | * | |
67 | * - We don't flush the flow table at the time we connect, because this | |
68 | * could cause network stuttering in a switch with lots of flows or very | |
69 | * high-bandwidth flows by suddenly throwing lots of packets down to | |
70 | * userspace. | |
71 | */ | |
72 | ||
064af421 BP |
73 | struct fail_open { |
74 | struct ofproto *ofproto; | |
19a87e36 | 75 | struct connmgr *connmgr; |
064af421 | 76 | int last_disconn_secs; |
7778bd15 BP |
77 | long long int next_bogus_packet_in; |
78 | struct rconn_packet_counter *bogus_packet_counter; | |
064af421 BP |
79 | }; |
80 | ||
2f6d3445 BP |
81 | static void fail_open_recover(struct fail_open *); |
82 | ||
76ce9432 BP |
83 | /* Returns the number of seconds of disconnection after which fail-open mode |
84 | * should activate. */ | |
85 | static int | |
86 | trigger_duration(const struct fail_open *fo) | |
064af421 | 87 | { |
19a87e36 | 88 | if (!connmgr_has_controllers(fo->connmgr)) { |
76ce9432 BP |
89 | /* Shouldn't ever arrive here, but if we do, never fail open. */ |
90 | return INT_MAX; | |
91 | } else { | |
92 | /* Otherwise, every controller must have a chance to send an | |
93 | * inactivity probe and reconnect before we fail open, so take the | |
94 | * maximum probe interval and multiply by 3: | |
95 | * | |
96 | * - The first interval is the idle time before sending an inactivity | |
97 | * probe. | |
98 | * | |
99 | * - The second interval is the time allowed for a response to the | |
100 | * inactivity probe. | |
101 | * | |
102 | * - The third interval is the time allowed to reconnect after no | |
103 | * response is received. | |
104 | */ | |
19a87e36 | 105 | return connmgr_get_max_probe_interval(fo->connmgr) * 3; |
76ce9432 | 106 | } |
7778bd15 BP |
107 | } |
108 | ||
109 | /* Returns true if 'fo' is currently in fail-open mode, otherwise false. */ | |
110 | bool | |
111 | fail_open_is_active(const struct fail_open *fo) | |
112 | { | |
113 | return fo->last_disconn_secs != 0; | |
114 | } | |
064af421 | 115 | |
7778bd15 | 116 | static void |
19a87e36 | 117 | send_bogus_packet_ins(struct fail_open *fo) |
7778bd15 | 118 | { |
0fb7792a | 119 | struct ofproto_packet_in pin; |
7778bd15 | 120 | uint8_t mac[ETH_ADDR_LEN]; |
7778bd15 | 121 | struct ofpbuf b; |
064af421 | 122 | |
7778bd15 | 123 | ofpbuf_init(&b, 128); |
70150daf | 124 | eth_addr_nicira_random(mac); |
2ea838ac | 125 | compose_rarp(&b, mac); |
7778bd15 | 126 | |
0b0517ef | 127 | memset(&pin, 0, sizeof pin); |
1f317cb5 PS |
128 | pin.up.packet = ofpbuf_data(&b); |
129 | pin.up.packet_len = ofpbuf_size(&b); | |
0fb7792a | 130 | pin.up.reason = OFPR_NO_MATCH; |
0fb7792a | 131 | pin.up.fmd.in_port = OFPP_LOCAL; |
1f317cb5 | 132 | pin.send_len = ofpbuf_size(&b); |
32260212 | 133 | pin.miss_type = OFPROTO_PACKET_IN_NO_MISS; |
0b0517ef BP |
134 | connmgr_send_packet_in(fo->connmgr, &pin); |
135 | ||
136 | ofpbuf_uninit(&b); | |
7778bd15 BP |
137 | } |
138 | ||
76ce9432 | 139 | /* Enter fail-open mode if we should be in it. */ |
7778bd15 BP |
140 | void |
141 | fail_open_run(struct fail_open *fo) | |
142 | { | |
19a87e36 | 143 | int disconn_secs = connmgr_failure_duration(fo->connmgr); |
76ce9432 | 144 | |
7778bd15 | 145 | /* Enter fail-open mode if 'fo' is not in it but should be. */ |
76ce9432 | 146 | if (disconn_secs >= trigger_duration(fo)) { |
7778bd15 | 147 | if (!fail_open_is_active(fo)) { |
5ec6690c JP |
148 | VLOG_WARN("Could not connect to controller (or switch failed " |
149 | "controller's post-connection admission control " | |
150 | "policy) for %d seconds, failing open", disconn_secs); | |
064af421 BP |
151 | fo->last_disconn_secs = disconn_secs; |
152 | ||
153 | /* Flush all OpenFlow and datapath flows. We will set up our | |
154 | * fail-open rule from fail_open_flushed() when | |
155 | * ofproto_flush_flows() calls back to us. */ | |
156 | ofproto_flush_flows(fo->ofproto); | |
7778bd15 BP |
157 | } else if (disconn_secs > fo->last_disconn_secs + 60) { |
158 | VLOG_INFO("Still in fail-open mode after %d seconds disconnected " | |
159 | "from controller", disconn_secs); | |
160 | fo->last_disconn_secs = disconn_secs; | |
064af421 | 161 | } |
064af421 | 162 | } |
7778bd15 BP |
163 | |
164 | /* Schedule a bogus packet-in if we're connected and in fail-open. */ | |
165 | if (fail_open_is_active(fo)) { | |
19a87e36 | 166 | if (connmgr_is_any_controller_connected(fo->connmgr)) { |
7778bd15 BP |
167 | bool expired = time_msec() >= fo->next_bogus_packet_in; |
168 | if (expired) { | |
76ce9432 | 169 | send_bogus_packet_ins(fo); |
7778bd15 BP |
170 | } |
171 | if (expired || fo->next_bogus_packet_in == LLONG_MAX) { | |
172 | fo->next_bogus_packet_in = time_msec() + 2000; | |
173 | } | |
174 | } else { | |
175 | fo->next_bogus_packet_in = LLONG_MAX; | |
176 | } | |
177 | } | |
178 | ||
064af421 BP |
179 | } |
180 | ||
7778bd15 BP |
181 | /* If 'fo' is currently in fail-open mode and its rconn has connected to the |
182 | * controller, exits fail open mode. */ | |
064af421 | 183 | void |
7778bd15 | 184 | fail_open_maybe_recover(struct fail_open *fo) |
feb8a80b | 185 | OVS_EXCLUDED(ofproto_mutex) |
064af421 | 186 | { |
19a87e36 BP |
187 | if (fail_open_is_active(fo) |
188 | && connmgr_is_any_controller_admitted(fo->connmgr)) { | |
2f6d3445 BP |
189 | fail_open_recover(fo); |
190 | } | |
191 | } | |
192 | ||
193 | static void | |
194 | fail_open_recover(struct fail_open *fo) | |
feb8a80b | 195 | OVS_EXCLUDED(ofproto_mutex) |
2f6d3445 | 196 | { |
81a76618 | 197 | struct match match; |
7778bd15 | 198 | |
19a87e36 BP |
199 | VLOG_WARN("No longer in fail-open mode"); |
200 | fo->last_disconn_secs = 0; | |
201 | fo->next_bogus_packet_in = LLONG_MAX; | |
7778bd15 | 202 | |
81a76618 BP |
203 | match_init_catchall(&match); |
204 | ofproto_delete_flow(fo->ofproto, &match, FAIL_OPEN_PRIORITY); | |
7778bd15 BP |
205 | } |
206 | ||
207 | void | |
208 | fail_open_wait(struct fail_open *fo) | |
209 | { | |
210 | if (fo->next_bogus_packet_in != LLONG_MAX) { | |
7cf8b266 | 211 | poll_timer_wait_until(fo->next_bogus_packet_in); |
7778bd15 | 212 | } |
064af421 BP |
213 | } |
214 | ||
215 | void | |
216 | fail_open_flushed(struct fail_open *fo) | |
15aaf599 | 217 | OVS_EXCLUDED(ofproto_mutex) |
064af421 | 218 | { |
19a87e36 | 219 | int disconn_secs = connmgr_failure_duration(fo->connmgr); |
76ce9432 | 220 | bool open = disconn_secs >= trigger_duration(fo); |
064af421 | 221 | if (open) { |
f25d0cf3 | 222 | struct ofpbuf ofpacts; |
81a76618 | 223 | struct match match; |
064af421 BP |
224 | |
225 | /* Set up a flow that matches every packet and directs them to | |
226 | * OFPP_NORMAL. */ | |
f25d0cf3 BP |
227 | ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE); |
228 | ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL; | |
229 | ofpact_pad(&ofpacts); | |
cf3fad8a | 230 | |
81a76618 BP |
231 | match_init_catchall(&match); |
232 | ofproto_add_flow(fo->ofproto, &match, FAIL_OPEN_PRIORITY, | |
1f317cb5 | 233 | ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts)); |
f25d0cf3 BP |
234 | |
235 | ofpbuf_uninit(&ofpacts); | |
064af421 BP |
236 | } |
237 | } | |
238 | ||
19a87e36 | 239 | /* Creates and returns a new struct fail_open for 'ofproto' and 'mgr'. */ |
064af421 | 240 | struct fail_open * |
19a87e36 | 241 | fail_open_create(struct ofproto *ofproto, struct connmgr *mgr) |
064af421 BP |
242 | { |
243 | struct fail_open *fo = xmalloc(sizeof *fo); | |
244 | fo->ofproto = ofproto; | |
19a87e36 | 245 | fo->connmgr = mgr; |
064af421 | 246 | fo->last_disconn_secs = 0; |
7778bd15 BP |
247 | fo->next_bogus_packet_in = LLONG_MAX; |
248 | fo->bogus_packet_counter = rconn_packet_counter_create(); | |
064af421 BP |
249 | return fo; |
250 | } | |
251 | ||
76ce9432 | 252 | /* Destroys 'fo'. */ |
064af421 BP |
253 | void |
254 | fail_open_destroy(struct fail_open *fo) | |
feb8a80b | 255 | OVS_EXCLUDED(ofproto_mutex) |
064af421 BP |
256 | { |
257 | if (fo) { | |
19a87e36 BP |
258 | if (fail_open_is_active(fo)) { |
259 | fail_open_recover(fo); | |
260 | } | |
261 | /* We don't own fo->connmgr. */ | |
7778bd15 | 262 | rconn_packet_counter_destroy(fo->bogus_packet_counter); |
064af421 BP |
263 | free(fo); |
264 | } | |
265 | } |