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.