L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
port.h
1/*
2 * Copyright (C) 2016-2018, 2020, 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 "virtio_net.h"
11#include "request.h"
12#include "transfer.h"
13#include "mac_addr.h"
14#include "vlan.h"
15
16#include <set>
17#include <vector>
18
35class Virtio_port : public Virtio_net
36{
37 /*
38 * VLAN related management information.
39 *
40 * A port may either be
41 * - a native port (_vlan_id == VLAN_ID_NATIVE), or
42 * - an access port (_vlan_id set accordingly), or
43 * - a trunk port (_vlan_id == VLAN_ID_TRUNK, _vlan_bloom_filter and
44 * _vlan_ids populated accordingly).
45 */
46 l4_uint16_t _vlan_id = VLAN_ID_NATIVE; // VID for native/access port
47 l4_uint32_t _vlan_bloom_filter = 0; // Bloom filter for trunk ports
48 std::set<l4_uint16_t> _vlan_ids; // Authoritative list of trunk VLANs
49
50 inline l4_uint32_t vlan_bloom_hash(l4_uint16_t vid)
51 { return 1UL << (vid & 31U); }
52
53 Mac_addr _mac;
54 char _name[20];
56public:
57 // delete copy and assignment
58 Virtio_port(Virtio_port const &) = delete;
59 Virtio_port &operator = (Virtio_port const &) = delete;
60
61 char const *get_name() const
62 { return _name; }
63
64 l4_uint16_t get_vlan() const
65 { return _vlan_id; }
66
67 inline bool is_trunk() const
68 { return _vlan_id == VLAN_ID_TRUNK; }
69
70 inline bool is_native() const
71 { return _vlan_id == VLAN_ID_NATIVE; }
72
73 inline bool is_access() const
74 { return !is_trunk() && !is_native(); }
75
84 {
85 assert(vlan_valid_id(id));
86 _vlan_id = id;
87 _vlan_bloom_filter = 0;
88 _vlan_ids.clear();
89 }
90
100 void set_vlan_trunk(const std::vector<l4_uint16_t> &ids)
101 {
102 // bloom filter to quickly reject packets that do not belong to this port
103 l4_uint32_t filter = 0;
104
105 _vlan_ids.clear();
106 for (const auto id : ids)
107 {
108 assert(vlan_valid_id(id));
109 filter |= vlan_bloom_hash(id);
110 _vlan_ids.insert(id);
111 }
112
113 _vlan_id = VLAN_ID_TRUNK;
114 _vlan_bloom_filter = filter;
115 }
116
124 {
125 _vlan_id = VLAN_ID_TRUNK;
126 _vlan_bloom_filter = 0;
127 }
128
137 bool match_vlan(uint16_t id)
138 {
139 // Regular case native/access port
140 if (id == _vlan_id)
141 return true;
142
143 // Quick check: does port probably accept this VLAN?
144 if ((_vlan_bloom_filter & vlan_bloom_hash(id)) == 0)
145 return false;
146
147 return _vlan_ids.find(id) != _vlan_ids.end();
148 }
149
156 inline Mac_addr mac() const
157 { return _mac; }
158
162 explicit Virtio_port(unsigned vq_max, unsigned num_ds, char const *name,
163 l4_uint8_t const *mac)
164 : Virtio_net(vq_max),
165 _mac(Mac_addr::Addr_unknown)
166 {
167 init_mem_info(num_ds);
168
169 strncpy(_name, name, sizeof(_name));
170 _name[sizeof(_name) - 1] = '\0';
171
172 Features hf = _dev_config.host_features(0);
173 if (mac)
174 {
175 _mac = Mac_addr((char const *)mac);
176 memcpy((void *)_dev_config.priv_config()->mac, mac,
177 sizeof(_dev_config.priv_config()->mac));
178
179 hf.mac() = true;
180 Dbg(Dbg::Port, Dbg::Info)
181 .printf("%s: Adding Mac to host features to %x\n", _name, hf.raw);
182 }
183 _dev_config.host_features(0) = hf.raw;
184 _dev_config.reset_hdr();
185 Dbg(Dbg::Port, Dbg::Info)
186 .printf("%s: Set host features to %x\n", _name,
187 _dev_config.host_features(0));
188 }
189
191 bool tx_work_pending() const
192 {
193 return L4_LIKELY(tx_q()->ready()) && tx_q()->desc_avail();
194 }
195
197 std::optional<Virtio_net_request> get_tx_request()
198 {
199 auto ret = Virtio_net_request::get_request(this, tx_q());
200
201 /*
202 * Trunk ports are required to have a VLAN tag and only accept packets that
203 * belong to a configured VLAN. Access ports must not be VLAN tagged to
204 * prevent double tagging attacks. Otherwise the packet is dropped.
205 */
206 if (ret)
207 {
208 if (is_trunk())
209 {
210 if (_vlan_ids.find(ret->vlan_id()) == _vlan_ids.end())
211 return std::nullopt;
212 }
213 else if (is_access() && ret->has_vlan())
214 return std::nullopt;
215 }
216
217 return ret;
218 }
219
227
237 Virtio_net_request const &request)
238 {
239 Virtio_vlan_mangle mangle;
240
241 if (is_trunk())
242 {
243 /*
244 * Add a VLAN tag only if the packet does not already have one (by
245 * coming from another trunk port) or if the packet does not belong to
246 * any VLAN (by coming from a native port). The latter case is only
247 * relevant if this is a monitor port. Otherwise traffic from native
248 * ports is never forwarded to trunk ports.
249 */
250 if (!src_port->is_trunk() && !src_port->is_native())
251 mangle = Virtio_vlan_mangle::add(src_port->_vlan_id);
252 }
253 else
254 /*
255 * Remove VLAN tag only if the packet actually has one (by coming from a
256 * trunk port).
257 */
258 if (src_port->is_trunk())
260
261 // throws Bad_descriptor exception raised in SRC port queue.
262 switch (Virtio_net_transfer::transfer(request, this, rx_q(), mangle))
263 {
264 case Virtio_net_transfer::Result::Delivered: [[fallthrough]];
265 case Virtio_net_transfer::Result::Exception: return;
266 case Virtio_net_transfer::Result::Dropped: break;
267 }
268
269 // Drop packet that could not be transferred
270 }
271};
void init_mem_info(unsigned num)
Initialize the memory region list to the given maximum.
Definition l4virtio:1006
A wrapper class around the value of a MAC address.
Definition mac_addr.h:20
Abstraction for a network request.
Definition request.h:36
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
static Result transfer(Virtio_net_request const &request, Virtio_net *dst_dev, L4virtio::Svr::Virtqueue *dst_queue, Virtio_vlan_mangle &mangle)
Deliver the request to the destination port.
Definition transfer.h:53
The Base class of a Port.
Definition virtio_net.h:74
Virtqueue * rx_q()
Getter for the receive queue.
Definition virtio_net.h:298
Virtqueue * tx_q()
Getter for the transmission queue.
Definition virtio_net.h:296
A Port on the Virtio Net Switch.
Definition port.h:36
std::optional< Virtio_net_request > get_tx_request()
Get one request from the transmission queue.
Definition port.h:197
void set_vlan_trunk(const std::vector< l4_uint16_t > &ids)
Set port as trunk port.
Definition port.h:100
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
Definition port.h:191
void set_monitor()
Set this port as monitor port.
Definition port.h:123
void set_vlan_access(l4_uint16_t id)
Set port as access port for a certain VLAN.
Definition port.h:83
void handle_request(Virtio_port *src_port, Virtio_net_request const &request)
Handle a request - send it to the guest associated with this port.
Definition port.h:236
Mac_addr mac() const
Get MAC address.
Definition port.h:156
bool match_vlan(uint16_t id)
Match VLAN id.
Definition port.h:137
Virtio_port(unsigned vq_max, unsigned num_ds, char const *name, l4_uint8_t const *mac)
Create a Virtio net port object.
Definition port.h:162
void drop_requests()
Drop all requests pending in the transmission queue.
Definition port.h:225
Class for VLAN packet rewriting.
Definition vlan.h:37
static constexpr Virtio_vlan_mangle remove()
Construct an object that removes the VLAN tag.
Definition vlan.h:75
static constexpr Virtio_vlan_mangle add(l4_uint16_t tci)
Construct an object that adds a VLAN tag.
Definition vlan.h:64
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
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:274