Skip to content

Commit 45b7035

Browse files
AahilAgregkh
authored andcommitted
bonding: Add independent control state machine
[ Upstream commit 240fd40 ] Add support for the independent control state machine per IEEE 802.1AX-2008 5.4.15 in addition to the existing implementation of the coupled control state machine. Introduces two new states, AD_MUX_COLLECTING and AD_MUX_DISTRIBUTING in the LACP MUX state machine for separated handling of an initial Collecting state before the Collecting and Distributing state. This enables a port to be in a state where it can receive incoming packets while not still distributing. This is useful for reducing packet loss when a port begins distributing before its partner is able to collect. Added new functions such as bond_set_slave_tx_disabled_flags and bond_set_slave_rx_enabled_flags to precisely manage the port's collecting and distributing states. Previously, there was no dedicated method to disable TX while keeping RX enabled, which this patch addresses. Note that the regular flow process in the kernel's bonding driver remains unaffected by this patch. The extension requires explicit opt-in by the user (in order to ensure no disruptions for existing setups) via netlink support using the new bonding parameter coupled_control. The default value for coupled_control is set to 1 so as to preserve existing behaviour. Signed-off-by: Aahil Awatramani <aahila@google.com> Reviewed-by: Hangbin Liu <liuhangbin@gmail.com> Link: https://lore.kernel.org/r/20240202175858.1573852-1-aahila@google.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Stable-dep-of: 0599640 ("bonding: send LACPDUs periodically in passive mode after receiving partner's LACPDU") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent f0c7885 commit 45b7035

10 files changed

Lines changed: 234 additions & 8 deletions

File tree

Documentation/networking/bonding.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,18 @@ arp_missed_max
444444

445445
The default value is 2, and the allowable range is 1 - 255.
446446

447+
coupled_control
448+
449+
Specifies whether the LACP state machine's MUX in the 802.3ad mode
450+
should have separate Collecting and Distributing states.
451+
452+
This is by implementing the independent control state machine per
453+
IEEE 802.1AX-2008 5.4.15 in addition to the existing coupled control
454+
state machine.
455+
456+
The default value is 1. This setting does not separate the Collecting
457+
and Distributing states, maintaining the bond in coupled control.
458+
447459
downdelay
448460

449461
Specifies the time, in milliseconds, to wait before disabling

drivers/net/bonding/bond_3ad.c

