diff --git a/repos/ports/src/virtualbox5/network.cpp b/repos/ports/src/virtualbox5/network.cpp index 9f1095a558..d9b7b3aced 100644 --- a/repos/ports/src/virtualbox5/network.cpp +++ b/repos/ports/src/virtualbox5/network.cpp @@ -110,8 +110,9 @@ class Nic_client Genode::Signal_handler _tx_ready_to_submit; Genode::Signal_handler _destruct_dispatcher; - bool _link_up = false; - bool _retry = false; + bool _link_up = false; + bool _retry = false; + bool _tx_wakeup = false; /* VM <-> device driver (down) <-> nic_client (up) <-> nic session */ PPDMINETWORKDOWN _down_net; @@ -120,10 +121,20 @@ class Nic_client void _handle_rx_packet_avail() { - while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) { - Nic::Packet_descriptor rx_packet = _nic.rx()->get_packet(); + auto &rx = *_nic.rx(); - char *rx_content = _nic.rx()->packet_content(rx_packet); + bool progress = false; + + while (rx.packet_avail() && rx.ready_to_ack()) { + auto const rx_packet = rx.try_get_packet(); + + if (!rx_packet.size()) + break; + + char *rx_content = rx.packet_content(rx_packet); + + if (!rx_content) + break; Libc::with_libc([&] () { int rc = _down_net->pfnWaitReceiveAvail(_down_net, RT_INDEFINITE_WAIT); @@ -131,10 +142,14 @@ class Nic_client rc = _down_net->pfnReceive(_down_net, rx_content, rx_packet.size()); AssertRC(rc); - }); - _nic.rx()->acknowledge_packet(rx_packet); + if (rx.try_ack_packet(rx_packet)) + progress = true; + }); } + + if (progress) + rx.wakeup(); } void _handle_rx_ready_to_ack() { _handle_rx_packet_avail(); } @@ -298,17 +313,27 @@ class Nic_client { if (!_link_up) { return VERR_NET_DOWN; } + auto &tx = *_nic.tx(); + if (tx_packet.size() < packet_len) { RTLogPrintf("%s: packet too large\n", __func__); - _nic.tx()->release_packet(tx_packet); + tx.release_packet(tx_packet); return VINF_SUCCESS; } /* send it */ - auto const tx_content = _nic.tx()->packet_content(tx_packet); + auto const tx_content = tx.packet_content(tx_packet); Genode::memcpy(tx_content, packet, packet_len); auto tx_packet_actual_len = Nic::Packet_descriptor(tx_packet.offset(), packet_len); - _nic.tx()->submit_packet(tx_packet_actual_len); + + if (!tx.try_submit_packet(tx_packet_actual_len)) { + RTLogPrintf("%s: drop packet\n", __func__); + tx.release_packet(tx_packet); + return VINF_SUCCESS; + } + + _tx_wakeup = true; + return VINF_SUCCESS; } @@ -318,6 +343,15 @@ class Nic_client Nic::Packet_allocator::OFFSET_PACKET_SIZE); _nic.tx()->release_packet(len); } + + void tx_wakeup() + { + if (!_tx_wakeup) + return; + + _tx_wakeup = false; + _nic.tx()->wakeup(); + } }; @@ -348,7 +382,11 @@ static DECLCALLBACK(int) drvNicNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bo */ static DECLCALLBACK(void) drvNicNetworkUp_EndXmit(PPDMINETWORKUP pInterface) { - PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface); + PDRVNIC const pThis = PDMINETWORKUP_2_DRVNIC(pInterface); + Nic_client * const nic_client = pThis->nic_client; + + nic_client->tx_wakeup(); + RTCritSectLeave(&pThis->XmitLock); } @@ -560,7 +598,8 @@ static DECLCALLBACK(void) drvNicDestruct(PPDMDRVINS pDrvIns) return; } - Genode::Signal_transmitter(nic_client->dispatcher()).submit(); + if (nic_client) + Genode::Signal_transmitter(nic_client->dispatcher()).submit(); /* wait until the recv thread exits */ destruct_blockade().block(); diff --git a/repos/ports/src/virtualbox6/network.cc b/repos/ports/src/virtualbox6/network.cc index 6634ea6776..1a5a150be8 100644 --- a/repos/ports/src/virtualbox6/network.cc +++ b/repos/ports/src/virtualbox6/network.cc @@ -126,8 +126,9 @@ class Nic_client Genode::Signal_handler _tx_ready_to_submit; Genode::Signal_handler _destruct_dispatcher; - bool _link_up = false; - bool _retry = false; + bool _link_up = false; + bool _retry = false; + bool _tx_wakeup = false; /* VM <-> device driver (down) <-> nic_client (up) <-> nic session */ PPDMINETWORKDOWN _down_net; @@ -136,10 +137,20 @@ class Nic_client void _handle_rx_packet_avail() { - while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) { - Nic::Packet_descriptor rx_packet = _nic.rx()->get_packet(); + auto &rx = *_nic.rx(); - char *rx_content = _nic.rx()->packet_content(rx_packet); + bool progress = false; + + while (rx.packet_avail() && rx.ready_to_ack()) { + auto const rx_packet = rx.try_get_packet(); + + if (!rx_packet.size()) + break; + + char *rx_content = rx.packet_content(rx_packet); + + if (!rx_content) + break; Libc::with_libc([&] () { int rc = _down_net->pfnWaitReceiveAvail(_down_net, RT_INDEFINITE_WAIT); @@ -147,10 +158,14 @@ class Nic_client rc = _down_net->pfnReceive(_down_net, rx_content, rx_packet.size()); AssertRC(rc); - }); - _nic.rx()->acknowledge_packet(rx_packet); + if (rx.try_ack_packet(rx_packet)) + progress = true; + }); } + + if (progress) + rx.wakeup(); } void _handle_rx_ready_to_ack() { _handle_rx_packet_avail(); } @@ -313,17 +328,27 @@ class Nic_client { if (!_link_up) { return VERR_NET_DOWN; } + auto &tx = *_nic.tx(); + if (tx_packet.size() < packet_len) { RTLogPrintf("%s: packet too large\n", __func__); - _nic.tx()->release_packet(tx_packet); + tx.release_packet(tx_packet); return VINF_SUCCESS; } /* send it */ - auto const tx_content = _nic.tx()->packet_content(tx_packet); + auto const tx_content = tx.packet_content(tx_packet); Genode::memcpy(tx_content, packet, packet_len); auto tx_packet_actual_len = Nic::Packet_descriptor(tx_packet.offset(), packet_len); - _nic.tx()->submit_packet(tx_packet_actual_len); + + if (!tx.try_submit_packet(tx_packet_actual_len)) { + RTLogPrintf("%s: drop packet\n", __func__); + tx.release_packet(tx_packet); + return VINF_SUCCESS; + } + + _tx_wakeup = true; + return VINF_SUCCESS; } @@ -333,6 +358,15 @@ class Nic_client Nic::Packet_allocator::OFFSET_PACKET_SIZE); _nic.tx()->release_packet(len); } + + void tx_wakeup() + { + if (!_tx_wakeup) + return; + + _tx_wakeup = false; + _nic.tx()->wakeup(); + } }; @@ -363,7 +397,11 @@ static DECLCALLBACK(int) drvNicNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bo */ static DECLCALLBACK(void) drvNicNetworkUp_EndXmit(PPDMINETWORKUP pInterface) { - PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface); + PDRVNIC const pThis = PDMINETWORKUP_2_DRVNIC(pInterface); + Nic_client * const nic_client = pThis->nic_client; + + nic_client->tx_wakeup(); + RTCritSectLeave(&pThis->XmitLock); }