This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch releases/13.1
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/releases/13.1 by this push:
new 9f84bf0b4d9 drivers/net: e1000, igb, igc: drop RX frames when no
packet is free.
9f84bf0b4d9 is described below
commit 9f84bf0b4d9137c86007eaa490c57210c31e9d92
Author: raiden00pl <[email protected]>
AuthorDate: Sat Oct 10 12:44:27 2026 +0200
drivers/net: e1000, igb, igc: drop RX frames when no packet is free.
The RX path replaced the packet of a received frame with a new one from
netpkt_alloc() and called PANIC() when that failed. netpkt_alloc()
fails whenever the IOB pool is used up, e.g. when a node sending bulk
TCP data holds the IOBs in its write buffers while ACKs come in, so the
system crashed under load (seen with e1000 on qemu-intel64 with iperf).
Drop the frame instead and give its packet back to the descriptor,
together with the other received frames in the ring, so that the ring
keeps receiving and the next interrupt starts a new RX poll. One pass
over the ring at most, so that the stack can run and free packets.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: raiden00pl <[email protected]>
---
drivers/net/e1000.c | 33 +++++++++++++++++++++++++++++++--
drivers/net/igb.c | 33 +++++++++++++++++++++++++++++++--
drivers/net/igc.c | 33 +++++++++++++++++++++++++++++++--
3 files changed, 93 insertions(+), 6 deletions(-)
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index d1487942096..2b6936523db 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -687,8 +687,37 @@ static FAR netpkt_t *e1000_receive(FAR struct
netdev_lowerhalf_s *dev)
priv->rx_pkt[desc] = netpkt_alloc(dev, NETPKT_RX);
if (priv->rx_pkt[desc] == NULL)
{
- nerr("alloc pkt_new failed\n");
- PANIC();
+ int i;
+
+ /* No free packet (e.g. the IOBs are held by the stack): drop this
+ * frame and the other received frames in the ring and give the
+ * descriptors their packets back, so that the ring keeps receiving
+ * and the next interrupt starts a new RX poll. Stop after one pass
+ * over the ring, so that the stack can run and free packets.
+ */
+
+ priv->rx_pkt[desc] = pkt;
+
+ for (i = 0; i < E1000_RX_DESC; i++)
+ {
+ NETDEV_RXDROPPED(&priv->dev.netdev);
+
+ rx->len = 0;
+ rx->status = 0;
+
+ e1000_putreg_mem(priv, E1000_RDT, desc);
+
+ desc = priv->rx_now;
+ rx = &priv->rx[desc];
+ if (!(rx->status & E1000_RDESC_STATUS_DD))
+ {
+ break;
+ }
+
+ priv->rx_now = (priv->rx_now + 1) % E1000_RX_DESC;
+ }
+
+ return NULL;
}
/* Set packet length */
diff --git a/drivers/net/igb.c b/drivers/net/igb.c
index abe38e1db8e..c1901025658 100644
--- a/drivers/net/igb.c
+++ b/drivers/net/igb.c
@@ -663,8 +663,37 @@ static FAR netpkt_t *igb_receive(FAR struct
netdev_lowerhalf_s *dev)
priv->rx_pkt[desc] = netpkt_alloc(dev, NETPKT_RX);
if (priv->rx_pkt[desc] == NULL)
{
- nerr("alloc pkt_new failed\n");
- PANIC();
+ int i;
+
+ /* No free packet (e.g. the IOBs are held by the stack): drop this
+ * frame and the other received frames in the ring and give the
+ * descriptors their packets back, so that the ring keeps receiving
+ * and the next interrupt starts a new RX poll. Stop after one pass
+ * over the ring, so that the stack can run and free packets.
+ */
+
+ priv->rx_pkt[desc] = pkt;
+
+ for (i = 0; i < IGB_RX_DESC; i++)
+ {
+ NETDEV_RXDROPPED(&priv->dev.netdev);
+
+ rx->len = 0;
+ rx->status = 0;
+
+ igb_putreg_mem(priv, IGB_RDT0, desc);
+
+ desc = priv->rx_now;
+ rx = &priv->rx[desc];
+ if (!(rx->status & IGB_RDESC_STATUS_DD))
+ {
+ break;
+ }
+
+ priv->rx_now = (priv->rx_now + 1) % IGB_RX_DESC;
+ }
+
+ return NULL;
}
/* Set packet length */
diff --git a/drivers/net/igc.c b/drivers/net/igc.c
index 546b280f0cf..5dcb80d4e9d 100644
--- a/drivers/net/igc.c
+++ b/drivers/net/igc.c
@@ -639,8 +639,37 @@ static FAR netpkt_t *igc_receive(FAR struct
netdev_lowerhalf_s *dev)
priv->rx_pkt[desc] = netpkt_alloc(dev, NETPKT_RX);
if (priv->rx_pkt[desc] == NULL)
{
- nerr("alloc pkt_new failed\n");
- PANIC();
+ int i;
+
+ /* No free packet (e.g. the IOBs are held by the stack): drop this
+ * frame and the other received frames in the ring and give the
+ * descriptors their packets back, so that the ring keeps receiving
+ * and the next interrupt starts a new RX poll. Stop after one pass
+ * over the ring, so that the stack can run and free packets.
+ */
+
+ priv->rx_pkt[desc] = pkt;
+
+ for (i = 0; i < IGC_RX_DESC; i++)
+ {
+ NETDEV_RXDROPPED(&priv->dev.netdev);
+
+ rx->len = 0;
+ rx->status = 0;
+
+ igc_putreg_mem(priv, IGC_RDT0, desc);
+
+ desc = priv->rx_now;
+ rx = &priv->rx[desc];
+ if (!(rx->status & IGC_RDESC_STATUS_DD))
+ {
+ break;
+ }
+
+ priv->rx_now = (priv->rx_now + 1) % IGC_RX_DESC;
+ }
+
+ return NULL;
}
/* Set packet length */