xref: /qemu/tests/qtest/virtio-net-test.c (revision 4d98618b)
11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth  * QTest testcase for VirtIO NIC
31e8a1faeSThomas Huth  *
41e8a1faeSThomas Huth  * Copyright (c) 2014 SUSE LINUX Products GmbH
51e8a1faeSThomas Huth  *
61e8a1faeSThomas Huth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
71e8a1faeSThomas Huth  * See the COPYING file in the top-level directory.
81e8a1faeSThomas Huth  */
91e8a1faeSThomas Huth 
101e8a1faeSThomas Huth #include "qemu/osdep.h"
111e8a1faeSThomas Huth #include "libqtest-single.h"
121e8a1faeSThomas Huth #include "qemu/iov.h"
131e8a1faeSThomas Huth #include "qemu/module.h"
141e8a1faeSThomas Huth #include "qapi/qmp/qdict.h"
151e8a1faeSThomas Huth #include "hw/virtio/virtio-net.h"
161e8a1faeSThomas Huth #include "libqos/qgraph.h"
171e8a1faeSThomas Huth #include "libqos/virtio-net.h"
181e8a1faeSThomas Huth 
191e8a1faeSThomas Huth #ifndef ETH_P_RARP
201e8a1faeSThomas Huth #define ETH_P_RARP 0x8035
211e8a1faeSThomas Huth #endif
221e8a1faeSThomas Huth 
231e8a1faeSThomas Huth #define PCI_SLOT_HP             0x06
241e8a1faeSThomas Huth #define PCI_SLOT                0x04
251e8a1faeSThomas Huth 
261e8a1faeSThomas Huth #define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000)
271e8a1faeSThomas Huth #define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf)
281e8a1faeSThomas Huth 
291e8a1faeSThomas Huth #ifndef _WIN32
301e8a1faeSThomas Huth 
rx_test(QVirtioDevice * dev,QGuestAllocator * alloc,QVirtQueue * vq,int socket)311e8a1faeSThomas Huth static void rx_test(QVirtioDevice *dev,
321e8a1faeSThomas Huth                     QGuestAllocator *alloc, QVirtQueue *vq,
331e8a1faeSThomas Huth                     int socket)
341e8a1faeSThomas Huth {
351e8a1faeSThomas Huth     QTestState *qts = global_qtest;
361e8a1faeSThomas Huth     uint64_t req_addr;
371e8a1faeSThomas Huth     uint32_t free_head;
381e8a1faeSThomas Huth     char test[] = "TEST";
391e8a1faeSThomas Huth     char buffer[64];
401e8a1faeSThomas Huth     int len = htonl(sizeof(test));
411e8a1faeSThomas Huth     struct iovec iov[] = {
421e8a1faeSThomas Huth         {
431e8a1faeSThomas Huth             .iov_base = &len,
441e8a1faeSThomas Huth             .iov_len = sizeof(len),
451e8a1faeSThomas Huth         }, {
461e8a1faeSThomas Huth             .iov_base = test,
471e8a1faeSThomas Huth             .iov_len = sizeof(test),
481e8a1faeSThomas Huth         },
491e8a1faeSThomas Huth     };
501e8a1faeSThomas Huth     int ret;
511e8a1faeSThomas Huth 
521e8a1faeSThomas Huth     req_addr = guest_alloc(alloc, 64);
531e8a1faeSThomas Huth 
541e8a1faeSThomas Huth     free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
551e8a1faeSThomas Huth     qvirtqueue_kick(qts, dev, vq, free_head);
561e8a1faeSThomas Huth 
571e8a1faeSThomas Huth     ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
581e8a1faeSThomas Huth     g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
591e8a1faeSThomas Huth 
601e8a1faeSThomas Huth     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
611e8a1faeSThomas Huth                            QVIRTIO_NET_TIMEOUT_US);
621e8a1faeSThomas Huth     memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
631e8a1faeSThomas Huth     g_assert_cmpstr(buffer, ==, "TEST");
641e8a1faeSThomas Huth 
651e8a1faeSThomas Huth     guest_free(alloc, req_addr);
661e8a1faeSThomas Huth }
671e8a1faeSThomas Huth 
tx_test(QVirtioDevice * dev,QGuestAllocator * alloc,QVirtQueue * vq,int socket)681e8a1faeSThomas Huth static void tx_test(QVirtioDevice *dev,
691e8a1faeSThomas Huth                     QGuestAllocator *alloc, QVirtQueue *vq,
701e8a1faeSThomas Huth                     int socket)
711e8a1faeSThomas Huth {
721e8a1faeSThomas Huth     QTestState *qts = global_qtest;
731e8a1faeSThomas Huth     uint64_t req_addr;
741e8a1faeSThomas Huth     uint32_t free_head;
751e8a1faeSThomas Huth     uint32_t len;
761e8a1faeSThomas Huth     char buffer[64];
771e8a1faeSThomas Huth     int ret;
781e8a1faeSThomas Huth 
791e8a1faeSThomas Huth     req_addr = guest_alloc(alloc, 64);
801e8a1faeSThomas Huth     memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4);
811e8a1faeSThomas Huth 
821e8a1faeSThomas Huth     free_head = qvirtqueue_add(qts, vq, req_addr, 64, false, false);
831e8a1faeSThomas Huth     qvirtqueue_kick(qts, dev, vq, free_head);
841e8a1faeSThomas Huth 
851e8a1faeSThomas Huth     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
861e8a1faeSThomas Huth                            QVIRTIO_NET_TIMEOUT_US);
871e8a1faeSThomas Huth     guest_free(alloc, req_addr);
881e8a1faeSThomas Huth 
89e7b79428SMarc-André Lureau     ret = recv(socket, &len, sizeof(len), 0);
901e8a1faeSThomas Huth     g_assert_cmpint(ret, ==, sizeof(len));
911e8a1faeSThomas Huth     len = ntohl(len);
921e8a1faeSThomas Huth 
93e7b79428SMarc-André Lureau     ret = recv(socket, buffer, len, 0);
94*4d98618bSZhu Jun     g_assert_cmpint(ret, ==, len);
951e8a1faeSThomas Huth     g_assert_cmpstr(buffer, ==, "TEST");
961e8a1faeSThomas Huth }
971e8a1faeSThomas Huth 
rx_stop_cont_test(QVirtioDevice * dev,QGuestAllocator * alloc,QVirtQueue * vq,int socket)981e8a1faeSThomas Huth static void rx_stop_cont_test(QVirtioDevice *dev,
991e8a1faeSThomas Huth                               QGuestAllocator *alloc, QVirtQueue *vq,
1001e8a1faeSThomas Huth                               int socket)
1011e8a1faeSThomas Huth {
1021e8a1faeSThomas Huth     QTestState *qts = global_qtest;
1031e8a1faeSThomas Huth     uint64_t req_addr;
1041e8a1faeSThomas Huth     uint32_t free_head;
1051e8a1faeSThomas Huth     char test[] = "TEST";
1061e8a1faeSThomas Huth     char buffer[64];
1071e8a1faeSThomas Huth     int len = htonl(sizeof(test));
1081e8a1faeSThomas Huth     QDict *rsp;
1091e8a1faeSThomas Huth     struct iovec iov[] = {
1101e8a1faeSThomas Huth         {
1111e8a1faeSThomas Huth             .iov_base = &len,
1121e8a1faeSThomas Huth             .iov_len = sizeof(len),
1131e8a1faeSThomas Huth         }, {
1141e8a1faeSThomas Huth             .iov_base = test,
1151e8a1faeSThomas Huth             .iov_len = sizeof(test),
1161e8a1faeSThomas Huth         },
1171e8a1faeSThomas Huth     };
1181e8a1faeSThomas Huth     int ret;
1191e8a1faeSThomas Huth 
1201e8a1faeSThomas Huth     req_addr = guest_alloc(alloc, 64);
1211e8a1faeSThomas Huth 
1221e8a1faeSThomas Huth     free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false);
1231e8a1faeSThomas Huth     qvirtqueue_kick(qts, dev, vq, free_head);
1241e8a1faeSThomas Huth 
1251e8a1faeSThomas Huth     rsp = qmp("{ 'execute' : 'stop'}");
1261e8a1faeSThomas Huth     qobject_unref(rsp);
1271e8a1faeSThomas Huth 
1281e8a1faeSThomas Huth     ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
1291e8a1faeSThomas Huth     g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
1301e8a1faeSThomas Huth 
1311e8a1faeSThomas Huth     /* We could check the status, but this command is more importantly to
1321e8a1faeSThomas Huth      * ensure the packet data gets queued in QEMU, before we do 'cont'.
1331e8a1faeSThomas Huth      */
1341e8a1faeSThomas Huth     rsp = qmp("{ 'execute' : 'query-status'}");
1351e8a1faeSThomas Huth     qobject_unref(rsp);
1361e8a1faeSThomas Huth     rsp = qmp("{ 'execute' : 'cont'}");
1371e8a1faeSThomas Huth     qobject_unref(rsp);
1381e8a1faeSThomas Huth 
1391e8a1faeSThomas Huth     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
1401e8a1faeSThomas Huth                            QVIRTIO_NET_TIMEOUT_US);
1411e8a1faeSThomas Huth     memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
1421e8a1faeSThomas Huth     g_assert_cmpstr(buffer, ==, "TEST");
1431e8a1faeSThomas Huth 
1441e8a1faeSThomas Huth     guest_free(alloc, req_addr);
1451e8a1faeSThomas Huth }
1461e8a1faeSThomas Huth 
send_recv_test(void * obj,void * data,QGuestAllocator * t_alloc)1471e8a1faeSThomas Huth static void send_recv_test(void *obj, void *data, QGuestAllocator *t_alloc)
1481e8a1faeSThomas Huth {
1491e8a1faeSThomas Huth     QVirtioNet *net_if = obj;
1501e8a1faeSThomas Huth     QVirtioDevice *dev = net_if->vdev;
1511e8a1faeSThomas Huth     QVirtQueue *rx = net_if->queues[0];
1521e8a1faeSThomas Huth     QVirtQueue *tx = net_if->queues[1];
1531e8a1faeSThomas Huth     int *sv = data;
1541e8a1faeSThomas Huth 
1551e8a1faeSThomas Huth     rx_test(dev, t_alloc, rx, sv[0]);
1561e8a1faeSThomas Huth     tx_test(dev, t_alloc, tx, sv[0]);
1571e8a1faeSThomas Huth }
1581e8a1faeSThomas Huth 
stop_cont_test(void * obj,void * data,QGuestAllocator * t_alloc)1591e8a1faeSThomas Huth static void stop_cont_test(void *obj, void *data, QGuestAllocator *t_alloc)
1601e8a1faeSThomas Huth {
1611e8a1faeSThomas Huth     QVirtioNet *net_if = obj;
1621e8a1faeSThomas Huth     QVirtioDevice *dev = net_if->vdev;
1631e8a1faeSThomas Huth     QVirtQueue *rx = net_if->queues[0];
1641e8a1faeSThomas Huth     int *sv = data;
1651e8a1faeSThomas Huth 
1661e8a1faeSThomas Huth     rx_stop_cont_test(dev, t_alloc, rx, sv[0]);
1671e8a1faeSThomas Huth }
1681e8a1faeSThomas Huth 
hotplug(void * obj,void * data,QGuestAllocator * t_alloc)1691e8a1faeSThomas Huth static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
1701e8a1faeSThomas Huth {
1711e8a1faeSThomas Huth     QVirtioPCIDevice *dev = obj;
1721e8a1faeSThomas Huth     QTestState *qts = dev->pdev->bus->qts;
1731e8a1faeSThomas Huth     const char *arch = qtest_get_arch();
1741e8a1faeSThomas Huth 
17502ee7a8aSEric Auger     if (dev->pdev->bus->not_hotpluggable) {
17602ee7a8aSEric Auger         g_test_skip("pci bus does not support hotplug");
17702ee7a8aSEric Auger         return;
17802ee7a8aSEric Auger     }
17902ee7a8aSEric Auger 
1801e8a1faeSThomas Huth     qtest_qmp_device_add(qts, "virtio-net-pci", "net1",
1811e8a1faeSThomas Huth                          "{'addr': %s}", stringify(PCI_SLOT_HP));
1821e8a1faeSThomas Huth 
1831e8a1faeSThomas Huth     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
1841e8a1faeSThomas Huth         qpci_unplug_acpi_device_test(qts, "net1", PCI_SLOT_HP);
1851e8a1faeSThomas Huth     }
1861e8a1faeSThomas Huth }
1871e8a1faeSThomas Huth 
announce_self(void * obj,void * data,QGuestAllocator * t_alloc)1881e8a1faeSThomas Huth static void announce_self(void *obj, void *data, QGuestAllocator *t_alloc)
1891e8a1faeSThomas Huth {
1901e8a1faeSThomas Huth     int *sv = data;
1911e8a1faeSThomas Huth     char buffer[60];
1921e8a1faeSThomas Huth     int len;
1931e8a1faeSThomas Huth     QDict *rsp;
1941e8a1faeSThomas Huth     int ret;
1951e8a1faeSThomas Huth     uint16_t *proto = (uint16_t *)&buffer[12];
1961e8a1faeSThomas Huth     size_t total_received = 0;
1971e8a1faeSThomas Huth     uint64_t start, now, last_rxt, deadline;
1981e8a1faeSThomas Huth 
1991e8a1faeSThomas Huth     /* Send a set of packets over a few second period */
2001e8a1faeSThomas Huth     rsp = qmp("{ 'execute' : 'announce-self', "
2011e8a1faeSThomas Huth                   " 'arguments': {"
2021e8a1faeSThomas Huth                       " 'initial': 20, 'max': 100,"
2031e8a1faeSThomas Huth                       " 'rounds': 300, 'step': 10, 'id': 'bob' } }");
2041e8a1faeSThomas Huth     assert(!qdict_haskey(rsp, "error"));
2051e8a1faeSThomas Huth     qobject_unref(rsp);
2061e8a1faeSThomas Huth 
2071e8a1faeSThomas Huth     /* Catch the first packet and make sure it's a RARP */
208e7b79428SMarc-André Lureau     ret = recv(sv[0], &len, sizeof(len), 0);
2091e8a1faeSThomas Huth     g_assert_cmpint(ret, ==,  sizeof(len));
2101e8a1faeSThomas Huth     len = ntohl(len);
2111e8a1faeSThomas Huth 
212e7b79428SMarc-André Lureau     ret = recv(sv[0], buffer, len, 0);
2131e8a1faeSThomas Huth     g_assert_cmpint(*proto, ==, htons(ETH_P_RARP));
2141e8a1faeSThomas Huth 
2151e8a1faeSThomas Huth     /*
21696420a30SMichael Tokarev      * Stop the announcement by settings rounds to 0 on the
2171e8a1faeSThomas Huth      * existing timer.
2181e8a1faeSThomas Huth      */
2191e8a1faeSThomas Huth     rsp = qmp("{ 'execute' : 'announce-self', "
2201e8a1faeSThomas Huth                   " 'arguments': {"
2211e8a1faeSThomas Huth                       " 'initial': 20, 'max': 100,"
2221e8a1faeSThomas Huth                       " 'rounds': 0, 'step': 10, 'id': 'bob' } }");
2231e8a1faeSThomas Huth     assert(!qdict_haskey(rsp, "error"));
2241e8a1faeSThomas Huth     qobject_unref(rsp);
2251e8a1faeSThomas Huth 
2261e8a1faeSThomas Huth     /* Now make sure the packets stop */
2271e8a1faeSThomas Huth 
2281e8a1faeSThomas Huth     /* Times are in us */
2291e8a1faeSThomas Huth     start = g_get_monotonic_time();
2301e8a1faeSThomas Huth     /* 30 packets, max gap 100ms, * 4 for wiggle */
2311e8a1faeSThomas Huth     deadline = start + 1000 * (100 * 30 * 4);
2321e8a1faeSThomas Huth     last_rxt = start;
2331e8a1faeSThomas Huth 
2341e8a1faeSThomas Huth     while (true) {
2351e8a1faeSThomas Huth         int saved_err;
236e7b79428SMarc-André Lureau         ret = recv(sv[0], buffer, 60, MSG_DONTWAIT);
2371e8a1faeSThomas Huth         saved_err = errno;
2381e8a1faeSThomas Huth         now = g_get_monotonic_time();
2391e8a1faeSThomas Huth         g_assert_cmpint(now, <, deadline);
2401e8a1faeSThomas Huth 
2411e8a1faeSThomas Huth         if (ret >= 0) {
2421e8a1faeSThomas Huth             if (ret) {
2431e8a1faeSThomas Huth                 last_rxt = now;
2441e8a1faeSThomas Huth             }
2451e8a1faeSThomas Huth             total_received += ret;
2461e8a1faeSThomas Huth 
2471e8a1faeSThomas Huth             /* Check it's not spewing loads */
2481e8a1faeSThomas Huth             g_assert_cmpint(total_received, <, 60 * 30 * 2);
2491e8a1faeSThomas Huth         } else {
2501e8a1faeSThomas Huth             g_assert_cmpint(saved_err, ==, EAGAIN);
2511e8a1faeSThomas Huth 
2521e8a1faeSThomas Huth             /* 400ms, i.e. 4 worst case gaps */
2531e8a1faeSThomas Huth             if ((now - last_rxt) > (1000 * 100 * 4)) {
2541e8a1faeSThomas Huth                 /* Nothings arrived for a while - must have stopped */
2551e8a1faeSThomas Huth                 break;
2561e8a1faeSThomas Huth             };
2571e8a1faeSThomas Huth 
2581e8a1faeSThomas Huth             /* 100ms */
2591e8a1faeSThomas Huth             g_usleep(1000 * 100);
2601e8a1faeSThomas Huth         }
2611e8a1faeSThomas Huth     };
2621e8a1faeSThomas Huth }
2631e8a1faeSThomas Huth 
virtio_net_test_cleanup(void * sockets)2641e8a1faeSThomas Huth static void virtio_net_test_cleanup(void *sockets)
2651e8a1faeSThomas Huth {
2661e8a1faeSThomas Huth     int *sv = sockets;
2671e8a1faeSThomas Huth 
2681e8a1faeSThomas Huth     close(sv[0]);
2691e8a1faeSThomas Huth     qos_invalidate_command_line();
2701e8a1faeSThomas Huth     close(sv[1]);
2711e8a1faeSThomas Huth     g_free(sv);
2721e8a1faeSThomas Huth }
2731e8a1faeSThomas Huth 
virtio_net_test_setup(GString * cmd_line,void * arg)2741e8a1faeSThomas Huth static void *virtio_net_test_setup(GString *cmd_line, void *arg)
2751e8a1faeSThomas Huth {
2761e8a1faeSThomas Huth     int ret;
2771e8a1faeSThomas Huth     int *sv = g_new(int, 2);
2781e8a1faeSThomas Huth 
2791e8a1faeSThomas Huth     ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
2801e8a1faeSThomas Huth     g_assert_cmpint(ret, !=, -1);
2811e8a1faeSThomas Huth 
2821e8a1faeSThomas Huth     g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ", sv[1]);
2831e8a1faeSThomas Huth 
2841e8a1faeSThomas Huth     g_test_queue_destroy(virtio_net_test_cleanup, sv);
2851e8a1faeSThomas Huth     return sv;
2861e8a1faeSThomas Huth }
2871e8a1faeSThomas Huth 
288cac4373aSBin Meng #endif /* _WIN32 */
289cac4373aSBin Meng 
large_tx(void * obj,void * data,QGuestAllocator * t_alloc)2901e8a1faeSThomas Huth static void large_tx(void *obj, void *data, QGuestAllocator *t_alloc)
2911e8a1faeSThomas Huth {
2921e8a1faeSThomas Huth     QVirtioNet *dev = obj;
2931e8a1faeSThomas Huth     QVirtQueue *vq = dev->queues[1];
2941e8a1faeSThomas Huth     uint64_t req_addr;
2951e8a1faeSThomas Huth     uint32_t free_head;
2961e8a1faeSThomas Huth     size_t alloc_size = (size_t)data / 64;
2971e8a1faeSThomas Huth     QTestState *qts = global_qtest;
2981e8a1faeSThomas Huth     int i;
2991e8a1faeSThomas Huth 
3001e8a1faeSThomas Huth     /* Bypass the limitation by pointing several descriptors to a single
3011e8a1faeSThomas Huth      * smaller area */
3021e8a1faeSThomas Huth     req_addr = guest_alloc(t_alloc, alloc_size);
3031e8a1faeSThomas Huth     free_head = qvirtqueue_add(qts, vq, req_addr, alloc_size, false, true);
3041e8a1faeSThomas Huth 
3051e8a1faeSThomas Huth     for (i = 0; i < 64; i++) {
3061e8a1faeSThomas Huth         qvirtqueue_add(qts, vq, req_addr, alloc_size, false, i != 63);
3071e8a1faeSThomas Huth     }
3081e8a1faeSThomas Huth     qvirtqueue_kick(qts, dev->vdev, vq, free_head);
3091e8a1faeSThomas Huth 
3101e8a1faeSThomas Huth     qvirtio_wait_used_elem(qts, dev->vdev, vq, free_head, NULL,
3111e8a1faeSThomas Huth                            QVIRTIO_NET_TIMEOUT_US);
3121e8a1faeSThomas Huth     guest_free(t_alloc, req_addr);
3131e8a1faeSThomas Huth }
3141e8a1faeSThomas Huth 
virtio_net_test_setup_nosocket(GString * cmd_line,void * arg)3151e8a1faeSThomas Huth static void *virtio_net_test_setup_nosocket(GString *cmd_line, void *arg)
3161e8a1faeSThomas Huth {
3171e8a1faeSThomas Huth     g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
3181e8a1faeSThomas Huth     return arg;
3191e8a1faeSThomas Huth }
3201e8a1faeSThomas Huth 
register_virtio_net_test(void)3211e8a1faeSThomas Huth static void register_virtio_net_test(void)
3221e8a1faeSThomas Huth {
323cac4373aSBin Meng     QOSGraphTestOptions opts = { 0 };
3241e8a1faeSThomas Huth 
3251e8a1faeSThomas Huth #ifndef _WIN32
326cac4373aSBin Meng     opts.before = virtio_net_test_setup;
327cac4373aSBin Meng     qos_add_test("hotplug", "virtio-net-pci", hotplug, &opts);
3281e8a1faeSThomas Huth     qos_add_test("basic", "virtio-net", send_recv_test, &opts);
3291e8a1faeSThomas Huth     qos_add_test("rx_stop_cont", "virtio-net", stop_cont_test, &opts);
3301e8a1faeSThomas Huth     qos_add_test("announce-self", "virtio-net", announce_self, &opts);
331cac4373aSBin Meng #endif
3321e8a1faeSThomas Huth 
3331e8a1faeSThomas Huth     /* These tests do not need a loopback backend.  */
3341e8a1faeSThomas Huth     opts.before = virtio_net_test_setup_nosocket;
3351e8a1faeSThomas Huth     opts.arg = (gpointer)UINT_MAX;
3361e8a1faeSThomas Huth     qos_add_test("large_tx/uint_max", "virtio-net", large_tx, &opts);
3371e8a1faeSThomas Huth     opts.arg = (gpointer)NET_BUFSIZE;
3381e8a1faeSThomas Huth     qos_add_test("large_tx/net_bufsize", "virtio-net", large_tx, &opts);
3391e8a1faeSThomas Huth }
3401e8a1faeSThomas Huth 
3411e8a1faeSThomas Huth libqos_init(register_virtio_net_test);
342