[RFC PATCH v2] net/bonding: restrict secondary control operations
Weijun Pan
wpan3636 at gmail.com
Sun Aug 23 17:16:25 CEST 2026
The bonding PMD currently supports secondary attach with safe fallback
burst functions, but bonding configuration and LACP state are owned by
the primary process.
Use a secondary-specific dev_ops table so unsupported operations are
rejected by ethdev before PMD callbacks can mutate shared device state.
Also reject bonding-specific control APIs from non-primary processes,
while keeping secondary detach and query paths available.
This keeps secondary process behavior safe while leaving room for future
limited datapath support.
Bugzilla ID: 1900
Signed-off-by: Weijun Pan <wpan3636 at gmail.com>
---
.../link_bonding_poll_mode_drv_lib.rst | 13 ++++++
doc/guides/rel_notes/release_26_11.rst | 6 +++
drivers/net/bonding/eth_bond_private.h | 8 ++++
drivers/net/bonding/rte_eth_bond_8023ad.c | 45 +++++++++++++++++++
drivers/net/bonding/rte_eth_bond_api.c | 44 ++++++++++++++++++
drivers/net/bonding/rte_eth_bond_pmd.c | 12 ++++-
6 files changed, 127 insertions(+), 1 deletion(-)
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..7ecb05d407 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,19 @@ 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 is owned by the primary process. Secondary
+processes may attach to an existing bonding device for query and detach
+operations, but must not change bonding configuration or device state.
+
+In a secondary process, bonding control operations such as configuring,
+starting or stopping the device, setting up queues, changing members,
+changing the bonding mode, updating RSS, changing MAC addresses, changing
+MTU, or configuring ``rte_flow`` rules are not supported.
+
+Secondary process datapath support is limited and bonding mode specific.
+Applications should not rely on secondary processes for bonding datapath
+operation unless support for the selected mode is explicitly documented.
+
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..8df012c99b 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -55,6 +55,12 @@ New Features
Also, make sure to start the actual text at the margin.
=======================================================
+* **Updated bonding PMD secondary process handling.**
+
+ Bonding devices now use a secondary-process device operations table to
+ keep query and detach paths available while rejecting unsupported control
+ operations before shared ethdev state can be modified. Bonding-specific
+ control APIs are also restricted to the primary process.
Removed Items
-------------
diff --git a/drivers/net/bonding/eth_bond_private.h b/drivers/net/bonding/eth_bond_private.h
index 378bbba4e6..750e5925df 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,12 @@ find_member_by_id(uint16_t *members, uint16_t members_count, uint16_t member_id)
return pos;
}
+static inline bool
+bond_process_is_primary(void)
+{
+ return rte_eal_process_type() == RTE_PROC_PRIMARY;
+}
+
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..e3d02f0539 100644
--- a/drivers/net/bonding/rte_eth_bond_8023ad.c
+++ b/drivers/net/bonding/rte_eth_bond_8023ad.c
@@ -1428,6 +1428,16 @@ rte_eth_bond_8023ad_conf_get(uint16_t port_id,
return 0;
}
+static int
+bond_8023ad_check_primary(const char *op)
+{
+ if (bond_process_is_primary())
+ return 0;
+
+ RTE_BOND_LOG(ERR, "%s not supported in non-primary process", op);
+ return -ENOTSUP;
+}
+
RTE_EXPORT_SYMBOL(rte_eth_bond_8023ad_agg_selection_set)
int
rte_eth_bond_8023ad_agg_selection_set(uint16_t port_id,
@@ -1436,6 +1446,11 @@ rte_eth_bond_8023ad_agg_selection_set(uint16_t port_id,
struct rte_eth_dev *bond_dev;
struct bond_dev_private *internals;
struct mode8023ad_private *mode4;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
if (valid_bonding_port_id(port_id) != 0)
return -EINVAL;
@@ -1508,6 +1523,11 @@ rte_eth_bond_8023ad_setup(uint16_t port_id,
{
struct rte_eth_dev *bond_dev;
int err;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
err = bond_8023ad_setup_validate(port_id, conf);
if (err != 0)
@@ -1592,6 +1612,11 @@ rte_eth_bond_8023ad_ext_collect(uint16_t port_id, uint16_t member_id,
{
struct port *port;
int res;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
@@ -1614,6 +1639,11 @@ rte_eth_bond_8023ad_ext_distrib(uint16_t port_id, uint16_t member_id,
{
struct port *port;
int res;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
@@ -1666,6 +1696,11 @@ rte_eth_bond_8023ad_ext_slowtx(uint16_t port_id, uint16_t member_id,
{
struct port *port;
int res;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
res = bond_8023ad_ext_validate(port_id, member_id);
if (res != 0)
@@ -1727,6 +1762,11 @@ rte_eth_bond_8023ad_dedicated_queues_enable(uint16_t port)
{
struct rte_eth_dev *dev;
struct bond_dev_private *internals;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
if (valid_bonding_port_id(port) != 0)
return -EINVAL;
@@ -1756,6 +1796,11 @@ rte_eth_bond_8023ad_dedicated_queues_disable(uint16_t port)
{
struct rte_eth_dev *dev;
struct bond_dev_private *internals;
+ int ret;
+
+ ret = bond_8023ad_check_primary(__func__);
+ if (ret != 0)
+ return ret;
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..c4f055bfa5 100644
--- a/drivers/net/bonding/rte_eth_bond_api.c
+++ b/drivers/net/bonding/rte_eth_bond_api.c
@@ -150,6 +150,17 @@ deactivate_member(struct rte_eth_dev *eth_dev, uint16_t port_id)
}
}
+static int
+bond_api_check_primary(const char *op)
+{
+ if (bond_process_is_primary())
+ return 0;
+
+ RTE_BOND_LOG(ERR, "%s not supported in non-primary process", op);
+ return -1;
+}
+
+
RTE_EXPORT_SYMBOL(rte_eth_bond_create)
int
rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
@@ -159,6 +170,9 @@ rte_eth_bond_create(const char *name, uint8_t mode, uint8_t socket_id)
char devargs[52];
int ret;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (name == NULL) {
RTE_BOND_LOG(ERR, "Invalid name specified");
return -EINVAL;
@@ -643,6 +657,9 @@ rte_eth_bond_member_add(uint16_t bonding_port_id, uint16_t member_port_id)
int retval;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -781,6 +798,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_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -802,6 +822,9 @@ rte_eth_bond_mode_set(uint16_t bonding_port_id, uint8_t mode)
{
struct rte_eth_dev *bonding_eth_dev;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -834,6 +857,9 @@ rte_eth_bond_primary_set(uint16_t bonding_port_id, uint16_t member_port_id)
{
struct bond_dev_private *internals;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -924,6 +950,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_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -950,6 +979,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_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -991,6 +1023,9 @@ rte_eth_bond_xmit_policy_set(uint16_t bonding_port_id, uint8_t policy)
{
struct bond_dev_private *internals;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1036,6 +1071,9 @@ rte_eth_bond_link_monitoring_set(uint16_t bonding_port_id, uint32_t internal_ms)
{
struct bond_dev_private *internals;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1065,6 +1103,9 @@ rte_eth_bond_link_down_prop_delay_set(uint16_t bonding_port_id,
{
struct bond_dev_private *internals;
+ if (bond_api_check_primary(__func__) != 0)
+ return -1;
+
if (valid_bonding_port_id(bonding_port_id) != 0)
return -1;
@@ -1093,6 +1134,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_api_check_primary(__func__) != 0)
+ 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 6a4f997b5a..f7fb562cee 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -3644,6 +3644,16 @@ bond_ethdev_priv_dump(struct rte_eth_dev *dev, FILE *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,
@@ -3828,7 +3838,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
More information about the dev
mailing list