Lines changed: 150 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ static void ad_agg_selection_logic(struct aggregator *aggregator,
106106
static void ad_clear_agg(struct aggregator *aggregator);
107107
static void ad_initialize_agg(struct aggregator *aggregator);
108108
static void ad_initialize_port(struct port *port, int lacp_fast);
109+
static void ad_enable_collecting(struct port *port);
110+
static void ad_disable_distributing(struct port *port,
111+
bool *update_slave_arr);
109112
static void ad_enable_collecting_distributing(struct port *port,
110113
bool *update_slave_arr);
111114
static void ad_disable_collecting_distributing(struct port *port,
@@ -171,9 +174,38 @@ static inline int __agg_has_partner(struct aggregator *agg)
171174
return !is_zero_ether_addr(agg->partner_system.mac_addr_value);
172175
}
173176

177+
/**
178+
* __disable_distributing_port - disable the port's slave for distributing.
179+
* Port will still be able to collect.
180+
* @port: the port we're looking at
181+
*
182+
* This will disable only distributing on the port's slave.
183+
*/
184+
static void __disable_distributing_port(struct port *port)
185+
{
186+
bond_set_slave_tx_disabled_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
187+
}
188+
189+
/**
190+
* __enable_collecting_port - enable the port's slave for collecting,
191+
* if it's up
192+
* @port: the port we're looking at
193+
*
194+
* This will enable only collecting on the port's slave.
195+
*/
196+
static void __enable_collecting_port(struct port *port)
197+
{
198+
struct slave *slave = port->slave;
199+
200+
if (slave->link == BOND_LINK_UP && bond_slave_is_up(slave))
201+
bond_set_slave_rx_enabled_flags(slave, BOND_SLAVE_NOTIFY_LATER);
202+
}
203+
174204
/**
175205
* __disable_port - disable the port's slave
176206
* @port: the port we're looking at
207+
*
208+
* This will disable both collecting and distributing on the port's slave.
177209
*/
178210
static inline void __disable_port(struct port *port)
179211
{
@@ -183,6 +215,8 @@ static inline void __disable_port(struct port *port)
183215
/**
184216
* __enable_port - enable the port's slave, if it's up
185217
* @port: the port we're looking at
218+
*
219+
* This will enable both collecting and distributing on the port's slave.
186220
*/
187221
static inline void __enable_port(struct port *port)
188222
{
@@ -193,10 +227,27 @@ static inline void __enable_port(struct port *port)
193227
}
194228

195229
/**
196-
* __port_is_enabled - check if the port's slave is in active state
230+
* __port_move_to_attached_state - check if port should transition back to attached
231+
* state.
232+
* @port: the port we're looking at
233+
*/
234+
static bool __port_move_to_attached_state(struct port *port)
235+
{
236+
if (!(port->sm_vars & AD_PORT_SELECTED) ||
237+
(port->sm_vars & AD_PORT_STANDBY) ||
238+
!(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
239+
!(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION))
240+
port->sm_mux_state = AD_MUX_ATTACHED;
241+
242+
return port->sm_mux_state == AD_MUX_ATTACHED;
243+
}
244+
245+
/**
246+
* __port_is_collecting_distributing - check if the port's slave is in the
247+
* combined collecting/distributing state
197248
* @port: the port we're looking at
198249
*/
199-
static inline int __port_is_enabled(struct port *port)
250+
static int __port_is_collecting_distributing(struct port *port)
200251
{
201252
return bond_is_active_slave(port->slave);
202253
}
@@ -942,6 +993,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
942993
*/
943994
static void ad_mux_machine(struct port *port, bool *update_slave_arr)
944995
{
996+
struct bonding *bond = __get_bond_by_port(port);
945997
mux_states_t last_state;
946998

947999
/* keep current State Machine state to compare later if it was
@@ -999,9 +1051,13 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
9991051
if ((port->sm_vars & AD_PORT_SELECTED) &&
10001052
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
10011053
!__check_agg_selection_timer(port)) {
1002-
if (port->aggregator->is_active)
1003-
port->sm_mux_state =
1004-
AD_MUX_COLLECTING_DISTRIBUTING;
1054+
if (port->aggregator->is_active) {
1055+
int state = AD_MUX_COLLECTING_DISTRIBUTING;
1056+
1057+
if (!bond->params.coupled_control)
1058+
state = AD_MUX_COLLECTING;
1059+
port->sm_mux_state = state;
1060+
}
10051061
} else if (!(port->sm_vars & AD_PORT_SELECTED) ||
10061062
(port->sm_vars & AD_PORT_STANDBY)) {
10071063
/* if UNSELECTED or STANDBY */
@@ -1019,19 +1075,53 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
10191075
}
10201076
break;
10211077
case AD_MUX_COLLECTING_DISTRIBUTING:
1078+
if (!__port_move_to_attached_state(port)) {
1079+
/* if port state hasn't changed make
1080+
* sure that a collecting distributing
1081+
* port in an active aggregator is enabled
1082+
*/
1083+
if (port->aggregator->is_active &&
1084+
!__port_is_collecting_distributing(port)) {
1085+
__enable_port(port);
1086+
*update_slave_arr = true;
1087+
}
1088+
}
1089+
break;
1090+
case AD_MUX_COLLECTING:
1091+
if (!__port_move_to_attached_state(port)) {
1092+
if ((port->sm_vars & AD_PORT_SELECTED) &&
1093+
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
1094+
(port->partner_oper.port_state & LACP_STATE_COLLECTING)) {
1095+
port->sm_mux_state = AD_MUX_DISTRIBUTING;
1096+
} else {
1097+
/* If port state hasn't changed, make sure that a collecting
1098+
* port is enabled for an active aggregator.
1099+
*/
1100+
struct slave *slave = port->slave;
1101+
1102+
if (port->aggregator->is_active &&
1103+
bond_is_slave_rx_disabled(slave)) {
1104+
ad_enable_collecting(port);
1105+
*update_slave_arr = true;
1106+
}
1107+
}
1108+
}
1109+
break;
1110+
case AD_MUX_DISTRIBUTING:
10221111
if (!(port->sm_vars & AD_PORT_SELECTED) ||
10231112
(port->sm_vars & AD_PORT_STANDBY) ||
1113+
!(port->partner_oper.port_state & LACP_STATE_COLLECTING) ||
10241114
!(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) ||
10251115
!(port->actor_oper_port_state & LACP_STATE_SYNCHRONIZATION)) {
1026-
port->sm_mux_state = AD_MUX_ATTACHED;
1116+
port->sm_mux_state = AD_MUX_COLLECTING;
10271117
} else {
10281118
/* if port state hasn't changed make
10291119
* sure that a collecting distributing
10301120
* port in an active aggregator is enabled
10311121
*/
10321122
if (port->aggregator &&
10331123
port->aggregator->is_active &&
1034-
!__port_is_enabled(port)) {
1124+
!__port_is_collecting_distributing(port)) {
10351125
__enable_port(port);
10361126
*update_slave_arr = true;
10371127
}
@@ -1082,6 +1172,20 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
10821172
update_slave_arr);
10831173
port->ntt = true;
10841174
break;
1175+
case AD_MUX_COLLECTING:
1176+
port->actor_oper_port_state |= LACP_STATE_COLLECTING;
1177+
port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING;
1178+
port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1179+
ad_enable_collecting(port);
1180+
ad_disable_distributing(port, update_slave_arr);
1181+
port->ntt = true;
1182+
break;
1183+
case AD_MUX_DISTRIBUTING:
1184+
port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
1185+
port->actor_oper_port_state |= LACP_STATE_SYNCHRONIZATION;
1186+
ad_enable_collecting_distributing(port,
1187+
update_slave_arr);
1188+
break;
10851189
default:
10861190
break;
10871191
}
@@ -1906,6 +2010,45 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
19062010
}
19072011
}
19082012

