Factor learning switch out of controller into library.
[sliver-openvswitch.git] / lib / rconn.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  * 
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  * 
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include "rconn.h"
35 #include <assert.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "buffer.h"
40 #include "poll-loop.h"
41 #include "ofp-print.h"
42 #include "util.h"
43 #include "vconn.h"
44
45 #define THIS_MODULE VLM_rconn
46 #include "vlog.h"
47
48 /* A reliable connection to an OpenFlow switch or controller.
49  *
50  * See the large comment in rconn.h for more information. */
51 struct rconn {
52     bool reliable;
53     char *name;
54     struct vconn *vconn;
55     bool connected;
56     struct queue txq;
57     int txq_limit;
58     time_t backoff_deadline;
59     int backoff;
60     time_t last_connected;
61     unsigned int packets_sent;
62 };
63
64 static struct rconn *create_rconn(const char *name, int txq_limit,
65                                   struct vconn *);
66 static int try_send(struct rconn *);
67 static void disconnect(struct rconn *, int error);
68
69 /* Creates and returns a new rconn that connects (and re-connects as necessary)
70  * to the vconn named 'name'.
71  *
72  * 'txq_limit' is the maximum length of the send queue, in packets. */
73 struct rconn *
74 rconn_new(const char *name, int txq_limit) 
75 {
76     return create_rconn(name, txq_limit, NULL);
77 }
78
79 /* Creates and returns a new rconn that is initially connected to 'vconn' and
80  * has the given 'name'.  The rconn will not re-connect after the connection
81  * drops.
82  *
83  * 'txq_limit' is the maximum length of the send queue, in packets. */
84 struct rconn *
85 rconn_new_from_vconn(const char *name, int txq_limit, struct vconn *vconn)
86 {
87     assert(vconn != NULL);
88     return create_rconn(name, txq_limit, vconn);
89 }
90
91 /* Disconnects 'rc' and frees the underlying storage. */
92 void
93 rconn_destroy(struct rconn *rc)
94 {
95     if (rc) {
96         free(rc->name);
97         vconn_close(rc->vconn);
98         queue_destroy(&rc->txq);
99         free(rc);
100     }
101 }
102
103 /* Performs whatever activities are necessary to maintain 'rc': if 'rc' is
104  * disconnected, attempts to (re)connect, backing off as necessary; if 'rc' is
105  * connected, attempts to send packets in the send queue, if any. */
106 void
107 rconn_run(struct rconn *rc)
108 {
109     if (!rc->vconn) {
110         if (rc->reliable && time(0) >= rc->backoff_deadline) {
111             int retval;
112
113             retval = vconn_open(rc->name, &rc->vconn);
114             if (!retval) {
115                 rc->backoff_deadline = time(0) + rc->backoff;
116                 rc->connected = false;
117             } else {
118                 VLOG_WARN("%s: connection failed (%s)",
119                           rc->name, strerror(retval)); 
120                 disconnect(rc, 0);
121             }
122         }
123     } else if (!rc->connected) {
124         int error = vconn_connect(rc->vconn);
125         if (!error) {
126             VLOG_WARN("%s: connected", rc->name);
127             if (vconn_is_passive(rc->vconn)) {
128                 fatal(0, "%s: passive vconn not supported in switch",
129                       rc->name);
130             }
131             rc->connected = true;
132         } else if (error != EAGAIN) {
133             VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(error));
134             disconnect(rc, 0);
135         }
136     } else {
137         while (rc->txq.n > 0) {
138             int error = try_send(rc);
139             if (error == EAGAIN) {
140                 break;
141             } else if (error) {
142                 disconnect(rc, error);
143                 return;
144             }
145         }
146     }
147 }
148
149 /* Causes the next call to poll_block() to wake up when rconn_run() should be
150  * called on 'rc'. */
151 void
152 rconn_run_wait(struct rconn *rc) 
153 {
154     if (rc->vconn) {
155         if (rc->txq.n) {
156             vconn_wait(rc->vconn, WAIT_SEND);
157         }
158     } else {
159         poll_timer_wait((rc->backoff_deadline - time(0)) * 1000);
160     }
161 }
162
163 /* Attempts to receive a packet from 'rc'.  If successful, returns the packet;
164  * otherwise, returns a null pointer.  The caller is responsible for freeing
165  * the packet (with buffer_delete()). */
166 struct buffer *
167 rconn_recv(struct rconn *rc)
168 {
169     if (rc->vconn && rc->connected) {
170         struct buffer *buffer;
171         int error = vconn_recv(rc->vconn, &buffer);
172         if (!error) {
173             rc->last_connected = time(0);
174             return buffer;
175         } else if (error != EAGAIN) {
176             disconnect(rc, error); 
177         }
178     }
179     return NULL;
180 }
181
182 /* Causes the next call to poll_block() to wake up when a packet may be ready
183  * to be received by vconn_recv() on 'rc'.  */
184 void
185 rconn_recv_wait(struct rconn *rc) 
186 {
187     if (rc->vconn) {
188         vconn_wait(rc->vconn, WAIT_RECV);
189     }
190 }
191
192 /* Sends 'b' on 'rc'.  Returns 0 if successful, EAGAIN if at least 'txq_limit'
193  * packets are already queued, otherwise a positive errno value. */
194 int
195 do_send(struct rconn *rc, struct buffer *b, int txq_limit)
196 {
197     if (rc->vconn) {
198         if (rc->txq.n < txq_limit) {
199             queue_push_tail(&rc->txq, b);
200             if (rc->txq.n == 1) {
201                 try_send(rc);
202             }
203             return 0;
204         } else {
205             return EAGAIN;
206         }
207     } else {
208         return ENOTCONN;
209     }
210 }
211
212 /* Sends 'b' on 'rc'.  Returns 0 if successful, EAGAIN if the send queue is
213  * full, or ENOTCONN if 'rc' is not currently connected.
214  *
215  * There is no rconn_send_wait() function: an rconn has a send queue that it
216  * takes care of sending if you call rconn_wait(), which will have the side
217  * effect of waking up poll_block(). */
218 int
219 rconn_send(struct rconn *rc, struct buffer *b)
220 {
221     return do_send(rc, b, rc->txq_limit);
222 }
223
224 /* Sends 'b' on 'rc'.  Returns 0 if successful, EAGAIN if the send queue is
225  * full, otherwise a positive errno value.
226  *
227  * Compared to rconn_send(), this function relaxes the queue limit, allowing
228  * more packets than usual to be queued. */
229 int
230 rconn_force_send(struct rconn *rc, struct buffer *b)
231 {
232     return do_send(rc, b, 2 * rc->txq_limit);
233 }
234
235 /* Returns true if 'rc''s send buffer is full,
236  * false if it has room for at least one more packet. */
237 bool
238 rconn_is_full(const struct rconn *rc) 
239 {
240     return rc->txq.n >= rc->txq_limit;
241 }
242
243 /* Returns the total number of packets successfully sent on the underlying
244  * vconn.  A packet is not counted as sent while it is still queued in the
245  * rconn, only when it has been successfuly passed to the vconn.  */
246 unsigned int
247 rconn_packets_sent(const struct rconn *rc) 
248 {
249     return rc->packets_sent;
250 }
251
252 /* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */
253 const char *
254 rconn_get_name(const struct rconn *rc) 
255 {
256     return rc->name;
257 }
258
259 /* Returns true if 'rconn' is connected or in the process of reconnecting,
260  * false if 'rconn' is disconnected and will not be reconnected. */
261 bool
262 rconn_is_alive(const struct rconn *rconn) 
263 {
264     return rconn->reliable || rconn->vconn;
265 }
266
267 /* Returns true if 'rconn' is connected, false otherwise. */
268 bool
269 rconn_is_connected(const struct rconn *rconn)
270 {
271     return rconn->vconn && !vconn_connect(rconn->vconn);
272 }
273
274 /* Returns 0 if 'rconn' is connected, otherwise the number of seconds that it
275  * has been disconnected. */
276 int
277 rconn_disconnected_duration(const struct rconn *rconn) 
278 {
279     return rconn_is_connected(rconn) ? 0 : time(0) - rconn->last_connected;
280 }
281 \f
282 static struct rconn *
283 create_rconn(const char *name, int txq_limit, struct vconn *vconn)
284 {
285     struct rconn *rc = xmalloc(sizeof *rc);
286     assert(txq_limit > 0);
287     rc->reliable = vconn == NULL;
288     rc->connected = vconn != NULL;
289     rc->name = xstrdup(name);
290     rc->vconn = vconn;
291     queue_init(&rc->txq);
292     rc->txq_limit = txq_limit;
293     rc->backoff_deadline = 0;
294     rc->backoff = 0;
295     rc->last_connected = time(0);
296     rc->packets_sent = 0;
297     return rc;
298 }
299
300 /* Tries to send a packet from 'rc''s send buffer.  Returns 0 if successful,
301  * otherwise a positive errno value. */
302 static int
303 try_send(struct rconn *rc)
304 {
305     int retval = 0;
306     struct buffer *next = rc->txq.head->next;
307     retval = vconn_send(rc->vconn, rc->txq.head);
308     if (retval) {
309         return retval;
310     }
311     rc->packets_sent++;
312     queue_advance_head(&rc->txq, next);
313     return 0;
314 }
315
316 /* Disconnects 'rc'.  'error' is used only for logging purposes.  If it is
317  * nonzero, then it should be EOF to indicate the connection was closed by the
318  * peer in a normal fashion or a positive errno value. */
319 static void
320 disconnect(struct rconn *rc, int error) 
321 {
322     time_t now = time(0);
323     
324     if (rc->vconn) {
325         if (error > 0) {
326             VLOG_WARN("%s: connection dropped (%s)",
327                       rc->name, strerror(error)); 
328         } else if (error == EOF) {
329             if (rc->reliable) {
330                 VLOG_WARN("%s: connection closed", rc->name);
331             }
332         } else {
333             VLOG_WARN("%s: connection dropped", rc->name); 
334         }
335         vconn_close(rc->vconn);
336         rc->vconn = NULL;
337         queue_clear(&rc->txq);
338     }
339
340     if (now >= rc->backoff_deadline) {
341         rc->backoff = 1;
342     } else {
343         rc->backoff = MIN(60, MAX(1, 2 * rc->backoff));
344         VLOG_WARN("%s: waiting %d seconds before reconnect\n",
345                   rc->name, rc->backoff);
346     }
347     rc->backoff_deadline = now + rc->backoff;
348 }