]>
git.proxmox.com Git - ovs.git/blob - tests/test-vconn.c
2 * Copyright (c) 2009 Nicira Networks.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include "poll-loop.h"
25 #include "socket-util.h"
41 fpv_create(const char *type
, struct fake_pvconn
*fpv
)
44 if (!strcmp(type
, "unix")) {
45 static int unix_count
= 0;
49 bind_path
= xasprintf("fake-pvconn.%d", unix_count
++);
50 fd
= make_unix_socket(SOCK_STREAM
, false, false, bind_path
, NULL
);
52 ovs_fatal(-fd
, "%s: could not bind to Unix domain socket",
56 fpv
->pvconn_name
= xasprintf("punix:%s", bind_path
);
57 fpv
->vconn_name
= xasprintf("unix:%s", bind_path
);
60 } else if (!strcmp(type
, "tcp")) {
61 struct sockaddr_in sin
;
65 /* Create TCP socket. */
66 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
68 ovs_fatal(errno
, "failed to create TCP socket");
71 /* Bind TCP socket to localhost on any available port. */
72 sin
.sin_family
= AF_INET
;
73 sin
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
74 sin
.sin_port
= htons(0);
75 if (bind(fd
, (struct sockaddr
*) &sin
, sizeof sin
) < 0) {
76 ovs_fatal(errno
, "failed to bind TCP socket");
79 /* Retrieve socket's port number. */
81 if (getsockname(fd
, (struct sockaddr
*)&sin
, &sin_len
) < 0) {
82 ovs_fatal(errno
, "failed to read TCP socket name");
84 if (sin_len
!= sizeof sin
|| sin
.sin_family
!= AF_INET
) {
85 ovs_fatal(errno
, "bad TCP socket name");
89 fpv
->pvconn_name
= xasprintf("ptcp:%"PRIu16
":127.0.0.1",
91 fpv
->vconn_name
= xasprintf("tcp:127.0.0.1:%"PRIu16
,
99 if (listen(fpv
->fd
, 0) < 0) {
100 ovs_fatal(errno
, "%s: listen failed", fpv
->vconn_name
);
105 fpv_accept(struct fake_pvconn
*fpv
)
109 fd
= accept(fpv
->fd
, NULL
, NULL
);
111 ovs_fatal(errno
, "%s: accept failed", fpv
->pvconn_name
);
117 fpv_close(struct fake_pvconn
*fpv
)
120 if (close(fpv
->fd
) < 0) {
121 ovs_fatal(errno
, "failed to close %s fake pvconn", fpv
->type
);
128 fpv_destroy(struct fake_pvconn
*fpv
)
131 free(fpv
->pvconn_name
);
132 free(fpv
->vconn_name
);
135 /* Connects to a fake_pvconn with vconn_open(), then closes the listener and
136 * verifies that vconn_connect() reports 'expected_error'. */
138 test_refuse_connection(const char *type
, int expected_error
)
140 struct fake_pvconn fpv
;
143 fpv_create(type
, &fpv
);
144 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
147 assert(vconn_connect(vconn
) == expected_error
);
152 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
153 * closes it immediately, and verifies that vconn_connect() reports
154 * 'expected_error'. */
156 test_accept_then_close(const char *type
, int expected_error
)
158 struct fake_pvconn fpv
;
161 fpv_create(type
, &fpv
);
162 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
164 close(fpv_accept(&fpv
));
166 assert(vconn_connect(vconn
) == expected_error
);
171 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
172 * reads the hello message from it, then closes the connection and verifies
173 * that vconn_connect() reports 'expected_error'. */
175 test_read_hello(const char *type
, int expected_error
)
177 struct fake_pvconn fpv
;
181 fpv_create(type
, &fpv
);
182 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
184 fd
= fpv_accept(&fpv
);
186 assert(!set_nonblocking(fd
));
188 struct ofp_header hello
;
191 retval
= read(fd
, &hello
, sizeof hello
);
192 if (retval
== sizeof hello
) {
193 assert(hello
.version
== OFP_VERSION
);
194 assert(hello
.type
== OFPT_HELLO
);
195 assert(hello
.length
== htons(sizeof hello
));
198 assert(errno
== EAGAIN
);
202 assert(vconn_connect(vconn
) == EAGAIN
);
203 vconn_run_wait(vconn
);
204 vconn_connect_wait(vconn
);
205 poll_fd_wait(fd
, POLLIN
);
209 assert(vconn_connect(vconn
) == expected_error
);
213 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
214 * sends the 'out' bytes in 'out_size' to it (presumably an OFPT_HELLO
215 * message), then verifies that vconn_connect() reports
216 * 'expect_connect_error'. */
218 test_send_hello(const char *type
, const void *out
, size_t out_size
,
219 int expect_connect_error
)
221 struct fake_pvconn fpv
;
223 bool read_hello
, connected
;
227 fpv_create(type
, &fpv
);
228 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
230 fd
= fpv_accept(&fpv
);
233 assert(write(fd
, out
, out_size
) == out_size
);
235 assert(!set_nonblocking(fd
));
237 read_hello
= connected
= false;
240 struct ofp_header hello
;
241 int retval
= read(fd
, &hello
, sizeof hello
);
242 if (retval
== sizeof hello
) {
243 assert(hello
.version
== OFP_VERSION
);
244 assert(hello
.type
== OFPT_HELLO
);
245 assert(hello
.length
== htons(sizeof hello
));
248 assert(errno
== EAGAIN
);
254 int error
= vconn_connect(vconn
);
255 if (error
== expect_connect_error
) {
264 assert(error
== EAGAIN
);
268 if (read_hello
&& connected
) {
272 vconn_run_wait(vconn
);
274 vconn_connect_wait(vconn
);
277 poll_fd_wait(fd
, POLLIN
);
282 assert(vconn_recv(vconn
, &msg
) == EOF
);
286 /* Try connecting and sending a normal hello, which should succeed. */
288 test_send_plain_hello(const char *type
)
290 struct ofp_header hello
;
292 hello
.version
= OFP_VERSION
;
293 hello
.type
= OFPT_HELLO
;
294 hello
.length
= htons(sizeof hello
);
295 hello
.xid
= htonl(0x12345678);
296 test_send_hello(type
, &hello
, sizeof hello
, 0);
299 /* Try connecting and sending an extra-long hello, which should succeed (since
300 * the specification says that implementations must accept and ignore extra
303 test_send_long_hello(const char *type
)
305 struct ofp_header hello
;
306 char buffer
[sizeof hello
* 2];
308 hello
.version
= OFP_VERSION
;
309 hello
.type
= OFPT_HELLO
;
310 hello
.length
= htons(sizeof buffer
);
311 hello
.xid
= htonl(0x12345678);
312 memset(buffer
, 0, sizeof buffer
);
313 memcpy(buffer
, &hello
, sizeof hello
);
314 test_send_hello(type
, buffer
, sizeof buffer
, 0);
317 /* Try connecting and sending an echo request instead of a hello, which should
318 * fail with EPROTO. */
320 test_send_echo_hello(const char *type
)
322 struct ofp_header echo
;
324 echo
.version
= OFP_VERSION
;
325 echo
.type
= OFPT_ECHO_REQUEST
;
326 echo
.length
= htons(sizeof echo
);
327 echo
.xid
= htonl(0x89abcdef);
328 test_send_hello(type
, &echo
, sizeof echo
, EPROTO
);
331 /* Try connecting and sending a hello packet that has its length field as 0,
332 * which should fail with EPROTO. */
334 test_send_short_hello(const char *type
)
336 struct ofp_header hello
;
338 memset(&hello
, 0, sizeof hello
);
339 test_send_hello(type
, &hello
, sizeof hello
, EPROTO
);
342 /* Try connecting and sending a hello packet that has a bad version, which
343 * should fail with EPROTO. */
345 test_send_invalid_version_hello(const char *type
)
347 struct ofp_header hello
;
349 hello
.version
= OFP_VERSION
- 1;
350 hello
.type
= OFPT_HELLO
;
351 hello
.length
= htons(sizeof hello
);
352 hello
.xid
= htonl(0x12345678);
353 test_send_hello(type
, &hello
, sizeof hello
, EPROTO
);
357 main(int argc UNUSED
, char *argv
[])
359 set_program_name(argv
[0]);
362 signal(SIGPIPE
, SIG_IGN
);
363 vlog_set_levels(VLM_ANY_MODULE
, VLF_ANY_FACILITY
, VLL_EMER
);
367 test_refuse_connection("unix", EPIPE
);
368 test_refuse_connection("tcp", ECONNRESET
);
370 test_accept_then_close("unix", EPIPE
);
371 test_accept_then_close("tcp", ECONNRESET
);
373 test_read_hello("unix", ECONNRESET
);
374 test_read_hello("tcp", ECONNRESET
);
376 test_send_plain_hello("unix");
377 test_send_plain_hello("tcp");
379 test_send_long_hello("unix");
380 test_send_long_hello("tcp");
382 test_send_echo_hello("unix");
383 test_send_echo_hello("tcp");
385 test_send_short_hello("unix");
386 test_send_short_hello("tcp");
388 test_send_invalid_version_hello("unix");
389 test_send_invalid_version_hello("tcp");