blob: b534f00e588291a9f4d8a233774a8d196ee438e4 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/device/ethernet.h>
#include "garnet/lib/machina/phys_mem_fake.h"
#include "garnet/lib/machina/virtio_net.h"
#include "garnet/lib/machina/virtio_queue_fake.h"
#include "gtest/gtest.h"
namespace machina {
namespace {
static constexpr uint16_t kVirtioNetQueueSize = 8;
class VirtioNetTest : public testing::Test {
public:
VirtioNetTest() : net_(phys_mem_, loop_.async()), queue_(net_.rx_queue()) {}
void SetUp() override {
ASSERT_EQ(queue_.Init(kVirtioNetQueueSize), ZX_OK);
ASSERT_EQ(zx_fifo_create(kVirtioNetQueueSize, sizeof(eth_fifo_entry_t), 0,
&fifos_.rx_fifo, &fifo_[0]),
ZX_OK);
ASSERT_EQ(zx_fifo_create(kVirtioNetQueueSize, sizeof(eth_fifo_entry_t), 0,
&fifos_.tx_fifo, &fifo_[1]),
ZX_OK);
fifos_.rx_depth = kVirtioNetQueueSize;
fifos_.tx_depth = kVirtioNetQueueSize;
ASSERT_EQ(net_.WaitOnFifos(fifos_), ZX_OK);
}
protected:
async::Loop loop_;
PhysMemFake phys_mem_;
VirtioNet net_;
VirtioQueueFake queue_;
// Fifo endpoints to provide to the net device.
eth_fifos_t fifos_;
// Fifo endpoints to simulate ethernet device activity.
zx_handle_t fifo_[2];
};
TEST_F(VirtioNetTest, DrainQueue) {
virtio_net_hdr_t hdr = {};
ASSERT_EQ(queue_.BuildDescriptor().AppendReadable(&hdr, sizeof(hdr)).Build(),
ZX_OK);
// Drain the queue, this will pull a descriptor from the queue and deposit
// an entry in the fifo.
size_t count;
eth_fifo_entry_t entry[fifos_.rx_depth];
// We should have no work at this point as all the buffers will be owned by
// the ethernet device.
loop_.RunUntilIdle();
ASSERT_EQ(0u, net_.rx_queue()->ring()->used->idx);
// Return a descriptor to the queue, this should trigger it to be returned.
ASSERT_EQ(ZX_OK, zx_fifo_read(fifo_[0], sizeof(entry[0]), entry,
countof(entry), &count));
ASSERT_EQ(1u, count);
ASSERT_EQ(ZX_OK,
zx_fifo_write(fifo_[0], sizeof(entry[0]), &entry[0], 1, nullptr));
// Run the async tasks, verify buffers are returned.
loop_.RunUntilIdle();
ASSERT_EQ(1u, net_.rx_queue()->ring()->used->idx);
}
TEST_F(VirtioNetTest, HeaderOnDifferentBuffer) {
virtio_net_hdr_t hdr = {};
// Ethernet FIFOs only support 32-bit VMO offsets which means validating
// against stack values may not be safe if they're above UINT32_MAX in our
// address space.
uint8_t* packet_ptr = reinterpret_cast<uint8_t*>(0x123456);
size_t packet_len = 512;
ASSERT_EQ(queue_.BuildDescriptor()
.AppendReadable(&hdr, sizeof(hdr))
.AppendReadable(packet_ptr, packet_len)
.Build(),
ZX_OK);
loop_.RunUntilIdle();
size_t count;
eth_fifo_entry_t entry[fifos_.rx_depth];
// Read the fifo entry.
ASSERT_EQ(ZX_OK, zx_fifo_read(fifo_[0], sizeof(entry[0]), entry,
countof(entry), &count));
ASSERT_EQ(1u, count);
ASSERT_EQ(reinterpret_cast<uintptr_t>(packet_ptr), entry[0].offset);
ASSERT_EQ(packet_len, entry[0].length);
}
TEST_F(VirtioNetTest, InvalidDesc) {
virtio_net_hdr_t hdr = {};
uint8_t packet[1024];
ASSERT_EQ(queue_.BuildDescriptor()
.AppendReadable(&hdr, sizeof(hdr))
.AppendReadable(packet, sizeof(packet))
.AppendReadable(packet, sizeof(packet))
.Build(),
ZX_OK);
// Expect nothing is written to the FIFO.
loop_.RunUntilIdle();
eth_fifo_entry_t entry[fifos_.rx_depth];
ASSERT_EQ(
zx_fifo_read(fifo_[0], sizeof(entry[0]), entry, countof(entry), nullptr),
ZX_ERR_SHOULD_WAIT);
}
TEST_F(VirtioNetTest, PeerClosed) {
virtio_net_hdr_t hdr = {};
ASSERT_EQ(queue_.BuildDescriptor().AppendReadable(&hdr, sizeof(hdr)).Build(),
ZX_OK);
ASSERT_EQ(zx_handle_close(fifo_[0]), ZX_OK);
ASSERT_EQ(zx_handle_close(fifo_[1]), ZX_OK);
loop_.RunUntilIdle();
}
} // namespace
} // namespace machina