13: _max_ports{max_ports},
16 _ports =
new Port_iface *[max_ports]();
20Virtio_switch::lookup_free_slot()
22 for (
unsigned idx = 0; idx < _max_ports; ++idx)
32 if (!port->mac().is_unknown())
33 for (
unsigned idx = 0; idx < _max_ports; ++idx)
34 if (_ports[idx] && _ports[idx]->mac() == port->mac())
36 Dbg(Dbg::Port, Dbg::Warn)
37 .printf(
"Rejecting port '%s'. MAC address already in use.\n",
42 int idx = lookup_free_slot();
46 unsigned uidx =
static_cast<unsigned>(idx);
48 if (_max_used == uidx)
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());
72 for (
unsigned idx = 0; idx < _max_used; ++idx)
74 Port_iface *port = _ports[idx];
75 if (port && port->is_gone())
77 Dbg(Dbg::Port, Dbg::Info)
78 .printf(
"Client on port %p has gone. Deleting...\n", port);
80 _ports[idx] =
nullptr;
81 if (idx == _max_used-1)
84 _mac_table.
flush(port);
89 if (_monitor && _monitor->is_gone())
98Virtio_switch::handle_tx_request(Port_iface *port, REQ
const &request)
102 if (port->is_trunk() && !port->match_vlan(request.vlan_id()))
105 port->stat_inc_tx_dropped();
110 if (port->is_access() && request.has_vlan())
113 port->stat_inc_tx_dropped();
117 auto handle_request = [](Port_iface *dst_port, Port_iface *src_port,
120 auto transfer_src = req.transfer_src();
122 auto res = dst_port->handle_request(src_port, transfer_src, &bytes);
125 case Port_iface::Result::Delivered:
126 dst_port->stat_inc_tx_num();
127 dst_port->stat_inc_tx_bytes(bytes);
128 src_port->stat_inc_rx_num();
129 src_port->stat_inc_rx_bytes(bytes);
131 case Port_iface::Result::Dropped:
133 case Port_iface::Result::Exception:
136 dst_port->stat_inc_tx_dropped();
143 auto dst = request.dst_mac();
145 uint16_t vlan = request.has_vlan() ? request.vlan_id() : port->get_vlan();
146 _mac_table.
learn(src, port, vlan);
149 auto *target = _mac_table.
lookup(dst, vlan);
157 handle_request(target, port, request);
158 if (_monitor && !filter_request(request))
159 handle_request(_monitor, port, request);
167 for (
unsigned idx = 0; idx < _max_used && _ports[idx]; ++idx)
169 auto *target = _ports[idx];
170 if (target != port && target->match_vlan(vlan))
171 handle_request(target, port, request);
175 if (_monitor && !filter_request(request))
176 handle_request(_monitor, port, request);
179template<
typename PORT>
181Virtio_switch::handle_tx_requests(PORT *port,
unsigned &num_reqs_handled)
183 while (
auto req = port->get_tx_request())
185 req->dump_request(port);
186 handle_tx_request(port, *req);
188 if (++num_reqs_handled >= Tx_burst)
199 Dbg(Dbg::Port, Dbg::Debug)
200 .printf(
"%s: Irq without pending work\n", port->get_name());
202 unsigned num_reqs_handled = 0;
205 port->
tx_q()->disable_notify();
206 port->
rx_q()->disable_notify();
208 if (num_reqs_handled >= Tx_burst)
210 Dbg(Dbg::Port, Dbg::Debug)
212 "%s: Tx burst limit hit, reschedule remaining Tx work.\n",
218 port->reschedule_pending_tx();
225 all_rx_notify_disable_and_remember();
230 handle_tx_requests(port, num_reqs_handled);
234 Dbg(Dbg::Port, Dbg::Warn,
"REQ")
235 .printf(
"%s: caught bad descriptor exception: %s - %i"
236 " -- Signal device error on device %p.\n",
237 __PRETTY_FUNCTION__, e.
message(), e.error, port);
239 all_rx_notify_emit_and_enable();
243 all_rx_notify_emit_and_enable();
245 port->
tx_q()->enable_notify();
246 port->
rx_q()->enable_notify();
258Virtio_switch::handle_ixl_port_tx(Ixl_port *port)
260 unsigned num_reqs_handled = 0;
262 all_rx_notify_disable_and_remember();
263 handle_tx_requests(port, num_reqs_handled);
264 all_rx_notify_emit_and_enable();
266 if (num_reqs_handled >= Tx_burst && port->tx_work_pending())
268 Dbg(Dbg::Port, Dbg::Info)
269 .printf(
"%s: Tx burst limit hit, reschedule remaining Tx work.\n",
275 port->reschedule_pending_tx();
void device_error()
Transition device into DEVICE_NEEDS_RESET state.
A Port on the Virtio Net Switch.
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
A wrapper class around the value of a MAC address.
bool is_broadcast() const
Check if MAC address is a broadcast or multicast address.
Port_iface * lookup(Mac_addr dst, l4_uint16_t vlan_id) const
Find the destination port for a MAC address and VLAN id.
void learn(Mac_addr src, Port_iface *port, l4_uint16_t vlan_id)
Learn a MAC address (add it to the MAC table).
void flush(Port_iface *port)
Flush all associations with a given port.
Virtqueue * rx_q()
Getter for the receive queue.
Virtqueue * tx_q()
Getter for the transmission queue.
void check_ports()
Check validity of ports.
Virtio_switch(unsigned max_ports)
Create a switch with n ports.
bool add_monitor_port(Port_iface *port)
Add a monitor port to the switch.
bool handle_l4virtio_port_tx(L4virtio_port *port)
Handle TX queue of the given port.
bool add_port(Port_iface *port)
Add a port to the switch.
unsigned long long l4_uint64_t
Unsigned 64bit value.
#define L4_LIKELY(x)
Expression is likely to execute.
Exception used by Queue to indicate descriptor errors.
char const * message() const
Get a human readable description of the error code.