X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=tests%2Ftest-vconn.c;h=ec66f862890b432387e8aba6823c38d0522691a3;hb=6dc5374435cc25bc4051b27bd52635e609a8872a;hp=34c2930a4944f53c28717e0ea29136f2e8fae48f;hpb=18b9283b986ab65f64385981f4ba8e237f658c0d;p=sliver-openvswitch.git diff --git a/tests/test-vconn.c b/tests/test-vconn.c index 34c2930a4..ec66f8628 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, 2012, 2013, 2014 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,11 +21,20 @@ #include #include #include +#include "command-line.h" +#include "fatal-signal.h" +#include "ofp-msgs.h" +#include "ofp-util.h" +#include "ofpbuf.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" +#include "ovstest.h" #undef NDEBUG #include @@ -34,94 +43,92 @@ 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) { + char *str_b = strdup(ovs_strerror(abs(b))); + ovs_fatal(0, "%s:%d: %s is %d (%s) but should be %d (%s)", + file, line, as, a, ovs_strerror(abs(a)), b, str_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, (struct sockaddr *)&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 +142,35 @@ 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]; struct fake_pvconn fpv; struct vconn *vconn; + int error; fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); + CHECK_ERRNO(vconn_open(fpv.vconn_name, 0, DSCP_DEFAULT, &vconn), 0); fpv_close(&fpv); - assert(vconn_connect(vconn) == expected_error); + vconn_run(vconn); + + error = vconn_connect_block(vconn); + if (!strcmp(type, "tcp")) { + if (error != ECONNRESET && error != EPIPE) { + ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", + error, ovs_strerror(error)); + } + } else if (!strcmp(type, "unix")) { + CHECK_ERRNO(error, EPIPE); + } else if (!strcmp(type, "ssl")) { + if (error != EPROTO && error != ECONNRESET) { + ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", + error, ovs_strerror(error)); + } + } else { + ovs_fatal(0, "invalid connection type %s", type); + } + vconn_close(vconn); fpv_destroy(&fpv); } @@ -152,16 +179,29 @@ 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]; struct fake_pvconn fpv; struct vconn *vconn; + int error; fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); - close(fpv_accept(&fpv)); + CHECK_ERRNO(vconn_open(fpv.vconn_name, 0, DSCP_DEFAULT, &vconn), 0); + vconn_run(vconn); + stream_close(fpv_accept(&fpv)); fpv_close(&fpv); - assert(vconn_connect(vconn) == expected_error); + + error = vconn_connect_block(vconn); + if (!strcmp(type, "tcp") || !strcmp(type, "unix")) { + if (error != ECONNRESET && error != EPIPE) { + ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", + error, ovs_strerror(error)); + } + } else { + CHECK_ERRNO(error, EPROTO); + } + vconn_close(vconn); fpv_destroy(&fpv); } @@ -170,38 +210,49 @@ 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; + int error; fpv_create(type, &fpv); - assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn)); - fd = fpv_accept(&fpv); + CHECK_ERRNO(vconn_open(fpv.vconn_name, 0, DSCP_DEFAULT, &vconn), 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)); + enum ofpraw raw; + + CHECK(hello.version, OFP13_VERSION); + CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0); + CHECK(raw, OFPRAW_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); + error = vconn_connect_block(vconn); + if (error != ECONNRESET && error != EPIPE) { + ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", + error, ovs_strerror(error)); + } vconn_close(vconn); } @@ -217,44 +268,65 @@ 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, 0, DSCP_DEFAULT, &vconn), 0); + vconn_run(vconn); + stream = fpv_accept(&fpv); fpv_destroy(&fpv); - assert(write(fd, out, out_size) == 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)); + enum ofpraw raw; + + CHECK(hello.version, OFP13_VERSION); + CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0); + CHECK(raw, OFPRAW_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,69 +334,71 @@ 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_block(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[]) { - struct ofp_header hello; + const char *type = argv[1]; + struct ofpbuf *hello; - hello.version = OFP_VERSION; - hello.type = OFPT_HELLO; - hello.length = htons(sizeof hello); - hello.xid = htonl(0x12345678); - test_send_hello(type, &hello, sizeof hello, 0); + hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, + htonl(0x12345678), 0); + test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); + ofpbuf_delete(hello); } /* Try connecting and sending an extra-long hello, which should succeed (since * 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[]) { - struct ofp_header hello; - char buffer[sizeof hello * 2]; - - hello.version = OFP_VERSION; - hello.type = OFPT_HELLO; - hello.length = htons(sizeof buffer); - hello.xid = htonl(0x12345678); - memset(buffer, 0, sizeof buffer); - memcpy(buffer, &hello, sizeof hello); - test_send_hello(type, buffer, sizeof buffer, 0); + const char *type = argv[1]; + struct ofpbuf *hello; + enum { EXTRA_BYTES = 8 }; + + hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, + htonl(0x12345678), EXTRA_BYTES); + ofpbuf_put_zeros(hello, EXTRA_BYTES); + ofpmsg_update_length(hello); + test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); + ofpbuf_delete(hello); } /* 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[]) { - struct ofp_header echo; + const char *type = argv[1]; + struct ofpbuf *echo; - echo.version = OFP_VERSION; - echo.type = OFPT_ECHO_REQUEST; - echo.length = htons(sizeof echo); - echo.xid = htonl(0x89abcdef); - test_send_hello(type, &echo, sizeof echo, EPROTO); + echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP13_VERSION, + htonl(0x12345678), 0); + test_send_hello(type, ofpbuf_data(echo), ofpbuf_size(echo), EPROTO); + ofpbuf_delete(echo); } /* 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 +408,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[]) { - struct ofp_header hello; - - hello.version = OFP_VERSION - 1; - hello.type = OFPT_HELLO; - hello.length = htons(sizeof hello); - hello.xid = htonl(0x12345678); - test_send_hello(type, &hello, sizeof hello, EPROTO); + const char *type = argv[1]; + struct ofpbuf *hello; + + hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, + htonl(0x12345678), 0); + ((struct ofp_header *) ofpbuf_data(hello))->version = 0; + test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO); + ofpbuf_delete(hello); } -int -main(int argc UNUSED, char *argv[]) +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}, +}; + +static void +test_vconn_main(int argc, char *argv[]) { set_program_name(argv[0]); - time_init(); - vlog_init(); - signal(SIGPIPE, SIG_IGN); - vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_EMER); + vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_EMER); + vlog_set_levels(NULL, VLF_CONSOLE, VLL_DBG); + fatal_ignore_sigpipe(); 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"); - - return 0; + run_command(argc - 1, argv + 1, commands); } + +OVSTEST_REGISTER("test-vconn", test_vconn_main);