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: 655f8919d5 ("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>
This commit is contained in:
Louis Scalbert 2026-06-03 17:03:28 +02:00 committed by Jakub Kicinski
parent 363037983c
commit 32b0b89533
9 changed files with 73 additions and 0 deletions

View 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-

View 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

View 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);

View 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;

View 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)
{

View 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
};

View 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];

View 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,
};

View 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,
};