2013+
/**
2014+
* ad_enable_collecting - enable a port's receive
2015+
* @port: the port we're looking at
2016+
*
2017+
* Enable @port if it's in an active aggregator
2018+
*/
2019+
static void ad_enable_collecting(struct port *port)
2020+
{
2021+
if (port->aggregator->is_active) {
2022+
struct slave *slave = port->slave;
2023+
2024+
slave_dbg(slave->bond->dev, slave->dev,
2025+
"Enabling collecting on port %d (LAG %d)\n",
2026+
port->actor_port_number,
2027+
port->aggregator->aggregator_identifier);
2028+
__enable_collecting_port(port);
2029+
}
2030+
}
2031+
2032+
/**
2033+
* ad_disable_distributing - disable a port's transmit
2034+
* @port: the port we're looking at
2035+
* @update_slave_arr: Does slave array need update?
2036+
*/
2037+
static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
2038+
{
2039+
if (port->aggregator &&
2040+
!MAC_ADDRESS_EQUAL(&port->aggregator->partner_system,
2041+
&(null_mac_addr))) {
2042+
slave_dbg(port->slave->bond->dev, port->slave->dev,
2043+
"Disabling distributing on port %d (LAG %d)\n",
2044+
port->actor_port_number,
2045+
port->aggregator->aggregator_identifier);
2046+
__disable_distributing_port(port);
2047+
/* Slave array needs an update */
2048+
*update_slave_arr = true;
2049+
}
2050+
}
2051+
19092052
/**
19102053
* ad_enable_collecting_distributing - enable a port's transmit/receive
19112054
* @port: the port we're looking at

drivers/net/bonding/bond_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6399,6 +6399,7 @@ static int __init bond_check_params(struct bond_params *params)
63996399
params->ad_actor_sys_prio = ad_actor_sys_prio;
64006400
eth_zero_addr(params->ad_actor_system);
64016401
params->ad_user_port_key = ad_user_port_key;
6402+
params->coupled_control = 1;
64026403
if (packets_per_slave > 0) {
64036404
params->reciprocal_packets_per_slave =
64046405
reciprocal_value(packets_per_slave);

drivers/net/bonding/bond_netlink.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
122122
[IFLA_BOND_PEER_NOTIF_DELAY] = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range),
123123
[IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 },
124124
[IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED },
125+
[IFLA_BOND_COUPLED_CONTROL] = { .type = NLA_U8 },
125126
};
126127

127128
static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
@@ -549,6 +550,16 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
549550
return err;
550551
}
551552

553+
if (data[IFLA_BOND_COUPLED_CONTROL]) {
554+
int coupled_control = nla_get_u8(data[IFLA_BOND_COUPLED_CONTROL]);
555+
556+
bond_opt_initval(&newval, coupled_control);
557+
err = __bond_opt_set(bond, BOND_OPT_COUPLED_CONTROL, &newval,
558+
data[IFLA_BOND_COUPLED_CONTROL], extack);
559+
if (err)
560+
return err;
561+
}
562+
552563
return 0;
553564
}
554565

@@ -615,6 +626,7 @@ static size_t bond_get_size(const struct net_device *bond_dev)
615626
/* IFLA_BOND_NS_IP6_TARGET */
616627
nla_total_size(sizeof(struct nlattr)) +
617628
nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS +
629+
nla_total_size(sizeof(u8)) + /* IFLA_BOND_COUPLED_CONTROL */
618630
0;
619631
}
620632

