]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: plumb drop reasons to __dev_queue_xmit()
authorEric Dumazet <edumazet@google.com>
Thu, 12 Mar 2026 20:18:24 +0000 (20:18 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 14 Mar 2026 15:38:06 +0000 (08:38 -0700)
Add drop reasons to __dev_queue_xmit():

- SKB_DROP_REASON_DEV_READY : device is not UP.

- SKB_DROP_REASON_RECURSION_LIMIT : recursion limit on virtual device is hit.

Also add an unlikely() for the SKB_DROP_REASON_DEV_READY case,
and reduce indentation level.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20260312201824.203093-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/dev.c

index f48dc299e4b270f2fedba11e669d4940e73f0d4d..200d44883fc130dcc80afa1ddccce68bf3ff592c 100644 (file)
@@ -4745,9 +4745,10 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
 {
        struct net_device *dev = skb->dev;
        struct netdev_queue *txq = NULL;
-       struct Qdisc *q;
-       int rc = -ENOMEM;
+       enum skb_drop_reason reason;
+       int cpu, rc = -ENOMEM;
        bool again = false;
+       struct Qdisc *q;
 
        skb_reset_mac_header(skb);
        skb_assert_len(skb);
@@ -4816,59 +4817,61 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
         * Check this and shot the lock. It is not prone from deadlocks.
         *Either shot noqueue qdisc, it is even simpler 8)
         */
-       if (dev->flags & IFF_UP) {
-               int cpu = smp_processor_id(); /* ok because BHs are off */
+       if (unlikely(!(dev->flags & IFF_UP))) {
+               reason = SKB_DROP_REASON_DEV_READY;
+               goto drop;
+       }
 
-               if (!netif_tx_owned(txq, cpu)) {
-                       bool is_list = false;
+       cpu = smp_processor_id(); /* ok because BHs are off */
 
-                       if (dev_xmit_recursion())
-                               goto recursion_alert;
+       if (likely(!netif_tx_owned(txq, cpu))) {
+               bool is_list = false;
 
-                       skb = validate_xmit_skb(skb, dev, &again);
-                       if (!skb)
-                               goto out;
+               if (dev_xmit_recursion())
+                       goto recursion_alert;
 
-                       HARD_TX_LOCK(dev, txq, cpu);
+               skb = validate_xmit_skb(skb, dev, &again);
+               if (!skb)
+                       goto out;
 
-                       if (!netif_xmit_stopped(txq)) {
-                               is_list = !!skb->next;
+               HARD_TX_LOCK(dev, txq, cpu);
 
-                               dev_xmit_recursion_inc();
-                               skb = dev_hard_start_xmit(skb, dev, txq, &rc);
-                               dev_xmit_recursion_dec();
+               if (!netif_xmit_stopped(txq)) {
+                       is_list = !!skb->next;
 
-                               /* GSO segments a single SKB into
-                                * a list of frames. TCP expects error
-                                * to mean none of the data was sent.
-                                */
-                               if (is_list)
-                                       rc = NETDEV_TX_OK;
-                       }
-                       HARD_TX_UNLOCK(dev, txq);
-                       if (!skb) /* xmit completed */
-                               goto out;
+                       dev_xmit_recursion_inc();
+                       skb = dev_hard_start_xmit(skb, dev, txq, &rc);
+                       dev_xmit_recursion_dec();
 
-                       net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
-                                            dev->name);
-                       /* NETDEV_TX_BUSY or queue was stopped */
-                       if (!is_list)
-                               rc = -ENETDOWN;
-               } else {
-                       /* Recursion is detected! It is possible,
-                        * unfortunately
+                       /* GSO segments a single SKB into a list of frames.
+                        * TCP expects error to mean none of the data was sent.
                         */
-recursion_alert:
-                       net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
-                                            dev->name);
-                       rc = -ENETDOWN;
+                       if (is_list)
+                               rc = NETDEV_TX_OK;
                }
+               HARD_TX_UNLOCK(dev, txq);
+               if (!skb) /* xmit completed */
+                       goto out;
+
+               net_crit_ratelimited("Virtual device %s asks to queue packet!\n",
+                                    dev->name);
+               /* NETDEV_TX_BUSY or queue was stopped */
+               if (!is_list)
+                       rc = -ENETDOWN;
+       } else {
+               /* Recursion is detected! It is possible unfortunately. */
+recursion_alert:
+               net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n",
+                                    dev->name);
+               rc = -ENETDOWN;
        }
 
+       reason = SKB_DROP_REASON_RECURSION_LIMIT;
+drop:
        rcu_read_unlock_bh();
 
        dev_core_stats_tx_dropped_inc(dev);
-       kfree_skb_list(skb);
+       kfree_skb_list_reason(skb, reason);
        return rc;
 out:
        rcu_read_unlock_bh();