12#include "request_l4virtio.h"
13#include "virtio_net.h"
42 explicit L4virtio_port(
unsigned vq_max,
unsigned num_ds,
char const *name,
44 : Port_iface(name), Virtio_net(vq_max)
48 Features hf = _dev_config.host_features(0);
52 memcpy((
void *)_dev_config.priv_config()->mac, mac,
53 sizeof(_dev_config.priv_config()->mac));
56 Dbg d(Dbg::Port, Dbg::Info);
57 d.cprintf(
"%s: Adding Mac '", _name);
59 d.cprintf(
"' to host features to %x\n", hf.
raw);
61 _dev_config.host_features(0) = hf.
raw;
62 _dev_config.reset_hdr();
63 Dbg(Dbg::Port, Dbg::Info)
64 .printf(
"%s: Set host features to %x\n", _name,
65 _dev_config.host_features(0));
67 _mac.to_array(_stats->mac);
71 void rx_notify_disable_and_remember()
override
73 kick_disable_and_remember();
76 void rx_notify_emit_and_enable()
override
78 kick_emit_and_enable();
81 bool is_gone()
const override
106 Result handle_request(Port_iface *src_port,
Net_transfer &src,
111 Dbg trace(Dbg::Request, Dbg::Trace,
"REQ-VIO");
112 trace.printf(
"%s: Transfer request %p.\n", _name, src.
req_id());
119 std::vector<Consumed_entry> consumed;
122 Virtqueue *dst_queue =
rx_q();
125 Virtio_net::Hdr *dst_header =
nullptr;
135 catch (L4virtio::Svr::Bad_descriptor &e)
137 trace.printf(
"\tTransfer failed, bad descriptor exception, dropping.\n");
140 if (!consumed.empty())
155 if (!dst_queue->
ready())
156 return Result::Dropped;
162 trace.printf(
"\tTransfer failed, destination queue depleted, dropping.\n");
164 if (!consumed.empty())
166 return Result::Dropped;
173 catch (L4virtio::Svr::Bad_descriptor &e)
175 Dbg(Dbg::Request, Dbg::Warn,
"REQ")
176 .printf(
"%s: bad descriptor exception: %s - %i"
177 " -- signal device error in destination device %p.\n",
178 __PRETTY_FUNCTION__, e.
message(), e.error, dst_dev);
181 return Result::Exception;
186 if (dst.
left <
sizeof(Virtio_net::Hdr))
188 "Target buffer too small for header");
189 dst_header =
reinterpret_cast<Virtio_net::Hdr *
>(dst.
pos);
190 trace.printf(
"\tCopying header to %p (size: %u)\n",
233 total =
sizeof(Virtio_net::Hdr);
241 bool has_dst_buffer = !dst.
done();
246 has_dst_buffer = dst_req_proc.
next(dst_dev->
mem_info(), &dst);
248 catch (L4virtio::Svr::Bad_descriptor &e)
250 Dbg(Dbg::Request, Dbg::Warn,
"REQ")
251 .printf(
"%s: bad descriptor exception: %s - %i"
252 " -- signal device error in destination device %p.\n",
253 __PRETTY_FUNCTION__, e.
message(), e.error, dst_dev);
255 return Result::Exception;
261 trace.printf(
"\tCopying %p#%p:%u (%x) -> %p#%p:%u (%x)\n",
262 src_port, src_buf.pos, src_buf.left, src_buf.left,
263 static_cast<Port_iface *
>(
this),
266 total += mangle.
copy_pkt(dst, src_buf);
268 else if (negotiated_features().mrg_rxbuf())
271 trace.printf(
"\tSaving descriptor for later\n");
272 consumed.push_back(Consumed_entry(dst_head, total));
273 total_merged += total;
275 dst_head = L4virtio::Svr::Virtqueue::Head_desc();
279 trace.printf(
"\tTransfer failed, destination buffer too small, dropping.\n");
282 return Result::Dropped;
295 trace.printf(
"\tTransfer - not started yet, dropping\n");
296 return Result::Dropped;
299 if (consumed.empty())
302 assert(num_merged == 1);
303 trace.printf(
"\tTransfer - Invoke dst_queue->finish()\n");
304 dst_header->num_buffers = 1;
305 dst_queue->
finish(dst_head, dst_dev, total);
306 *bytes_transferred = total;
311 dst_header->num_buffers = num_merged;
312 consumed.push_back(Consumed_entry(dst_head, total));
313 trace.printf(
"\tTransfer - Invoke dst_queue->finish(iter)\n");
314 *bytes_transferred = total + total_merged;
315 dst_queue->
finish(consumed.begin(), consumed.end(), dst_dev);
317 return Result::Delivered;
l4_msgtag_t validate(l4_utcb_t *u=l4_utcb()) const noexcept
Check whether a capability is present (refers to an object).
void device_error()
Transition device into DEVICE_NEEDS_RESET state.
void init_mem_info(unsigned num)
Mem_list const * mem_info() const
Get the memory region list used for this device.
Encapsulate the state for processing a VIRTIO request.
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
VIRTIO request, essentially a descriptor from the available ring.
bool desc_avail() const
Test for available descriptors.
Request next_avail()
Get the next available descriptor from the available ring.
void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len=0)
Add a descriptor to the used ring, and notify an observer.
void rewind_avail(Head_desc const &d)
Return unfinished descriptors to the available ring, i.e.
bool ready() const
Test if this queue is in working state.
void drop_requests()
Drop all requests pending in the transmission queue.
L4virtio_port(unsigned vq_max, unsigned num_ds, char const *name, l4_uint8_t const *mac)
Create a Virtio net port object.
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
std::optional< Virtio_net_request > get_tx_request()
Get one request from the transmission queue.
A wrapper class around the value of a MAC address.
A network request to only a single destination.
virtual void copy_header(Virtio_net::Hdr *dst_header) const =0
Populate the virtio-net header for the destination.
void const * req_id() const
Identifier for the underlying Net_request, used for logging purposes.
virtual bool done()=0
Check whether the transfer has been completed, i.e.
Buffer & cur_buf()
Buffer containing (a part of) the packet data.
static std::optional< Virtio_net_request > get_request(Virtio_net *dev, L4virtio::Svr::Virtqueue *queue)
Construct a request from the next entry of a provided queue.
static void drop_requests(Virtio_net *dev, L4virtio::Svr::Virtqueue *queue)
Drop all requests of a specific queue.
The Base class of a Port.
Virtqueue * rx_q()
Getter for the receive queue.
Virtqueue * tx_q()
Getter for the transmission queue.
Class for VLAN packet rewriting.
void rewrite_hdr(Virtio_net::Hdr *hdr)
Rewrite the virtio network header.
l4_uint32_t copy_pkt(Buffer &dst, Buffer &src)
Copy packet from src to dst.
unsigned char l4_uint8_t
Unsigned 8bit value.
unsigned short int l4_uint16_t
Unsigned 16bit value.
unsigned long long l4_uint64_t
Unsigned 64bit value.
@ L4_EINVAL
Invalid argument.
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
#define L4_LIKELY(x)
Expression is likely to execute.
Data buffer used to transfer packets.
Cap< L4virtio::Device > obj_cap() const
char const * message() const
Get a human readable description of the error code.
l4_uint32_t left
Bytes left in buffer.
char * pos
Current buffer position.
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
bool done() const
Check if there are no more bytes left in the buffer.
l4_uint32_t raw
The raw value of the features bitmap.
long label() const L4_NOTHROW
Get the protocol value.