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 non-primary 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 <[email protected]>
---
v4:
- Use rte_eth_linkstatus_set() in link update.
- Document supported secondary query and detach paths.
- Move the release note to API Changes.
- Keep secondary private dump but skip LACP state.

 .../link_bonding_poll_mode_drv_lib.rst        | 30 ++++++++++
 doc/guides/rel_notes/release_26_11.rst        |  6 ++
 drivers/net/bonding/eth_bond_private.h        | 12 ++++
 drivers/net/bonding/rte_eth_bond_8023ad.c     | 48 +++++++++++++++
 drivers/net/bonding/rte_eth_bond_api.c        | 53 ++++++++++++++++-
 drivers/net/bonding/rte_eth_bond_pmd.c        | 58 +++++++++++--------
 6 files changed, 182 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..60d8146d68 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -81,6 +81,12 @@ Removed Items
 API Changes
 -----------
 
+* **Restricted bonding device control to the primary process.**
+
+  Bonding device configuration and LACP runtime state operations are now
+  rejected in secondary processes. Secondary processes may detach and use
+  supported query operations only.
+
 .. This section should contain API changes. Sample format:
 
    * sample: Add a short 1-2 sentence description of the API change
diff --git a/drivers/net/bonding/eth_bond_private.h 
b/drivers/net/bonding/eth_bond_private.h
index 378bbba4e6..526bcd0363 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 int
+bond_check_primary(const char *op, int err)
+{
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+               return 0;
+
+       RTE_BOND_LOG(ERR, "%s not supported in non-primary process", op);
+       return err;
+}
+
 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..65f417a444 100644
--- a/drivers/net/bonding/rte_eth_bond_8023ad.c
+++ b/drivers/net/bonding/rte_eth_bond_8023ad.c
@@ -1436,6 +1436,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_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(port_id) != 0)
                return -EINVAL;
@@ -1508,6 +1513,11 @@ rte_eth_bond_8023ad_setup(uint16_t port_id,
 {
        struct rte_eth_dev *bond_dev;
        int err;
+       int ret;
+
+       ret = bond_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        err = bond_8023ad_setup_validate(port_id, conf);
        if (err != 0)
@@ -1531,6 +1541,11 @@ rte_eth_bond_8023ad_member_info(uint16_t port_id, 
uint16_t member_id,
        struct rte_eth_dev *bond_dev;
        struct bond_dev_private *internals;
        struct port *port;
+       int ret;
+
+       ret = bond_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        if (info == NULL || valid_bonding_port_id(port_id) != 0 ||
                        rte_eth_bond_mode_get(port_id) != BONDING_MODE_8023AD)
@@ -1592,6 +1607,11 @@ rte_eth_bond_8023ad_ext_collect(uint16_t port_id, 
uint16_t member_id,
 {
        struct port *port;
        int res;
+       int ret;
+
+       ret = bond_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        res = bond_8023ad_ext_validate(port_id, member_id);
        if (res != 0)
@@ -1614,6 +1634,11 @@ rte_eth_bond_8023ad_ext_distrib(uint16_t port_id, 
uint16_t member_id,
 {
        struct port *port;
        int res;
+       int ret;
+
+       ret = bond_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        res = bond_8023ad_ext_validate(port_id, member_id);
        if (res != 0)
@@ -1636,6 +1661,10 @@ rte_eth_bond_8023ad_ext_distrib_get(uint16_t port_id, 
uint16_t member_id)
        struct port *port;
        int err;
 
+       err = bond_check_primary(__func__, -ENOTSUP);
+       if (err != 0)
+               return err;
+
        err = bond_8023ad_ext_validate(port_id, member_id);
        if (err != 0)
                return err;
@@ -1651,6 +1680,10 @@ rte_eth_bond_8023ad_ext_collect_get(uint16_t port_id, 
uint16_t member_id)
        struct port *port;
        int err;
 
+       err = bond_check_primary(__func__, -ENOTSUP);
+       if (err != 0)
+               return err;
+
        err = bond_8023ad_ext_validate(port_id, member_id);
        if (err != 0)
                return err;
@@ -1666,6 +1699,11 @@ rte_eth_bond_8023ad_ext_slowtx(uint16_t port_id, 
uint16_t member_id,
 {
        struct port *port;
        int res;
+       int ret;
+
+       ret = bond_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        res = bond_8023ad_ext_validate(port_id, member_id);
        if (res != 0)
@@ -1727,6 +1765,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_check_primary(__func__, -ENOTSUP);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(port) != 0)
                return -EINVAL;
@@ -1756,6 +1799,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_check_primary(__func__, -ENOTSUP);
+       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..029e141d89 100644
--- a/drivers/net/bonding/rte_eth_bond_api.c
+++ b/drivers/net/bonding/rte_eth_bond_api.c
@@ -159,6 +159,10 @@ rte_eth_bond_create(const char *name, uint8_t mode, 
uint8_t socket_id)
        char devargs[52];
        int ret;
 
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
+
        if (name == NULL) {
                RTE_BOND_LOG(ERR, "Invalid name specified");
                return -EINVAL;
@@ -640,9 +644,12 @@ 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;
 
+       retval = bond_check_primary(__func__, -1);
+       if (retval != 0)
+               return retval;
+
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
 
@@ -781,6 +788,10 @@ rte_eth_bond_member_remove(uint16_t bonding_port_id, 
uint16_t member_port_id)
        struct bond_dev_private *internals;
        int retval;
 
+       retval = bond_check_primary(__func__, -1);
+       if (retval != 0)
+               return retval;
+
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
 
@@ -801,6 +812,11 @@ int
 rte_eth_bond_mode_set(uint16_t bonding_port_id, uint8_t mode)
 {
        struct rte_eth_dev *bonding_eth_dev;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -833,6 +849,11 @@ int
 rte_eth_bond_primary_set(uint16_t bonding_port_id, uint16_t member_port_id)
 {
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -923,6 +944,11 @@ rte_eth_bond_mac_address_set(uint16_t bonding_port_id,
 {
        struct rte_eth_dev *bonding_eth_dev;
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -949,6 +975,11 @@ rte_eth_bond_mac_address_reset(uint16_t bonding_port_id)
 {
        struct rte_eth_dev *bonding_eth_dev;
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -990,6 +1021,11 @@ int
 rte_eth_bond_xmit_policy_set(uint16_t bonding_port_id, uint8_t policy)
 {
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -1035,6 +1071,11 @@ int
 rte_eth_bond_link_monitoring_set(uint16_t bonding_port_id, uint32_t 
internal_ms)
 {
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -1064,6 +1105,11 @@ rte_eth_bond_link_down_prop_delay_set(uint16_t 
bonding_port_id,
 
 {
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        if (valid_bonding_port_id(bonding_port_id) != 0)
                return -1;
@@ -1092,6 +1138,11 @@ rte_eth_bond_link_up_prop_delay_set(uint16_t 
bonding_port_id, uint32_t delay_ms)
 
 {
        struct bond_dev_private *internals;
+       int ret;
+
+       ret = bond_check_primary(__func__, -1);
+       if (ret != 0)
+               return ret;
 
        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 6f10dbb0c7..bba93a5638 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;
 }
 
@@ -3641,12 +3640,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,
@@ -3831,7 +3841,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

Reply via email to