]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bonding: 3ad: add lacp_strict configuration knob
authorLouis Scalbert <louis.scalbert@6wind.com>
Wed, 3 Jun 2026 15:03:28 +0000 (17:03 +0200)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 14:53:26 +0000 (07:53 -0700)
When an 802.3ad (LACP) bonding interface has no slaves in the
collecting/distributing state, the bonding master still reports
carrier as up as long as at least 'min_links' slaves have carrier.

In this situation, only one slave is effectively used for TX/RX,
while traffic received on other slaves is dropped. Upper-layer
daemons therefore consider the interface operational, even though
traffic may be blackholed if the lack of LACP negotiation means
the partner is not ready to deal with traffic.

Introduce a configuration knob to control this behavior. It allows
the bonding master to assert carrier only when at least 'min_links'
slaves are in Collecting_Distributing state.

The default mode preserves the existing behavior. This patch only
introduces the knob; its behavior is implemented in the subsequent
commit.

Fixes: 655f8919d549 ("bonding: add min links parameter to 802.3ad")
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
Acked-by: Jay Vosburgh <jv@jvosburgh.net>
Link: https://patch.msgid.link/20260603150331.1919611-4-louis.scalbert@6wind.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/netlink/specs/rt-link.yaml
Documentation/networking/bonding.rst
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
include/net/bond_options.h
include/net/bonding.h
include/uapi/linux/if_link.h
tools/include/uapi/linux/if_link.h

index 694fd0a3a0c15960cca9b8865eeb5be27771ac5f..892979da098ed1e52a70bae49c9b05cba63988dd 100644 (file)
@@ -1356,6 +1356,9 @@ attribute-sets:
       -
         name: broadcast-neigh
         type: u8
+      -
+        name: lacp-strict
+        type: u8
   -
     name: bond-ad-info-attrs
     name-prefix: ifla-bond-ad-info-
index e700bf1d095c35b2970a92ab7a920a9e4d785f18..33ca5afafdf6dd52c573aee9b285ba011754900c 100644 (file)
@@ -619,6 +619,29 @@ min_links
        aggregator cannot be active without at least one available link,
        setting this option to 0 or to 1 has the exact same effect.
 
+lacp_strict
+
+       Specifies the fallback behavior of a bonding when LACP negotiation
+       fails on all slave links, i.e. when no slave is in the
+       Collecting_Distributing state, while at least `min_links` link still
+       reports carrier up.
+
+       This option is only applicable to 802.3ad mode (mode 4).
+
+       Valid values are:
+
+       off or 0
+               One interface of the bond is selected to be active, in order to
+               facilitate communication with peer devices that do not implement
+               LACP.
+
+       on or 1
+               Interfaces are only permitted to be made active if they have an
+               active LACP partner and have successfully reached
+               Collecting_Distributing state.
+
+       The default value is 0 (off).
+
 mode
 
        Specifies one of the bonding policies. The default is
index be50125f0635403efd4c7b5c8d9d0f9153c5ba62..e044fc733b8c0311c17a3e0b9c0b15fcc1159d21 100644 (file)
@@ -6457,6 +6457,7 @@ static int __init bond_check_params(struct bond_params *params)
        params->ad_user_port_key = ad_user_port_key;
        params->coupled_control = 1;
        params->broadcast_neighbor = 0;
+       params->lacp_strict = 0;
        if (packets_per_slave > 0) {
                params->reciprocal_packets_per_slave =
                        reciprocal_value(packets_per_slave);
index 90365d3f7ebff7f762b4cb10303a3dd3fdd49cc6..4a11572f663d3127fb2901468939556d34df16ed 100644 (file)
@@ -143,6 +143,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
        [IFLA_BOND_NS_IP6_TARGET]       = { .type = NLA_NESTED },
        [IFLA_BOND_COUPLED_CONTROL]     = { .type = NLA_U8 },
        [IFLA_BOND_BROADCAST_NEIGH]     = { .type = NLA_U8 },
+       [IFLA_BOND_LACP_STRICT]         = { .type = NLA_U8 },
 };
 
 static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
@@ -599,6 +600,16 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        return err;
        }
 
+       if (data[IFLA_BOND_LACP_STRICT]) {
+               int fallback_mode = nla_get_u8(data[IFLA_BOND_LACP_STRICT]);
+
+               bond_opt_initval(&newval, fallback_mode);
+               err = __bond_opt_set(bond, BOND_OPT_LACP_STRICT, &newval,
+                                    data[IFLA_BOND_LACP_STRICT], extack);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -671,6 +682,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
                nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS +
                nla_total_size(sizeof(u8)) +    /* IFLA_BOND_COUPLED_CONTROL */
                nla_total_size(sizeof(u8)) +    /* IFLA_BOND_BROADCAST_NEIGH */
+               nla_total_size(sizeof(u8)) +    /* IFLA_BOND_LACP_STRICT */
                0;
 }
 
