diff --git a/net/knet/src/consts.rs b/net/knet/src/consts.rs index 0d14225cfea96ae2b52d41791ed00af040929f60..d56aedc010b985d424f40bfcfe277a5f954c895f 100644 --- a/net/knet/src/consts.rs +++ b/net/knet/src/consts.rs @@ -27,4 +27,4 @@ pub const RAW_TX_BUF_LEN: usize = 64 * 1024; pub const LISTEN_QUEUE_SIZE: usize = 512; pub const SOCKET_BUFFER_SIZE: usize = 64; -pub const ETHERNET_MAX_PENDING_PACKETS: usize = 32; +pub const ETHERNET_MAX_PENDING_PACKETS: usize = 128; diff --git a/net/knet/src/device/ethernet.rs b/net/knet/src/device/ethernet.rs index e91d626442e810e6a8208401f8e714e2a7cd63ec..07f387568ff7ae2cc27a4d4f011ce16be48f2f9c 100644 --- a/net/knet/src/device/ethernet.rs +++ b/net/knet/src/device/ethernet.rs @@ -3,7 +3,7 @@ // See LICENSES for license details. //! Ethernet device adapter for the smoltcp stack. -use alloc::{string::String, vec}; +use alloc::{string::String, vec, vec::Vec}; use core::task::Waker; use hashbrown::HashMap; @@ -42,7 +42,7 @@ pub struct EthernetDevice { pending_tx: PacketBuffer<'static, IpAddress>, } impl EthernetDevice { - const NEIGHBOR_TTL: Duration = Duration::from_secs(60); + const NEIGHBOR_TTL: Duration = Duration::from_secs(300); /// Create a new Ethernet device wrapper. pub fn new(name: String, inner: ClassDevice, ip: Ipv4Cidr) -> Self { @@ -172,7 +172,7 @@ impl EthernetDevice { fn handle_arp_packet(&mut self, payload: &[u8], now: Instant) { let Ok(repr) = ArpPacket::new_checked(payload).and_then(|packet| ArpRepr::parse(&packet)) else { - warn!("Dropping malformed ARP packet"); + debug!("Dropping malformed ARP packet"); return; }; @@ -235,36 +235,52 @@ impl EthernetDevice { }); } - if self - .pending_tx - .peek() - .is_ok_and(|it| it.0 == &IpAddress::Ipv4(source_protocol_addr)) - { - while let Ok((&next_hop, buf)) = self.pending_tx.peek() { - // TODO: optimize logic such that one long-pending ARP - // request does not block all other packets - - let Some(Some(neighbor)) = self.neighbors.get(&next_hop) else { - break; - }; - if neighbor.expires_at <= now { - // Neighbor is expired, we need to request ARP again - self.send_arp_request(next_hop); - break; + enum PendingAction { + Send(EthernetAddress), + Keep, + Refresh, + } + + let mut kept_packets = Vec::with_capacity(ETHERNET_MAX_PENDING_PACKETS); + for _ in 0..ETHERNET_MAX_PENDING_PACKETS { + let Ok((&next_hop, buf)) = self.pending_tx.peek() else { + break; + }; + + let payload = buf.to_vec(); + let action = match self.neighbors.get(&next_hop) { + Some(Some(neighbor)) if neighbor.expires_at > now => { + PendingAction::Send(neighbor.hardware_address) } + Some(Some(_)) => PendingAction::Refresh, + _ => PendingAction::Keep, + }; - self.inner.with_mut(|inner| { - Self::send_to( - inner.as_mut(), - neighbor.hardware_address, - buf.len(), - |b| b.copy_from_slice(buf), - EthernetProtocol::Ipv4, - ); - }); - let _ = self.pending_tx.dequeue(); + let _ = self.pending_tx.dequeue(); + match action { + PendingAction::Send(hardware_address) => Self::send_to( + &mut self.inner, + hardware_address, + payload.len(), + |b| b.copy_from_slice(&payload), + EthernetProtocol::Ipv4, + ), + PendingAction::Keep => kept_packets.push((next_hop, payload)), + PendingAction::Refresh => { + self.neighbors.remove(&next_hop); + self.send_arp_request(next_hop); + kept_packets.push((next_hop, payload)); + } } } + + for (next_hop, payload) in kept_packets { + let Ok(buf) = self.pending_tx.enqueue(payload.len(), next_hop) else { + warn!("Pending packets buffer is full, dropping packet"); + continue; + }; + buf.copy_from_slice(&payload); + } } } }