* [PATCH net v4] xfrm: propagate -EINPROGRESS from validate_xmit_xfrm()
@ 2026-06-03 6:46 Petr Wozniak
2026-06-04 11:29 ` Sabrina Dubroca
0 siblings, 1 reply; 2+ messages in thread
From: Petr Wozniak @ 2026-06-03 6:46 UTC (permalink / raw)
To: netdev; +Cc: sd, steffen.klassert, pabeni, edumazet, Petr Wozniak
validate_xmit_xfrm() returns NULL both when a packet is dropped and
when it is stolen by async crypto (-EINPROGRESS from ->xmit()).
Callers cannot distinguish the two cases.
f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.")
changed the semantics of a NULL return from "dropped" to "stolen or
dropped", but __dev_queue_xmit() was not updated. On virtual/bridge
interfaces (noqueue qdisc) __dev_queue_xmit() initialises rc=-ENOMEM
and jumps to out: when skb is NULL, returning -ENOMEM to the caller
even though the packet will be delivered correctly via xfrm_dev_resume().
Return ERR_PTR(-EINPROGRESS) from validate_xmit_xfrm() for the async
case so callers can tell it apart from a real drop. Update
__dev_queue_xmit() to handle ERR_PTR(-EINPROGRESS) from
validate_xmit_skb() correctly. Update validate_xmit_skb_list() to
use IS_ERR_OR_NULL() so that ERR_PTR(-EINPROGRESS) is not mistakenly
added to the transmitted list.
Fixes: f53c723902d1 ("net: Add asynchronous callbacks for xfrm on layer 2.")
Suggested-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com>
---
Changes in v4:
- Drop bool stolen tracking in validate_xmit_skb_list() and ERR_PTR
return from that function; use IS_ERR_OR_NULL() in the loop so
stolen skbs are silently skipped (same as the pre-patch NULL behaviour)
(Sabrina Dubroca)
- Drop ERR_PTR(-EINPROGRESS) handling in __dev_direct_xmit(); callers
cannot reach the -EINPROGRESS path of validate_xmit_xfrm()
(Sabrina Dubroca)
- Move validate_xmit_skb() return-value comment above the function
instead of inline in __dev_queue_xmit() (Sabrina Dubroca)
Changes in v3:
- Fix validate_xmit_skb_list(): set stolen=true only for -EINPROGRESS,
not for all IS_ERR() cases (Sabrina Dubroca)
- Update __dev_direct_xmit() to handle ERR_PTR(-EINPROGRESS) from
validate_xmit_skb_list() before kfree_skb_list() which would crash
on an ERR_PTR (Sabrina Dubroca / sashiko)
Changes in v2:
- Only reset rc to NET_XMIT_SUCCESS when PTR_ERR(skb) == -EINPROGRESS,
not for any IS_ERR() result (Sabrina Dubroca)
- Add comment explaining why rc is reset and the async delivery path
- Fix validate_xmit_skb_list(): track stolen skbs and return
ERR_PTR(-EINPROGRESS) when all skbs in the list were stolen by
async crypto, not NULL (Sabrina Dubroca)
---
net/core/dev.c | 11 ++++++++---
net/xfrm/xfrm_device.c | 2 +-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 0c6c270d9..18e92bef7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4016,6 +4016,9 @@ static struct sk_buff *validate_xmit_unreadable_skb(struct sk_buff *skb,
return NULL;
}
+/* Returns the skb on success, NULL if dropped, or ERR_PTR(-EINPROGRESS)
+ * if stolen by async xfrm crypto (delivered via xfrm_dev_resume()).
+ */
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool *again)
{
netdev_features_t features;
@@ -4078,7 +4081,6 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again)
{
struct sk_buff *next, *head = NULL, *tail;
-
for (; skb != NULL; skb = next) {
next = skb->next;
skb_mark_not_on_list(skb);
@@ -4087,7 +4089,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
skb->prev = skb;
skb = validate_xmit_skb(skb, dev, again);
- if (!skb)
+ if (IS_ERR_OR_NULL(skb))
continue;
if (!head)
@@ -4858,8 +4860,11 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
goto recursion_alert;
skb = validate_xmit_skb(skb, dev, &again);
- if (!skb)
+ if (IS_ERR_OR_NULL(skb)) {
+ if (PTR_ERR(skb) == -EINPROGRESS)
+ rc = NET_XMIT_SUCCESS;
goto out;
+ }
HARD_TX_LOCK(dev, txq, cpu);
diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
index 550457e4c..bb0c0fafa 100644
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -182,7 +182,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
err = x->type_offload->xmit(x, skb, esp_features);
if (err) {
if (err == -EINPROGRESS)
- return NULL;
+ return ERR_PTR(-EINPROGRESS);
XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
kfree_skb(skb);
--
2.51.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH net v4] xfrm: propagate -EINPROGRESS from validate_xmit_xfrm()
2026-06-03 6:46 [PATCH net v4] xfrm: propagate -EINPROGRESS from validate_xmit_xfrm() Petr Wozniak
@ 2026-06-04 11:29 ` Sabrina Dubroca
0 siblings, 0 replies; 2+ messages in thread
From: Sabrina Dubroca @ 2026-06-04 11:29 UTC (permalink / raw)
To: Petr Wozniak; +Cc: netdev, steffen.klassert, pabeni, edumazet
2026-06-03, 08:46:59 +0200, Petr Wozniak wrote:
> +/* Returns the skb on success, NULL if dropped, or ERR_PTR(-EINPROGRESS)
> + * if stolen by async xfrm crypto (delivered via xfrm_dev_resume()).
> + */
> static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool *again)
> {
> netdev_features_t features;
> @@ -4078,7 +4081,6 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
> struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again)
> {
> struct sk_buff *next, *head = NULL, *tail;
> -
nit: no, that blank line needs to stay
> for (; skb != NULL; skb = next) {
> next = skb->next;
> skb_mark_not_on_list(skb);
> @@ -4087,7 +4089,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
> skb->prev = skb;
>
> skb = validate_xmit_skb(skb, dev, again);
> - if (!skb)
> + if (IS_ERR_OR_NULL(skb))
> continue;
>
> if (!head)
[...]
> diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c
> index 550457e4c..bb0c0fafa 100644
> --- a/net/xfrm/xfrm_device.c
> +++ b/net/xfrm/xfrm_device.c
> @@ -182,7 +182,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
> err = x->type_offload->xmit(x, skb, esp_features);
> if (err) {
> if (err == -EINPROGRESS)
> - return NULL;
> + return ERR_PTR(-EINPROGRESS);
>
> XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
> kfree_skb(skb);
Could you please explain why you're ignoring my comment about the
2nd x->type_offload->xmit() call in this function?
Thanks,
--
Sabrina
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-04 11:29 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 6:46 [PATCH net v4] xfrm: propagate -EINPROGRESS from validate_xmit_xfrm() Petr Wozniak
2026-06-04 11:29 ` Sabrina Dubroca
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox