X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=tests%2Ftest-vconn.c;h=3398c4aa3d0f2d1aede5dd3bc193473d48e8c0e7;hb=e0edde6fee279cdbbf3c179f5f50adaf0c7c7f1e;hp=7f85137af4c87af6e7442e2d39aaf8aac23d1691;hpb=1d87357a1322c2faa290452c08c7f794c0be848b;p=sliver-openvswitch.git diff --git a/tests/test-vconn.c b/tests/test-vconn.c index 7f85137af..3398c4aa3 100644 --- a/tests/test-vconn.c +++ b/tests/test-vconn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Nicira Networks. + * Copyright (c) 2009, 2010, 2011 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,12 @@ #include #include #include +#include "command-line.h" +#include "openflow/openflow.h" #include "poll-loop.h" #include "socket-util.h" +#include "stream.h" +#include "stream-ssl.h" #include "timeval.h" #include "util.h" #include "vlog.h" @@ -34,94 +38,91 @@ struct fake_pvconn { const char *type; char *pvconn_name; char *vconn_name; - int fd; + struct pstream *pstream; }; +static void +check(int a, int b, const char *as, const char *file, int line) +{ + if (a != b) { + ovs_fatal(0, "%s:%d: %s is %d but should be %d", file, line, as, a, b); + } +} + + +#define CHECK(A, B) check(A, B, #A, __FILE__, __LINE__) + +static void +check_errno(int a, int b, const char *as, const char *file, int line) +{ + if (a != b) { + ovs_fatal(0, "%s:%d: %s is %d (%s) but should be %d (%s)", + file, line, as, a, strerror(abs(a)), b, strerror(abs(b))); + } +} + +#define CHECK_ERRNO(A, B) check_errno(A, B, #A, __FILE__, __LINE__) + static void fpv_create(const char *type, struct fake_pvconn *fpv) { +#ifdef HAVE_OPENSSL + if (!strcmp(type, "ssl")) { + stream_ssl_set_private_key_file("testpki-privkey.pem"); + stream_ssl_set_certificate_file("testpki-cert.pem"); + stream_ssl_set_ca_cert_file("testpki-cacert.pem", false); + } +#endif + fpv->type = type; if (!strcmp(type, "unix")) { static int unix_count = 0; char *bind_path; - int fd; bind_path = xasprintf("fake-pvconn.%d", unix_count++); - fd = make_unix_socket(SOCK_STREAM, false, false, bind_path, NULL); - if (fd < 0) { - ovs_fatal(-fd, "%s: could not bind to Unix domain socket", - bind_path); - } - fpv->pvconn_name = xasprintf("punix:%s", bind_path); fpv->vconn_name = xasprintf("unix:%s", bind_path); - fpv->fd = fd; + CHECK_ERRNO(pstream_open(fpv->pvconn_name, &fpv->pstream, + DSCP_DEFAULT), 0); free(bind_path); - } else if (!strcmp(type, "tcp")) { - struct sockaddr_in sin; - socklen_t sin_len; - int fd; - - /* Create TCP socket. */ - fd = socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - ovs_fatal(errno, "failed to create TCP socket"); - } + } else if (!strcmp(type, "tcp") || !strcmp(type, "ssl")) { + char *s, *port, *save_ptr = NULL; + char *open_name; - /* Bind TCP socket to localhost on any available port. */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_port = htons(0); - if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) { - ovs_fatal(errno, "failed to bind TCP socket"); - } + open_name = xasprintf("p%s:0:127.0.0.1", type); + CHECK_ERRNO(pstream_open(open_name, &fpv->pstream, DSCP_DEFAULT), 0); - /* Retrieve socket's port number. */ - sin_len = sizeof sin; - if (getsockname(fd, &sin, &sin_len) < 0) { - ovs_fatal(errno, "failed to read TCP socket name"); - } - if (sin_len != sizeof sin || sin.sin_family != AF_INET) { - ovs_fatal(errno, "bad TCP socket name"); - } + /* Extract bound port number from pstream name. */ + s = xstrdup(pstream_get_name(fpv->pstream)); + strtok_r(s, ":", &save_ptr); + port = strtok_r(NULL, ":", &save_ptr); /* Save info. */ - fpv->pvconn_name = xasprintf("ptcp:%"PRIu16":127.0.0.1", - ntohs(sin.sin_port)); - fpv->vconn_name = xasprintf("tcp:127.0.0.1:%"PRIu16, - ntohs(sin.sin_port)); - fpv->fd = fd; + fpv->pvconn_name = xstrdup(pstream_get_name(fpv->pstream)); + fpv->vconn_name = xasprintf("%s:127.0.0.1:%s", type, port); + + free(open_name); + free(s); } else { abort(); } - - /* Listen. */ - if (listen(fpv->fd, 0) < 0) { - ovs_fatal(errno, "%s: listen failed", fpv->vconn_name); - } } -static int +static struct stream * fpv_accept(struct fake_pvconn *fpv) { - int fd; + struct stream *stream; - fd = accept(fpv->fd, NULL, NULL); - if (fd < 0) { - ovs_fatal(errno, "%s: accept failed", fpv->pvconn_name); - } - return fd; + CHECK_ERRNO(pstream_accept_block(fpv->pstream, &stream), 0); + + return stream; } static void fpv_close(struct fake_pvconn *fpv) { - if (fpv->fd >= 0) { - if (close(fpv->fd) < 0) { - ovs_fatal(errno, "failed to close %s fake pvconn", fpv->type); - } - fpv->fd = -1; - } + pstream_close(fpv->pstream); + fpv->pstream = NULL; } static void @@ -135,15 +136,23 @@ fpv_destroy(struct fake_pvconn *fpv) /* Connects to a fake_pvconn with vconn_open(), then closes the listener and * verifies that vconn_connect() reports 'expected_error'. */ static void -test_refuse_connection(const char *type, int expected_error) +test_refuse_connection(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; + int expected_error; struct fake_pvconn fpv; struct vconn *vconn; + expected_error = (!strcmp(type, "unix") ? EPIPE + : !strcmp(type, "tcp") ? ECONNRESET + : EPROTO); + fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, + DSCP_DEFAULT), 0); fpv_close(&fpv); - assert(vconn_connect(vconn) == expected_error); + vconn_run(vconn); + CHECK_ERRNO(vconn_connect(vconn), expected_error); vconn_close(vconn); fpv_destroy(&fpv); } @@ -152,16 +161,24 @@ test_refuse_connection(const char *type, int expected_error) * closes it immediately, and verifies that vconn_connect() reports * 'expected_error'. */ static void -test_accept_then_close(const char *type, int expected_error) +test_accept_then_close(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; + int expected_error; struct fake_pvconn fpv; struct vconn *vconn; + expected_error = (!strcmp(type, "unix") ? EPIPE + : !strcmp(type, "tcp") ? ECONNRESET + : EPROTO); + fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); - close(fpv_accept(&fpv)); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, + DSCP_DEFAULT), 0); + vconn_run(vconn); + stream_close(fpv_accept(&fpv)); fpv_close(&fpv); - assert(vconn_connect(vconn) == expected_error); + CHECK_ERRNO(vconn_connect(vconn), expected_error); vconn_close(vconn); fpv_destroy(&fpv); } @@ -170,38 +187,42 @@ test_accept_then_close(const char *type, int expected_error) * reads the hello message from it, then closes the connection and verifies * that vconn_connect() reports 'expected_error'. */ static void -test_read_hello(const char *type, int expected_error) +test_read_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct fake_pvconn fpv; struct vconn *vconn; - int fd; + struct stream *stream; fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); - fd = fpv_accept(&fpv); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, + DSCP_DEFAULT), 0); + vconn_run(vconn); + stream = fpv_accept(&fpv); fpv_destroy(&fpv); - assert(!set_nonblocking(fd)); for (;;) { struct ofp_header hello; int retval; - retval = read(fd, &hello, sizeof hello); + retval = stream_recv(stream, &hello, sizeof hello); if (retval == sizeof hello) { - assert(hello.version == OFP_VERSION); - assert(hello.type == OFPT_HELLO); - assert(hello.length == htons(sizeof hello)); + CHECK(hello.version, OFP10_VERSION); + CHECK(hello.type, OFPT_HELLO); + CHECK(ntohs(hello.length), sizeof hello); break; } else { - assert(errno == EAGAIN); + CHECK_ERRNO(retval, -EAGAIN); } - assert(vconn_connect(vconn) == EAGAIN); + vconn_run(vconn); + CHECK_ERRNO(vconn_connect(vconn), EAGAIN); + vconn_run_wait(vconn); vconn_connect_wait(vconn); - poll_fd_wait(fd, POLLIN); + stream_recv_wait(stream); poll_block(); } - close(fd); - assert(vconn_connect(vconn) == expected_error); + stream_close(stream); + CHECK_ERRNO(vconn_connect(vconn), ECONNRESET); vconn_close(vconn); } @@ -217,44 +238,63 @@ test_send_hello(const char *type, const void *out, size_t out_size, struct vconn *vconn; bool read_hello, connected; struct ofpbuf *msg; - int fd; + struct stream *stream; + size_t n_sent; fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); - fd = fpv_accept(&fpv); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, + DSCP_DEFAULT), 0); + vconn_run(vconn); + stream = fpv_accept(&fpv); fpv_destroy(&fpv); - write(fd, out, out_size); - - assert(!set_nonblocking(fd)); + n_sent = 0; + while (n_sent < out_size) { + int retval; + + retval = stream_send(stream, (char *) out + n_sent, out_size - n_sent); + if (retval > 0) { + n_sent += retval; + } else if (retval == -EAGAIN) { + stream_run(stream); + vconn_run(vconn); + stream_recv_wait(stream); + vconn_connect_wait(vconn); + vconn_run_wait(vconn); + poll_block(); + } else { + ovs_fatal(0, "stream_send returned unexpected value %d", retval); + } + } read_hello = connected = false; for (;;) { if (!read_hello) { struct ofp_header hello; - int retval = read(fd, &hello, sizeof hello); + int retval = stream_recv(stream, &hello, sizeof hello); if (retval == sizeof hello) { - assert(hello.version == OFP_VERSION); - assert(hello.type == OFPT_HELLO); - assert(hello.length == htons(sizeof hello)); + CHECK(hello.version, OFP10_VERSION); + CHECK(hello.type, OFPT_HELLO); + CHECK(ntohs(hello.length), sizeof hello); read_hello = true; } else { - assert(errno == EAGAIN); + CHECK_ERRNO(retval, -EAGAIN); } } + vconn_run(vconn); if (!connected) { int error = vconn_connect(vconn); if (error == expect_connect_error) { if (!error) { connected = true; } else { - close(fd); + stream_close(stream); vconn_close(vconn); return; } } else { - assert(error == EAGAIN); + CHECK_ERRNO(error, EAGAIN); } } @@ -262,26 +302,28 @@ test_send_hello(const char *type, const void *out, size_t out_size, break; } + vconn_run_wait(vconn); if (!connected) { vconn_connect_wait(vconn); } if (!read_hello) { - poll_fd_wait(fd, POLLIN); + stream_recv_wait(stream); } poll_block(); } - close(fd); - assert(vconn_recv(vconn, &msg) == EOF); + stream_close(stream); + CHECK_ERRNO(vconn_recv(vconn, &msg), EOF); vconn_close(vconn); } /* Try connecting and sending a normal hello, which should succeed. */ static void -test_send_plain_hello(const char *type) +test_send_plain_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct ofp_header hello; - hello.version = OFP_VERSION; + hello.version = OFP10_VERSION; hello.type = OFPT_HELLO; hello.length = htons(sizeof hello); hello.xid = htonl(0x12345678); @@ -292,12 +334,13 @@ test_send_plain_hello(const char *type) * the specification says that implementations must accept and ignore extra * data). */ static void -test_send_long_hello(const char *type) +test_send_long_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct ofp_header hello; char buffer[sizeof hello * 2]; - hello.version = OFP_VERSION; + hello.version = OFP10_VERSION; hello.type = OFPT_HELLO; hello.length = htons(sizeof buffer); hello.xid = htonl(0x12345678); @@ -309,11 +352,12 @@ test_send_long_hello(const char *type) /* Try connecting and sending an echo request instead of a hello, which should * fail with EPROTO. */ static void -test_send_echo_hello(const char *type) +test_send_echo_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct ofp_header echo; - echo.version = OFP_VERSION; + echo.version = OFP10_VERSION; echo.type = OFPT_ECHO_REQUEST; echo.length = htons(sizeof echo); echo.xid = htonl(0x89abcdef); @@ -323,8 +367,9 @@ test_send_echo_hello(const char *type) /* Try connecting and sending a hello packet that has its length field as 0, * which should fail with EPROTO. */ static void -test_send_short_hello(const char *type) +test_send_short_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct ofp_header hello; memset(&hello, 0, sizeof hello); @@ -334,51 +379,41 @@ test_send_short_hello(const char *type) /* Try connecting and sending a hello packet that has a bad version, which * should fail with EPROTO. */ static void -test_send_invalid_version_hello(const char *type) +test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[]) { + const char *type = argv[1]; struct ofp_header hello; - hello.version = OFP_VERSION - 1; + hello.version = OFP10_VERSION - 1; hello.type = OFPT_HELLO; hello.length = htons(sizeof hello); hello.xid = htonl(0x12345678); test_send_hello(type, &hello, sizeof hello, EPROTO); } +static const struct command commands[] = { + {"refuse-connection", 1, 1, test_refuse_connection}, + {"accept-then-close", 1, 1, test_accept_then_close}, + {"read-hello", 1, 1, test_read_hello}, + {"send-plain-hello", 1, 1, test_send_plain_hello}, + {"send-long-hello", 1, 1, test_send_long_hello}, + {"send-echo-hello", 1, 1, test_send_echo_hello}, + {"send-short-hello", 1, 1, test_send_short_hello}, + {"send-invalid-version-hello", 1, 1, test_send_invalid_version_hello}, + {NULL, 0, 0, NULL}, +}; + int -main(int argc UNUSED, char *argv[]) +main(int argc, char *argv[]) { set_program_name(argv[0]); - time_init(); - vlog_init(); + vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_EMER); + vlog_set_levels(NULL, VLF_CONSOLE, VLL_DBG); signal(SIGPIPE, SIG_IGN); - vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_EMER); time_alarm(10); - test_refuse_connection("unix", EPIPE); - test_refuse_connection("tcp", ECONNRESET); - - test_accept_then_close("unix", EPIPE); - test_accept_then_close("tcp", ECONNRESET); - - test_read_hello("unix", ECONNRESET); - test_read_hello("tcp", ECONNRESET); - - test_send_plain_hello("unix"); - test_send_plain_hello("tcp"); - - test_send_long_hello("unix"); - test_send_long_hello("tcp"); - - test_send_echo_hello("unix"); - test_send_echo_hello("tcp"); - - test_send_short_hello("unix"); - test_send_short_hello("tcp"); - - test_send_invalid_version_hello("unix"); - test_send_invalid_version_hello("tcp"); + run_command(argc - 1, argv + 1, commands); return 0; }