]>
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
, &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
));
146 assert(vconn_connect(vconn
) == expected_error
);
151 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
152 * closes it immediately, and verifies that vconn_connect() reports
153 * 'expected_error'. */
155 test_accept_then_close(const char *type
, int expected_error
)
157 struct fake_pvconn fpv
;
160 fpv_create(type
, &fpv
);
161 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
162 close(fpv_accept(&fpv
));
164 assert(vconn_connect(vconn
) == expected_error
);
169 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
170 * reads the hello message from it, then closes the connection and verifies
171 * that vconn_connect() reports 'expected_error'. */
173 test_read_hello(const char *type
, int expected_error
)
175 struct fake_pvconn fpv
;
179 fpv_create(type
, &fpv
);
180 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
181 fd
= fpv_accept(&fpv
);
183 assert(!set_nonblocking(fd
));
185 struct ofp_header hello
;
188 retval
= read(fd
, &hello
, sizeof hello
);
189 if (retval
== sizeof hello
) {
190 assert(hello
.version
== OFP_VERSION
);
191 assert(hello
.type
== OFPT_HELLO
);
192 assert(hello
.length
== htons(sizeof hello
));
195 assert(errno
== EAGAIN
);
198 assert(vconn_connect(vconn
) == EAGAIN
);
199 vconn_connect_wait(vconn
);
200 poll_fd_wait(fd
, POLLIN
);
204 assert(vconn_connect(vconn
) == expected_error
);
208 /* Connects to a fake_pvconn with vconn_open(), accepts that connection and
209 * sends the 'out' bytes in 'out_size' to it (presumably an OFPT_HELLO
210 * message), then verifies that vconn_connect() reports
211 * 'expect_connect_error'. */
213 test_send_hello(const char *type
, const void *out
, size_t out_size
,
214 int expect_connect_error
)
216 struct fake_pvconn fpv
;
218 bool read_hello
, connected
;
222 fpv_create(type
, &fpv
);
223 assert(!vconn_open(fpv
.vconn_name
, OFP_VERSION
, &vconn
));
224 fd
= fpv_accept(&fpv
);
227 write(fd
, out
, out_size
);
229 assert(!set_nonblocking(fd
));
231 read_hello
= connected
= false;
234 struct ofp_header hello
;
235 int retval
= read(fd
, &hello
, sizeof hello
);
236 if (retval
== sizeof hello
) {
237 assert(hello
.version
== OFP_VERSION
);
238 assert(hello
.type
== OFPT_HELLO
);
239 assert(hello
.length
== htons(sizeof hello
));
242 assert(errno
== EAGAIN
);
247 int error
= vconn_connect(vconn
);
248 if (error
== expect_connect_error
) {
257 assert(error
== EAGAIN
);
261 if (read_hello
&& connected
) {
266 vconn_connect_wait(vconn
);
269 poll_fd_wait(fd
, POLLIN
);
274 assert(vconn_recv(vconn
, &msg
) == EOF
);
278 /* Try connecting and sending a normal hello, which should succeed. */
280 test_send_plain_hello(const char *type
)
282 struct ofp_header hello
;
284 hello
.version
= OFP_VERSION
;
285 hello
.type
= OFPT_HELLO
;
286 hello
.length
= htons(sizeof hello
);
287 hello
.xid
= htonl(0x12345678);
288 test_send_hello(type
, &hello
, sizeof hello
, 0);
291 /* Try connecting and sending an extra-long hello, which should succeed (since
292 * the specification says that implementations must accept and ignore extra
295 test_send_long_hello(const char *type
)
297 struct ofp_header hello
;
298 char buffer
[sizeof hello
* 2];
300 hello
.version
= OFP_VERSION
;
301 hello
.type
= OFPT_HELLO
;
302 hello
.length
= htons(sizeof buffer
);
303 hello
.xid
= htonl(0x12345678);
304 memset(buffer
, 0, sizeof buffer
);
305 memcpy(buffer
, &hello
, sizeof hello
);
306 test_send_hello(type
, buffer
, sizeof buffer
, 0);
309 /* Try connecting and sending an echo request instead of a hello, which should
310 * fail with EPROTO. */
312 test_send_echo_hello(const char *type
)
314 struct ofp_header echo
;
316 echo
.version
= OFP_VERSION
;
317 echo
.type
= OFPT_ECHO_REQUEST
;
318 echo
.length
= htons(sizeof echo
);
319 echo
.xid
= htonl(0x89abcdef);
320 test_send_hello(type
, &echo
, sizeof echo
, EPROTO
);
323 /* Try connecting and sending a hello packet that has its length field as 0,
324 * which should fail with EPROTO. */
326 test_send_short_hello(const char *type
)
328 struct ofp_header hello
;
330 memset(&hello
, 0, sizeof hello
);
331 test_send_hello(type
, &hello
, sizeof hello
, EPROTO
);
334 /* Try connecting and sending a hello packet that has a bad version, which
335 * should fail with EPROTO. */
337 test_send_invalid_version_hello(const char *type
)
339 struct ofp_header hello
;
341 hello
.version
= OFP_VERSION
- 1;
342 hello
.type
= OFPT_HELLO
;
343 hello
.length
= htons(sizeof hello
);
344 hello
.xid
= htonl(0x12345678);
345 test_send_hello(type
, &hello
, sizeof hello
, EPROTO
);
349 main(int argc UNUSED
, char *argv
[])
351 set_program_name(argv
[0]);
354 signal(SIGPIPE
, SIG_IGN
);
355 vlog_set_levels(VLM_ANY_MODULE
, VLF_ANY_FACILITY
, VLL_EMER
);
359 test_refuse_connection("unix", EPIPE
);
360 test_refuse_connection("tcp", ECONNRESET
);
362 test_accept_then_close("unix", EPIPE
);
363 test_accept_then_close("tcp", ECONNRESET
);
365 test_read_hello("unix", ECONNRESET
);
366 test_read_hello("tcp", ECONNRESET
);
368 test_send_plain_hello("unix");
369 test_send_plain_hello("tcp");
371 test_send_long_hello("unix");
372 test_send_long_hello("tcp");
374 test_send_echo_hello("unix");
375 test_send_echo_hello("tcp");
377 test_send_short_hello("unix");
378 test_send_short_hello("tcp");
380 test_send_invalid_version_hello("unix");
381 test_send_invalid_version_hello("tcp");