blob: f28516dc418c525a77c842a0fa11c92eea91d72f [file] [log] [blame]
// Copyright 2019 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 SRC_VIRTUALIZATION_TESTS_FAKE_NETSTACK_H_
#define SRC_VIRTUALIZATION_TESTS_FAKE_NETSTACK_H_
#include <fuchsia/hardware/ethernet/c/fidl.h>
#include <fuchsia/netstack/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/wait.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/bridge.h>
#include <zircon/device/ethernet.h>
#include <map>
#include <vector>
class Device {
public:
static zx_status_t Create(fuchsia::hardware::ethernet::DeviceSyncPtr eth_device,
std::unique_ptr<Device>* out);
zx_status_t Start(async_dispatcher_t* dispatcher);
fit::promise<std::vector<uint8_t>, zx_status_t> ReadPacket();
fit::promise<void, zx_status_t> WritePacket(std::vector<uint8_t> packet);
private:
Device(fuchsia::hardware::ethernet::DeviceSyncPtr eth_device, zx::fifo rx, zx::fifo tx,
zx::vmo vmo, uintptr_t io_addr)
: eth_device_(std::move(eth_device)),
rx_(std::move(rx)),
tx_(std::move(tx)),
vmo_(std::move(vmo)),
io_addr_(io_addr) {
rx_wait_.set_trigger(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED);
rx_wait_.set_object(rx_.get());
tx_wait_.set_trigger(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED);
tx_wait_.set_object(tx_.get());
}
void OnReceive(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal);
void OnTransmit(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal);
fit::promise<eth_fifo_entry_t, zx_status_t> GetRxEntry();
fit::promise<eth_fifo_entry_t, zx_status_t> GetTxEntry();
fuchsia::hardware::ethernet::DeviceSyncPtr eth_device_;
zx::fifo rx_;
zx::fifo tx_;
zx::vmo vmo_;
const uintptr_t io_addr_;
std::mutex mutex_;
std::vector<fit::completer<eth_fifo_entry_t, zx_status_t>> rx_completers_ __TA_GUARDED(mutex_);
std::vector<fit::completer<eth_fifo_entry_t, zx_status_t>> tx_completers_ __TA_GUARDED(mutex_);
async::WaitMethod<Device, &Device::OnReceive> rx_wait_{this};
async::WaitMethod<Device, &Device::OnTransmit> tx_wait_{this};
};
class FakeNetstack : public fuchsia::netstack::Netstack {
public:
FakeNetstack() {
// Start a thread for the Device waiters. We can't use the main test thread, because it will
// block to run test utils and deadlock the test.
loop_.StartThread("FakeNetstack");
}
~FakeNetstack() {
loop_.Quit();
loop_.JoinThreads();
loop_.Shutdown();
}
void GetInterfaces(GetInterfacesCallback callback) override {}
void GetInterfaces2(GetInterfaces2Callback callback) override {}
void GetRouteTable(GetRouteTableCallback callback) override {}
void GetRouteTable2(GetRouteTable2Callback callback) override {}
void SetInterfaceStatus(uint32_t nicid, bool enabled) override {}
void SetInterfaceAddress(uint32_t nicid, fuchsia::net::IpAddress addr, uint8_t prefixLen,
SetInterfaceAddressCallback callback) override;
void RemoveInterfaceAddress(uint32_t nicid, fuchsia::net::IpAddress addr, uint8_t prefixLen,
RemoveInterfaceAddressCallback callback) override {}
void SetInterfaceMetric(uint32_t nicid, uint32_t metric,
SetInterfaceMetricCallback callback) override {}
void GetDhcpClient(uint32_t nicid, ::fidl::InterfaceRequest<::fuchsia::net::dhcp::Client> client,
GetDhcpClientCallback callback) override {}
void BridgeInterfaces(std::vector<uint32_t> nicids, BridgeInterfacesCallback callback) override {}
void AddEthernetDevice(std::string topological_path,
fuchsia::netstack::InterfaceConfig interfaceConfig,
::fidl::InterfaceHandle<::fuchsia::hardware::ethernet::Device> device,
AddEthernetDeviceCallback callback) override;
void StartRouteTableTransaction(
::fidl::InterfaceRequest<fuchsia::netstack::RouteTableTransaction> routeTableTransaction,
StartRouteTableTransactionCallback callback) override {}
fidl::InterfaceRequestHandler<fuchsia::netstack::Netstack> GetHandler() {
return bindings_.GetHandler(this);
}
// Send a packet with UDP headers, including the ethernet and IPv6 headers, to the interface with
// the specified MAC address.
fit::promise<void, zx_status_t> SendUdpPacket(
const fuchsia::hardware::ethernet::MacAddress& mac_addr, std::vector<uint8_t> packet);
// Send a raw packet to the interface with the specified MAC address.
fit::promise<void, zx_status_t> SendPacket(
const fuchsia::hardware::ethernet::MacAddress& mac_addr, std::vector<uint8_t> packet);
// Receive a raw packet from the interface with the specified MAC address.
fit::promise<std::vector<uint8_t>, zx_status_t> ReceivePacket(
const fuchsia::hardware::ethernet::MacAddress& mac_addr);
private:
struct CompareMacAddress {
bool operator()(const fuchsia::hardware::ethernet::MacAddress& a,
const fuchsia::hardware::ethernet::MacAddress& b) const {
// The octets of a MacAddress are a std::array, which implements lexigraphical ordering.
return a.octets < b.octets;
}
};
fit::promise<Device*> GetDevice(const fuchsia::hardware::ethernet::MacAddress& mac_addr);
fidl::BindingSet<fuchsia::netstack::Netstack> bindings_;
std::mutex mutex_;
// Maps MAC addresses to devices.
std::map<fuchsia::hardware::ethernet::MacAddress, std::unique_ptr<Device>, CompareMacAddress>
devices_ __TA_GUARDED(mutex_);
// Maps MAC addresses to completers, to enable the GetDevice promises.
std::map<fuchsia::hardware::ethernet::MacAddress, std::vector<fit::completer<Device*>>,
CompareMacAddress>
completers_ __TA_GUARDED(mutex_);
async::Loop loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
uint8_t nic_counter_ = 0;
};
#endif // SRC_VIRTUALIZATION_TESTS_FAKE_NETSTACK_H_