L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
switch.cc
1/*
2 * Copyright (C) 2016-2018, 2020, 2023-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#include "debug.h"
9#include "switch.h"
10#include "filter.h"
11
13: _max_ports{max_ports},
14 _max_used{0}
15{
16 _ports = new Virtio_port *[max_ports]();
17}
18
19int
20Virtio_switch::lookup_free_slot()
21{
22 for (unsigned idx = 0; idx < _max_ports; ++idx)
23 if (!_ports[idx])
24 return idx;
25
26 return -1;
27}
28
29bool
31{
32 if (!port->mac().is_unknown())
33 for (unsigned idx = 0; idx < _max_ports; ++idx)
34 if (_ports[idx] && _ports[idx]->mac() == port->mac())
35 {
36 Dbg(Dbg::Port, Dbg::Warn)
37 .printf("Rejecting port '%s'. MAC address already in use.\n",
38 port->get_name());
39 return false;
40 }
41
42 int idx = lookup_free_slot();
43 if (idx < 0)
44 return false;
45
46 unsigned uidx = static_cast<unsigned>(idx);
47 _ports[uidx] = port;
48 if (_max_used == uidx)
49 ++_max_used;
50
51 return true;
52}
53
54bool
56{
57 if (!_monitor)
58 {
59 _monitor = port;
60 return true;
61 }
62
63 Dbg(Dbg::Port, Dbg::Warn).printf("'%s' already defined as monitor port,"
64 " rejecting monitor port '%s'\n",
65 _monitor->get_name(), port->get_name());
66 return false;
67}
68
69void
71{
72 for (unsigned idx = 0; idx < _max_used; ++idx)
73 {
74 Virtio_port *port = _ports[idx];
75 if (port && port->obj_cap() && !port->obj_cap().validate().label())
76 {
77 Dbg(Dbg::Port, Dbg::Info)
78 .printf("Client on port %p has gone. Deleting...\n", port);
79
80 _ports[idx] = nullptr;
81 if (idx == _max_used-1)
82 --_max_used;
83
84 _mac_table.flush(port);
85 delete(port);
86 }
87 }
88
89 if ( _monitor && _monitor->obj_cap()
90 && !_monitor->obj_cap().validate().label())
91 {
92 delete(_monitor);
93 _monitor = nullptr;
94 }
95}
96
97void
98Virtio_switch::handle_tx_queue(Virtio_port *port)
99{
100 auto request = port->get_tx_request();
101 if (!request)
102 return;
103
104 Mac_addr src = request->src_mac();
105 _mac_table.learn(src, port);
106
107 auto dst = request->dst_mac();
108 bool is_broadcast = dst.is_broadcast();
109 uint16_t vlan = request->has_vlan() ? request->vlan_id() : port->get_vlan();
110 if (L4_LIKELY(!is_broadcast))
111 {
112 auto *target = _mac_table.lookup(dst);
113 if (target)
114 {
115 // Do not send packets to the port they came in; they might
116 // be sent to us by another switch which does not know how
117 // to reach the target.
118 if (target != port && target->match_vlan(vlan))
119 {
120 target->handle_request(port, *request);
121 if (_monitor && !filter_request(*request))
122 _monitor->handle_request(port, *request);
123 }
124 return;
125 }
126 }
127
128 // It is either a broadcast or an unknown destination - send to all
129 // known ports except the source port
130 for (unsigned idx = 0; idx < _max_used && _ports[idx]; ++idx)
131 {
132 auto *target = _ports[idx];
133 if (target != port && target->match_vlan(vlan))
134 target->handle_request(port, *request);
135 }
136
137 // Send a copy to the monitor port
138 if (_monitor && !filter_request(*request))
139 _monitor->handle_request(port, *request);
140}
141
142void
144{
145 /* handle IRQ on one port for the time being */
146 if (!port->tx_work_pending())
147 Dbg(Dbg::Port, Dbg::Info)
148 .printf("Port %s: Irq without pending work\n", port->get_name());
149
150 do
151 {
152 port->tx_q()->disable_notify();
153 port->rx_q()->disable_notify();
154
155 // Within the loop, to trigger before enabling notifications again.
156 all_kick_disable_remember();
157
158 try
159 {
160 // throws Bad_descriptor exceptions raised on SRC port
161 while (port->tx_work_pending())
162 handle_tx_queue(port);
163 }
165 {
166 Dbg(Dbg::Port, Dbg::Warn, "REQ")
167 .printf("%s: caught bad descriptor exception: %s - %i"
168 " -- Signal device error on device %p.\n",
169 __PRETTY_FUNCTION__, e.message(), e.error, port);
170 port->device_error();
171 all_kick_emit_enable();
172 return;
173 }
174
175 all_kick_emit_enable();
176
177 port->tx_q()->enable_notify();
178 port->rx_q()->enable_notify();
179
180 L4virtio::wmb();
181 L4virtio::rmb();
182 }
183 while (port->tx_work_pending());
184
185}
void device_error()
Transition device into DEVICE_NEEDS_RESET state.
Definition l4virtio:1018
A wrapper class around the value of a MAC address.
Definition mac_addr.h:20
bool is_unknown() const
Check if the MAC address is not yet known.
Definition mac_addr.h:63
void flush(Virtio_port *port)
Flush all associations with a given port.
Definition mac_table.h:122
Virtio_port * lookup(Mac_addr dst) const
Find the destination port for a MAC address.
Definition mac_table.h:56
void learn(Mac_addr src, Virtio_port *port)
Learn a MAC address (add it to the MAC table).
Definition mac_table.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
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
Definition port.h:191
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 add_monitor_port(Virtio_port *port)
Add a monitor port to the switch.
Definition switch.cc:55
void check_ports()
Check validity of ports.
Definition switch.cc:70
bool add_port(Virtio_port *port)
Add a port to the switch.
Definition switch.cc:30
Virtio_switch(unsigned max_ports)
Create a switch with n ports.
Definition switch.cc:12
void handle_port_irq(Virtio_port *port)
Handle an incoming irq on a given port.
Definition switch.cc:143
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:274
Debug C interface.
Cap< RPC_IFACE > obj_cap() const
Get the (typed) capability to this object.
Definition ipc_epiface:269
Exception used by Queue to indicate descriptor errors.
Definition virtio:398
char const * message() const
Get a human readable description of the error code.
Definition virtio:430