13: _ports{new Port_iface *[max_ports]()},
19Virtio_switch::lookup_free_slot()
21 for (
unsigned idx = 0; idx < _max_ports; ++idx)
32 for (
unsigned idx = 0; idx < _max_ports; ++idx)
33 if (_ports[idx] && _ports[idx]->mac() == port->mac())
35 Dbg(Dbg::Port, Dbg::Warn)
36 .printf(
"Rejecting port '%s'. MAC address already in use.\n",
41 int idx = lookup_free_slot();
45 unsigned uidx =
static_cast<unsigned>(idx);
47 if (_max_used == uidx)
62 Dbg(Dbg::Port, Dbg::Warn).printf(
"'%s' already defined as monitor port,"
63 " rejecting monitor port '%s'\n",
64 _monitor->get_name(), port->get_name());
71 for (
unsigned idx = 0; idx < _max_used; ++idx)
73 Port_iface *port = _ports[idx];
74 if (port && port->is_gone())
76 Dbg(Dbg::Port, Dbg::Info)
77 .printf(
"Client on port %p has gone. Deleting...\n", port);
79 _ports[idx] =
nullptr;
80 if (idx == _max_used-1)
83 _mac_table.flush(port);
88 if (_monitor && _monitor->is_gone())
97Virtio_switch::handle_tx_request(Port_iface *port, REQ
const &request)
101 if (port->is_trunk() && !port->match_vlan(request.vlan_id()))
104 port->stat_inc_tx_dropped();
109 if (port->is_access() && request.has_vlan())
112 port->stat_inc_tx_dropped();
116 auto handle_request = [](Port_iface *dst_port, Port_iface *src_port,
119 auto transfer_src = req.transfer_src();
121 auto res = dst_port->handle_request(src_port, transfer_src, &bytes);
124 case Port_iface::Result::Delivered:
125 dst_port->stat_inc_tx_num();
126 dst_port->stat_inc_tx_bytes(bytes);
127 src_port->stat_inc_rx_num();
128 src_port->stat_inc_rx_bytes(bytes);
130 case Port_iface::Result::Dropped:
132 case Port_iface::Result::Exception:
135 dst_port->stat_inc_tx_dropped();
140 Mac_addr src = request.src_mac();
142 auto dst = request.dst_mac();
143 bool is_broadcast = dst.is_broadcast();
144 uint16_t vlan = request.has_vlan() ? request.vlan_id() : port->get_vlan();
145 _mac_table.learn(src, port, vlan);
148 auto *target = _mac_table.lookup(dst, vlan);
156 handle_request(target, port, request);
157 if (_monitor && !filter_request(request))
158 handle_request(_monitor, port, request);
166 for (
unsigned idx = 0; idx < _max_used && _ports[idx]; ++idx)
168 auto *target = _ports[idx];
169 if (target != port && target->match_vlan(vlan))
170 handle_request(target, port, request);
174 if (_monitor && !filter_request(request))
175 handle_request(_monitor, port, request);
178template<
typename PORT>
180Virtio_switch::handle_tx_requests(PORT *port,
unsigned &num_reqs_handled)
182 while (
auto req = port->get_tx_request())
184 req->dump_request(port);
185 handle_tx_request(port, *req);
187 if (++num_reqs_handled >= Tx_burst)
198 Dbg(Dbg::Port, Dbg::Debug)
199 .printf(
"%s: Irq without pending work\n", port->get_name());
201 unsigned num_reqs_handled = 0;
207 if (num_reqs_handled >= Tx_burst)
209 Dbg(Dbg::Port, Dbg::Debug)
211 "%s: Tx burst limit hit, reschedule remaining Tx work.\n",
217 port->reschedule_pending_tx();
224 all_rx_notify_disable_and_remember();
229 handle_tx_requests(port, num_reqs_handled);
233 Dbg(Dbg::Port, Dbg::Warn,
"REQ")
234 .printf(
"%s: caught bad descriptor exception: %s - %i"
235 " -- Signal device error on device %p.\n",
236 __PRETTY_FUNCTION__, e.
message(), e.error, port);
238 all_rx_notify_emit_and_enable();
242 all_rx_notify_emit_and_enable();
257Virtio_switch::handle_ixl_port_tx(Ixl_port *port)
259 unsigned num_reqs_handled = 0;
261 all_rx_notify_disable_and_remember();
262 handle_tx_requests(port, num_reqs_handled);
263 all_rx_notify_emit_and_enable();
265 if (num_reqs_handled >= Tx_burst && port->tx_work_pending())
267 Dbg(Dbg::Port, Dbg::Info)
268 .printf(
"%s: Tx burst limit hit, reschedule remaining Tx work.\n",
274 port->reschedule_pending_tx();
void device_error()
Transition device into DEVICE_NEEDS_RESET state.
void enable_notify()
Clear the 'no notify' flag for this queue.
void disable_notify()
Set the 'no notify' flag for this queue.
A Port on the Virtio Net Switch.
bool tx_work_pending() const
Check whether there is any work pending on the transmission queue.
bool is_unknown() const
Check if the MAC address is not yet known.
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.