qemu/tests/qtest/test-filter-redirector.c
<<
>>
Prefs
   1/*
   2 * QTest testcase for filter-redirector
   3 *
   4 * Copyright (c) 2016 FUJITSU LIMITED
   5 * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or
   8 * later.  See the COPYING file in the top-level directory.
   9 *
  10 * Case 1, tx traffic flow:
  11 *
  12 * qemu side              | test side
  13 *                        |
  14 * +---------+            |  +-------+
  15 * | backend <---------------+ sock0 |
  16 * +----+----+            |  +-------+
  17 *      |                 |
  18 * +----v----+  +-------+ |
  19 * |  rd0    +->+chardev| |
  20 * +---------+  +---+---+ |
  21 *                  |     |
  22 * +---------+      |     |
  23 * |  rd1    <------+     |
  24 * +----+----+            |
  25 *      |                 |
  26 * +----v----+            |  +-------+
  27 * |  rd2    +--------------->sock1  |
  28 * +---------+            |  +-------+
  29 *                        +
  30 *
  31 * --------------------------------------
  32 * Case 2, rx traffic flow
  33 * qemu side              | test side
  34 *                        |
  35 * +---------+            |  +-------+
  36 * | backend +---------------> sock1 |
  37 * +----^----+            |  +-------+
  38 *      |                 |
  39 * +----+----+  +-------+ |
  40 * |  rd0    +<-+chardev| |
  41 * +---------+  +---+---+ |
  42 *                  ^     |
  43 * +---------+      |     |
  44 * |  rd1    +------+     |
  45 * +----^----+            |
  46 *      |                 |
  47 * +----+----+            |  +-------+
  48 * |  rd2    <---------------+sock0  |
  49 * +---------+            |  +-------+
  50 *                        +
  51 */
  52
  53#include "qemu/osdep.h"
  54#include "qemu-common.h"
  55#include "libqos/libqtest.h"
  56#include "qapi/qmp/qdict.h"
  57#include "qemu/iov.h"
  58#include "qemu/sockets.h"
  59#include "qemu/error-report.h"
  60#include "qemu/main-loop.h"
  61
  62/* TODO actually test the results and get rid of this */
  63#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
  64
  65static const char *get_devstr(void)
  66{
  67    if (g_str_equal(qtest_get_arch(), "s390x")) {
  68        return "virtio-net-ccw";
  69    }
  70
  71    return "rtl8139";
  72}
  73
  74
  75static void test_redirector_tx(void)
  76{
  77    int backend_sock[2], recv_sock;
  78    uint32_t ret = 0, len = 0;
  79    char send_buf[] = "Hello!!";
  80    char sock_path0[] = "filter-redirector0.XXXXXX";
  81    char sock_path1[] = "filter-redirector1.XXXXXX";
  82    char *recv_buf;
  83    uint32_t size = sizeof(send_buf);
  84    size = htonl(size);
  85    QTestState *qts;
  86
  87    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
  88    g_assert_cmpint(ret, !=, -1);
  89
  90    ret = mkstemp(sock_path0);
  91    g_assert_cmpint(ret, !=, -1);
  92    ret = mkstemp(sock_path1);
  93    g_assert_cmpint(ret, !=, -1);
  94
  95    qts = qtest_initf(
  96        "-netdev socket,id=qtest-bn0,fd=%d "
  97        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
  98        "-chardev socket,id=redirector0,path=%s,server=on,wait=off "
  99        "-chardev socket,id=redirector1,path=%s,server=on,wait=off "
 100        "-chardev socket,id=redirector2,path=%s "
 101        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
 102        "queue=tx,outdev=redirector0 "
 103        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
 104        "queue=tx,indev=redirector2 "
 105        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
 106        "queue=tx,outdev=redirector1 ", backend_sock[1], get_devstr(),
 107        sock_path0, sock_path1, sock_path0);
 108
 109    recv_sock = unix_connect(sock_path1, NULL);
 110    g_assert_cmpint(recv_sock, !=, -1);
 111
 112    /* send a qmp command to guarantee that 'connected' is setting to true. */
 113    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
 114
 115    struct iovec iov[] = {
 116        {
 117            .iov_base = &size,
 118            .iov_len = sizeof(size),
 119        }, {
 120            .iov_base = send_buf,
 121            .iov_len = sizeof(send_buf),
 122        },
 123    };
 124
 125    ret = iov_send(backend_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
 126    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
 127    close(backend_sock[0]);
 128
 129    ret = qemu_recv(recv_sock, &len, sizeof(len), 0);
 130    g_assert_cmpint(ret, ==, sizeof(len));
 131    len = ntohl(len);
 132
 133    g_assert_cmpint(len, ==, sizeof(send_buf));
 134    recv_buf = g_malloc(len);
 135    ret = qemu_recv(recv_sock, recv_buf, len, 0);
 136    g_assert_cmpstr(recv_buf, ==, send_buf);
 137
 138    g_free(recv_buf);
 139    close(recv_sock);
 140    unlink(sock_path0);
 141    unlink(sock_path1);
 142    qtest_quit(qts);
 143}
 144
 145static void test_redirector_rx(void)
 146{
 147    int backend_sock[2], send_sock;
 148    uint32_t ret = 0, len = 0;
 149    char send_buf[] = "Hello!!";
 150    char sock_path0[] = "filter-redirector0.XXXXXX";
 151    char sock_path1[] = "filter-redirector1.XXXXXX";
 152    char *recv_buf;
 153    uint32_t size = sizeof(send_buf);
 154    size = htonl(size);
 155    QTestState *qts;
 156
 157    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
 158    g_assert_cmpint(ret, !=, -1);
 159
 160    ret = mkstemp(sock_path0);
 161    g_assert_cmpint(ret, !=, -1);
 162    ret = mkstemp(sock_path1);
 163    g_assert_cmpint(ret, !=, -1);
 164
 165    qts = qtest_initf(
 166        "-netdev socket,id=qtest-bn0,fd=%d "
 167        "-device %s,netdev=qtest-bn0,id=qtest-e0 "
 168        "-chardev socket,id=redirector0,path=%s,server=on,wait=off "
 169        "-chardev socket,id=redirector1,path=%s,server=on,wait=off "
 170        "-chardev socket,id=redirector2,path=%s "
 171        "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0,"
 172        "queue=rx,indev=redirector0 "
 173        "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0,"
 174        "queue=rx,outdev=redirector2 "
 175        "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0,"
 176        "queue=rx,indev=redirector1 ", backend_sock[1], get_devstr(),
 177        sock_path0, sock_path1, sock_path0);
 178
 179    struct iovec iov[] = {
 180        {
 181            .iov_base = &size,
 182            .iov_len = sizeof(size),
 183        }, {
 184            .iov_base = send_buf,
 185            .iov_len = sizeof(send_buf),
 186        },
 187    };
 188
 189    send_sock = unix_connect(sock_path1, NULL);
 190    g_assert_cmpint(send_sock, !=, -1);
 191    /* send a qmp command to guarantee that 'connected' is setting to true. */
 192    qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
 193
 194    ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf));
 195    g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
 196
 197    ret = qemu_recv(backend_sock[0], &len, sizeof(len), 0);
 198    g_assert_cmpint(ret, ==, sizeof(len));
 199    len = ntohl(len);
 200
 201    g_assert_cmpint(len, ==, sizeof(send_buf));
 202    recv_buf = g_malloc(len);
 203    ret = qemu_recv(backend_sock[0], recv_buf, len, 0);
 204    g_assert_cmpstr(recv_buf, ==, send_buf);
 205
 206    close(send_sock);
 207    g_free(recv_buf);
 208    unlink(sock_path0);
 209    unlink(sock_path1);
 210    qtest_quit(qts);
 211}
 212
 213int main(int argc, char **argv)
 214{
 215    g_test_init(&argc, &argv, NULL);
 216    qtest_add_func("/netfilter/redirector_tx", test_redirector_tx);
 217    qtest_add_func("/netfilter/redirector_rx", test_redirector_rx);
 218    return g_test_run();
 219}
 220