summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Scalbert <louis.scalbert@6wind.com>2026-06-03 17:03:28 +0200
committerJakub Kicinski <kuba@kernel.org>2026-06-10 07:53:26 -0700
commit32b0b8953343eaceaa816a9ead3b6bb66355c64e (patch)
tree92f6c0d87ec67532667c545a27ff6bdd76335ad6
parent363037983cc503eb0b5a5c0ab80bf1434cfd168a (diff)
downloadlinux-32b0b8953343eaceaa816a9ead3b6bb66355c64e.tar.gz
linux-32b0b8953343eaceaa816a9ead3b6bb66355c64e.tar.bz2
linux-32b0b8953343eaceaa816a9ead3b6bb66355c64e.zip
bonding: 3ad: add lacp_strict configuration knob
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>
-rw-r--r--Documentation/netlink/specs/rt-link.yaml3
-rw-r--r--Documentation/networking/bonding.rst23
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/bonding/bond_netlink.c16
-rw-r--r--drivers/net/bonding/bond_options.c26
-rw-r--r--include/net/bond_options.h1
-rw-r--r--include/net/bonding.h1
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--tools/include/uapi/linux/if_link.h1
9 files changed, 73 insertions, 0 deletions
diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml
index 694fd0a3a0c1..892979da098e 100644
--- a/Documentation/netlink/specs/rt-link.yaml
+++ b/Documentation/netlink/specs/rt-link.yaml
@@ -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-
diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst
index e700bf1d095c..33ca5afafdf6 100644
--- a/Documentation/networking/bonding.rst
+++ b/Documentation/networking/bonding.rst
@@ -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
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index be50125f0635..e044fc733b8c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -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);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 90365d3f7ebf..4a11572f663d 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -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;
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 5095ac3dad2c..f01b3baa57b4 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -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)
{
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index e6eedf23aea1..52b966e92793 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -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
};
diff --git a/include/net/bonding.h b/include/net/bonding.h
index edd1942dcd73..2c54a36a8477 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -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];
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 363526549a01..43cecca49f01 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -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,
};
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index 97a2d4411534..757ce5e9426e 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -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,
};