]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
e0edde6f | 2 | * Copyright (c) 2008, 2009, 2010, 2011 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> | |
064af421 BP |
18 | #include <assert.h> |
19 | #include <errno.h> | |
20 | #include <poll.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
23 | #include <sys/types.h> | |
24 | #include <unistd.h> | |
56192221 | 25 | #include "fatal-signal.h" |
064af421 BP |
26 | #include "leak-checker.h" |
27 | #include "ofpbuf.h" | |
28 | #include "openflow/openflow.h" | |
29 | #include "poll-loop.h" | |
30 | #include "socket-util.h" | |
fe55ad15 | 31 | #include "stream.h" |
064af421 BP |
32 | #include "util.h" |
33 | #include "vconn-provider.h" | |
34 | #include "vconn.h" | |
064af421 | 35 | #include "vlog.h" |
5136ce49 | 36 | |
d98e6007 | 37 | VLOG_DEFINE_THIS_MODULE(vconn_stream); |
064af421 BP |
38 | |
39 | /* Active stream socket vconn. */ | |
40 | ||
fe55ad15 | 41 | struct vconn_stream |
064af421 BP |
42 | { |
43 | struct vconn vconn; | |
fe55ad15 | 44 | struct stream *stream; |
064af421 BP |
45 | struct ofpbuf *rxbuf; |
46 | struct ofpbuf *txbuf; | |
1e3c0047 | 47 | int n_packets; |
064af421 BP |
48 | }; |
49 | ||
50 | static struct vconn_class stream_vconn_class; | |
51 | ||
52 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 25); | |
53 | ||
fe55ad15 | 54 | static void vconn_stream_clear_txbuf(struct vconn_stream *); |
064af421 | 55 | |
fe55ad15 BP |
56 | static struct vconn * |
57 | vconn_stream_new(struct stream *stream, int connect_status) | |
064af421 | 58 | { |
fe55ad15 | 59 | struct vconn_stream *s; |
064af421 BP |
60 | |
61 | s = xmalloc(sizeof *s); | |
fe55ad15 BP |
62 | vconn_init(&s->vconn, &stream_vconn_class, connect_status, |
63 | stream_get_name(stream)); | |
64 | s->stream = stream; | |
064af421 | 65 | s->txbuf = NULL; |
064af421 | 66 | s->rxbuf = NULL; |
1e3c0047 | 67 | s->n_packets = 0; |
64616112 TN |
68 | s->vconn.remote_ip = stream_get_remote_ip(stream); |
69 | s->vconn.remote_port = stream_get_remote_port(stream); | |
70 | s->vconn.local_ip = stream_get_local_ip(stream); | |
71 | s->vconn.local_port = stream_get_local_port(stream); | |
fe55ad15 BP |
72 | return &s->vconn; |
73 | } | |
74 | ||
75 | /* Creates a new vconn that will send and receive data on a stream named 'name' | |
76 | * and stores a pointer to the vconn in '*vconnp'. | |
77 | * | |
78 | * Returns 0 if successful, otherwise a positive errno value. */ | |
79 | static int | |
f39dc942 | 80 | vconn_stream_open(const char *name, char *suffix OVS_UNUSED, |
f125905c | 81 | struct vconn **vconnp, uint8_t dscp) |
fe55ad15 BP |
82 | { |
83 | struct stream *stream; | |
fe55ad15 BP |
84 | int error; |
85 | ||
f39dc942 | 86 | error = stream_open_with_default_ports(name, OFP_TCP_PORT, OFP_SSL_PORT, |
f125905c | 87 | &stream, dscp); |
b0bfeb3e BP |
88 | if (!error) { |
89 | error = stream_connect(stream); | |
90 | if (!error || error == EAGAIN) { | |
91 | *vconnp = vconn_stream_new(stream, error); | |
92 | return 0; | |
93 | } | |
fe55ad15 BP |
94 | } |
95 | ||
b0bfeb3e BP |
96 | stream_close(stream); |
97 | return error; | |
064af421 BP |
98 | } |
99 | ||
fe55ad15 BP |
100 | static struct vconn_stream * |
101 | vconn_stream_cast(struct vconn *vconn) | |
064af421 | 102 | { |
fe55ad15 | 103 | return CONTAINER_OF(vconn, struct vconn_stream, vconn); |
064af421 BP |
104 | } |
105 | ||
106 | static void | |
fe55ad15 | 107 | vconn_stream_close(struct vconn *vconn) |
064af421 | 108 | { |
fe55ad15 | 109 | struct vconn_stream *s = vconn_stream_cast(vconn); |
1e3c0047 BP |
110 | |
111 | if ((vconn->error == EPROTO || s->n_packets < 1) && s->rxbuf) { | |
112 | stream_report_content(s->rxbuf->data, s->rxbuf->size, STREAM_OPENFLOW, | |
113 | THIS_MODULE, vconn_get_name(vconn)); | |
114 | } | |
115 | ||
fe55ad15 BP |
116 | stream_close(s->stream); |
117 | vconn_stream_clear_txbuf(s); | |
064af421 | 118 | ofpbuf_delete(s->rxbuf); |
064af421 BP |
119 | free(s); |
120 | } | |
121 | ||
122 | static int | |
fe55ad15 | 123 | vconn_stream_connect(struct vconn *vconn) |
064af421 | 124 | { |
fe55ad15 BP |
125 | struct vconn_stream *s = vconn_stream_cast(vconn); |
126 | return stream_connect(s->stream); | |
064af421 BP |
127 | } |
128 | ||
129 | static int | |
c088c3be | 130 | vconn_stream_recv__(struct vconn_stream *s, int rx_len) |
064af421 | 131 | { |
c088c3be BP |
132 | struct ofpbuf *rx = s->rxbuf; |
133 | int want_bytes, retval; | |
064af421 | 134 | |
c088c3be | 135 | want_bytes = rx_len - rx->size; |
064af421 | 136 | ofpbuf_prealloc_tailroom(rx, want_bytes); |
fe55ad15 | 137 | retval = stream_recv(s->stream, ofpbuf_tail(rx), want_bytes); |
064af421 BP |
138 | if (retval > 0) { |
139 | rx->size += retval; | |
c088c3be | 140 | return retval == want_bytes ? 0 : EAGAIN; |
064af421 BP |
141 | } else if (retval == 0) { |
142 | if (rx->size) { | |
143 | VLOG_ERR_RL(&rl, "connection dropped mid-packet"); | |
144 | return EPROTO; | |
064af421 | 145 | } |
c088c3be | 146 | return EOF; |
064af421 | 147 | } else { |
fe55ad15 | 148 | return -retval; |
064af421 BP |
149 | } |
150 | } | |
151 | ||
c088c3be BP |
152 | static int |
153 | vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp) | |
154 | { | |
155 | struct vconn_stream *s = vconn_stream_cast(vconn); | |
156 | const struct ofp_header *oh; | |
157 | int rx_len; | |
158 | ||
159 | /* Allocate new receive buffer if we don't have one. */ | |
160 | if (s->rxbuf == NULL) { | |
161 | s->rxbuf = ofpbuf_new(1564); | |
162 | } | |
163 | ||
164 | /* Read ofp_header. */ | |
165 | if (s->rxbuf->size < sizeof(struct ofp_header)) { | |
166 | int retval = vconn_stream_recv__(s, sizeof(struct ofp_header)); | |
167 | if (retval) { | |
168 | return retval; | |
169 | } | |
170 | } | |
171 | ||
172 | /* Read payload. */ | |
173 | oh = s->rxbuf->data; | |
174 | rx_len = ntohs(oh->length); | |
175 | if (rx_len < sizeof(struct ofp_header)) { | |
b56042ac | 176 | VLOG_ERR_RL(&rl, "received too-short ofp_header (%d bytes)", rx_len); |
c088c3be BP |
177 | return EPROTO; |
178 | } else if (s->rxbuf->size < rx_len) { | |
179 | int retval = vconn_stream_recv__(s, rx_len); | |
180 | if (retval) { | |
181 | return retval; | |
182 | } | |
183 | } | |
184 | ||
1e3c0047 | 185 | s->n_packets++; |
c088c3be BP |
186 | *bufferp = s->rxbuf; |
187 | s->rxbuf = NULL; | |
188 | return 0; | |
189 | } | |
190 | ||
064af421 | 191 | static void |
fe55ad15 | 192 | vconn_stream_clear_txbuf(struct vconn_stream *s) |
064af421 BP |
193 | { |
194 | ofpbuf_delete(s->txbuf); | |
195 | s->txbuf = NULL; | |
064af421 BP |
196 | } |
197 | ||
198 | static int | |
fe55ad15 | 199 | vconn_stream_send(struct vconn *vconn, struct ofpbuf *buffer) |
064af421 | 200 | { |
fe55ad15 | 201 | struct vconn_stream *s = vconn_stream_cast(vconn); |
064af421 BP |
202 | ssize_t retval; |
203 | ||
204 | if (s->txbuf) { | |
205 | return EAGAIN; | |
206 | } | |
207 | ||
fe55ad15 | 208 | retval = stream_send(s->stream, buffer->data, buffer->size); |
064af421 BP |
209 | if (retval == buffer->size) { |
210 | ofpbuf_delete(buffer); | |
211 | return 0; | |
fe55ad15 | 212 | } else if (retval >= 0 || retval == -EAGAIN) { |
064af421 BP |
213 | leak_checker_claim(buffer); |
214 | s->txbuf = buffer; | |
215 | if (retval > 0) { | |
216 | ofpbuf_pull(buffer, retval); | |
217 | } | |
064af421 BP |
218 | return 0; |
219 | } else { | |
fe55ad15 | 220 | return -retval; |
064af421 BP |
221 | } |
222 | } | |
223 | ||
60cb3eb8 | 224 | static void |
fe55ad15 | 225 | vconn_stream_run(struct vconn *vconn) |
60cb3eb8 | 226 | { |
fe55ad15 BP |
227 | struct vconn_stream *s = vconn_stream_cast(vconn); |
228 | ssize_t retval; | |
60cb3eb8 | 229 | |
12d68589 | 230 | stream_run(s->stream); |
60cb3eb8 BP |
231 | if (!s->txbuf) { |
232 | return; | |
233 | } | |
234 | ||
fe55ad15 BP |
235 | retval = stream_send(s->stream, s->txbuf->data, s->txbuf->size); |
236 | if (retval < 0) { | |
237 | if (retval != -EAGAIN) { | |
238 | VLOG_ERR_RL(&rl, "send: %s", strerror(-retval)); | |
239 | vconn_stream_clear_txbuf(s); | |
60cb3eb8 BP |
240 | return; |
241 | } | |
fe55ad15 BP |
242 | } else if (retval > 0) { |
243 | ofpbuf_pull(s->txbuf, retval); | |
60cb3eb8 | 244 | if (!s->txbuf->size) { |
fe55ad15 | 245 | vconn_stream_clear_txbuf(s); |
60cb3eb8 BP |
246 | return; |
247 | } | |
248 | } | |
249 | } | |
250 | ||
251 | static void | |
fe55ad15 | 252 | vconn_stream_run_wait(struct vconn *vconn) |
60cb3eb8 | 253 | { |
fe55ad15 | 254 | struct vconn_stream *s = vconn_stream_cast(vconn); |
60cb3eb8 | 255 | |
12d68589 | 256 | stream_run_wait(s->stream); |
60cb3eb8 | 257 | if (s->txbuf) { |
fe55ad15 | 258 | stream_send_wait(s->stream); |
60cb3eb8 BP |
259 | } |
260 | } | |
261 | ||
064af421 | 262 | static void |
fe55ad15 | 263 | vconn_stream_wait(struct vconn *vconn, enum vconn_wait_type wait) |
064af421 | 264 | { |
fe55ad15 | 265 | struct vconn_stream *s = vconn_stream_cast(vconn); |
064af421 BP |
266 | switch (wait) { |
267 | case WAIT_CONNECT: | |
fe55ad15 | 268 | stream_connect_wait(s->stream); |
064af421 BP |
269 | break; |
270 | ||
271 | case WAIT_SEND: | |
272 | if (!s->txbuf) { | |
fe55ad15 | 273 | stream_send_wait(s->stream); |
064af421 | 274 | } else { |
fe55ad15 BP |
275 | /* Nothing to do: need to drain txbuf first. |
276 | * vconn_stream_run_wait() will arrange to wake up when there room | |
277 | * to send data, so there's no point in calling poll_fd_wait() | |
278 | * redundantly here. */ | |
064af421 BP |
279 | } |
280 | break; | |
281 | ||
282 | case WAIT_RECV: | |
fe55ad15 | 283 | stream_recv_wait(s->stream); |
064af421 BP |
284 | break; |
285 | ||
286 | default: | |
287 | NOT_REACHED(); | |
288 | } | |
289 | } | |
064af421 BP |
290 | \f |
291 | /* Passive stream socket vconn. */ | |
292 | ||
fe55ad15 | 293 | struct pvconn_pstream |
064af421 BP |
294 | { |
295 | struct pvconn pvconn; | |
fe55ad15 | 296 | struct pstream *pstream; |
064af421 BP |
297 | }; |
298 | ||
299 | static struct pvconn_class pstream_pvconn_class; | |
300 | ||
fe55ad15 BP |
301 | static struct pvconn_pstream * |
302 | pvconn_pstream_cast(struct pvconn *pvconn) | |
064af421 | 303 | { |
fe55ad15 | 304 | return CONTAINER_OF(pvconn, struct pvconn_pstream, pvconn); |
064af421 BP |
305 | } |
306 | ||
fe55ad15 BP |
307 | /* Creates a new pvconn named 'name' that will accept new connections using |
308 | * pstream_accept() and stores a pointer to the pvconn in '*pvconnp'. | |
56192221 BP |
309 | * |
310 | * Returns 0 if successful, otherwise a positive errno value. (The current | |
311 | * implementation never fails.) */ | |
fe55ad15 | 312 | static int |
f39dc942 | 313 | pvconn_pstream_listen(const char *name, char *suffix OVS_UNUSED, |
f125905c | 314 | struct pvconn **pvconnp, uint8_t dscp) |
064af421 | 315 | { |
fe55ad15 BP |
316 | struct pvconn_pstream *ps; |
317 | struct pstream *pstream; | |
fe55ad15 BP |
318 | int error; |
319 | ||
f39dc942 | 320 | error = pstream_open_with_default_ports(name, OFP_TCP_PORT, OFP_SSL_PORT, |
f125905c | 321 | &pstream, dscp); |
fe55ad15 BP |
322 | if (error) { |
323 | return error; | |
324 | } | |
325 | ||
326 | ps = xmalloc(sizeof *ps); | |
f39dc942 | 327 | pvconn_init(&ps->pvconn, &pstream_pvconn_class, name); |
fe55ad15 | 328 | ps->pstream = pstream; |
064af421 BP |
329 | *pvconnp = &ps->pvconn; |
330 | return 0; | |
331 | } | |
332 | ||
333 | static void | |
fe55ad15 | 334 | pvconn_pstream_close(struct pvconn *pvconn) |
064af421 | 335 | { |
fe55ad15 BP |
336 | struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn); |
337 | pstream_close(ps->pstream); | |
064af421 BP |
338 | free(ps); |
339 | } | |
340 | ||
341 | static int | |
fe55ad15 | 342 | pvconn_pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp) |
064af421 | 343 | { |
fe55ad15 BP |
344 | struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn); |
345 | struct stream *stream; | |
346 | int error; | |
347 | ||
348 | error = pstream_accept(ps->pstream, &stream); | |
349 | if (error) { | |
350 | if (error != EAGAIN) { | |
351 | VLOG_DBG_RL(&rl, "%s: accept: %s", | |
352 | pstream_get_name(ps->pstream), strerror(error)); | |
064af421 | 353 | } |
fe55ad15 | 354 | return error; |
064af421 BP |
355 | } |
356 | ||
fe55ad15 BP |
357 | *new_vconnp = vconn_stream_new(stream, 0); |
358 | return 0; | |
064af421 BP |
359 | } |
360 | ||
361 | static void | |
fe55ad15 | 362 | pvconn_pstream_wait(struct pvconn *pvconn) |
064af421 | 363 | { |
fe55ad15 BP |
364 | struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn); |
365 | pstream_wait(ps->pstream); | |
064af421 | 366 | } |
56192221 | 367 | \f |
fe55ad15 BP |
368 | /* Stream-based vconns and pvconns. */ |
369 | ||
740bc6a4 BP |
370 | #define STREAM_INIT(NAME) \ |
371 | { \ | |
372 | NAME, \ | |
fe55ad15 BP |
373 | vconn_stream_open, \ |
374 | vconn_stream_close, \ | |
375 | vconn_stream_connect, \ | |
376 | vconn_stream_recv, \ | |
377 | vconn_stream_send, \ | |
378 | vconn_stream_run, \ | |
379 | vconn_stream_run_wait, \ | |
380 | vconn_stream_wait, \ | |
740bc6a4 | 381 | } |
fe55ad15 | 382 | |
740bc6a4 BP |
383 | #define PSTREAM_INIT(NAME) \ |
384 | { \ | |
385 | NAME, \ | |
fe55ad15 BP |
386 | pvconn_pstream_listen, \ |
387 | pvconn_pstream_close, \ | |
388 | pvconn_pstream_accept, \ | |
389 | pvconn_pstream_wait \ | |
740bc6a4 | 390 | } |
fe55ad15 | 391 | |
740bc6a4 BP |
392 | static struct vconn_class stream_vconn_class = STREAM_INIT("stream"); |
393 | static struct pvconn_class pstream_pvconn_class = PSTREAM_INIT("pstream"); | |
fe55ad15 | 394 | |
740bc6a4 BP |
395 | struct vconn_class tcp_vconn_class = STREAM_INIT("tcp"); |
396 | struct pvconn_class ptcp_pvconn_class = PSTREAM_INIT("ptcp"); | |
fe55ad15 | 397 | |
740bc6a4 BP |
398 | struct vconn_class unix_vconn_class = STREAM_INIT("unix"); |
399 | struct pvconn_class punix_pvconn_class = PSTREAM_INIT("punix"); | |
fe55ad15 BP |
400 | |
401 | #ifdef HAVE_OPENSSL | |
740bc6a4 BP |
402 | struct vconn_class ssl_vconn_class = STREAM_INIT("ssl"); |
403 | struct pvconn_class pssl_pvconn_class = PSTREAM_INIT("pssl"); | |
fe55ad15 | 404 | #endif |