L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
virtio_net.h
1/*
2 * Copyright (C) 2016-2017, 2019, 2022-2024 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
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
95 {
96 Features() = default;
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 _dev_config(L4VIRTIO_VENDOR_KK, L4VIRTIO_ID_NET, 2),
142 _vq_max(vq_max)
143 {
144 Features hf(0);
145 hf.ring_indirect_desc() = true;
146 hf.mrg_rxbuf() = true;
147#if 0
148 // disable currently unsupported options, but leave them in for
149 // documentation purposes
150 hf.csum() = true;
151 hf.host_tso4() = true;
152 hf.host_tso6() = true;
153 hf.host_ufo() = true;
154 hf.host_ecn() = true;
155
156 hf.guest_csum() = true;
157 hf.guest_tso4() = true;
158 hf.guest_tso6() = true;
159 hf.guest_ufo() = true;
160 hf.guest_ecn() = true;
161#endif
162
163 _dev_config.host_features(0) = hf.raw;
164 _dev_config.set_host_feature(L4VIRTIO_FEATURE_VERSION_1);
165 _dev_config.reset_hdr();
166
167 reset_queue_config(Rx, vq_max);
168 reset_queue_config(Tx, vq_max);
169 }
170
171 void reset() override
172 {
173 for (L4virtio::Svr::Virtqueue &q: _q)
174 q.disable();
175
176 reset_queue_config(Rx, _vq_max);
177 reset_queue_config(Tx, _vq_max);
178 _dev_config.reset_hdr();
179 }
180
181 template<typename T, unsigned N >
182 static unsigned array_length(T (&)[N]) { return N; }
183
184 int reconfig_queue(unsigned index) override
185 {
186 Dbg(Dbg::Virtio, Dbg::Info, "Virtio")
187 .printf("(%p): Reconfigure queue %d (%p): Status: %02x\n",
188 this, index, _q + index, _dev_config.status().raw);
189
190 if (index >= array_length(_q))
191 return -L4_ERANGE;
192
193 if (setup_queue(_q + index, index, _vq_max))
194 return 0;
195
196 return -L4_EINVAL;
197 }
198
199 void dump_features(Dbg const &dbg, const volatile l4_uint32_t *p)
200 {
201 dbg.cprintf("%08x:%08x:%08x:%08x:%08x:%08x:%08x:%08x\n",
202 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[17]);
203 }
204
205 void dump_features()
206 {
207 Dbg info(Dbg::Virtio, Dbg::Info, "Virtio");
208 if (!info.is_active())
209 return;
210
211 auto *hdr = _dev_config.hdr();
212
213 info.printf("Device %p running (%02x)\n\thost features: ",
214 this, _dev_config.status().raw);
215 dump_features(info, hdr->dev_features_map);
216 info.printf("\tguest features: ");
217 dump_features(info, hdr->driver_features_map);
218 }
219
220 bool device_needs_reset() const
221 { return _dev_config.status().device_needs_reset(); }
222
224 bool check_queues() override
225 {
226 for (L4virtio::Svr::Virtqueue &q: _q)
227 if (!q.ready())
228 {
229 reset();
230 Err().printf("failed to start queues\n");
231 return false;
232 }
233 dump_features();
234 return true;
235 }
236
237 Server_iface *server_iface() const override
238 { return L4::Epiface::server_iface(); }
239
245 {
246 _kick_guest_irq = L4Re::Util::Unique_cap<L4::Irq>(
247 L4Re::chkcap(server_iface()->template rcv_cap<L4::Irq>(0)));
248 L4Re::chksys(server_iface()->realloc_rcv_cap(0));
249 }
250
252 {
253 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_CONFIG);
254 _kick_guest_irq->trigger();
255 }
256
264 {
265 // Downcast to Virtqueue to access kick_queue() - we know that our
266 // queues have the type Virtqueue.
267 Virtqueue *q = static_cast<Virtqueue*>(queue);
268 if (q->kick_queue())
269 {
270 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
271 _kick_guest_irq->trigger();
272 }
273 }
274
275 void kick_emit_and_enable()
276 {
277 bool kick_pending = false;
278
279 for (auto &q : _q)
280 kick_pending |= q.kick_enable_get_pending();
281
282 if (kick_pending)
283 {
284 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
285 _kick_guest_irq->trigger();
286 }
287 }
288
289 void kick_disable_and_remember()
290 {
291 for (auto &q : _q)
292 q.kick_disable_and_remember();
293 }
294
296 Virtqueue *tx_q() { return &_q[Tx]; }
298 Virtqueue *rx_q() { return &_q[Rx]; }
300 Virtqueue const *tx_q() const { return &_q[Tx]; }
302 Virtqueue const *rx_q() const { return &_q[Rx]; }
303
304private:
306 unsigned _vq_max;
308 Virtqueue _q[2];
313 L4Re::Util::Unique_cap<L4::Irq> _kick_guest_irq;
314};
Server-side L4-VIRTIO device stub.
Definition l4virtio:796
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Enable/disable the specified queue.
Definition l4virtio:1041
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false)
Trigger reset for the configuration space for queue idx.
Definition l4virtio:996
Virtqueue implementation for the device.
Definition virtio:88
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:413
The Base class of a Port.
Definition virtio_net.h:74
int reconfig_queue(unsigned index) override
callback for client queue-config request
Definition virtio_net.h:184
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
Definition virtio_net.h:251
Virtqueue const * tx_q() const
Getter for the transmission queue.
Definition virtio_net.h:300
void notify_queue(L4virtio::Svr::Virtqueue *queue)
Trigger the _kick_guest_irq IRQ.
Definition virtio_net.h:263
void reset() override
reset callback, called for doing a device reset
Definition virtio_net.h:171
bool check_queues() override
Check whether both virtqueues are ready.
Definition virtio_net.h:224
void register_single_driver_irq() override
Save the _kick_guest_irq that the client sent via device_notification_irq().
Definition virtio_net.h:244
Virtqueue * rx_q()
Getter for the receive queue.
Definition virtio_net.h:298
Virtqueue const * rx_q() const
Getter for the receive queue.
Definition virtio_net.h:302
Virtqueue * tx_q()
Getter for the transmission queue.
Definition virtio_net.h:296
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:48
@ L4_EINVAL
Invalid argument.
Definition err.h:46
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
Definition virtio.h:99
@ L4VIRTIO_ID_NET
Virtual ethernet card.
Definition virtio.h:63
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
Definition virtio.h:110
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
Definition virtio.h:111
L4::Detail::Unique_cap_impl< T, 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
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition error_helper:72
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition error_helper:149
Debug C interface.
Epiface implementation for Kobject-based interface implementations.
Definition ipc_epiface:504
Server_iface * server_iface() const
Get pointer to server interface at which the object is currently registered.
Definition ipc_epiface:213
Ipc_svr::Server_iface Server_iface
Type for abstract server interface.
Definition ipc_epiface:151
Type for device feature bitmap.
Definition virtio:67
l4_uint32_t raw
The raw value of the features bitmap.
Definition virtio:68
Unique_cap / Unique_del_cap.