blob: 2187d17ce5d52c17659fde3997433a4b9e0e893a [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.
#ifndef GARNET_BIN_GUEST_VMM_VIRTIO_NET_LEGACY_H_
#define GARNET_BIN_GUEST_VMM_VIRTIO_NET_LEGACY_H_
#include <atomic>
#include <vector>
#include <fbl/unique_fd.h>
#include <fuchsia/hardware/ethernet/c/fidl.h>
#include <lib/async/cpp/wait.h>
#include <lib/zx/channel.h>
#include <trace-engine/types.h>
#include <virtio/net.h>
#include <virtio/virtio_ids.h>
#include "garnet/bin/guest/vmm/virtio_device.h"
#include "garnet/bin/guest/vmm/virtio_queue_waiter.h"
static constexpr uint16_t kVirtioNetLegacyNumQueues = 2;
static_assert(kVirtioNetLegacyNumQueues % 2 == 0,
"There must be a queue for both RX and TX");
static constexpr uint16_t kVirtioNetLegacyRxQueueIndex = 0;
static constexpr uint16_t kVirtioNetLegacyTxQueueIndex = 1;
static_assert(kVirtioNetLegacyRxQueueIndex != kVirtioNetLegacyTxQueueIndex,
"RX and TX queues must be distinct");
// Implements a Virtio Ethernet device.
class VirtioNetLegacy
: public VirtioInprocessDevice<VIRTIO_ID_NET, kVirtioNetLegacyNumQueues,
virtio_net_config_t> {
public:
VirtioNetLegacy(const PhysMem& phys_mem, async_dispatcher_t* dispatcher);
~VirtioNetLegacy() override;
// Starts the Virtio Ethernet device based on the path provided.
zx_status_t Start(const char* path);
VirtioQueue* rx_queue() { return queue(kVirtioNetLegacyRxQueueIndex); }
VirtioQueue* tx_queue() { return queue(kVirtioNetLegacyTxQueueIndex); }
protected:
// Helper function to initialize the IO bufs structure that gets shared with
// the ethdriver. This is protected to allow for a mock VirtioNet to be easily
// constructed for testing without needing a fully mocked ethernet driver.
zx_status_t InitIoBuffer(size_t count, size_t elem_size);
zx_status_t WaitOnFifos(const fuchsia_hardware_ethernet_Fifos& fifos);
private:
// Ethernet control plane.
fuchsia_hardware_ethernet_Fifos fifos_ = {};
// Connection to the Ethernet device.
zx::channel net_svc_;
std::atomic<trace_async_id_t>* rx_trace_flow_id() {
return trace_flow_id(kVirtioNetLegacyRxQueueIndex);
}
std::atomic<trace_async_id_t>* tx_trace_flow_id() {
return trace_flow_id(kVirtioNetLegacyTxQueueIndex);
}
class IoBuffer {
public:
IoBuffer() {}
zx::vmo& vmo() { return vmo_; }
zx_status_t Init(size_t count, size_t elem_size);
zx_status_t Allocate(uintptr_t* offset);
void Free(uintptr_t offset);
private:
std::vector<uint16_t> free_list_;
size_t elem_size_;
zx::vmo vmo_;
};
// A single data stream (either RX or TX).
class Stream {
public:
Stream(const PhysMem& phys_mem, async_dispatcher_t* dispatcher,
VirtioQueue* queue, std::atomic<trace_async_id_t>* trace_flow_id,
IoBuffer* iobufs);
zx_status_t Start(zx_handle_t fifo, size_t fifo_num_entries, bool rx);
private:
// Move buffers from VirtioQueue -> FIFO.
zx_status_t WaitOnQueue();
void OnQueueReady(zx_status_t status, uint16_t index);
zx_status_t WaitOnFifoWritable();
void OnFifoWritable(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal);
// Return buffers from FIFO to VirtioQueue.
zx_status_t WaitOnFifoReadable();
void OnFifoReadable(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal);
virtio_net_hdr_t* ReadPacketInfo(uint16_t index, uintptr_t* offset,
uintptr_t* length);
const PhysMem& phys_mem_;
async_dispatcher_t* dispatcher_;
VirtioQueue* queue_;
std::atomic<trace_async_id_t>* trace_flow_id_;
zx_handle_t fifo_ = ZX_HANDLE_INVALID;
bool rx_ = false;
IoBuffer* io_buf_;
std::vector<fuchsia_hardware_ethernet_FifoEntry> fifo_entries_;
// Number of entries in |fifo_entries_| that have not yet been written
// to the fifo.
size_t fifo_num_entries_ = 0;
// In the case of a short write to the fifo, we'll need to resume writing
// from the middle of |fifo_entries_|. This is the index of the first item
// to be written.
size_t fifo_entries_write_index_ = 0;
VirtioQueueWaiter queue_wait_;
async::WaitMethod<Stream, &Stream::OnFifoWritable> fifo_writable_wait_{
this};
async::WaitMethod<Stream, &Stream::OnFifoReadable> fifo_readable_wait_{
this};
};
Stream rx_stream_;
Stream tx_stream_;
IoBuffer io_buf_;
};
#endif // GARNET_BIN_GUEST_VMM_VIRTIO_NET_LEGACY_H_