Netdev List
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: den@openvz.org
Cc: netdev@vger.kernel.org, dev@openvswitch.org, aconole@redhat.com,
	echaudro@redhat.com, i.maximets@ovn.org, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org
Subject: Re: [PATCH v2] openvswitch: fix soft lockup in the netlink flow dump
Date: Fri, 18 Sep 2026 06:27:02 +0000	[thread overview]
Message-ID: <178971282245.22033.17364092566029672665@kernel.org> (raw)
In-Reply-To: <20260915122401.3910188-1-den@openvz.org>

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 · Low: 1

- [Medium] The patch converts the whole netlink flow-dump callback into a
  softirq-disabled - and on !PREEMPT_RT CONFIG_PREEMPT kernels fully…
- [Low] The submission fixes a user-visible production failure (soft
  lockup and panic inside a single OVS_FLOW_CMD_GET netlink dump) but…

--

openvswitch: fix soft lockup in the netlink flow dump

The patch wraps the whole ovs_flow_cmd_dump() callback in
local_bh_disable()/local_bh_enable() so that the nested spin_unlock_bh()
calls inside ovs_flow_stats_get() no longer drain the softirq backlog in
the dumping thread's context.  The dump loop already runs under
rcu_read_lock() and does not sleep.

A couple of questions below.

[Severity: Low]
The change repairs a user-visible failure (soft lockup and panic in a
single OVS_FLOW_CMD_GET dump), but the trailer block carries only a
Signed-off-by, with no Fixes: tag and no stable indication.

Documentation/process/maintainer-netdev.rst says:

 - for fixes the ``Fixes:`` tag is required, regardless of the tree

The offending construct, the per-CPU spin_lock_bh()/spin_unlock_bh() pair
in ovs_flow_stats_get() executed once per CPU in flow->cpu_used_mask for
every emitted flow, is long standing, so the affected stable range is
wide.  Could a Fixes: tag (and a note on whether this is stable material)
be added so backporters know which trees are in scope?

> diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
> index 631a03136fa14..a80bac81c0430 100644
> --- a/net/openvswitch/datapath.c
> +++ b/net/openvswitch/datapath.c
> @@ -1532,6 +1532,11 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
>  		return -ENODEV;
>  	}
>  
> +	/*
> +	 * Not needed for safety. Stops every spin_unlock_bh() in
> +	 * ovs_flow_stats_get() from running the softirq backlog here.
> +	 */
> +	local_bh_disable();
>  	ti = rcu_dereference(dp->table.ti);
>  	for (;;) {
>  		struct sw_flow *flow;

[Severity: Medium]
Is the length of this new softirq-disabled region actually bounded by
anything small?

The commit message says:

    That region is bounded by the skb and the table size, where the
    softirq backlog it used to absorb is not.

The table size is the part that worries me.  ovs_flow_tbl_dump_next()
sweeps buckets with no per-callback budget:

net/openvswitch/flow_table.c:ovs_flow_tbl_dump_next() {
	while (*bucket < ti->n_buckets) {
		i = 0;
		head = &ti->buckets[*bucket];
		hlist_for_each_entry_rcu(flow, head, flow_table.node[ver]) {
		...
		(*bucket)++;
		*last = 0;
	}
}

and n_buckets only ever grows: table_instance_expand() doubles it when
table->count > ti->n_buckets, while ovs_flow_tbl_remove() and
table_instance_flow_free() only decrement table->count and never shrink
the bucket array.  So a datapath that once held a very large number of
flows keeps a large sparse table, and the last callback of a dump can
walk all remaining empty buckets in one BH-off region, with no
cond_resched() or other break point in the loop.

For every emitted flow the region also runs one lock/unlock pair per CPU:

net/openvswitch/flow.c:ovs_flow_stats_get() {
	for_each_cpu(cpu, flow->cpu_used_mask) {
		...
			spin_lock_bh(&stats->lock);
		...
			spin_unlock_bh(&stats->lock);
	}
}

While that region is held, NET_RX/NET_TX, timer and RCU softirqs are all
suppressed on the dumping CPU, so NAPI stalls and the rx backlog can
overflow.  The loop also loses the preemption it previously had inside the
preemptible rcu_read_lock() section on CONFIG_PREEMPT.

The dump is reachable without privileges:

	{ .cmd = OVS_FLOW_CMD_GET,
	  .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
	  .flags = 0,		    /* OK for unprivileged users. */
	  .doit = ovs_flow_cmd_get,
	  .dumpit = ovs_flow_cmd_dump
	},

so a process can repeatedly force these windows on a host with a large
datapath table.

Would a per-callback budget work here, emitting N flows or scanning M
buckets and then returning so netlink re-invokes the callback with BH
re-enabled?  Alternatively, could the BH-off region be scoped to the
for_each_cpu() loop inside ovs_flow_stats_get() rather than the whole
callback?

I note ctnetlink_dump_table() already has the same whole-callback shape
over nf_conntrack_htable_size buckets, so the approach itself is not
unprecedented in net/; the question is only about bounding the OVS sweep.

> @@ -1552,6 +1557,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
>  		cb->args[0] = bucket;
>  		cb->args[1] = obj;
>  	}
> +	local_bh_enable();
>  	rcu_read_unlock();
>  	return skb->len;
>  }

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260915122401.3910188-1-den%40openvz.org

  reply	other threads:[~2026-09-18  6:27 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15 12:24 [PATCH v2] openvswitch: fix soft lockup in the netlink flow dump Denis V. Lunev
2026-09-18  6:27 ` netdev-bot+sashiko [this message]
2026-09-18 11:08 ` Ilya Maximets

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178971282245.22033.17364092566029672665@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=aconole@redhat.com \
    --cc=davem@davemloft.net \
    --cc=den@openvz.org \
    --cc=dev@openvswitch.org \
    --cc=echaudro@redhat.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=i.maximets@ovn.org \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox