diff mbox series

sch_api: Don't skip qdisc attach on ingress

Message ID 20220112102805.488510-1-maximmi@nvidia.com (mailing list archive)
State Accepted
Commit de2d807b294d3d2ce5e59043ae2634016765d076
Delegated to: Netdev Maintainers
Headers show
Series sch_api: Don't skip qdisc attach on ingress | expand

Checks

Context Check Description
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/cc_maintainers fail 1 blamed authors not CCed: maximmi@mellanox.com; 1 maintainers not CCed: maximmi@mellanox.com
netdev/build_clang success Errors and warnings before: 22 this patch: 22
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 8 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Maxim Mikityanskiy Jan. 12, 2022, 10:28 a.m. UTC
The attach callback of struct Qdisc_ops is used by only a few qdiscs:
mq, mqprio and htb. qdisc_graft() contains the following logic
(pseudocode):

    if (!qdisc->ops->attach) {
        if (ingress)
            do ingress stuff;
        else
            do egress stuff;
    }
    if (!ingress) {
        ...
        if (qdisc->ops->attach)
            qdisc->ops->attach(qdisc);
    } else {
        ...
    }

As we see, the attach callback is not called if the qdisc is being
attached to ingress (TC_H_INGRESS). That wasn't a problem for mq and
mqprio, since they contain a check that they are attached to TC_H_ROOT,
and they can't be attached to TC_H_INGRESS anyway.

However, the commit cited below added the attach callback to htb. It is
needed for the hardware offload, but in the non-offload mode it
simulates the "do egress stuff" part of the pseudocode above. The
problem is that when htb is attached to ingress, neither "do ingress
stuff" nor attach() is called. It results in an inconsistency, and the
following message is printed to dmesg:

unregister_netdevice: waiting for lo to become free. Usage count = 2

This commit addresses the issue by running "do ingress stuff" in the
ingress flow even in the attach callback is present, which is fine,
because attach isn't going to be called afterwards.

The bug was found by syzbot and reported by Eric.

Fixes: d03b195b5aa0 ("sch_htb: Hierarchical QoS hardware offload")
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reported-by: Eric Dumazet <edumazet@google.com>
---
 net/sched/sch_api.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Eric Dumazet Jan. 12, 2022, 1:06 p.m. UTC | #1
On Wed, Jan 12, 2022 at 2:28 AM Maxim Mikityanskiy <maximmi@nvidia.com> wrote:
>
> The attach callback of struct Qdisc_ops is used by only a few qdiscs:
> mq, mqprio and htb. qdisc_graft() contains the following logic
> (pseudocode):
>
>     if (!qdisc->ops->attach) {
>         if (ingress)
>             do ingress stuff;
>         else
>             do egress stuff;
>     }
>     if (!ingress) {
>         ...
>         if (qdisc->ops->attach)
>             qdisc->ops->attach(qdisc);
>     } else {
>         ...
>     }
>
> unregister_netdevice: waiting for lo to become free. Usage count = 2
>
> This commit addresses the issue by running "do ingress stuff" in the
> ingress flow even in the attach callback is present, which is fine,
> because attach isn't going to be called afterwards.
>
> The bug was found by syzbot and reported by Eric.
>
> Fixes: d03b195b5aa0 ("sch_htb: Hierarchical QoS hardware offload")
> Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
> Reported-by: Eric Dumazet <edumazet@google.com>
> ---

Thanks for fixing this issue.

Reviewed-by: Eric Dumazet <edumazet@google.com>
patchwork-bot+netdevbpf@kernel.org Jan. 13, 2022, 12:40 p.m. UTC | #2
Hello:

This patch was applied to netdev/net.git (master)
by David S. Miller <davem@davemloft.net>:

On Wed, 12 Jan 2022 12:28:05 +0200 you wrote:
> The attach callback of struct Qdisc_ops is used by only a few qdiscs:
> mq, mqprio and htb. qdisc_graft() contains the following logic
> (pseudocode):
> 
>     if (!qdisc->ops->attach) {
>         if (ingress)
>             do ingress stuff;
>         else
>             do egress stuff;
>     }
>     if (!ingress) {
>         ...
>         if (qdisc->ops->attach)
>             qdisc->ops->attach(qdisc);
>     } else {
>         ...
>     }
> 
> [...]

Here is the summary with links:
  - sch_api: Don't skip qdisc attach on ingress
    https://git.kernel.org/netdev/net/c/de2d807b294d

You are awesome, thank you!
diff mbox series

Patch

diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c9c6f49f9c28..2cb496c84878 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1062,7 +1062,7 @@  static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
 
 		qdisc_offload_graft_root(dev, new, old, extack);
 
-		if (new && new->ops->attach)
+		if (new && new->ops->attach && !ingress)
 			goto skip;
 
 		for (i = 0; i < num_q; i++) {