diff --git a/Config.uk b/Config.uk new file mode 100644 index 0000000..d2a320d --- /dev/null +++ b/Config.uk @@ -0,0 +1,64 @@ +### Invisible option for dependencies +menu "UK Netdev Test" + +config UKNETDEVTEST_INIT + bool "Init Test" + default n + depends on LIBUKNETDEV + +config UKNETDEVTEST_FETCH + bool "Fetch Test" + default n + depends on LIBUKNETDEV + +config UKNETDEVTEST_CONFIGURE + bool "Config Test" + default n + select UKNETDEVTEST_FETCH + +config UKNETDEVTEST_CONFIGURE_RX + bool "RX Config Test" + default n + select UKNETDEVTEST_CONFIGURE + +config UKNETDEVTEST_CONFIGURE_TX + bool "TX Config Test" + default n + select UKNETDEVTEST_CONFIGURE + +config UKNETDEVTEST_RX_INTR + bool "RX Enable interrupt" + default n + select UKNETDEVTEST_CONFIGURE_RX + +config UKNETDEVTEST_START + bool "Net device start" + default n + select UKNETDEVTEST_CONFIGURE_RX + select UKNETDEVTEST_CONFIGURE_TX + +config UKNETDEVTEST_RX + bool "Enable RX" + default n + select UKNETDEVTEST_START + +config UKNETDEVTEST_DESCADD + bool "Netbuf add descriptor" + default n + select UKNETDEVTEST_START + +endmenu + +menu "Virtio Net Test" +config VIRTIO_NET_TEST + bool "Virtio Net Device Test" + default n + depends on !LIBUKNETDEV + +if VIRTIO_NET_TEST +config LIBUKNETDEV + bool "Mock UK netdev Test" + default y +endif + +endmenu diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a1a8ecf --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +UK_ROOT=../Unikraft +ifndef UK_ROOT +$(error Error:UK_ROOT does not exist) +endif +all: + @make -C $(UK_ROOT) A=$(PWD) L=$(LIBS) + +$(MAKECMDGOALS): + @make -C $(UK_ROOT) A=$(PWD) L=$(LIBS) $(MAKECMDGOALS) diff --git a/Makefile.uk b/Makefile.uk new file mode 100644 index 0000000..3e81ccb --- /dev/null +++ b/Makefile.uk @@ -0,0 +1,4 @@ +$(eval $(call addlib,apptestuknet)) + +APPTESTUKNET_SRCS-y += $(APPTESTUKNET_BASE)/main.c +APPTESTUKNET_CFLAGS-y += -g -I$(APPTESTUKNET_BASE)/include diff --git a/include/assert_test.h b/include/assert_test.h new file mode 100644 index 0000000..ca8e6fa --- /dev/null +++ b/include/assert_test.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Sharan Santhanam + * + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#include +#define TEST_ZERO_CHK(val) \ + do { \ + UK_ASSERT(val == 0); \ + } while(0) + +#define TEST_NOT_ZERO_CHK(val) \ + do { \ + UK_ASSERT(val != 0); \ + } while(0) + +#define TEST_EXPR(expr) \ + do { \ + UK_ASSERT(expr);\ + } while(0) + +#define TEST_NOT_NULL(val) \ + do { \ + UK_ASSERT(val); \ + } while(0) diff --git a/main.c b/main.c new file mode 100644 index 0000000..cf08918 --- /dev/null +++ b/main.c @@ -0,0 +1,340 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Sharan Santhanam + * + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define NET_DEVICE_COUNT 2 +#define EXPECTED_PKT (0x50) +#define NET_DATA_SIZE (1530) +#define DESC_COUNT (0x100) + +static struct uk_alloc *a = NULL; +static struct uk_sched *s = NULL; +static struct uk_netdev *netdevice[NET_DEVICE_COUNT] = {0}; +static __u16 desc_cnt[NET_DEVICE_COUNT] = {0}; +static struct uk_netbuf *spare_buf[NET_DEVICE_COUNT]; +static __atomic pkt_cnt[NET_DEVICE_COUNT]; +static struct uk_semaphore sem_flag; +static struct uk_netdev_info dev_info[NET_DEVICE_COUNT] = {0}; + +static void netdev_test_callback(struct uk_netdev *dev, + uint16_t queue_id, void *cookie); + +static void netdev_print_reply(struct uk_netbuf *buf) +{ + __u16 ethertype = *(__u16 *)(buf->data + 12); + uk_pr_err("Ethertype %04x\n", ethertype); +} + +static void netdev_test_data_tx(uint16_t queue_id, + struct uk_netbuf *buf, int instance) +{ + struct uk_netbuf *sendbuf = NULL; + int rc = 0; + uk_pr_err("Allocating send buffer\n"); + sendbuf = uk_netbuf_alloc_buf(uk_alloc_get_default(), + NET_DATA_SIZE, dev_info[instance].nb_encap_tx, 0, NULL); + TEST_NOT_NULL(sendbuf); + uk_pr_err("Copying data of length %d\n", buf->len); + memcpy(sendbuf->data, buf->data, buf->len); + sendbuf->len = buf->len; + UK_ASSERT(!sendbuf->prev); + netdev_print_reply(sendbuf); + uk_pr_err("Sending(%d) data of length %d\n", + instance, sendbuf->len); + rc = uk_netdev_tx_one(netdevice[instance], queue_id, sendbuf); + TEST_EXPR(rc == 2); +} + +static void netdev_test_callback(struct uk_netdev *dev, uint16_t queue_id, + void *cookie) +{ + struct uk_netbuf *buf = NULL, *fill_buf = NULL; + struct uk_netbuf *sendbuf = NULL; + __u16 count = 0; + int rc = 0; + static int rcv_stat = 0; + int instance = (int) cookie; + uk_pr_err("Recv Identifier %d\n", instance); + + do { + if (spare_buf[instance]) { + fill_buf = spare_buf[instance]; + spare_buf[instance] = NULL; + count = 1; + } + UK_ASSERT(fill_buf); + rc = uk_netdev_rx_one(dev, queue_id, &buf, &fill_buf, &count); + if (rc < 0) { + uk_pr_err("Error receiving packet\n"); + TEST_ZERO_CHK(rc); + } + + uk_pr_err("Receive return code %d\n", rc); + if (rc > 0) { + TEST_NOT_NULL(buf); + TEST_ZERO_CHK(count); + } else { + TEST_EXPR(!buf); + TEST_EXPR(count == 1); + spare_buf[instance] = fill_buf; + break; + } + uk_pr_err("instance %d\n", instance); + netdev_test_data_tx(queue_id, buf, 1 - instance); + uk_netbuf_free(buf); + buf = uk_netbuf_alloc_buf(uk_alloc_get_default(), + NET_DATA_SIZE, dev_info[instance].nb_encap_rx, 0, NULL); + TEST_NOT_NULL(buf); + buf->len = NET_DATA_SIZE - dev_info[instance].nb_encap_rx; + count = 1; + spare_buf[instance] = buf; + + uk_pr_err("packet processed %d reset length:%d\n" + ,++rcv_stat, spare_buf[instance]->len); + if (rc == 1) { + uk_pr_err("Enabling interrupt returned %d\n", + rc); + rc = uk_netdev_rxq_intr_enable(dev, queue_id); + uk_pr_err("Interrupt enable: %d\n", rc); + } + } while (rc > 1 && rcv_stat < EXPECTED_PKT); + + uk_pr_err("out of loop %d\n", rcv_stat); + ukarch_inc(&pkt_cnt[instance].counter); + if (pkt_cnt[instance].counter == EXPECTED_PKT) { + uk_pr_err("uping the sem\n"); + uk_semaphore_up(&sem_flag); + } +} + +void netdev_init(uint32_t *count) +{ + *count = uk_netdev_count(); +} + +void netdev_test_init() +{ + int count = 0; + netdev_init(&count); + TEST_NOT_ZERO_CHK(count); +} + +void netdev_test_fetch(int count) +{ + int i = 0; + struct uk_netdev *dev; + for (i = 0; i < count; i++) { + uk_pr_err("Fetching index %d\n", i); + dev = uk_netdev_get(i); + TEST_NOT_NULL(dev); + netdevice[i] = dev; + } +} + +void netdev_test_invalid_configure(int instance) +{ + struct uk_netdev_conf conf = {0}; + int rc = 0; + conf.nb_rx_queues = 5; + conf.nb_tx_queues = 5; + rc = uk_netdev_configure(netdevice[instance], &conf); + TEST_NOT_ZERO_CHK(rc); +} + + +void netdev_test_configure(int instance) +{ + struct uk_netdev_info *info = &dev_info[instance]; + int rc = 0; + struct uk_netdev_conf conf; + + uk_netdev_info_get(netdevice[instance], info); + TEST_NOT_ZERO_CHK(info->nb_encap_rx); + TEST_NOT_ZERO_CHK(info->nb_encap_tx); + uk_pr_err("RX Encap %d: TX Encap %d\n", info->nb_encap_rx, info->nb_encap_tx); + + conf.nb_rx_queues = info->max_rx_queues; + conf.nb_tx_queues = info->max_tx_queues; + rc = uk_netdev_configure(netdevice[instance], &conf); + TEST_ZERO_CHK(rc); +} + +void netdev_test_rx_queue_configure(int instance) +{ + struct uk_netdev_rxqueue_conf conf = {0}; + int rc = 0; + conf.s = uk_sched_get_default(); + conf.a = uk_alloc_get_default(); + conf.callback = netdev_test_callback; + conf.callback_cookie = (void *) instance; + rc = uk_netdev_rxq_configure(netdevice[instance], 0, DESC_COUNT, + &conf); + TEST_ZERO_CHK(rc); +} + +void netdev_test_tx_queue_configure(int instance) +{ + struct uk_netdev_txqueue_conf conf = {0}; + int rc = 0; + conf.a = uk_alloc_get_default(); + rc = uk_netdev_txq_configure(netdevice[instance], 0, DESC_COUNT, + &conf); + TEST_ZERO_CHK(rc); +} + +void netdev_test_start(int instance) +{ + int rc = 0; + uk_pr_err("Starting the netdevice\n"); + rc = uk_netdev_start(netdevice[instance]); + TEST_ZERO_CHK(rc); +} + +void netdev_test_rxq_intr_enable(int instance) +{ + struct uk_netdev_rxqueue_conf conf = {0}; + int rc = 0; + conf.s = uk_sched_get_default(); + conf.a = uk_alloc_get_default(); + rc = uk_netdev_rxq_intr_enable(netdevice[instance], 0); + TEST_ZERO_CHK(rc); +} + +void netdev_test_add_recv_desc_append(int instance) +{ + __u16 count = 1; + int rc = 0, i = 0; + struct uk_netbuf *buf = NULL; + struct uk_netdev_info *conf = &dev_info[instance]; + uk_pr_info("RX queue hdr %d\n", conf->nb_encap_rx); + + /** + * Test a single buffer allocation. + */ + for (i = 0; i < DESC_COUNT; i++) { + buf = uk_netbuf_alloc_buf(uk_alloc_get_default(), + NET_DATA_SIZE, conf->nb_encap_rx, 0, NULL); + TEST_NOT_NULL(buf); + buf->len = NET_DATA_SIZE - conf->nb_encap_rx; + count = 1; + rc = uk_netdev_rx_one(netdevice[instance], 0, NULL, &buf, + &count); + TEST_ZERO_CHK(rc); + if (count == 0) { + desc_cnt[instance]++; + } else { + uk_pr_err("The virtqueue is full %d\n", + desc_cnt[instance]); + spare_buf[instance] = buf; + break; + } + } +} + +static void netdev_receive_prepare(int instance __unused) +{ + uk_pr_err("Sleeping %ld\n", sem_flag.count); + uk_semaphore_down(&sem_flag); + uk_pr_err("Waking up %ld\n", sem_flag.count); +} + +int main() +{ + /* Hold the main thread */ + uk_semaphore_init(&sem_flag, 0); + uk_pr_err("Semaphore %ld\n", sem_flag.count); + pkt_cnt[0].counter = 0; + pkt_cnt[1].counter = 0; +#ifdef CONFIG_UKNETDEVTEST_INIT + netdev_test_init(); + uk_pr_err("Semaphore after init %ld\n", sem_flag.count); +#endif /* CONFIG_UKNETDEVTEST_INIT */ + +#ifdef CONFIG_UKNETDEVTEST_FETCH + uint32_t count = 0; + netdev_init(&count); + uk_pr_err("Device Count %d\n", count); + netdev_test_fetch(count); +#endif /* CONFIG_UKNETDEVTEST_FETCH */ + +#ifdef CONFIG_UKNETDEVTEST_CONFIGURE + netdev_test_configure(0); + netdev_test_configure(1); + uk_pr_err("Semaphore after configure %ld\n", sem_flag.count); + netdev_test_invalid_configure(0); +#endif /* CONFIG_UKNETDEVTEST_CONFIGURE */ + +#ifdef CONFIG_UKNETDEVTEST_CONFIGURE_RX + netdev_test_rx_queue_configure(0); + netdev_test_rx_queue_configure(1); + uk_pr_err("Semaphore after rx configure %ld\n", sem_flag.count); +#endif /* CONFIG_UKNETDEVTEST_CONFIGURE_RX */ +#ifdef CONFIG_UKNETDEVTEST_CONFIGURE_TX + netdev_test_tx_queue_configure(0); + netdev_test_tx_queue_configure(1); + uk_pr_err("Semaphore after tx configure %ld\n", sem_flag.count); +#endif /* CONFIG_UKNETDEVTEST_CONFIGURE_TX */ + +#ifdef CONFIG_UKNETDEVTEST_START + netdev_test_start(0); + uk_pr_err("Semaphore after start %ld\n", sem_flag.count); + netdev_test_start(1); + uk_pr_err("Semaphore after start %ld\n", sem_flag.count); +#endif /* CONFIG_UKNETDEVTEST_START */ + +#ifdef CONFIG_UKNETDEVTEST_RX_INTR + netdev_test_rxq_intr_enable(0); + uk_pr_err("Semaphore after intr enable %ld\n", sem_flag.count); + netdev_test_rxq_intr_enable(1); + uk_pr_err("Semaphore after intr enable %ld\n", sem_flag.count); + uk_pr_info("Enabling interrupt\n"); +#endif /* CONFIG_UKNETDEVTEST_RX_INTR */ + +#ifdef CONFIG_UKNETDEVTEST_DESCADD + netdev_test_add_recv_desc_append(0); + uk_pr_err("Semaphore after desc 1 %ld\n", sem_flag.count); + netdev_test_add_recv_desc_append(1); + uk_pr_err("Semaphore after desc 1 %ld\n", sem_flag.count); +#endif /* CONFIG_UKNETDEVTEST_DESCADD */ + + netdev_receive_prepare(0); + return 0; +}