net: plumb drop reasons to __dev_queue_xmit()

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>
This commit is contained in:
Eric Dumazet 2026-03-12 20:18:24 +00:00 committed by Jakub Kicinski
parent d15d3de94a
commit 045f977dd4

View 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 (!netif_tx_owned(txq, cpu)) {
bool is_list = false;
if (dev_xmit_recursion())
goto recursion_alert;
skb = validate_xmit_skb(skb, dev, &again);
if (!skb)
goto out;
HARD_TX_LOCK(dev, txq, cpu);
if (!netif_xmit_stopped(txq)) {
is_list = !!skb->next;
dev_xmit_recursion_inc();
skb = dev_hard_start_xmit(skb, dev, txq, &rc);
dev_xmit_recursion_dec();
/* 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;
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;
}
if (unlikely(!(dev->flags & IFF_UP))) {
reason = SKB_DROP_REASON_DEV_READY;
goto drop;
}
cpu = smp_processor_id(); /* ok because BHs are off */
if (likely(!netif_tx_owned(txq, cpu))) {
bool is_list = false;
if (dev_xmit_recursion())
goto recursion_alert;
skb = validate_xmit_skb(skb, dev, &again);
if (!skb)
goto out;
HARD_TX_LOCK(dev, txq, cpu);
if (!netif_xmit_stopped(txq)) {
is_list = !!skb->next;
dev_xmit_recursion_inc();
skb = dev_hard_start_xmit(skb, dev, txq, &rc);
dev_xmit_recursion_dec();
/* 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;
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();