L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
request.h
1/*
2 * Copyright (C) 2016-2017, 2020, 2022, 2024 Kernkonzept GmbH.
3 * Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
4 *
5 * License: see LICENSE.spdx (in this directory or the directories above)
6 */
7#pragma once
8
9#include <l4/l4virtio/server/virtio>
10#include <l4/util/assert.h>
11
12#include "virtio_net_buffer.h"
13#include "virtio_net.h"
14#include "mac_addr.h"
15#include "debug.h"
16#include "vlan.h"
17
18#include <optional>
19#include <utility>
20
36{
37private:
38 /* needed for Virtqueue::finish() */
40 Virtio_net *_dev;
44
45 /* the actual request processor, encapsulates the decoding of the request */
47
48 /* A request to the virtio net layer consists of one or more buffers
49 containing the Virtio_net::Hdr and the actual packet. To make a
50 switching decision we need to be able to look at the packet while
51 still being able access the Virtio_net::Hdr for the actual copy
52 operation. Therefore we keep track of two locations, the header
53 location and the start of the packet (which might be in a
54 different buffer) */
55 Virtio_net::Hdr *_header;
56 Buffer _pkt;
57
58 bool _next_buffer(Buffer *buf)
59 { return _req_proc.next(_dev->mem_info(), buf); }
60
67 void finish()
68 {
69 if (_queue == nullptr || !_queue->ready())
70 return;
71
72 Dbg(Dbg::Virtio, Dbg::Trace).printf("%s(%p)\n", __PRETTY_FUNCTION__, this);
73 _queue->finish(_head, _dev, 0);
74 _queue = nullptr;
75 }
76
77public:
78
90 const uint8_t *buffer(size_t *size) const
91 {
92 *size = _pkt.left;
93 return (uint8_t *)_pkt.pos;
94 }
95
96 void dump_request(Virtio_net *dev) const
97 {
98 uint8_t *packet = (uint8_t *)_pkt.pos;
99 Dbg debug(Dbg::Request, Dbg::Debug, "REQ");
100 if (debug.is_active())
101 {
102 debug.printf("%p: Next packet: %p:%p - %x bytes\n",
103 dev, _header, packet, _pkt.left);
104 if (_header->flags.raw || _header->gso_type)
105 {
106 debug.cprintf("flags:\t%x\n\t"
107 "gso_type:\t%x\n\t"
108 "header len:\t%x\n\t"
109 "gso size:\t%x\n\t"
110 "csum start:\t%x\n\t"
111 "csum offset:\t%x\n"
112 "\tnum buffer:\t%x\n",
113 _header->flags.raw,
114 _header->gso_type, _header->hdr_len,
115 _header->gso_size,
116 _header->csum_start, _header->csum_offset,
117 _header->num_buffers);
118 }
119 }
120 Dbg pkt_debug(Dbg::Packet, Dbg::Debug, "PKT");
121 if (pkt_debug.is_active())
122 {
123 pkt_debug.cprintf("\t");
124 src_mac().print(pkt_debug);
125 pkt_debug.cprintf(" -> ");
126 dst_mac().print(pkt_debug);
127 pkt_debug.cprintf("\n");
128 if (Dbg::is_active(Dbg::Packet, Dbg::Trace))
129 {
130 pkt_debug.cprintf("\n\tEthertype: ");
131 uint16_t ether_type = (uint16_t)*(packet + 12) << 8
132 | (uint16_t)*(packet + 13);
133 char const *protocol;
134 switch (ether_type)
135 {
136 case 0x0800: protocol = "IPv4"; break;
137 case 0x0806: protocol = "ARP"; break;
138 case 0x8100: protocol = "Vlan"; break;
139 case 0x86dd: protocol = "IPv6"; break;
140 case 0x8863: protocol = "PPPoE Discovery"; break;
141 case 0x8864: protocol = "PPPoE Session"; break;
142 default: protocol = nullptr;
143 }
144 if (protocol)
145 pkt_debug.cprintf("%s\n", protocol);
146 else
147 pkt_debug.cprintf("%04x\n", ether_type);
148 }
149 }
150 }
151
152 // delete copy constructor and copy assignment operator
153 Virtio_net_request(Virtio_net_request const &) = delete;
154 Virtio_net_request &operator = (Virtio_net_request const &) = delete;
155
156 // define move constructor and copy assignment operator
158 : _dev(other._dev),
159 _queue(other._queue),
160 _head(std::move(other._head)),
161 _req_proc(std::move(other._req_proc)),
162 _header(other._header),
163 _pkt(std::move(other._pkt))
164 {
165
166 // Invalidate other.
167 other._queue = nullptr;
168 }
169
170 Virtio_net_request &operator = (Virtio_net_request &&other)
171 {
172 // Invalidate self.
173 finish();
174
175 _dev = other._dev;
176 _queue = other._queue;
177 _head = std::move(other._head);
178 _req_proc = std::move(other._req_proc);
179 _header = other._header;
180 _pkt = std::move(other._pkt);
181
182 // Invalidate other.
183 other._queue = nullptr;
184
185 return *this;
186 }
187
189 L4virtio::Svr::Virtqueue::Request const &req)
190 : _dev(dev), _queue(queue)
191 {
192 _head = _req_proc.start(_dev->mem_info(), req, &_pkt);
193
194 _header = (Virtio_net::Hdr *)_pkt.pos;
195 l4_uint32_t skipped = _pkt.skip(sizeof(Virtio_net::Hdr));
196
197 if (L4_UNLIKELY( (skipped != sizeof(Virtio_net::Hdr))
198 || (_pkt.done() && !_next_buffer(&_pkt))))
199 {
200 _header = 0;
201 Dbg(Dbg::Queue, Dbg::Warn).printf("Invalid request\n");
202 return;
203 }
204 }
205
207 { finish(); }
208
209 bool valid() const
210 { return _header != 0; }
211
222 static void drop_requests(Virtio_net *dev,
224 {
225 if (L4_UNLIKELY(!queue->ready()))
226 return;
227
228 if (queue->desc_avail())
229 Dbg(Dbg::Request, Dbg::Debug)
230 .printf("Dropping incoming packets on monitor port\n");
231
233 Buffer pkt;
234
235 while (auto req = queue->next_avail())
236 {
237 auto head = req_proc.start(dev->mem_info(), req, &pkt);
238 queue->finish(head, dev, 0);
239 }
240 }
241
248 static std::optional<Virtio_net_request>
250 {
251 if (L4_UNLIKELY(!queue->ready()))
252 return std::nullopt;
253
254 if (auto r = queue->next_avail())
255 {
256 // Virtio_net_request keeps "a lot of internal state",
257 // therefore we create the object before creating the
258 // state.
259 // We might check later on whether it is possible to
260 // save the state when we actually have to because a
261 // transfer is blocking on a port.
262 auto request = Virtio_net_request(dev, queue, r);
263 if (request.valid())
264 {
265 request.dump_request(dev);
266 return request;
267 }
268 }
269 return std::nullopt;
270 }
271
272 Buffer const &first_buffer() const
273 { return _pkt; }
274
275 Virtio_net::Hdr const *header() const
276 { return _header; }
277
280 {
281 return (_pkt.pos && _pkt.left >= Mac_addr::Addr_length)
282 ? Mac_addr(_pkt.pos)
283 : Mac_addr(Mac_addr::Addr_unknown);
284 }
285
288 {
289 return (_pkt.pos && _pkt.left >= Mac_addr::Addr_length * 2)
290 ? Mac_addr(_pkt.pos + Mac_addr::Addr_length)
291 : Mac_addr(Mac_addr::Addr_unknown);
292 }
293
294 bool has_vlan() const
295 {
296 if (!_pkt.pos || _pkt.left < 14)
297 return false;
298
299 uint8_t *p = reinterpret_cast<uint8_t*>(_pkt.pos);
300 return p[12] == 0x81U && p[13] == 0x00U;
301 }
302
303 uint16_t vlan_id() const
304 {
305 if (!has_vlan() || _pkt.left < 16)
306 return VLAN_ID_NATIVE;
307
308 uint8_t *p = reinterpret_cast<uint8_t*>(_pkt.pos);
309 return ((uint16_t)p[14] << 8 | (uint16_t)p[15]) & 0xfffU;
310 }
311
312 L4virtio::Svr::Request_processor const &get_request_processor() const
313 { return _req_proc; }
314
315 Virtio_net const *dev() const
316 { return _dev; }
317};
Mem_list const * mem_info() const
Get the memory region list used for this device.
Definition l4virtio:892
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 wrapper class around the value of a MAC address.
Definition mac_addr.h:20
Abstraction for a network request.
Definition request.h:36
const uint8_t * buffer(size_t *size) const
Get the location and size of the current buffer.
Definition request.h:90
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.
Definition request.h:249
static void drop_requests(Virtio_net *dev, L4virtio::Svr::Virtqueue *queue)
Drop all requests of a specific queue.
Definition request.h:222
Mac_addr src_mac() const
Get the Mac address of the source port.
Definition request.h:287
Mac_addr dst_mac() const
Get the Mac address of the destination port.
Definition request.h:279
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.
l4_uint32_t left
Bytes left in buffer.
Definition virtio:309
char * pos
Current buffer position.
Definition virtio:308
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
Definition virtio:375
bool done() const
Check if there are no more bytes left in the buffer.
Definition virtio:388
Some useful assert-style macros.