This is an automated email from the ASF dual-hosted git repository.

jerpelea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new bb4d8691759 drivers/net: e1000, igb, igc: drop RX frames when no 
packet is free.
bb4d8691759 is described below

commit bb4d8691759e59aaab6f9fb604a29cf3e6d3705a
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 b00b18be465..dc9254e0a83 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 12c22ece813..9294a166c57 100644
--- a/drivers/net/igb.c
+++ b/drivers/net/igb.c
@@ -662,8 +662,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 85b89968beb..e4353ea1415 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 */

Reply via email to