@@ -774,6 +786,10 @@ static int bond_fill_info(struct sk_buff *skb,
774786
bond->params.missed_max))
775787
goto nla_put_failure;
776788

789+
if (nla_put_u8(skb, IFLA_BOND_COUPLED_CONTROL,
790+
bond->params.coupled_control))
791+
goto nla_put_failure;
792+
777793
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
778794
struct ad_info info;
779795

drivers/net/bonding/bond_options.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond,
8585
const struct bond_opt_value *newval);
8686
static int bond_option_missed_max_set(struct bonding *bond,
8787
const struct bond_opt_value *newval);
88-
88+
static int bond_option_coupled_control_set(struct bonding *bond,
89+
const struct bond_opt_value *newval);
8990

9091
static const struct bond_opt_value bond_mode_tbl[] = {
9192
{ "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
@@ -233,6 +234,12 @@ static const struct bond_opt_value bond_missed_max_tbl[] = {
233234
{ NULL, -1, 0},
234235
};
235236

237+
static const struct bond_opt_value bond_coupled_control_tbl[] = {
238+
{ "on", 1, BOND_VALFLAG_DEFAULT},
239+
{ "off", 0, 0},
240+
{ NULL, -1, 0},
241+
};
242+
236243
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
237244
[BOND_OPT_MODE] = {
238245
.id = BOND_OPT_MODE,
@@ -497,6 +504,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
497504
.desc = "Delay between each peer notification on failover event, in milliseconds",
498505
.values = bond_peer_notif_delay_tbl,
499506
.set = bond_option_peer_notif_delay_set
507+
},
508+
[BOND_OPT_COUPLED_CONTROL] = {
509+
.id = BOND_OPT_COUPLED_CONTROL,
510+
.name = "coupled_control",
511+
.desc = "Opt into using coupled control MUX for LACP states",
512+
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
513+
.flags = BOND_OPTFLAG_IFDOWN,
514+
.values = bond_coupled_control_tbl,
515+
.set = bond_option_coupled_control_set,
500516
}
501517
};
502518

@@ -1812,3 +1828,13 @@ static int bond_option_ad_user_port_key_set(struct bonding *bond,
18121828
bond->params.ad_user_port_key = newval->value;
18131829
return 0;
18141830
}
1831+
1832+
static int bond_option_coupled_control_set(struct bonding *bond,
1833+
const struct bond_opt_value *newval)
1834+
{
1835+
netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n",
1836+
newval->string, newval->value);
1837+
1838+
bond->params.coupled_control = newval->value;
1839+
return 0;
1840+
}

include/net/bond_3ad.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ typedef enum {
5454
AD_MUX_DETACHED, /* mux machine */
5555
AD_MUX_WAITING, /* mux machine */
5656
AD_MUX_ATTACHED, /* mux machine */
57+
AD_MUX_COLLECTING, /* mux machine */
58+
AD_MUX_DISTRIBUTING, /* mux machine */
5759
AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */
5860
} mux_states_t;
5961

include/net/bond_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum {
7676
BOND_OPT_MISSED_MAX,
7777
BOND_OPT_NS_TARGETS,
7878
BOND_OPT_PRIO,
79+
BOND_OPT_COUPLED_CONTROL,
7980
BOND_OPT_LAST
8081
};
8182

0 commit comments

Comments
 (0)