From: Stephen Hemminger <stephen@networkplumber.org>
To: Weijun Pan <wpan3636@gmail.com>
Cc: Chas Williams <3chas3@gmail.com>,
"Min Hu (Connor)" <humin29@huawei.com>,
Anatoly Burakov <anatoly.burakov@intel.com>,
dev@dpdk.org
Subject: Re: [RFC PATCH] net/bonding: reject control operations in secondary
Date: Sun, 26 Jul 2026 10:32:43 -0700 [thread overview]
Message-ID: <20260726103243.437be4b2@phoenix.local> (raw)
In-Reply-To: <20260708174204.72574-1-wpan3636@gmail.com>
On Wed, 8 Jul 2026 12:42:04 -0500
Weijun Pan <wpan3636@gmail.com> wrote:
> The bonding PMD installs safe secondary burst functions when real
> secondary datapath support is not available. This avoids crashes, but
> secondary processes must not be able to change bonding control-plane
> state if the primary process is the owner of that state.
>
> Reject bonding control-plane operations from secondary processes. This
> keeps bonding configuration and LACP state owned by the primary process
> and is a prerequisite for future limited secondary datapath support.
>
> Bugzilla ID: 1900
>
> Signed-off-by: Weijun Pan <wpan3636@gmail.com>
> ---
This is the right path, but AI review found things that need work.
Review: [RFC PATCH] net/bonding: reject control operations in secondary
Message-Id: <20260708174204.72574-1-wpan3636@gmail.com>
Verified against DPDK main (38f72e500b3b). Applies cleanly, builds clean
with -Dwerror=true, checkpatches.sh reports no issues.
The intent is right, but the checks are placed one layer too low, which
means the stated goal -- "secondary processes must not be able to change
bonding control-plane state" -- is not actually met for dev_configure,
and one legitimate secondary path is broken.
Errors
------
1. rte_eth_bond_pmd.c: bond_ethdev_configure()
Returning -ENOTSUP from the dev_configure op does not prevent the
secondary from mutating shared state -- it makes it worse.
rte_eth_dev_configure() has already done this before it calls the PMD
(lib/ethdev/rte_ethdev.c):
1364 memcpy(&orig_conf, &dev->data->dev_conf, ...)
1587 diag = eth_dev_rx_queue_config(dev, nb_rx_q);
1596 diag = eth_dev_tx_queue_config(dev, nb_tx_q);
1606 diag = dev->dev_ops->dev_configure(dev);
1646 reset_queues:
1647 eth_dev_rx_queue_config(dev, 0);
1648 eth_dev_tx_queue_config(dev, 0);
On the -ENOTSUP the code jumps to reset_queues, and
eth_dev_rx_queue_config(dev, 0) calls dev_ops->rx_queue_release() on
every queue and rte_free()s dev->data->rx_queues, then sets
nb_rx_queues = 0 (lib/ethdev/ethdev_private.c:455). Those are the
primary's queues in shared memory. bond_ethdev_rx_queue_release() /
bond_ethdev_tx_queue_release() are not gated by this patch, so they
run.
Net effect: a stray rte_eth_dev_configure() from a secondary now
destroys the primary's Rx/Tx queue arrays instead of being rejected.
2. rte_eth_bond_api.c: rte_eth_bond_free()
This blocks the only supported way for a secondary to detach its
local port. rte_vdev_uninit() is process-local and works in a
secondary; bond_remove() has a deliberate secondary branch
(rte_eth_bond_pmd.c:4003):
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return rte_eth_dev_release_port(eth_dev);
That branch is now unreachable through the public API. Compare
bond_ethdev_close() ten lines away (2310), which returns 0 rather
than an error for non-primary, and the comment in
rte_eth_dev_close() explaining that a secondary must be able to
close to release its process-private resources. Teardown paths need
to stay callable; only reconfiguration should be rejected.
Warnings
--------
3. Structural: use a separate ops table rather than 17 in-function
checks.
bond_probe() already installs the ops table for the secondary
explicitly (rte_eth_bond_pmd.c:3889):
eth_dev->dev_ops = &default_dev_ops;
ethdev already returns -ENOTSUP for every one of these ops when the
pointer is NULL -- dev_configure (1347), dev_start (1801),
rx_queue_setup (2307), promiscuous_enable (3027), mtu_set (4400),
reta_update (5007), mac_addr_add (5415), mac_addr_remove (5479),
and so on -- and it does so *before* touching dev->data, which is
exactly what fixes finding 1. Defining
static const struct eth_dev_ops secondary_dev_ops = {
.dev_close = bond_ethdev_close,
.dev_infos_get = bond_ethdev_info,
.link_update = bond_ethdev_link_update,
.stats_get = bond_ethdev_stats_get,
.reta_query = bond_ethdev_rss_reta_query,
.rss_hash_conf_get = bond_ethdev_rss_hash_conf_get,
.eth_dev_priv_dump = bond_ethdev_priv_dump,
};
and assigning it in the secondary branch of bond_probe() gets you
identical semantics with one hunk instead of eighteen, and no
runtime check on the primary's path.
4. Wrong polarity. All three helpers test
rte_eal_process_type() != RTE_PROC_SECONDARY
The established idiom is != RTE_PROC_PRIMARY: 357 occurrences under
drivers/ against 3 of the form used here, and both existing checks
in this driver (bond_ethdev_close at 2310, bond_remove at 4003) use
the primary form. As written, RTE_PROC_AUTO and RTE_PROC_INVALID
fall through to the permissive path.
5. Three byte-identical static helpers in three files
(bond_8023ad_primary_only, bond_api_primary_only,
bond_ethdev_primary_only). One static inline in
eth_bond_private.h.
6. The helper's return value is computed and discarded:
if (bond_8023ad_primary_only(__func__) != 0)
return -ENOTSUP;
Either propagate it (ret = ...; if (ret != 0) return ret;) or make
the helper return bool and name it accordingly.
7. Coverage gaps. flow_ops_get is not gated, so rte_flow_create() /
rte_flow_destroy() from a secondary still mutate bonding state.
rx_queue_release / tx_queue_release are ungated while the
corresponding setup ops are gated -- see finding 1 for why that
combination bites.
8. No documentation. This changes the observable behaviour of exported
API, but doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst
says nothing about multi-process, and
doc/guides/rel_notes/release_26_07.rst is not touched. The guide
needs a short section stating which operations are primary-only.
9. Bugzilla ID 1900 is cited with no Fixes: tag and no
Cc: stable@dpdk.org. If 1900 is a crash being fixed, both are
needed. If this is groundwork for secondary datapath support, say
so and drop the implication.
Info
----
10. Statements are inserted ahead of the declarations in every touched
function. Legal under c11, but it inverts the DPDK function layout
(declarations, blank line, statements) throughout. Folding the
check into the existing declaration block would avoid it; the ops
table in finding 3 avoids it entirely. Also, rte_eth_bond_api.c
gains a double blank line after bond_api_primary_only().
11. rte_eth_dev_stop() resets that process's fast-path ops to the dummy
functions before calling dev_stop (rte_ethdev.c:1819). With
bond_ethdev_stop() now returning -ENOTSUP, a secondary that calls
stop ends up with a dead local datapath, dev_started still 1, and
no way to restart since dev_start is also gated.
Given findings 1 and 2, no Reviewed-by on this revision.
prev parent reply other threads:[~2026-07-26 17:32 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-08 17:42 [RFC PATCH] net/bonding: reject control operations in secondary Weijun Pan
2026-07-22 23:10 ` Stephen Hemminger
2026-07-26 17:32 ` Stephen Hemminger [this message]
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=20260726103243.437be4b2@phoenix.local \
--to=stephen@networkplumber.org \
--cc=3chas3@gmail.com \
--cc=anatoly.burakov@intel.com \
--cc=dev@dpdk.org \
--cc=humin29@huawei.com \
--cc=wpan3636@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.