L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
request_l4virtio.h
1/*
2 * Copyright (C) 2016-2017, 2020, 2022, 2024 Kernkonzept GmbH.
3 * Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
4 * Georg Kotheimer <georg.kotheimer@kernkonzept.com>
5 *
6 * License: see LICENSE.spdx (in this directory or the directories above)
7 */
8#pragma once
9
10#include "debug.h"
11#include "port.h"
12#include "request.h"
13#include "virtio_net.h"
14
15#include <l4/l4virtio/server/virtio>
16#include <l4/util/assert.h>
17
18#include <optional>
19#include <utility>
20
35class Virtio_net_request final : public Net_request
36{
37public:
38 class Virtio_net_transfer final : public Net_transfer
39 {
40 public:
41 explicit Virtio_net_transfer(Virtio_net_request const &request)
42 : _request(request),
43 // We already looked at the very first buffer to find the target of the
44 // packet. The request processor of the "parent request" contains the
45 // current state of the transaction up to this point. Since there might be
46 // more then one target for the request we have to keep track of our own
47 // state and need our own request processor instance, which will be
48 // initialized using the current state of the "parent request".
49 _req_proc(_request.get_request_processor())
50 {
51 // The buffer descriptors used for this transaction and the amount of bytes
52 // copied to the current target descriptor.
53 _cur_buf = request.first_buffer();
54 _req_id = _request.header();
55 }
56
57 // delete copy constructor and copy assignment operator
58 Virtio_net_transfer(Virtio_net_transfer const &) = delete;
59 Virtio_net_transfer &operator = (Virtio_net_transfer const &) = delete;
60
61 void copy_header(Virtio_net::Hdr *dst_header) const override
62 {
63 memcpy(dst_header, _request.header(), sizeof(Virtio_net::Hdr));
64 }
65
66 bool done() override
67 {
68 return _cur_buf.done() && !_req_proc.next(_request.dev()->mem_info(), &_cur_buf);
69 }
70
71 private:
72 Virtio_net_request const &_request;
74 };
75
76 void dump_request(Port_iface *port) const
77 {
78 Dbg debug(Dbg::Request, Dbg::Debug, "REQ-VIO");
79 if (debug.is_active())
80 {
81 debug.printf("%s: Next packet: %p:%p - %x bytes\n",
82 port->get_name(), _header, _pkt.pos, _pkt.left);
83 if (_header->flags.raw || _header->gso_type)
84 {
85 debug.cprintf("flags:\t%x\n\t"
86 "gso_type:\t%x\n\t"
87 "header len:\t%x\n\t"
88 "gso size:\t%x\n\t"
89 "csum start:\t%x\n\t"
90 "csum offset:\t%x\n"
91 "\tnum buffer:\t%x\n",
92 _header->flags.raw,
93 _header->gso_type, _header->hdr_len,
94 _header->gso_size,
95 _header->csum_start, _header->csum_offset,
96 _header->num_buffers);
97 }
98 }
99 dump_pkt();
100 }
101
102 // delete copy constructor and copy assignment operator
103 Virtio_net_request(Virtio_net_request const &) = delete;
104 Virtio_net_request &operator = (Virtio_net_request const &) = delete;
105
106 // define move constructor and copy assignment operator
108 : _dev(other._dev),
109 _queue(other._queue),
110 _head(std::move(other._head)),
111 _req_proc(std::move(other._req_proc)),
112 _header(other._header)
113 {
114 _pkt = std::move(other._pkt);
115
116 // Invalidate other.
117 other._queue = nullptr;
118 }
119
120 Virtio_net_request &operator = (Virtio_net_request &&other)
121 {
122 // Invalidate self.
123 finish();
124
125 _dev = other._dev;
126 _queue = other._queue;
127 _head = std::move(other._head);
128 _req_proc = std::move(other._req_proc);
129 _header = other._header;
130 _pkt = std::move(other._pkt);
131
132 // Invalidate other.
133 other._queue = nullptr;
134
135 return *this;
136 }
137
139 L4virtio::Svr::Virtqueue::Request const &req)
140 : _dev(dev), _queue(queue)
141 {
142 _head = _req_proc.start(_dev->mem_info(), req, &_pkt);
143
144 _header = (Virtio_net::Hdr *)_pkt.pos;
145 l4_uint32_t skipped = _pkt.skip(sizeof(Virtio_net::Hdr));
146
147 if (L4_UNLIKELY( (skipped != sizeof(Virtio_net::Hdr))
148 || (_pkt.done() && !_next_buffer(&_pkt))))
149 {
150 _header = 0;
151 Dbg(Dbg::Queue, Dbg::Warn).printf("Invalid request\n");
152 return;
153 }
154 }
155
157 { finish(); }
158
159 bool valid() const
160 { return _header != 0; }
161
172 static void drop_requests(Virtio_net *dev,
174 {
175 if (L4_UNLIKELY(!queue->ready()))
176 return;
177
178 if (queue->desc_avail())
179 Dbg(Dbg::Request, Dbg::Debug)
180 .printf("Dropping incoming packets on monitor port\n");
181
183 Buffer pkt;
184
185 while (auto req = queue->next_avail())
186 {
187 auto head = req_proc.start(dev->mem_info(), req, &pkt);
188 queue->finish(head, dev, 0);
189 }
190 }
191
198 static std::optional<Virtio_net_request>
200 {
201 if (L4_UNLIKELY(!queue->ready()))
202 return std::nullopt;
203
204 if (auto r = queue->next_avail())
205 {
206 // Virtio_net_request keeps "a lot of internal state",
207 // therefore we create the object before creating the
208 // state.
209 // We might check later on whether it is possible to
210 // save the state when we actually have to because a
211 // transfer is blocking on a port.
212 auto request = Virtio_net_request(dev, queue, r);
213 if (request.valid())
214 return request;
215 }
216 return std::nullopt;
217 }
218
219 Buffer const &first_buffer() const
220 { return _pkt; }
221
222 Virtio_net::Hdr const *header() const
223 { return _header; }
224
225 L4virtio::Svr::Request_processor const &get_request_processor() const
226 { return _req_proc; }
227
228 Virtio_net const *dev() const
229 { return _dev; }
230
231 Virtio_net_transfer transfer_src() const
232 { return Virtio_net_transfer(*this); }
233
234private:
235 /* needed for Virtqueue::finish() */
237 Virtio_net *_dev;
241
242 /* the actual request processor, encapsulates the decoding of the request */
244
245 /* A request to the virtio net layer consists of one or more buffers
246 containing the Virtio_net::Hdr and the actual packet. To make a
247 switching decision we need to be able to look at the packet while
248 still being able access the Virtio_net::Hdr for the actual copy
249 operation. Therefore we keep track of two locations, the header
250 location and the start of the packet (which might be in a
251 different buffer) */
252 Virtio_net::Hdr *_header;
253
254 bool _next_buffer(Buffer *buf)
255 { return _req_proc.next(_dev->mem_info(), buf); }
256
263 void finish()
264 {
265 if (_queue == nullptr || !_queue->ready())
266 return;
267
268 Dbg(Dbg::Virtio, Dbg::Trace).printf("%s(%p)\n", __PRETTY_FUNCTION__, this);
269 _queue->finish(_head, _dev, 0);
270 _queue = nullptr;
271 }
272};
273
Mem_list const * mem_info() const
Get the memory region list used for this device.
Definition l4virtio:898
Encapsulate the state for processing a VIRTIO request.
Definition virtio:473
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
Definition virtio:570
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition virtio:501
VIRTIO request, essentially a descriptor from the available ring.
Definition virtio:94
Virtqueue implementation for the device.
Definition virtio:88
bool desc_avail() const
Test for available descriptors.
Definition virtio:175
Request next_avail()
Get the next available descriptor from the available ring.
Definition virtio:136
void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len=0)
Add a descriptor to the used ring, and notify an observer.
Definition virtio:240
bool ready() const
Test if this queue is in working state.
Definition virtqueue:399
A network request to only a single destination.
Definition request.h:34
Abstraction for a network request.
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.
Definition virtio_net.h:74
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:275
Debug C interface.
Data buffer used to transfer packets.
bool done() const
Check if there are no more bytes left in the buffer.
Definition virtio:388
Some useful assert-style macros.