From: Weijun Pan <wpan3636@gmail.com>
To: Chas Williams <3chas3@gmail.com>,
"Min Hu (Connor)" <humin29@huawei.com>,
Anatoly Burakov <anatoly.burakov@intel.com>
Cc: dev@dpdk.org, Stephen Hemminger <stephen@networkplumber.org>,
Weijun Pan <wpan3636@gmail.com>
Subject: [RFC PATCH v5 2/2] net/bonding: restrict secondary control operations
Date: Sun, 30 Aug 2026 11:35:39 -0500 [thread overview]
Message-ID: <20260830163539.21099-2-wpan3636@gmail.com> (raw)
In-Reply-To: <20260830163539.21099-1-wpan3636@gmail.com>
Bonding configuration and LACP runtime state are owned by the primary
process. Install a reduced dev_ops table in secondary processes so
ethdev rejects control operations, and reject bonding control APIs
when called from a secondary process.
Supported query and detach paths remain available, while LACP runtime
state queries are restricted to the primary process.
Bugzilla ID: 1900
Signed-off-by: Weijun Pan <wpan3636@gmail.com>
---
v5:
- Simplify the helper and release note wording.
v4:
- Address secondary link update, docs, and private dump handling.
.../link_bonding_poll_mode_drv_lib.rst | 30 ++++++++++
doc/guides/rel_notes/release_26_11.rst | 5 ++
drivers/net/bonding/eth_bond_private.h | 12 ++++
drivers/net/bonding/rte_eth_bond_8023ad.c | 30 ++++++++++
drivers/net/bonding/rte_eth_bond_api.c | 34 ++++++++++-
drivers/net/bonding/rte_eth_bond_pmd.c | 58 +++++++++++--------
6 files changed, 144 insertions(+), 25 deletions(-)
diff --git a/doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst b/doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst
index 2fa1ac4028..a3f197c8b5 100644
--- a/doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst
+++ b/doc/guides/prog_guide/link_bonding_poll_mode_drv_lib.rst
@@ -254,6 +254,36 @@ Like all other PMD, all functions exported by a PMD are lock-free functions
that are assumed not to be invoked in parallel on different logical cores to
work on the same target object.
+Bonding device configuration and LACP runtime state are owned by the primary
+process. Secondary processes may attach to an existing bonding device for
+detach and supported query operations only.
+
+Supported secondary-process queries include device information, statistics,
+link status, RETA query, RSS hash configuration, bonding mode, member list,
+primary member, transmit policy, link monitoring configuration, and LACP
+configuration. Private dump is limited to shared bonding information and skips
+LACP runtime state in a secondary process.
+
+Control operations are restricted to the primary process. This includes
+configuring, starting or stopping the device, setting up queues, changing
+members, changing the bonding mode, selecting the primary member, changing the
+transmit policy, changing link monitoring or propagation delays, updating RSS,
+changing MAC addresses, changing MTU, configuring VLAN filters, changing
+promiscuous or all-multicast mode, resetting statistics, configuring
+``rte_flow`` rules, and changing 802.3ad settings, including aggregation
+selection, external collect/distribute/slow-Tx controls, and dedicated queue
+enable or disable.
+
+LACP runtime state queries, including ``rte_eth_bond_8023ad_member_info()``,
+``rte_eth_bond_8023ad_ext_collect_get()``, and
+``rte_eth_bond_8023ad_ext_distrib_get()``, are also restricted to the primary
+process.
+
+Rx and Tx are not supported on a bonding device in a secondary process;
+receive returns no packets and transmit drops packets. In a secondary process,
+``rte_eth_dev_stop()`` returns ``-ENOTSUP`` and ``rte_eth_dev_close()`` is the
+detach operation.
+
It should also be noted that the PMD receive function should not be invoked
directly on a member devices after they have been to a bonding device since
packets read directly from the member device will no longer be available to the
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index c8cc86295d..2a8e3a2d20 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -24,6 +24,11 @@ DPDK Release 26.11
New Features
------------
+* **Added bonding PMD secondary-process support.**
+
+ Added support for querying and detaching bonding devices from secondary
+ processes.
+
.. This section should contain new features added in this release.
Sample format:
diff --git a/drivers/net/bonding/eth_bond_private.h b/drivers/net/bonding/eth_bond_private.h
index 378bbba4e6..b3c2ddf24e 100644
--- a/drivers/net/bonding/eth_bond_private.h
+++ b/drivers/net/bonding/eth_bond_private.h
@@ -7,12 +7,14 @@
#include <stdint.h>
#include <sys/queue.h>
+#include <stdbool.h>
#include <ethdev_driver.h>
#include <rte_flow.h>
#include <rte_spinlock.h>
#include <rte_bitmap.h>
#include <rte_flow_driver.h>
+#include <rte_eal.h>
#include "rte_eth_bond.h"
#include "eth_bond_8023ad_private.h"
@@ -212,6 +214,16 @@ find_member_by_id(uint16_t *members, uint16_t members_count, uint16_t member_id)
return pos;
}
+static inline bool
+bond_check_primary(const char *op)
+{
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+ return true;
+
+ RTE_BOND_LOG(ERR, "%s not supported in secondary process", op);
+ return false;
+}
+
int
valid_port_id(uint16_t port_id);
diff --git a/drivers/net/bonding/rte_eth_bond_8023ad.c b/drivers/net/bonding/rte_eth_bond_8023ad.c
index d1f30229d0..5f52cc2bcc 100644
--- a/drivers/net/bonding/rte_eth_bond_8023ad.c
+++ b/drivers/net/bonding/rte_eth_bond_8023ad.c
@@ -1437,6 +1437,9 @@ rte_eth_bond_8023ad_agg_selection_set(uint16_t port_id,
struct bond_dev_private *internals;
struct mode8023ad_private *mode4;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
if (valid_bonding_port_id(port_id) != 0)
return -EINVAL;
@@ -1509,6 +1512,9 @@ rte_eth_bond_8023ad_setup(uint16_t port_id,
struct rte_eth_dev *bond_dev;
int err;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
err = bond_8023ad_setup_validate(port_id, conf);
if (err != 0)
return err;
@@ -1532,6 +1538,9 @@ rte_eth_bond_8023ad_member_info(uint16_t port_id, uint16_t member_id,
struct bond_dev_private *internals;
struct port *port;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
if (info == NULL || valid_bonding_port_id(port_id) != 0 ||
rte_eth_bond_mode_get(port_id) != BONDING_MODE_8023AD)
return -EINVAL;
@@ -1593,6 +1602,9 @@ rte_eth_bond_8023ad_ext_collect(uint16_t port_id, uint16_t member_id,
struct port *port;
int res;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
return res;
@@ -1615,6 +1627,9 @@ rte_eth_bond_8023ad_ext_distrib(uint16_t port_id, uint16_t member_id,
struct port *port;
int res;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
return res;
@@ -1636,6 +1651,9 @@ rte_eth_bond_8023ad_ext_distrib_get(uint16_t port_id, uint16_t member_id)
struct port *port;
int err;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
err = bond_8023ad_ext_validate(port_id, member_id);
if (err != 0)
return err;
@@ -1651,6 +1669,9 @@ rte_eth_bond_8023ad_ext_collect_get(uint16_t port_id, uint16_t member_id)
struct port *port;
int err;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
err = bond_8023ad_ext_validate(port_id, member_id);
if (err != 0)
return err;
@@ -1667,6 +1688,9 @@ rte_eth_bond_8023ad_ext_slowtx(uint16_t port_id, uint16_t member_id,
struct port *port;
int res;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
return res;
@@ -1728,6 +1752,9 @@ rte_eth_bond_8023ad_dedicated_queues_enable(uint16_t port)
struct rte_eth_dev *dev;
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
if (valid_bonding_port_id(port) != 0)
return -EINVAL;
@@ -1757,6 +1784,9 @@ rte_eth_bond_8023ad_dedicated_queues_disable(uint16_t port)
struct rte_eth_dev *dev;
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -ENOTSUP;
+
if (valid_bonding_port_id(port) != 0)
return -EINVAL;
diff --git a/drivers/net/bonding/rte_eth_bond_api.c b/drivers/net/bonding/rte_eth_bond_api.c
index d9b6f1c417..91207e8573 100644
--- a/drivers/net/bonding/rte_eth_bond_api.c
+++ b/drivers/net/bonding/rte_eth_bond_api.c
@@ -159,6 +159,9 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
char devargs[52];
int ret;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (name == NULL) {
RTE_BOND_LOG(ERR, "Invalid name specified");
return -EINVAL;
@@ -640,9 +643,11 @@ rte_eth_bond_member_add(uint16_t bonding_port_id, uint16_t member_port_id)
{
struct rte_eth_dev *bonding_eth_dev;
struct bond_dev_private *internals;
-
int retval;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -781,6 +786,9 @@ rte_eth_bond_member_remove(uint16_t bonding_port_id, uint16_t member_port_id)
struct bond_dev_private *internals;
int retval;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -802,6 +810,9 @@ rte_eth_bond_mode_set(uint16_t bonding_port_id, uint8_t mode)
{
struct rte_eth_dev *bonding_eth_dev;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -834,6 +845,9 @@ rte_eth_bond_primary_set(uint16_t bonding_port_id, uint16_t member_port_id)
{
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -924,6 +938,9 @@ rte_eth_bond_mac_address_set(uint16_t bonding_port_id,
struct rte_eth_dev *bonding_eth_dev;
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -950,6 +967,9 @@ rte_eth_bond_mac_address_reset(uint16_t bonding_port_id)
struct rte_eth_dev *bonding_eth_dev;
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -991,6 +1011,9 @@ rte_eth_bond_xmit_policy_set(uint16_t bonding_port_id, uint8_t policy)
{
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1036,6 +1059,9 @@ rte_eth_bond_link_monitoring_set(uint16_t bonding_port_id, uint32_t internal_ms)
{
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1065,6 +1091,9 @@ rte_eth_bond_link_down_prop_delay_set(uint16_t bonding_port_id,
{
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1093,6 +1122,9 @@ rte_eth_bond_link_up_prop_delay_set(uint16_t bonding_port_id, uint32_t delay_ms)
{
struct bond_dev_private *internals;
+ if (!bond_check_primary(__func__))
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index 63f21d8522..04a2d6f1d2 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -2558,22 +2558,24 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
struct bond_dev_private *bond_ctx;
struct rte_eth_link member_link;
+ struct rte_eth_link bond_link;
bool one_link_update_succeeded;
uint32_t idx;
int ret;
- bond_ctx = ethdev->data->dev_private;
+ rte_eth_linkstatus_get(ethdev, &bond_link);
+ bond_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
- ethdev->data->dev_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+ bond_ctx = ethdev->data->dev_private;
if (ethdev->data->dev_started == 0 ||
bond_ctx->active_member_count == 0) {
- ethdev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
- return 0;
+ bond_link.link_status = RTE_ETH_LINK_DOWN;
+ goto out;
}
- ethdev->data->dev_link.link_status = RTE_ETH_LINK_UP;
+ bond_link.link_status = RTE_ETH_LINK_UP;
if (wait_to_complete)
link_update = rte_eth_link_get;
@@ -2586,7 +2588,7 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
* Setting link speed to UINT32_MAX to ensure we pick up the
* value of the first active member
*/
- ethdev->data->dev_link.link_speed = UINT32_MAX;
+ bond_link.link_speed = UINT32_MAX;
/**
* link speed is minimum value of all the members link speed as
@@ -2597,19 +2599,16 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
ret = link_update(bond_ctx->active_members[idx],
&member_link);
if (ret < 0) {
- ethdev->data->dev_link.link_speed =
- RTE_ETH_SPEED_NUM_NONE;
+ bond_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
RTE_BOND_LOG(ERR,
"Member (port %u) link get failed: %s",
bond_ctx->active_members[idx],
rte_strerror(-ret));
- return 0;
+ goto out;
}
- if (member_link.link_speed <
- ethdev->data->dev_link.link_speed)
- ethdev->data->dev_link.link_speed =
- member_link.link_speed;
+ if (member_link.link_speed < bond_link.link_speed)
+ bond_link.link_speed = member_link.link_speed;
}
break;
case BONDING_MODE_ACTIVE_BACKUP:
@@ -2619,15 +2618,15 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
RTE_BOND_LOG(ERR, "Member (port %u) link get failed: %s",
bond_ctx->current_primary_port,
rte_strerror(-ret));
- return 0;
+ goto out;
}
- ethdev->data->dev_link.link_speed = member_link.link_speed;
+ bond_link.link_speed = member_link.link_speed;
break;
case BONDING_MODE_8023AD:
- ethdev->data->dev_link.link_autoneg =
+ bond_link.link_autoneg =
bond_ctx->mode4.member_link.link_autoneg;
- ethdev->data->dev_link.link_duplex =
+ bond_link.link_duplex =
bond_ctx->mode4.member_link.link_duplex;
/* fall through */
/* to update link speed */
@@ -2640,7 +2639,7 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
* In theses mode the maximum theoretical link speed is the sum
* of all the members
*/
- ethdev->data->dev_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+ bond_link.link_speed = RTE_ETH_SPEED_NUM_NONE;
one_link_update_succeeded = false;
for (idx = 0; idx < bond_ctx->active_member_count; idx++) {
@@ -2655,17 +2654,17 @@ bond_ethdev_link_update(struct rte_eth_dev *ethdev, int wait_to_complete)
}
one_link_update_succeeded = true;
- ethdev->data->dev_link.link_speed +=
- member_link.link_speed;
+ bond_link.link_speed += member_link.link_speed;
}
if (!one_link_update_succeeded) {
RTE_BOND_LOG(ERR, "All members link get failed");
- return 0;
+ goto out;
}
}
-
+out:
+ rte_eth_linkstatus_set(ethdev, &bond_link);
return 0;
}
@@ -3640,12 +3639,23 @@ bond_ethdev_priv_dump(struct rte_eth_dev *dev, FILE *f)
const struct bond_dev_private *internals = dev->data->dev_private;
dump_basic(dev, f);
- if (internals->mode == BONDING_MODE_8023AD)
+ if (internals->mode == BONDING_MODE_8023AD &&
+ rte_eal_process_type() == RTE_PROC_PRIMARY)
dump_lacp(dev->data->port_id, f);
return 0;
}
+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,
+};
+
const struct eth_dev_ops default_dev_ops = {
.dev_start = bond_ethdev_start,
.dev_stop = bond_ethdev_stop,
@@ -3830,7 +3840,7 @@ bond_probe(struct rte_vdev_device *dev)
return -1;
}
- eth_dev->dev_ops = &default_dev_ops;
+ eth_dev->dev_ops = &secondary_dev_ops;
eth_dev->device = &dev->device;
/*
--
2.34.1
next prev parent reply other threads:[~2026-08-30 16:35 UTC|newest]
Thread overview: 33+ 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
2026-08-23 15:16 ` [RFC PATCH v2] net/bonding: restrict secondary control operations Weijun Pan
2026-08-23 15:43 ` Stephen Hemminger
2026-08-24 2:39 ` Weijun Pan
2026-08-24 16:15 ` Stephen Hemminger
2026-08-26 16:10 ` [RFC PATCH v3] " Weijun Pan
2026-08-26 17:53 ` Stephen Hemminger
2026-08-30 1:14 ` [RFC PATCH v4 1/2] net/bonding: skip unavailable member stats Weijun Pan
2026-08-30 1:14 ` [RFC PATCH v4 2/2] net/bonding: restrict secondary control operations Weijun Pan
2026-08-30 4:29 ` Stephen Hemminger
2026-08-30 4:22 ` [RFC PATCH v4 1/2] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-30 16:35 ` [RFC PATCH v5 " Weijun Pan
2026-08-30 16:35 ` Weijun Pan [this message]
2026-08-30 20:23 ` [PATCH 0/8] net/bonding: fixes and per-member statistics Stephen Hemminger
2026-08-30 20:23 ` [PATCH 1/8] net/bonding: fix TLB member ordering with unusable member Stephen Hemminger
2026-08-30 20:23 ` [PATCH 2/8] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-30 20:23 ` [PATCH 3/8] net/bonding: skip unavailable members in device info Stephen Hemminger
2026-08-30 20:23 ` [PATCH 4/8] net/bonding: use atomic link status accessors Stephen Hemminger
2026-08-30 20:23 ` [PATCH 5/8] net/bonding: restrict control operations in secondary process Stephen Hemminger
2026-08-30 20:23 ` [PATCH 6/8] net/bonding: add extended statistics Stephen Hemminger
2026-08-30 20:23 ` [PATCH 7/8] test/bonding: add extended statistics test Stephen Hemminger
2026-08-30 20:23 ` [PATCH 8/8] doc: add bonding features matrix Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 0/8] net/bonding: fixes and per-member stats Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 1/8] net/bonding: fix TLB member ordering with unusable member Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 2/8] net/bonding: skip unavailable member stats Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 3/8] net/bonding: skip unavailable members in device info Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 4/8] net/bonding: use atomic link status accessors Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 5/8] net/bonding: restrict control ops in secondary process Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 6/8] net/bonding: add extended statistics Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 7/8] test/bonding: add extended statistics test Stephen Hemminger
2026-08-31 16:06 ` [PATCH v2 8/8] doc: add bonding features matrix Stephen Hemminger
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=20260830163539.21099-2-wpan3636@gmail.com \
--to=wpan3636@gmail.com \
--cc=3chas3@gmail.com \
--cc=anatoly.burakov@intel.com \
--cc=dev@dpdk.org \
--cc=humin29@huawei.com \
--cc=stephen@networkplumber.org \
/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.