Loading...
Searching...
No Matches
virtio_net.h
/*
* Copyright (C) 2016-2017, 2019, 2022-2024 Kernkonzept GmbH.
* Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
* Alexander Warg <warg@os.inf.tu-dresden.de>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/re/dataspace>
#include <l4/re/util/unique_cap>
#include <l4/sys/cxx/ipc_epiface>
#include <l4/l4virtio/server/virtio>
#include <l4/l4virtio/server/l4virtio>
#include <l4/l4virtio/l4virtio>
#include "debug.h"
class Virtqueue : public L4virtio::Svr::Virtqueue
{
public:
bool kick_queue()
{
if (no_notify_guest())
return false;
if (_do_kick)
return true;
_kick_pending = true;
return false;
}
bool kick_enable_get_pending()
{
_do_kick = true;
return _kick_pending;
}
void kick_disable_and_remember()
{
_do_kick = false;
_kick_pending = false;
}
private:
bool _do_kick = true;
bool _kick_pending = false;
};
class Virtio_net :
public L4virtio::Svr::Device,
public L4::Epiface_t<Virtio_net, L4virtio::Device>
{
public:
struct Hdr_flags
{
l4_uint8_t raw;
CXX_BITFIELD_MEMBER( 0, 0, need_csum, raw);
CXX_BITFIELD_MEMBER( 1, 1, data_valid, raw);
};
struct Hdr
{
Hdr_flags flags;
l4_uint8_t gso_type;
l4_uint16_t hdr_len;
l4_uint16_t gso_size;
l4_uint16_t csum_start;
l4_uint16_t csum_offset;
l4_uint16_t num_buffers;
};
struct Features : L4virtio::Svr::Dev_config::Features
{
Features() = default;
Features(l4_uint32_t raw) : L4virtio::Svr::Dev_config::Features(raw) {}
CXX_BITFIELD_MEMBER( 0, 0, csum, raw); // host handles partial csum
CXX_BITFIELD_MEMBER( 1, 1, guest_csum, raw); // guest handles partial csum
CXX_BITFIELD_MEMBER( 5, 5, mac, raw); // host has given mac
CXX_BITFIELD_MEMBER( 6, 6, gso, raw); // host handles packets /w any GSO
CXX_BITFIELD_MEMBER( 7, 7, guest_tso4, raw); // guest handles TSOv4 in
CXX_BITFIELD_MEMBER( 8, 8, guest_tso6, raw); // guest handles TSOv6 in
CXX_BITFIELD_MEMBER( 9, 9, guest_ecn, raw); // guest handles TSO[6] with ECN in
CXX_BITFIELD_MEMBER(10, 10, guest_ufo, raw); // guest handles UFO in
CXX_BITFIELD_MEMBER(11, 11, host_tso4, raw); // host handles TSOv4 in
CXX_BITFIELD_MEMBER(12, 12, host_tso6, raw); // host handles TSOv6 in
CXX_BITFIELD_MEMBER(13, 13, host_ecn, raw); // host handles TSO[6] with ECN in
CXX_BITFIELD_MEMBER(14, 14, host_ufo, raw); // host handles UFO
CXX_BITFIELD_MEMBER(15, 15, mrg_rxbuf, raw); // host can merge receive buffers
CXX_BITFIELD_MEMBER(16, 16, status, raw); // virtio_net_config.status available
CXX_BITFIELD_MEMBER(17, 17, ctrl_vq, raw); // Control channel available
CXX_BITFIELD_MEMBER(18, 18, ctrl_rx, raw); // Control channel RX mode support
CXX_BITFIELD_MEMBER(19, 19, ctrl_vlan, raw); // Control channel VLAN filtering
CXX_BITFIELD_MEMBER(20, 20, ctrl_rx_extra, raw); // Extra RX mode control support
CXX_BITFIELD_MEMBER(21, 21, guest_announce, raw); // Guest can announce device on the network
CXX_BITFIELD_MEMBER(22, 22, mq, raw); // Device supports Receive Flow Steering
CXX_BITFIELD_MEMBER(23, 23, ctrl_mac_addr, raw); // Set MAC address
};
enum
{
Rx = 0,
Tx = 1,
};
struct Net_config_space
{
// The config defining mac address (if VIRTIO_NET_F_MAC aka Features::mac)
l4_uint8_t mac[6];
// currently not used ...
l4_uint16_t status;
l4_uint16_t max_virtqueue_pairs;
};
L4virtio::Svr::Dev_config_t<Net_config_space> _dev_config;
explicit Virtio_net(unsigned vq_max)
: L4virtio::Svr::Device(&_dev_config),
_dev_config(L4VIRTIO_VENDOR_KK, L4VIRTIO_ID_NET, 2),
_vq_max(vq_max)
{
Features hf(0);
hf.ring_indirect_desc() = true;
hf.mrg_rxbuf() = true;
#if 0
// disable currently unsupported options, but leave them in for
// documentation purposes
hf.csum() = true;
hf.host_tso4() = true;
hf.host_tso6() = true;
hf.host_ufo() = true;
hf.host_ecn() = true;
hf.guest_csum() = true;
hf.guest_tso4() = true;
hf.guest_tso6() = true;
hf.guest_ufo() = true;
hf.guest_ecn() = true;
#endif
_dev_config.host_features(0) = hf.raw;
_dev_config.set_host_feature(L4VIRTIO_FEATURE_VERSION_1);
_dev_config.reset_hdr();
reset_queue_config(Rx, vq_max);
reset_queue_config(Tx, vq_max);
}
void reset() override
{
for (L4virtio::Svr::Virtqueue &q: _q)
q.disable();
reset_queue_config(Rx, _vq_max);
reset_queue_config(Tx, _vq_max);
_dev_config.reset_hdr();
}
template<typename T, unsigned N >
static unsigned array_length(T (&)[N]) { return N; }
int reconfig_queue(unsigned index) override
{
Dbg(Dbg::Virtio, Dbg::Info, "Virtio")
.printf("(%p): Reconfigure queue %d (%p): Status: %02x\n",
this, index, _q + index, _dev_config.status().raw);
if (index >= array_length(_q))
return -L4_ERANGE;
if (setup_queue(_q + index, index, _vq_max))
return 0;
return -L4_EINVAL;
}
void dump_features(Dbg const &dbg, const volatile l4_uint32_t *p)
{
dbg.cprintf("%08x:%08x:%08x:%08x:%08x:%08x:%08x:%08x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[17]);
}
void dump_features()
{
Dbg info(Dbg::Virtio, Dbg::Info, "Virtio");
if (!info.is_active())
return;
auto *hdr = _dev_config.hdr();
info.printf("Device %p running (%02x)\n\thost features: ",
this, _dev_config.status().raw);
dump_features(info, hdr->dev_features_map);
info.printf("\tguest features: ");
dump_features(info, hdr->driver_features_map);
}
bool check_features() override
{
_negotiated_features = _dev_config.negotiated_features(0);
return true;
}
bool device_needs_reset() const
{ return _dev_config.status().device_needs_reset(); }
bool check_queues() override
{
for (L4virtio::Svr::Virtqueue &q: _q)
if (!q.ready())
{
reset();
Err().printf("failed to start queues\n");
return false;
}
dump_features();
return true;
}
Server_iface *server_iface() const override
{ return L4::Epiface::server_iface(); }
void register_single_driver_irq() override
{
_kick_guest_irq = L4Re::Util::Unique_cap<L4::Irq>(
L4Re::chkcap(server_iface()->template rcv_cap<L4::Irq>(0)));
L4Re::chksys(server_iface()->realloc_rcv_cap(0));
}
void trigger_driver_config_irq() override
{
_dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_CONFIG);
_kick_guest_irq->trigger();
}
void notify_queue(L4virtio::Svr::Virtqueue *queue)
{
// Downcast to Virtqueue to access kick_queue() - we know that our
// queues have the type Virtqueue.
Virtqueue *q = static_cast<Virtqueue*>(queue);
if (q->kick_queue())
{
_dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
_kick_guest_irq->trigger();
}
}
void kick_emit_and_enable()
{
bool kick_pending = false;
for (auto &q : _q)
kick_pending |= q.kick_enable_get_pending();
if (kick_pending)
{
_dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
_kick_guest_irq->trigger();
}
}
void kick_disable_and_remember()
{
for (auto &q : _q)
q.kick_disable_and_remember();
}
Features negotiated_features() const
{ return _negotiated_features; }
Virtqueue *tx_q() { return &_q[Tx]; }
Virtqueue *rx_q() { return &_q[Rx]; }
Virtqueue const *tx_q() const { return &_q[Tx]; }
Virtqueue const *rx_q() const { return &_q[Rx]; }
private:
Features _negotiated_features;
unsigned _vq_max;
Virtqueue _q[2];
L4Re::Util::Unique_cap<L4::Irq> _kick_guest_irq;
};
L4virtio::Svr::Dev_config::add_irq_status
void add_irq_status(l4_uint32_t status)
Adds irq status bit.
Definition l4virtio:265
L4virtio::Svr::Dev_config::status
Status status() const
Get current device status (trusted).
Definition l4virtio:222
L4virtio::Svr::Device_t< No_custom_data >::setup_queue
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Definition l4virtio:1047
L4virtio::Svr::Device_t< No_custom_data >::reset_queue_config
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false)
Definition l4virtio:1002
L4virtio::Svr::Virtqueue
Virtqueue implementation for the device.
Definition virtio:88
L4virtio::Virtqueue::no_notify_guest
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:414
Virtio_net::reconfig_queue
int reconfig_queue(unsigned index) override
callback for client queue-config request
Definition virtio_net.h:184
Virtio_net::trigger_driver_config_irq
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
Definition virtio_net.h:257
Virtio_net::check_features
bool check_features() override
callback for checking the subset of accepted features
Definition virtio_net.h:220
Virtio_net::tx_q
Virtqueue const * tx_q() const
Getter for the transmission queue.
Definition virtio_net.h:309
Virtio_net::notify_queue
void notify_queue(L4virtio::Svr::Virtqueue *queue)
Trigger the _kick_guest_irq IRQ.
Definition virtio_net.h:269
Virtio_net::reset
void reset() override
reset callback, called for doing a device reset
Definition virtio_net.h:171
Virtio_net::check_queues
bool check_queues() override
Check whether both virtqueues are ready.
Definition virtio_net.h:230
Virtio_net::register_single_driver_irq
void register_single_driver_irq() override
Save the _kick_guest_irq that the client sent via device_notification_irq().
Definition virtio_net.h:250
Virtio_net::rx_q
Virtqueue * rx_q()
Getter for the receive queue.
Definition virtio_net.h:307
Virtio_net::rx_q
Virtqueue const * rx_q() const
Getter for the receive queue.
Definition virtio_net.h:311
Virtio_net::tx_q
Virtqueue * tx_q()
Getter for the transmission queue.
Definition virtio_net.h:305
dataspace
Dataspace interface.
l4_uint8_t
unsigned char l4_uint8_t
Unsigned 8bit value.
Definition l4int.h:25
l4_uint32_t
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
l4_uint16_t
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
L4_ERANGE
@ L4_ERANGE
Range error.
Definition err.h:48
L4_EINVAL
@ L4_EINVAL
Invalid argument.
Definition err.h:46
L4VIRTIO_FEATURE_VERSION_1
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
Definition virtio.h:101
L4VIRTIO_ID_NET
@ L4VIRTIO_ID_NET
Virtual ethernet card.
Definition virtio.h:64
L4VIRTIO_IRQ_STATUS_VRING
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
Definition virtio.h:112
L4VIRTIO_IRQ_STATUS_CONFIG
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
Definition virtio.h:113
L4Re::Util::Unique_cap
L4::Detail::Unique_cap_impl< T, Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
Definition unique_cap:43
L4Re::chksys
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition error_helper:72
L4Re::chkcap
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition error_helper:149
L4::Epiface_t
Epiface implementation for Kobject-based interface implementations.
Definition ipc_epiface:504
L4::Epiface::server_iface
Server_iface * server_iface() const
Get pointer to server interface at which the object is currently registered.
Definition ipc_epiface:213
L4::Epiface::Server_iface
Ipc_svr::Server_iface Server_iface
Type for abstract server interface.
Definition ipc_epiface:151
L4virtio::Svr::Dev_features::raw
l4_uint32_t raw
The raw value of the features bitmap.
Definition virtio:68
L4virtio::Svr::Dev_features::ring_indirect_desc
constexpr ring_indirect_desc_bfm_t::Val ring_indirect_desc() const
Get the ring_indirect_desc bits (28 to 28) of raw.
Definition virtio:74
L4virtio::Svr::Dev_status::device_needs_reset
constexpr device_needs_reset_bfm_t::Val device_needs_reset() const
Get the device_needs_reset bits (6 to 6) of raw.
Definition virtio:45
unique_cap
Unique_cap / Unique_del_cap.