@@ -838,6 +850,10 @@ static int bond_fill_info(struct sk_buff *skb,
                       bond->params.broadcast_neighbor))
                goto nla_put_failure;
 
+       if (nla_put_u8(skb, IFLA_BOND_LACP_STRICT,
+                      bond->params.lacp_strict))
+               goto nla_put_failure;
+
        if (BOND_MODE(bond) == BOND_MODE_8023AD) {
                struct ad_info info;
 
index 5095ac3dad2cd924ff548343c7c1afe3e57e3065..f01b3baa57b4e1138a9d3ea7ee173e6de4a880fb 100644 (file)
@@ -68,6 +68,8 @@ static int bond_option_lacp_active_set(struct bonding *bond,
                                       const struct bond_opt_value *newval);
 static int bond_option_lacp_rate_set(struct bonding *bond,
                                     const struct bond_opt_value *newval);
+static int bond_option_lacp_strict_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
 static int bond_option_ad_select_set(struct bonding *bond,
                                     const struct bond_opt_value *newval);
 static int bond_option_queue_id_set(struct bonding *bond,
@@ -162,6 +164,12 @@ static const struct bond_opt_value bond_lacp_rate_tbl[] = {
        { NULL,   -1,           0},
 };
 
+static const struct bond_opt_value bond_lacp_strict_tbl[] = {
+       { "off", 0, BOND_VALFLAG_DEFAULT},
+       { "on",  1, 0},
+       { NULL, -1, 0 }
+};
+
 static const struct bond_opt_value bond_ad_select_tbl[] = {
        { "stable",          BOND_AD_STABLE,    BOND_VALFLAG_DEFAULT},
        { "bandwidth",       BOND_AD_BANDWIDTH, 0},
@@ -363,6 +371,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
                .values = bond_lacp_rate_tbl,
                .set = bond_option_lacp_rate_set
        },
+       [BOND_OPT_LACP_STRICT] = {
+               .id = BOND_OPT_LACP_STRICT,
+               .name = "lacp_strict",
+               .desc = "Define the LACP fallback mode when no slaves have negotiated",
+               .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+               .values = bond_lacp_strict_tbl,
+               .set = bond_option_lacp_strict_set
+       },
        [BOND_OPT_MINLINKS] = {
                .id = BOND_OPT_MINLINKS,
                .name = "min_links",
@@ -1685,6 +1701,16 @@ static int bond_option_lacp_rate_set(struct bonding *bond,
        return 0;
 }
 
+static int bond_option_lacp_strict_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
+{
+       netdev_dbg(bond->dev, "Setting LACP fallback to %s (%llu)\n",
+                  newval->string, newval->value);
+       bond->params.lacp_strict = newval->value;
+
+       return 0;
+}
+
 static int bond_option_ad_select_set(struct bonding *bond,
                                     const struct bond_opt_value *newval)
 {
index e6eedf23aea1a3adeb2f7f5bb7b6c176a689226f..52b966e927938a41a234b1fe09263c42b6c93d94 100644 (file)
@@ -79,6 +79,7 @@ enum {
        BOND_OPT_COUPLED_CONTROL,
        BOND_OPT_BROADCAST_NEIGH,
        BOND_OPT_ACTOR_PORT_PRIO,
+       BOND_OPT_LACP_STRICT,
        BOND_OPT_LAST
 };
 
index edd1942dcd736d3601e799dfbc9aeb8da0835902..2c54a36a8477b98dc7a4a1f45d27f7972efecba0 100644 (file)
@@ -129,6 +129,7 @@ struct bond_params {
        int peer_notif_delay;
        int lacp_active;
        int lacp_fast;
+       int lacp_strict;
        unsigned int min_links;
        int ad_select;
        char primary[IFNAMSIZ];
index 363526549a01cb1d956f2a8d337a22c10975e53a..43cecca49f017a7c4131d2ff47434f8cba227224 100644 (file)
@@ -1603,6 +1603,7 @@ enum {
        IFLA_BOND_NS_IP6_TARGET,
        IFLA_BOND_COUPLED_CONTROL,
        IFLA_BOND_BROADCAST_NEIGH,
+       IFLA_BOND_LACP_STRICT,
        __IFLA_BOND_MAX,
 };
 
index 97a2d4411534aec07a44a512cec2a590edc688bf..757ce5e9426e9202cb7b90a45bde3d5982741529 100644 (file)
@@ -1527,6 +1527,7 @@ enum {
        IFLA_BOND_NS_IP6_TARGET,
        IFLA_BOND_COUPLED_CONTROL,
        IFLA_BOND_BROADCAST_NEIGH,
+       IFLA_BOND_LACP_STRICT,
        __IFLA_BOND_MAX,
 };