L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
virtio_net.h
1/*
2 * Copyright (C) 2016-2017, 2019, 2022-2025 Kernkonzept GmbH.
3 * Author(s): Jean Wolter <jean.wolter@kernkonzept.com>
4 * Alexander Warg <warg@os.inf.tu-dresden.de>
5 *
6 * License: see LICENSE.spdx (in this directory or the directories above)
7 */
8#pragma once
9
10#include <l4/re/dataspace>
11#include <l4/re/util/unique_cap>
12
13#include <l4/sys/cxx/ipc_epiface>
14
15#include <l4/l4virtio/server/virtio>
16#include <l4/l4virtio/server/l4virtio>
17#include <l4/l4virtio/l4virtio>
18
19#include "debug.h"
24class Virtqueue : public L4virtio::Svr::Virtqueue
25{
26public:
27 bool kick_queue()
28 {
29 if (no_notify_guest())
30 return false;
31
32 if (_do_kick)
33 return true;
34
35 _kick_pending = true;
36 return false;
37 }
38
39 bool kick_enable_get_pending()
40 {
41 _do_kick = true;
42 return _kick_pending;
43 }
44
45 void kick_disable_and_remember()
46 {
47 _do_kick = false;
48 _kick_pending = false;
49 }
50
51private:
52 bool _do_kick = true;
53 bool _kick_pending = false;
54};
55
71class Virtio_net :
72 public L4virtio::Svr::Device,
73 public L4::Epiface_t<Virtio_net, L4virtio::Device>
74{
75public:
76 struct Hdr_flags
77 {
78 l4_uint8_t raw;
79 CXX_BITFIELD_MEMBER( 0, 0, need_csum, raw);
80 CXX_BITFIELD_MEMBER( 1, 1, data_valid, raw);
81 };
82
83 struct Hdr
84 {
85 Hdr_flags flags;
86 l4_uint8_t gso_type;
87 l4_uint16_t hdr_len;
88 l4_uint16_t gso_size;
89 l4_uint16_t csum_start;
90 l4_uint16_t csum_offset;
91 l4_uint16_t num_buffers;
92 };
93
94 struct Features : L4virtio::Svr::Dev_config::Features
95 {
96 Features() = default;
97 Features(l4_uint32_t raw) : L4virtio::Svr::Dev_config::Features(raw) {}
98
99 CXX_BITFIELD_MEMBER( 0, 0, csum, raw); // host handles partial csum
100 CXX_BITFIELD_MEMBER( 1, 1, guest_csum, raw); // guest handles partial csum
101 CXX_BITFIELD_MEMBER( 5, 5, mac, raw); // host has given mac
102 CXX_BITFIELD_MEMBER( 6, 6, gso, raw); // host handles packets /w any GSO
103 CXX_BITFIELD_MEMBER( 7, 7, guest_tso4, raw); // guest handles TSOv4 in
104 CXX_BITFIELD_MEMBER( 8, 8, guest_tso6, raw); // guest handles TSOv6 in
105 CXX_BITFIELD_MEMBER( 9, 9, guest_ecn, raw); // guest handles TSO[6] with ECN in
106 CXX_BITFIELD_MEMBER(10, 10, guest_ufo, raw); // guest handles UFO in
107 CXX_BITFIELD_MEMBER(11, 11, host_tso4, raw); // host handles TSOv4 in
108 CXX_BITFIELD_MEMBER(12, 12, host_tso6, raw); // host handles TSOv6 in
109 CXX_BITFIELD_MEMBER(13, 13, host_ecn, raw); // host handles TSO[6] with ECN in
110 CXX_BITFIELD_MEMBER(14, 14, host_ufo, raw); // host handles UFO
111 CXX_BITFIELD_MEMBER(15, 15, mrg_rxbuf, raw); // host can merge receive buffers
112 CXX_BITFIELD_MEMBER(16, 16, status, raw); // virtio_net_config.status available
113 CXX_BITFIELD_MEMBER(17, 17, ctrl_vq, raw); // Control channel available
114 CXX_BITFIELD_MEMBER(18, 18, ctrl_rx, raw); // Control channel RX mode support
115 CXX_BITFIELD_MEMBER(19, 19, ctrl_vlan, raw); // Control channel VLAN filtering
116 CXX_BITFIELD_MEMBER(20, 20, ctrl_rx_extra, raw); // Extra RX mode control support
117 CXX_BITFIELD_MEMBER(21, 21, guest_announce, raw); // Guest can announce device on the network
118 CXX_BITFIELD_MEMBER(22, 22, mq, raw); // Device supports Receive Flow Steering
119 CXX_BITFIELD_MEMBER(23, 23, ctrl_mac_addr, raw); // Set MAC address
120 };
121
122 enum
123 {
124 Rx = 0,
125 Tx = 1,
126 };
127
128 struct Net_config_space
129 {
130 // The config defining mac address (if VIRTIO_NET_F_MAC aka Features::mac)
131 l4_uint8_t mac[6];
132 // currently not used ...
133 l4_uint16_t status;
134 l4_uint16_t max_virtqueue_pairs;
135 };
136
137 L4virtio::Svr::Dev_config_t<Net_config_space> _dev_config;
138
139 explicit Virtio_net(unsigned vq_max)
140 : L4virtio::Svr::Device(&_dev_config,
141 Dbg{Dbg::Virtio, Dbg::Warn},
142 Dbg{Dbg::Virtio, Dbg::Debug}),
143 _dev_config(L4VIRTIO_VENDOR_KK, L4VIRTIO_ID_NET, 2),
144 _vq_max(vq_max)
145 {
146 Features hf(0);
147 hf.ring_indirect_desc() = true;
148 hf.mrg_rxbuf() = true;
149#if 0
150 // disable currently unsupported options, but leave them in for
151 // documentation purposes
152 hf.csum() = true;
153 hf.host_tso4() = true;
154 hf.host_tso6() = true;
155 hf.host_ufo() = true;
156 hf.host_ecn() = true;
157
158 hf.guest_csum() = true;
159 hf.guest_tso4() = true;
160 hf.guest_tso6() = true;
161 hf.guest_ufo() = true;
162 hf.guest_ecn() = true;
163#endif
164
165 _dev_config.host_features(0) = hf.raw;
166 _dev_config.set_host_feature(L4VIRTIO_FEATURE_VERSION_1);
167 _dev_config.reset_hdr();
168
169 reset_queue_config(Rx, vq_max);
170 reset_queue_config(Tx, vq_max);
171 }
172
173 void reset() override
174 {
175 for (L4virtio::Svr::Virtqueue &q: _q)
176 q.disable();
177
178 reset_queue_config(Rx, _vq_max);
179 reset_queue_config(Tx, _vq_max);
180 _dev_config.reset_hdr();
181 }
182
183 template<typename T, unsigned N >
184 static unsigned array_length(T (&)[N]) { return N; }
185
186 int reconfig_queue(unsigned index) override
187 {
188 Dbg(Dbg::Virtio, Dbg::Info, "Virtio")
189 .printf("(%p): Reconfigure queue %d (%p): Status: %02x\n",
190 this, index, _q + index, _dev_config.status().raw);
191
192 if (index >= array_length(_q))
193 return -L4_ERANGE;
194
195 if (setup_queue(_q + index, index, _vq_max))
196 return 0;
197
198 return -L4_EINVAL;
199 }
200
201 void dump_features(Dbg const &dbg, const volatile l4_uint32_t *p)
202 {
203 dbg.cprintf("%08x:%08x:%08x:%08x:%08x:%08x\n",
204 p[0], p[1], p[2], p[3], p[4], p[5]);
205 }
206
207 void dump_features()
208 {
209 Dbg info(Dbg::Virtio, Dbg::Info, "Virtio");
210 if (!info.is_active())
211 return;
212
213 auto *hdr = _dev_config.hdr();
214
215 info.printf("Device %p running (%02x)\n\thost features: ",
216 this, _dev_config.status().raw);
217 dump_features(info, hdr->dev_features_map);
218 info.printf("\tguest features: ");
219 dump_features(info, hdr->driver_features_map);
220 }
221
222 bool check_features() override
223 {
224 _negotiated_features = _dev_config.negotiated_features(0);
225 return true;
226 }
227
228 bool device_needs_reset() const
229 { return _dev_config.status().device_needs_reset(); }
230
232 bool check_queues() override
233 {
234 for (L4virtio::Svr::Virtqueue &q: _q)
235 if (!q.ready())
236 {
237 reset();
238 Err().printf("failed to start queues\n");
239 return false;
240 }
241 dump_features();
242 return true;
243 }
244
245 Server_iface *server_iface() const override
246 { return L4::Epiface::server_iface(); }
247
253 {
254 _kick_guest_irq = L4Re::Util::Unique_cap<L4::Irq>(
255 L4Re::chkcap(server_iface()->template rcv_cap<L4::Irq>(0)));
256 L4Re::chksys(server_iface()->realloc_rcv_cap(0));
257 }
258
260 {
261 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_CONFIG);
262 _kick_guest_irq->trigger();
263 }
264
272 {
273 // Downcast to Virtqueue to access kick_queue() - we know that our
274 // queues have the type Virtqueue.
275 Virtqueue *q = static_cast<Virtqueue*>(queue);
276 if (q->kick_queue())
277 {
278 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
279 _kick_guest_irq->trigger();
280 }
281 }
282
283 void kick_emit_and_enable()
284 {
285 bool kick_pending = false;
286
287 for (auto &q : _q)
288 kick_pending |= q.kick_enable_get_pending();
289
290 if (kick_pending)
291 {
293 _kick_guest_irq->trigger();
294 }
295 }
296
297 void kick_disable_and_remember()
298 {
299 for (auto &q : _q)
300 q.kick_disable_and_remember();
301 }
302
303 Features negotiated_features() const
304 { return _negotiated_features; }
305
307 Virtqueue *tx_q() { return &_q[Tx]; }
309 Virtqueue *rx_q() { return &_q[Rx]; }
311 Virtqueue const *tx_q() const { return &_q[Tx]; }
313 Virtqueue const *rx_q() const { return &_q[Rx]; }
314
315private:
316 Features _negotiated_features;
318 unsigned _vq_max;
320 Virtqueue _q[2];
325 L4Re::Util::Unique_cap<L4::Irq> _kick_guest_irq;
326};
327
void add_irq_status(l4_uint32_t status)
Adds irq status bit.
Definition l4virtio:274
Status status() const
Get current device status (trusted).
Definition l4virtio:231
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Definition l4virtio:1080
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false, unsigned device_notify_index=0)
Definition l4virtio:1033
Virtqueue implementation for the device.
Definition virtio:88
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:431
int reconfig_queue(unsigned index) override
callback for client queue-config request
Definition virtio_net.h:186
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
Definition virtio_net.h:259
bool check_features() override
callback for checking the subset of accepted features
Definition virtio_net.h:222
Virtqueue const * tx_q() const
Getter for the transmission queue.
Definition virtio_net.h:311
void notify_queue(L4virtio::Svr::Virtqueue *queue)
Trigger the _kick_guest_irq IRQ.
Definition virtio_net.h:271
void reset() override
reset callback, called for doing a device reset
Definition virtio_net.h:173
bool check_queues() override
Check whether both virtqueues are ready.
Definition virtio_net.h:232
void register_single_driver_irq() override
Save the _kick_guest_irq that the client sent via device_notification_irq().
Definition virtio_net.h:252
Virtqueue * rx_q()
Getter for the receive queue.
Definition virtio_net.h:309
Virtqueue const * rx_q() const
Getter for the receive queue.
Definition virtio_net.h:313
Virtqueue * tx_q()
Getter for the transmission queue.
Definition virtio_net.h:307
Dataspace interface.
unsigned char l4_uint8_t
Unsigned 8bit value.
Definition l4int.h:25
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
@ L4_ERANGE
Range error.
Definition err.h:49
@ L4_EINVAL
Invalid argument.
Definition err.h:47
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
Definition virtio.h:104
@ L4VIRTIO_ID_NET
Virtual ethernet card.
Definition virtio.h:64
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
Definition virtio.h:115
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
Definition virtio.h:116
L4::Detail::Unique_cap_impl< T, L4Re::Util::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
T chkcap(T &&cap, char const *extra="", l4_ret_t err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition error_helper:149
l4_ret_t chksys(l4_ret_t err, char const *extra="", l4_ret_t ret=0)
Generate C++ exception on error.
Definition error_helper:72
Epiface implementation for Kobject-based interface implementations.
Definition ipc_epiface:659
Ipc_svr::Server_iface Server_iface
Type for abstract server interface.
Definition ipc_epiface:263
Server_iface * server_iface() const
Get pointer to server interface at which the object is currently registered.
Definition ipc_epiface:325
l4_uint32_t raw
The raw value of the features bitmap.
Definition virtio:68
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
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_del_cap.